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.
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



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.
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):
<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 / property | Default | Effect |
|---|---|---|
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
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.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.<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.