motion-curve
Animates each character of a sentence along a continuous sine-wave curve. Letters rotate to follow the tangent (the wave's direction at each point), giving the text a natural, fluid motion.
Preview
Import
import 'motion-components/motion-curve' // just this one
import 'motion-components' // or the whole libraryUsage
Static content
Write the text as a child. The browser shows it as plain text before the element is defined, so the page never paints an empty gap while the library loads.
<motion-curve amplitude="28" wave-length="260" wave-duration="2.5">
Make it wave.
</motion-curve>Dynamic content
Use the text attribute when text changes at runtime. Setting the property restarts the animation automatically.
const el = document.querySelector('motion-curve')
el.text = 'UPDATED' // animation restartsIf both are present, the attribute wins and the child text stays as the pre-upgrade fallback. For long marquee strings in loop mode, prefer the attribute: a long fallback would wrap across several lines before the element upgrades.
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.
<motion-curve
text="Make it wave · Physics-based · Zero CSS · "
loop
amplitude="22"
wave-length="320"
wave-duration="3.33"
loop-speed="70"
></motion-curve>Loop gap
By default a 48px gap separates each repetition. Set
<motion-curve
text="Spring physics · No CSS · Framework-free · "
loop
loop-gap="0"
></motion-curve>Pause on hover
Add pause-on-hover to freeze the wave (and scroll in loop mode) when the cursor enters, resuming on leave.
<motion-curve
text="Make it wave · Hover to pause · Zero CSS · "
loop
pause-on-hover
></motion-curve>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:
Properties
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
| | | string | — | The sentence to animate. Falls back to the child text when unset |
| | | number | 24 | Peak vertical offset in px |
| | | number | 280 | Horizontal distance of one full wave cycle in px |
| | | number | 2.5 | Seconds for one full wave cycle. Lower is faster, |
| | | 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 |
| | | boolean | false | Remove the vertical padding added to accommodate the wave. |
| | | boolean | false | Pause the wave and scroll on mouseenter, resume on mouseleave. |
JavaScript API
Control the curve programmatically with play(), pause(), finish(), and cancel().
Accessibility
When prefers-reduced-motion is set, the animation does not start and the text renders flat.