3D✨ Premium

Wave Path

Three violet, pink and cyan dots (14, 10 and 8 px) follow one another one second apart along a two-crest sine wave, at constant speed, in 4 s: a small line moving up and down the waves without the gaps changing — CSS only, zero JavaScript, three dots resting on the wave when the user reduces motion.

CSSWaveStagger

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

The duck and her ducklings on the pond — teaching farm page — Wave Path example 1

① The duck and her ducklings on the pond — teaching farm page

WhenAnnouncement of the week's births: the pond seen from above, the brown duck leads and two yellow ducklings follow her, weaving along the wake, above the visiting hours.
WhyThree dots of decreasing size following each other on the wave: it is the duck and her young, as is, and the constant gap says "they never lose her".
SettingsWave turned into a wake (white at 40%, dashed) on a blue pond, scene enlarged (transform: scale(1.6)); big brown dot #7c4a24 put in the lead (animation-delay: -2s), yellow ducklings at -1.35s and -0.8s, closer behind her; offset-rotate: 0deg.
The bunch on the hilly course — sportive ride page — Wave Path example 2

② The bunch on the hilly course — sportive ride page

WhenCourse presentation: the wave becomes the stage profile, filled in green, and three dots labeled "Leaders", "Bunch" and "Sweep car" ride up and down the hills, above the kilometer marks and feed stations.
WhyThe constant offset between the dots shows gaps that hold through the hills, which a table of split times says less quickly.
SettingsScene enlarged (transform: scale(1.5)); area under the curve added in the same svg (green gradient); "Leaders" = pink dot recolored red at -2s, "Bunch" = big blue dot at -1.1s, "Sweep car" = small gray dot at 0s; labels placed INSIDE the dots, hence offset-rotate: 0deg.
Three skiers on the mogul run — ski school page — Wave Path example 3

③ Three skiers on the mogul run — ski school page

WhenPage for the "moguls" class, 3rd star level: the tilted wave becomes a snowy run, and three skiers in red, yellow and blue take the moguls one behind the other.
WhyDots rising and falling one after the other, at constant speed, convey the steady rhythm of a mogul run, the one the instructor asks for.
SettingsScene tilted and enlarged (transform: rotate(13deg) scale(1.45)); snow added under the curve in the same svg, svg overflow made visible; dots recolored red, yellow and blue, original delays.

How it works

The .fx-0037-root root (background #0a0a0f, at least 300 px tall) centers a 300 × 200 px .mp-wave-scene. An <svg> draws, in white at 6%, a sine wave with two full crests: four 75 px wide cubic Bézier curves that rise and fall 37.5 px around the center line y = 100. Three .mp-wave-dot divs get the same path as offset-path: path(…) and the same animation: offset-distance from 0 to 100% in 4 s, linear, looping.

The offset is what makes the line. The 14 px violet dot #8b5cf6 starts at 0, the 10 px pink #ec4899 has animation-delay: -1s, the 8 px cyan #06b6d4 -2s: a negative delay starts the animation "midway", so the cyan one leads, the pink one is in the middle, and the big violet one brings up the rear, each a quarter of the path (111 px along the curve) from the next. With linear, the speed along the curve is constant: the gaps do not move, even on the climbs. At the end of the path, each dot starts again on the left; since the wave ends at the height where it begins, that return is a horizontal jump from one edge to the other.

The dots have no negative margin: the browser places their center on the path, so all three run exactly on the drawn line whatever their size (measured gap: 0.03 px in Chromium 151, Firefox 153 and WebKit 26). By default, offset-rotate is auto: each dot turns with the slope. On a circle you cannot see it; if you put a label or an icon in it, add offset-rotate: 0deg, as in the second scene above.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0037-root stops the three dots on the wave, at 15, 40 and 65% of the path: the same quarter gap, a crest, a trough, a crest. Measured: 0% of pixels change over 0.8 s in Chromium, Firefox and WebKit, versus 0.9% in normal mode.
  • Decorative content: the dots are empty divs ignored by screen readers. If each dot stands for someone or something (a group of riders, an animal), write it in a caption or in the dot, with offset-rotate: 0deg.
  • Contrast: on the dark background, all three colors pass the 3:1 threshold for graphical elements; the wave, at 6%, is only a guide. On a light background, darken it.
  • Rhythm: a 4 s loop at constant speed, no flashing.

Browser compatibility

CSS only: offset-path: path(), animated offset-distance and negative animation-delay, no JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26 (Safari's engine): same positions for the three dots, same gaps, same stop under reduced motion. Not checked on a real Safari.

Chrome 55+✓ Full
Firefox 72+✓ Full
Safari 16+✓ WebKit 26 measured, Safari not checked
Edge 79+✓ Full
Mobile iOS 16+✓ Not checked on a device
Android Chrome✓ Full

A browser without offset-path stacks the three dots, still, at the top left of the scene; the wave stays drawn.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0037-root">
  <div class="mp-wave-scene">
    <svg viewBox="0 0 300 200" fill="none">
      <path d="M0,100 C25,50 50,50 75,100 … 300,100" … />
    </svg>
    <div class="mp-wave-dot mp-wave-dot--1"></div>
    <div class="mp-wave-dot mp-wave-dot--2"></div>
    <div class="mp-wave-dot mp-wave-dot--3"></div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Colors and sizes (CSS — .mp-wave-dot--1, --2, --3) Violet 14 px, pink 10 px, cyan 8 px Change background, box-shadow, width and height. The center stays on the wave whatever the size: no margin to recompute.
Order and spacing of the line (CSS — animation-delay) 0s, -1s, -2s (a quarter of the path between two dots) The most negative delay leads. To put the big dot in front, swap them: -2s for --1, 0s for --3. Closer delays (-0.5s) tighten the line.
Speed (CSS — 4s in the animation) 4 s Keep the delays proportional to the duration (a quarter of the duration for a quarter of the path). linear keeps the gaps constant; another easing would make them vary.
Wave shape (HTML + CSS) 2 crests of 37.5 px over 300 px The path is written twice, in the svg path d and in the offset-path: change both.
Label or icon in a dot (HTML + CSS) Empty dots Put a span in the dot, with position: absolute, and add offset-rotate: 0deg to the dot, otherwise the text turns with the slope.
Background (CSS — .fx-0037-root) #0a0a0f Change or remove the background; on a light background, darken the wave (white at 6% by default).

FAQ

The path is open: it starts at the left edge and ends at the right edge, at the same height. At the end of each loop the dot starts over, which makes a horizontal jump. To soften it, put the scene in a frame narrower than the wave (overflow: hidden) so the jump happens out of view, or add a fade at both ends with opacity keyframes.
Yes, along the curve: with linear, each dot moves at the same speed on the path, and a quarter of the duration separates two dots. Seen horizontally, the gap varies a little, since the wave rises and falls; measured, all three dots stay on the line within 0.03 px in the three engines.
Wave Path is the only trajectory where several objects of different sizes follow each other on the same path at a fixed gap: a line. SVG Path Follow moves a single dot along a curve with a trail of echoes; Bounce Path bounces a ball lower and lower. For a group moving together (animals, riders, skiers), use Wave Path.