Docs
Cursor Attractor & Gravity

Cursor Attractor & Gravity

A set of wrapper components for creating physics-based attractors and gravity animations with Matter.js.

weanalyzemillionsofdatapointspersecondtoprovideyouwiththemostaccurateinsights.

Installation


npx shadcn@latest add "https://fancycomponents.dev/r/cursor-attractor-and-gravity.json"

Usage


First, you need to wrap your scene / content with the Gravity component. Set the attraction point coordinates in the attractorPoint prop. This point will either attract or repel all the bodies inside the container. Then, in order to transform your regular HTML elements into Matter bodies, you need to wrap them with the MatterBody component. You need to set each bodies x and y position, either as a percentage of your container size, or as a number. You do not need to set the width and height manually, everything else is taken care of by component :). Lastly, set the strength and radius of the cursor attractor, which will also attract or repell all bodies. High-level example:

<Gravity attractorPoint={{ x: "50%", y: "50%" }} attractorStrength={0.0006} cursorStrength={-0.005} cursorFieldRadius={200}>
  <MatterBody x="50%" y="50%">
    <div>Hello world!</div>
  </MatterBody>
  <MatterBody x="10%" y="10%">
    <div>fancy!</div>
  </MatterBody>
</Gravity>

Understanding the component


Please refer to the Gravity documentation, since the component is almost identical. The only difference is that in this component that we don't use a directional gravitational force.Instead, we use attractor force(s), either from a defined static point (optional), and/or from the cursor position, that attract or repel all bodies inside the container. This is achieved by calculating the distance between the attractor point(s) and each body, and applying a force in the opposite direction of the body's velocity. The force is proportional to the distance and inversely proportional to the mass of the body.

Examples


Repel


By setting one of the attractor points' strength to a negative value, you can create a repelling effect. The following demo showcases a negative force from the cursor by applying a negative value to the cursorStrength prop.

join the community

Avatar 0
Avatar 1
Avatar 2
Avatar 3
Avatar 4
Avatar 5
Avatar 6
Avatar 7
Avatar 8
Avatar 9
Avatar 10
Avatar 11
Avatar 12
Avatar 13
Avatar 14
Avatar 15
Avatar 16
Avatar 17
Avatar 18
Avatar 19
Avatar 20
Avatar 21
Avatar 22
Avatar 23
Avatar 24
Avatar 25
Avatar 26
Avatar 27
Avatar 28
Avatar 29
Avatar 30
Avatar 31
Avatar 32
Avatar 33
Avatar 34
Avatar 35
Avatar 36
Avatar 37
Avatar 38
Avatar 39
Avatar 40
Avatar 41
Avatar 42
Avatar 43
Avatar 44
Avatar 45
Avatar 46
Avatar 47
Avatar 48
Avatar 49

SVGs

Youy can choose svg as a bodyType for your matter bodies. This is particularly useful for creating custom-shaped physics objects that match your SVG graphics.

Here's how it works:

  1. The component takes your SVG element and extracts the path data
  2. It converts the path into a series of vertices (points) that outline the shape (with a custom converter using the svg-path-commander package)
  3. These vertices are then converted into polygons by matter.js (with the help of the poly-decomp package).
  4. The resulting polygons are then used to create Matter.js bodies

fancy components

As you can see in the demo above, SVG bodies can produce varying results. Simple shapes like some of the stars translate well, but some of them are a bit rough.

This variance in quality stems from the challenging process of converting SVG paths to physics bodies. Therefore, there are a few caveats to keep in mind:

  1. SVG Requirements:

    • Keep them simple. The simpler the SVG, the better the decomposition, and the simulation.
    • It's only tested with single-path SVGs, and it probably won't work with nested paths.
    • Avoid shapes with holes or complex curves, or shapes that are seem to be too complex to decompose into polygons.
  2. Performance Impact:

    • Complex SVGs create more detailed physics bodies, which can slow down the simulation
    • More vertices mean more calculations
    • The initial path-to-vertices conversion can be slow.

If you're not getting the desired results, you have several options:

  1. Break down complex SVGs into simpler shapes
  2. Use basic physics bodies (rectangles/circles) with the SVG as a visual overlay
  3. Fine-tune the vertex sampling with the sampleLength prop

You more than likely will need to experiment with different settings to get the desired results. Use the debug prop to visualize the physics bodies and their vertices, and adjust the sampleLength prop to control the accuracy of the conversion.

For more details on the decomposition process, refer to the poly-decomp documentation, the Matter.js documentation, and to the SVG path commander documentation.

Props


PropTypeDefaultDescription
children*React.ReactNode-The content to be displayed
attractorPoint{ x: number | string; y: number | string }{ x: 0.5, y: 0.5 }The attractor point coordinates
attractorStrengthnumber0.001The strength of the attractor force
cursorStrengthnumber0.0005The strength of the cursor force
cursorFieldRadiusnumber100The radius of the cursor field
resetOnResizebooleantrueWhether to reset the physics world when the window is resized
addTopWallbooleantrueWhether to add a wall at the top of the canvas
autoStartbooleantrueWhether to automatically start the physics simulation
classNamestring-Additional CSS classes for styling