OrbLoader
A floating orb with two pinging rings and a mark turning at its centre — the full-page hold, seated on your seam and your own logo rather than a stock spinner.
Install
$ npx shadcn@latest add wisp.pouriah.com/r/orb-loader.jsonLoader · CSSfull-screen
seated on your seam
"use client";
import * as React from "react";
import { cx } from "@pouriahlabs/wisp-ui";
/**
* OrbLoader — the full-page hold a product shows before it has anything to show.
*
* A radial-gradient orb that floats, two rings that ping outward on offset
* clocks, and a mark that turns and breathes at the centre. Everything is drawn
* from your two tokens: the orb's wash, the rings and the mark all read `--wisp`
* and `--lantern` (or whatever pair you point it at), so it turns with the rest
* of the page when the theme changes.
*
* Pass your own logo as children — that is the point of it over a stock spinner.
* With nothing passed it falls back to a seam-coloured dot, so it is never an
* empty ring. The whole thing is CSS: no timers, no canvas.
*/
export interface OrbLoaderProps extends React.HTMLAttributes<HTMLDivElement> {
/** Token for the orb's inner wash, the primary ring and the mark. */
fromToken?: string;
/** Token for the outer ring — the second half of the seam. */
toToken?: string;
/** Orb diameter, as any CSS length. */
size?: string;
/** Accessible status text announced while the loader is on screen. */
label?: string;
/** What sits at the centre — a logo mark, a glyph. Falls back to a seam dot. */
children?: React.ReactNode;
}
export function OrbLoader({
fromToken = "--wisp",
toToken = "--lantern",
size = "8rem",
label = "Loading",
className,
children,
style,
...props
}: OrbLoaderProps) {
return (
<div
className={cx("wisp-orb", className)}
role="status"
aria-live="polite"
aria-label={label}
style={
{
"--wisp-orb-from": `var(${fromToken})`,
"--wisp-orb-to": `var(${toToken})`,
"--wisp-orb-size": size,
...style,
} as React.CSSProperties
}
{...props}
>
<span className="wisp-orb-core" aria-hidden>
<span className="wisp-orb-ring is-primary" />
<span className="wisp-orb-ring is-secondary" />
<span className="wisp-orb-mark">{children ?? <span className="wisp-orb-dot" />}</span>
</span>
</div>
);
}
Certified against the contract
- ✓Reduced motion paints one composed still frame — never a blank box
- ✓Pauses off-screen and in hidden tabs
- ✓Re-reads design tokens when the theme changes
- ✓SSR-safe: no hydration mismatch, no layout shift
- ✓Decorative layers are aria-hidden and pointer-events-none
- ✓Device pixel ratio clamped
- ✓Zero runtime dependencies beyond React