motion-curve
Animates each character of a sentence along a continuous sine-wave curve. Letters rotate to follow the tangent, giving the text a natural, fluid motion.
Preview
Import
Usage
Loop mode
Add loop to scroll the text continuously like a ticker, with the wave applied as it travels. The text is duplicated for a seamless loop.
Loop gap
By default a 48px gap separates each repetition. Set loop-gap="0" for continuous text with no visible break.
Pause on hover
Add pause-on-hover to freeze the wave (and scroll in loop mode) when the cursor enters, resuming on leave.
How it works
Each character is wrapped in an inline-block span. After render, the component measures each span's pixel x-offset. A
requestAnimationFrame loop then computes a sine value and tangent angle for each character based on its x-position and the current phase, applying
translateY + rotate. The phase advances each frame, making the wave travel through the text.
The rotation is derived from the curve's tangent: angle = atan(A · k · cos(kx − phase)), so letters lean naturally into the curve rather
than staying upright.
Properties
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
| | | string | — | The sentence to animate |
| | | number | 24 | Peak vertical offset in px |
| | | number | 280 | Horizontal distance of one full wave cycle in px |
| | | number | 0.4 | Wave cycles per second |
| | | boolean | false | Scroll the text in a seamless continuous loop |
| | | number | 80 | Horizontal scroll speed in px/s (loop mode only) |
| | | number | 48 | Space in px between the end of one loop repetition and the start of the next. Set to 0 for continuous text with no gap. |
| | | boolean | false | Remove the vertical padding added to accommodate the wave. |
| | | boolean | false | Pause the wave and scroll on mouseenter, resume on mouseleave. |
Accessibility
When prefers-reduced-motion is set, the animation does not start and the text renders flat.