webdevpuneet.com

Wave Loader — Liquid Fill Loader HTML CSS JS SVG

Wave Loader · Loaders · Plain HTML, CSS & JS · Live preview

CategoryLoaders

Copy & paste

Source Code

<div class="wl-stage">
  <div class="wl-orb">
    <svg class="wl-svg" viewBox="0 0 120 120">
      <defs><clipPath id="wlClip"><circle cx="60" cy="60" r="56"/></clipPath></defs>
      <circle cx="60" cy="60" r="56" class="wl-ring"/>
      <g clip-path="url(#wlClip)">
        <rect x="0" y="0" width="120" height="120" class="wl-fill" id="wlFill"/>
        <path class="wl-wave" id="wlWave1"/>
        <path class="wl-wave wl-wave2" id="wlWave2"/>
      </g>
    </svg>
    <div class="wl-pct" id="wlPct">0%</div>
  </div>
  <input type="range" id="wlRange" min="0" max="100" value="65" aria-label="Fill level">
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Sine-generated waves
The rippled surface is an SVG path built from sin(), so amplitude and wavelength are parameters.
Two-layer parallax
Two waves at different speeds and directions give the liquid depth and life.
Seamless looping
The path is double-width so it slides one wavelength and loops without a seam.
Clip-path container
Rectangular waves are masked to the orb shape via a clipPath.
Level-driven fill
The fill level sets the wave baseline, from empty at 0% to full at 100%.
Centred percentage
A tabular-figures label shows the level over the liquid.
Pure-CSS ripple
The horizontal slide is a CSS animation, independent of the fill level.
Reshapeable & no library
Swap the clip shape to refill any outline — plain HTML/CSS/SVG/JS.

About this UI Snippet

Wave Loader — A Liquid-Fill Orb with Two Animated Sine Waves

Screenshot of the Wave Loader snippet rendered live

The wave (or liquid-fill) loader shows progress as liquid rising in a container, its surface rippling with animated waves — a richer, more organic alternative to a plain bar or spinner. This snippet builds it in plain HTML, CSS, SVG, and vanilla JavaScript: a circular orb that fills to any percentage with two layered sine waves sliding across the surface — no library.

Waves drawn as sine paths

The wave surface is an SVG path generated from the sine function: wavePath() walks across the width sampling sin() to build the rippled top edge, then closes the path down to the bottom to form a filled body of liquid. The path is drawn twice as wide as the orb (240 across a 120 viewBox) so it can slide a full wavelength and loop seamlessly. Generating the wave from sin() (rather than a static image) means the amplitude, wavelength, and fill level are all parameters you control.

Two layers for depth

Two wave paths are stacked — one taller-amplitude and more opaque, one shorter and translucent — animated at different speeds and opposite directions. This parallax of two offset waves is what makes the liquid look alive and three-dimensional rather than a single flat ripple; it is the same trick used in app liquid-progress widgets. A faint static fill rectangle behind them gives the body colour.

Clipped to the container shape

Everything inside the orb is wrapped in a clipPath of the circle, so the rectangular waves and fill are masked to the round shape — the liquid appears to sit inside the orb with a clean curved edge. Swapping the clip shape (a rounded rect, a logo path) reshapes the container without touching the wave logic, which is the flexibility the clip approach gives.

Level-driven fill

The fill level (0–100%) sets the waves' baseline y — at 100% the surface is at the top, at 0% at the bottom — and a percentage label sits centred over the orb. Here a slider drives the level live so you can see it fill and drain; in real use you would set the level from your actual progress (upload percent, score, capacity). The horizontal sliding is pure CSS animation, independent of the level, so the liquid keeps rippling at any fill.

Drop-in and adaptable

Tune the wave amplitude, wavelength, colours, and speeds, or change the clip shape to fit your design. It is a complete, dependency-free reference for sine-wave path generation, layered wave parallax, and clip-path container masking — the foundation of any liquid-fill loader or gauge. Because update() rewrites the d attribute on every change rather than only animating the CSS slide, regenerating the path is the right place to put any easing if you switch the level from a slider to programmatic progress updates — wrap the level changes in a short transition loop (or animate a JS value over a few hundred milliseconds and call update() each frame) so the surface rises smoothly instead of jumping straight to the new height.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA liquid orb renders, filled with two rippling waves, and a slider to set the level.
  2. 2
    Drag the sliderChange the fill level 0-100% and watch the liquid rise or drain while the waves ripple.
  3. 3
    Drive from real progressSet range.value (or call update with your level) from upload percent, score, or capacity.
  4. 4
    Tune the wavesAdjust the amplitude, wavelength, and animation speeds for calmer or choppier liquid.
  5. 5
    Reshape the containerChange the clipPath shape to a rounded rect or logo to fill a different outline.
  6. 6
    Restyle itEdit the wave colours, body fill, and ring to match your theme.

Real-world uses

Common Use Cases

Upload and download progress
Show transfer progress as liquid rising in an orb, with the surface path built from sin() so amplitude and wavelength stay adjustable.
Capacity and storage meters
Visualise used capacity alongside a quota usage meter, where the fill level reads instantly without a number.
Score and goal completion
Offer a playful fill for scores or goals, next to activity rings in a fitness or learning dashboard.
Water and battery trackers
Display hydration or charge as a liquid level, with two parallax wave layers moving at different speeds for depth.
Calming hero accents
Place beside a breathing animation in a wellness page, using a double-width path that loops seamlessly.

Got questions?

Frequently Asked Questions

wavePath() walks across the width in small steps, computing each point's y as the fill baseline plus sin(x) × amplitude, building an SVG path of the rippled surface, then closes it down to the bottom to form a filled body. Because it is generated from sin() rather than a fixed image, you control the amplitude (wave height), wavelength, and baseline (fill level) as parameters.

A single ripple looks flat. Stacking two waves — one taller and more opaque, one shorter and translucent — animated at different speeds and opposite directions creates a parallax that reads as real, three-dimensional liquid. This layered-wave technique is what app liquid-progress widgets use to make the fill feel alive at any level.

The wave path is drawn twice as wide as the visible orb (240 across a 120 viewBox). The CSS animation translates it left by exactly one orb-width (120px), so when it resets, the second half of the wave has moved into the position the first half started in — a continuous sine pattern means the wave looks identical, and the loop is seamless.

The fill level comes from the slider's 0-100 value, which sets the wave baseline and the static fill height. In real use, set that level from your actual progress — assign range.value or call update() with your percentage from an upload's loaded/total, a score, or a capacity figure. The wave ripple animation is independent of the level, so it keeps moving as the liquid rises.

Hold the fill level in state and recompute the wave path d attributes from it in the render (or imperatively via a ref). In React use useState and set the paths in an effect or inline; in Vue bind :d with a computed; in Angular bind [attr.d] with a getter. The wavePath() sine math and the CSS ripple animation are framework-agnostic — only the level state moves into the framework.