Liquid✨ Premium

Splash Effect

On click, 30 blue droplets burst from the touched point, rise, fall back under gravity, and three indigo rings widen 100 ms apart, on a canvas that keeps a trail: a brief, punchy splash, drawn as vectors so it stays sharp on Retina screens — 5.2 KB of JavaScript, no frame computed between two clicks.

CanvasInteractiveParticles

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Liquid has 31 effects, including 6 free. Explore the category →

3 usage examples

A shot that lands "in the water" — online naval battle game — Splash Effect example 1

① A shot that lands "in the water" — online naval battle game

WhenOn the opponent's grid, the player fires at B7 and misses: a spray bursts from the cell, a white dot marks the missed shot and the message "Splash! Miss in B7" shows under the grid.
WhyThe spray falling back says "missed, in the water" in a split second; a slow wave would slow the game down.
SettingsFull-frame canvas, a 10 × 8 grid of 31 px cells laid on top with pointer-events: none; a scene script listens to the same click on .splash-container to name the cell and count shots; as long as nobody has touched, the scene replays a splash every 1.9 s through a simulated click, stopped at the first real gesture and absent under reduced motion.
Wishing fountain — fundraising page of a neighborhood committee — Splash Effect example 2

② Wishing fountain — fundraising page of a neighborhood committee

WhenThe square's fountain seen from above, the "148 wishes made" counter and the instruction "Touch the water to toss a coin"; each touch in the basin sends up a spray and adds a wish.
WhySpray and rings start from the exact spot that was touched, like the falling coin: immediate, cheerful feedback for a symbolic gift.
SettingsFull-frame canvas; stone rim and paving in a radial gradient laid on top, with a 158 px radius basin cut out: drops leaving the basin pass under the paving; counter with role="status" that only goes up for a touch inside the basin; same demo loop as the previous example.
Reporting a water leak on the sidewalk — map in a city's citizen app — Splash Effect example 3

③ Reporting a water leak on the sidewalk — map in a city's citizen app

WhenOn the neighborhood map, the resident touches the spot of the leak: the splash starts from the touched point, a pin drops there and the bottom card reads "Leak reported — rue des Tanneurs".
WhyThe splash marks the exact spot then fades quickly: it confirms the report without hiding the map.
SettingsFull-frame canvas under a translucent SVG map (blocks at 7% opacity, streets at 16%) that lets the spray show; pin and nearest street name set by a scene script on the same click; confirmation card with role="status".

How it works

The .fx-0399-root block is 300 px high and takes the full available width. Its .splash-container (pointer cursor) holds a <canvas class="splash-canvas"> set to display: block at 100% of the frame, painted #1a1a24, and a help line at the bottom, "Click to create a splash". The height comes from the root's CSS and the canvas fits into it: 20 resizes in a row, 0 px of drift (Chromium and Firefox).

A click creates 30 droplets at the touched point. Each one sets off in a random direction at 2 to 8 px per frame, with a 5 px upward push, then gravity adds 0.2 px per frame downward: the spray rises in a crown and falls back. Radius 2 to 6 px, hue 200 to 240° (sky blue to indigo blue), opacity dropping by 0.02 to 0.04 per frame: each drop lives 25 to 50 frames. At the same time three indigo rings (rgba(99, 102, 241)) go off, at 0, 100 and 200 ms: they grow by 3 px per frame from 5 to 80 px radius while fading, their stroke going from 3 px to nothing. On every frame the canvas is not cleared but covered with a 20% opacity veil of the background: earlier frames fade out over a few frames, hence the trails behind the drops.

