Start with occupation, not animation
Before text can loop or collide on a path, you need to know how much of the path it actually occupies. That single measurement — the rendered text width as a fraction of arc length — is the foundation everything else builds on.
This lab breaks the problem into live prototypes. The first two show how to measure and animate a seamless marquee. The third introduces physics: a text block that slides, settles, and eventually collides with others.
1. Measuring text length on a path
SVG's textLength attribute can force a span, but for a natural marquee you want the real rendered width — which means one JS call to getComputedTextLength(). Once you have that number, the animation itself can be entirely declarative.
Declarative: SVG SMIL
SVG has native animation support via SMIL. With the measured span and gap converted to path percentages, the browser can drive the marquee without any per-frame script.
The SMIL version runs in the browser's own animation engine — no frame callbacks, no state updates. The tradeoff: it is static after setup. Changing text or timing requires rebuilding the animated elements (the demo re-keys the group on gap changes, which causes a brief flash). Pause and resume require calling the SVG-level pauseAnimations() API rather than toggling a flag. SMIL is also formally deprecated in favour of CSS/Web Animations, though all major browsers still support it.
Imperative: requestAnimationFrame
For full runtime control — dynamic text, smooth gap changes, play/pause, speed scrubbing — a RAF loop gives complete flexibility.
Steps to reproduce a seamless text marquee on an SVG path:
- Measure in SVG units. Render the text in a hidden off-screen
<text>element using the same font settings as the visible copies. CallgetComputedTextLength()— this returns the natural glyph width in SVG user units, the same coordinate system as the path, so no scaling conversion is needed. - Convert to a path percentage. Divide the text width by the path's total arc length and multiply by 100. This is the fraction of the path a single copy occupies.
- Add the gap. Convert the desired gap between copies from SVG units to a path percentage the same way. The loop step is
textSpan + gapSpan. - Generate copies. Place the first copy at offset
−scrollPct(just behind the path origin), then repeat everystepuntil the offset exceeds 100%. - Animate with the correct period. Advance
scrollPcteach frame byspeed × dt. Wrap atstep, not at 100. Because the visual pattern repeats exactly everystep, the wrap lands in an indistinguishable state and the loop is seamless.
2. Gravity well
A text block on a path can be represented as a 1D interval: a center percentage and a fixed occupied span. Gravity is then simply the y-component of the normalized path tangent at that center point. When the path slopes downward, ty is positive and the block accelerates forward; when it slopes upward, ty is negative and the block decelerates. No spring target is needed — the well emerges from the path geometry itself.
The path is presampled at 600 arc-length-equal intervals. Each frame the physics reads the tangent ty at the block's center, integrates the resulting acceleration (with linear friction), and updates the path percentage. The HUD shows the live slope value so the relationship between geometry and motion stays visible.