Utilities✨ Premium

Hypno Cascade

A pure-CSS waiting indicator: 24 rainbow petals breathe in a wave around a label read by screen readers, at whatever size you need.

CSSsibling-indexZero-JS

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Budget app — one account syncing in the list — Hypno Cascade example 1

① Budget app — one account syncing in the list

WhenIn Sorevance, the "My accounts" list opens: the current account and the savings account are up to date, the joint account is syncing with its bank. In place of its balance, a 52 px crown spins next to "Syncing…", then the balance comes back with "just now".
WhyThe wait does not lock the screen: only the row concerned shows it, the other balances stay readable. Scaled down, the crown keeps its 24 petals and fits in the height of a list row; the hidden label "Syncing the joint account" is still read by screen readers.
Settings--hcx-size: 52px, 52×52 px root in the row, .hcx-label visually hidden by the scene CSS, visible text next to it in aria-hidden. The scene shows the crown for 1.6 s then the balance for 1.3 s, in a loop (hidden attribute on the block that holds the root).
Full-screen ride search — waiting without a blank screen — Hypno Cascade example 2

② Full-screen ride search — waiting without a blank screen

WhenAfter picking departure and arrival in the Trajenda carpool app, the dark screen shows the large crown breathing in the centre, the requested trip at the top and a tip at the bottom.
WhyLarge, the rainbow wave fills the wait: the screen does not look frozen, and the word "Searching" says what is going on.
Settings--hcx-size: 250px, label "Searching", stylised map background under the crown. Original colours and timing.
Sofa configurator — a waiting veil after "Apply" — Hypno Cascade example 3

③ Sofa configurator — a waiting veil after "Apply"

WhenIn the Atelier Sofrandel configurator, you pick a fabric then "Apply": a dark veil covers the preview with the crown and "Updating…", then the preview comes back in the new colour.
WhyThe indicator appears in response to a click, exactly where things will change: it is clear that the preview is being recomputed, not the whole page.
Settings--hcx-size: 230px in an rgba(18, 14, 26, .72) veil shown through the hidden attribute. The click, the 1.3 s wait and the fabric change are played by the scene, looped for the capture.

How it works

The crown holds 24 .hcx-petal petals. Each one is rotated, tinted and delayed according to its place: sibling-index() when the browser knows it (Chrome 138, Safari 26.2), otherwise the --i variable written in the HTML. The hue follows the colour wheel in oklch; each petal stretches and shrinks over 2.4 s (hcx-breathe), 0.1 s after its neighbour, which sends a wave of light around the ring.

The tints go through two colours declared with @property (--hcx-tint, --hcx-glow): this way each petal computes its own. That is what fixes Safari 26, which otherwise painted the whole crown in the same pink.

Size is set with --hcx-size on the root (300 px by default). All petal measurements are in container units (cqi): the crown keeps its proportions at 64 px as at 300 px, and shrinks by itself in a container narrower than --hcx-size. No JavaScript: it is up to you to show the indicator when the wait starts and remove it when it ends.

Accessibility

  • Wait announced: the label carries role="status". For it to be read, insert the indicator into the page when the wait starts, or change the label text at that moment: a status region announces its changes, not its initial content.
  • Decorative crown: the petals sit in an aria-hidden="true" container, and so do the animated dots; only the word is read.
  • Reduced motion: under prefers-reduced-motion: reduce, petals stop at mid-length, clearly visible (opacity 0.8), and the dots stop blinking. The indicator stays, frozen.
  • Small sizes: below about 120 px, the label runs over the petals; hide it visually (keeping role="status") and write the wait next to it, as in the account row example.

Browser compatibility

100 % CSS. oklch colours: Chrome 111, Firefox 113, Safari 15.4. Container units: Chrome 105, Firefox 110, Safari 16. @property: Chrome 85, Firefox 128, Safari 16.4. sibling-index(): Chrome 138, Safari 26.2, Firefox 154 (not available in Firefox 153: the --i variable takes over). Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): each petal has its own hue in all three, sizes 300, 160 and 120 px, two copies, reduced motion, 0 errors.

Chrome 111+✓ Full (measured)
Firefox 113+✓ Full, rotation through --i (measured)
Safari 16.4+✓ Full (measured in WebKit)
Edge 111+✓ Full (Chromium engine)
Mobile iOS 16.4+✓ WebKit engine, not checked on a device
Android Chrome 111+✓ Full (Chromium engine)

Without oklch (old browsers), the crown loses its rainbow: plain pink petals, or no colour at all depending on the browser; the label remains. Without container units, petals lose their dimensions: plan a plain waiting message for those browsers if you target them.

The code

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

index.html — structure
<div class="fx-0818-root">
  <div class="hcx-stage">
    <div class="hcx-ring" aria-hidden="true">
      <span class="hcx-petal" style="--i: 0"></span>
      <!-- … 24 petals, --i from 0 to 23 -->
    </div>
    <p class="hcx-label" role="status">Generating<span class="hcx-dots" aria-hidden="true">…</span></p>
  </div>
</div>

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

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Size (CSS — --hcx-size on .fx-0818-root) 300px From 64 px (in a button, a bubble) to 400 px (a waiting screen). Petals, radius and glow follow.
Speed (CSS — hcx-breathe duration in .hcx-petal) 2.4s 1.6 s for a brisk wait, 4 s for a calm screen; also change the -.1s offset to keep a single wave.
Colours (CSS — --hcx-tint in .hcx-petal) oklch(78% .29 hue) around the whole wheel Set your brand's lightness and chroma, or replace 360 with 120 in the hue calculation for a gradient over a third of the wheel.
Label (HTML — text of .hcx-label) "Generating" The word that describes the wait: "Searching", "Calculating", "Sending". Keep it short, it has to fit inside the ring.
Background (CSS — background of .fx-0818-root) #0a0a0f, 300 px minimum height The glowing petals stand out on a dark background; set min-height: 0 to drop it into a component.

FAQ

Firefox 153 does not know sibling-index() yet (planned for Firefox 154): without --i, all petals would stack there. The CSS uses sibling-index() when available and falls back to --i otherwise.
Insert the root, or remove the hidden attribute from a block around it (set on the root itself, it does not hide it: its display: flex wins), just before calling your server, then remove it in the promise's finally. The indicator has no JavaScript: it runs as long as it is in the page.
Yes: change the number of <span class="hcx-petal"> and the --n value (24) in .hcx-petal. With 12 petals, widen them a little (width) to keep a dense crown.