The loop only runs during a splash. Once the last drop and the last ring are gone, the script runs 30 more frames of veil to wipe the trails, repaints the background clean and stops: about 77 frames in all (1.3 s at 60 Hz), then 0 calls to requestAnimationFrame until the next click (measured). It also pauses off screen (IntersectionObserver) and when the tab is hidden. The canvas holds devicePixelRatio pixels per CSS pixel (up to 3) and the script draws in CSS pixels thanks to setTransform: drops and rings stay round and sharp on Retina screens. Measured cost: under 0.1 ms per frame in Chromium and WebKit, up to 4 ms in Firefox depending on canvas size (the veil repaints the whole surface). The script animates every .fx-0399-root on the page separately.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, nothing bursts or falls. The 30 drops appear straight away in a crown around the touched point (12 to 52 px, flattened by 30% vertically) along with three still rings of 18, 34 and 50 px; everything fades in place, without moving, within 25 to 50 frames. Measured in Chromium and Firefox: the loop then stops by itself.
  • Keyboard: the splash follows the click (mouse or finger), not the keyboard. When it goes with an action (a shot, a donation, a report), trigger the action through a button or form reachable by keyboard and announce the result in a role="status" area; the splash is only its visual echo.
  • Brevity: the splash lasts under two seconds and carries no information on its own. Always write the result as text ("Splash! Miss", "Wish made", "Leak reported"), as in the three examples.
  • Contrast: the help text, white at 50% on #1a1a24, reaches 5.2:1 (computed).

Browser compatibility

Canvas 2D (arc, setTransform, globalAlpha), ResizeObserver, IntersectionObserver, matchMedia: 5.2 KB of JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26: same spray, same rings, canvas at 1,280 × 600 on a Retina screen, loop stopped between clicks, still crown under reduced motion, 0 errors. Speeds and durations are counted per displayed frame: on a 120 Hz screen the splash lasts half as long as at 60 Hz.

Chrome 64+✓ Full
Firefox 69+✓ Full
Safari 13.1+✓ Full
Edge 79+✓ Full
Mobile iOS 13.4+✓ Full (by touch)
Android Chrome 64+✓ Full (by touch)

Without ResizeObserver, the script follows the window resize event; without IntersectionObserver, a splash in progress finishes off screen. Without JavaScript, the frame stays empty with its help text.

The code

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

index.html — structure
<div class="fx-0399-root">
  <div class="splash-container">
    <canvas class="splash-canvas"></canvas>
    <span class="splash-hint">Click to create a splash</span>
  </div>
</div>

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

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Number of drops (JS — for (var i = 0; i < 30; i++) in the click listener) 30 12 drops for a discreet drip, 60 for a dense spray.
Force and gravity (JS — 2 + 6 * Math.random(), - 5, this.gravity = 0.2) 2 to 8 px per frame, 5 px upward push, gravity 0.2 A - 2 push and a 0.1 gravity give a low, slow spray; a - 8 push, a high jet. With zero gravity, the drops fly out in a star, shifted upward by the push, without falling back.
Colors (JS — 'hsl(' + (200 + 40 * Math.random()) + ', 80%, 60%)' and rgba(99, 102, 241, …)) sky blue to indigo drops, indigo rings 'hsl(' + (150 + 30 * Math.random()) + ', 70%, 55%)' for a green splash. Keep lightness between 55 and 65% so the drops stand out from the dark background.
Trail (JS — TRAIL = 'rgba(26, 26, 36, 0.2)') background veil at 20% 0.4 wipes almost everything from one frame to the next (sharp drops, no trail); 0.1 stretches trails into long threads. Keep the same color as BACKGROUND.
Rings (JS — this.maxRadius = 80, this.speed = still ? 0 : 3, 100 and 200 ms delays) from 5 to 80 px, +3 px per frame, three rings maxRadius = 140 for wider rings that last longer; remove both setTimeout calls for a single ring.
Background (JS — BACKGROUND = '#1a1a24' and the root's CSS) #1a1a24 Change the color here, in TRAIL (same values as rgba) and on .fx-0399-root. The canvas is opaque: it repaints its background on every frame.

FAQ

Yes, without touching the script: send a click to the container, container.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: x, clientY: y })), with window coordinates (the canvas corner plus the offset you want). That is what the examples do to replay the splash every 1.9 s as long as nobody has touched.
Not as is: the canvas is opaque, it repaints its background (#1a1a24) at 20% on every frame to make the trails. For a transparent canvas, replace that veil with a partial erase, ctx.globalCompositeOperation = 'destination-out' then the same fillRect at 20% and back to 'source-over', and the final repaint with ctx.clearRect; the photo then shows underneath, trails included.
Splash Effect is a brief gesture: a spray of drops that rises and falls back in under two seconds, on a dark background. Water Ripple simulates a water surface: a slow wave that spreads, bounces off the edges and mixes with others for several seconds. Pick Splash Effect for an energetic reaction (a shot, a donation), Water Ripple to leave a calm trace where the user touched.