crucıble

Swell

Sprung wave lattice: depth-graded rows of smooth lines ride an orbital noise field with woven coherence while a slow autonomous swell front rolls through every ~8s. Cursor swipes inject velocity impulses along the travel direction, proportional to cursor speed, then spring home on damped Hooke springs with a tanh soft-clip on stretch. Deep-sea steel default. Canvas 2D, seeded, offscreen-paused, DPR-clamped with device-pixel-aligned strokes, reduced-motion-safe (crest frozen mid-roll); idles on its own when untouched — a seeded ghost cursor swipes through.

canvasfree

Installation

CLI

npx shadcn@latest add @crucible/swell

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal""horizontal" — rows of swell lines, depth rising toward the bottom of the frame (an open-sea read). "vertical" — hanging curtains of line with seeded depth layers.
gap{ x: number; y: number }{ x: 28, y: 26 }Lattice spacing in CSS px: x = horizontal spacing, y = vertical spacing. For horizontal orientation y sets the row gap and x the sample step along each row (vertical orientation swaps roles). Each axis clamped 8–200.
amplitudenumber16Idle wave amplitude in CSS px — how far points orbit their anchors.
speednumber1Animation-speed multiplier for drift and the swell front. 1 = default.
intensitynumber1Line brightness, 0–2.
tensionnumber150Spring stiffness pulling displaced points home (per s²). Higher = faster, tighter snap-back. Clamped 1–600.
frictionnumber0.93Spring velocity retention per frame at 60fps, 0–0.999 (applied frame-rate-independently). Lower = deader, higher = wobblier.
maxStretchnumber48CSS-px displacement the cursor can stretch a point toward. Rendered through a tanh soft-clip, so stretch saturates smoothly — never a hard stop.
swellIntervalnumber8Period in seconds of the autonomous swell front — a slow pressure wave that rolls through the lattice so the field breathes with no cursor.
colors[string, string]["#31404f", "#7dd3fc"]Two tones [far, near] graded across row depth. Defaults to deep-sea steel: dim slate far rows rising to cyan-tinged near rows. Pass warm tones for a dune-wind look.
interactivebooleantrueWhen true, cursor swipes inject velocity impulses along the travel direction, proportional to smoothed cursor speed, then spring back.
idlebooleantrueIdle autoplay: after ~1.5s with no real pointer, a seeded ghost cursor sweeps slow figure-eights through the lattice (with an occasional faster swipe) so thumbnails and heroes never sit still; the real pointer takes over instantly. Requires interactive. Never runs under reduced motion.
seednumber1Deterministic seed for depth layout and drift phases.
dprnumber2devicePixelRatio ceiling. Clamped 1–2.
pausedbooleanfalseFreeze at a static frame with the swell front mid-roll (never flat).
Also accepts all props of React.ComponentPropsWithoutRef<"div"> — they pass through to the underlying element.

Honors prefers-reduced-motion with a designed static fallback, pauses offscreen and on hidden tabs, and passes className through.