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
text text string The sentence to animate
amplitude amplitude number 24 Peak vertical offset in px
wave-length waveLength number 280 Horizontal distance of one full wave cycle in px
speed speed number 0.4 Wave cycles per second
loop loop boolean false Scroll the text in a seamless continuous loop
loop-speed loopSpeed number 80 Horizontal scroll speed in px/s (loop mode only)
loop-gap loopGap 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.
no-pad noPad boolean false Remove the vertical padding added to accommodate the wave.
pause-on-hover pauseOnHover 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.