Infinity Loop
A pink dot closely followed by a blurred glow travels endlessly along a sideways figure eight (∞) drawn as a thin line, at constant speed, 5 s per loop, never stopping — pure CSS with offset-path; when the visitor asks for less animation, the dot waits still at the top of the right loop.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →
3 usage examples



How it works
On a #0a0a0f background at least 300 px tall, .fx-0034-root puts a 300 × 200 px scene, .mp-infinity-scene, in the middle. The eight is drawn there by an <svg> of the same dimensions (viewBox="0 0 300 200"), in pink at 12% with a 1.5 px line: four Bézier curves that leave the central crossing (150, 100), loop on the right, come back through the crossing and loop on the left. Total length: 479 px.
The 16 px dot (#ec4899, glow as a box-shadow) and, under it, an 8 px pink disc at 40% softened by filter: blur(4px) are anchored to the scene's upper left corner. Their offset-path: path(…) repeats the SVG drawing word for word, so their center hugs the line of the eight: 0.1 px off at most, whichever engine is tested. A mpOrbit loop pushes offset-distance up to 100% in 5 s, linear, forever: roughly 96 px per second, in the bends as at the crossing, and the closed path brings the dot back to the center, where it sets off again without a hitch.
For the glow, animation-delay: -4.8s: on a 5 s loop, starting 4.8 s early amounts to lagging 0.2 s behind, about twenty pixels, from the first frame. That short pink trail shows which way the dot is going. The code has no JavaScript and no id, and two eights on the same page turn independently. If the system asks for reduced motion, a media query aimed only at .fx-0034-root holds the dot at the top of the right loop (18% of the course) and the glow just before it (15%).
Accessibility
- Less animation: when the visitor has asked for it (
prefers-reduced-motion: reduce), dot and glow stay put on the right loop, the glow on the side the dot comes from. Checked in Chromium, Firefox and WebKit: no active animation left, not one pixel moving over 800 ms. - Continuous motion: the loop never stops on its own. Avoid placing it next to a long text to read; in an exercise where following the dot is the goal (first example), add a button that sets
animation-play-state: pausedon both circles. - Path contrast: the pink at 12% is a faint guide. If the drawing of the eight matters (an exam course), raise it to 30% or more, or use white dashes on a dark background as in the second example.
- Nothing to operate: mouse, finger and keyboard have no effect on the eight. Hide the root from screen readers (
aria-hidden="true") and write the instruction next to it.
Browser compatibility
Pure CSS: offset-path: path(), animated offset-distance, filter: blur(), inline SVG for the line. No dependency, no JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5: dot and glow centered on the line (less than 0.1 px off), glow behind the dot, stop under reduced motion, two independent copies.
Without offset-path (Safari before 16), the eight shows but the dot and its glow stay still in the scene's top left corner (measured by removing the property). An @supports not (offset-path: path("M 0 0")) rule can hide them.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0034-root">
<div class="mp-infinity-scene"> <!-- 300 × 200 px -->
<svg viewBox="0 0 300 200" fill="none">
<path d="M150,100 C150,55 210,30 230,70 … C90,170 150,145 150,100" …></path>
</svg>
<div class="mp-infinity-glow"></div> <!-- blurred glow, 0.2 s behind -->
<div class="mp-infinity-dot"></div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Loop duration (CSS — 5s in both animations) |
5 s | Change it on the dot AND the glow, and recompute the glow's delay: delay = -(duration - lag). For 8 s and a 0.2 s lag: -7.8s. |
Glow distance (CSS — animation-delay of .mp-infinity-glow) |
-4.8s (0.2 s behind) |
-4.6s moves it to 0.4 s, about forty pixels: the trail shows more. |
Enlarge (CSS — transform: scale() on .mp-infinity-scene) |
none (168 × 100 px eight) | offset-path is in pixels: a scale() enlarges the line and the path together, whereas a width change would only distort the line. |
Line visibility (CSS — .mp-infinity-scene path { stroke: … }) |
pink at 12%, 1.5 px | The CSS rule wins over the SVG stroke attribute. Dashes (stroke-dasharray) give a track or road-marking look. |
Colors (CSS — background and box-shadow) |
pink #ec4899 |
Change the dot's color, its box-shadow and the glow together, or the trail looks like a different hue. |
Direction (CSS — reverse in animation) |
right loop, upward first | Add reverse to both circles: the glow stays behind the dot, its delay does not need to change. |
FAQ
d attribute and offset-path), with the same coordinates, in the 300 × 200 px scene's coordinate system. Keep a closed path that returns to its starting point, or the dot will jump from one end to the other on every lap. To simply enlarge it, transform: scale() on the scene is enough.