Solvent
Interactive fluid ink — a real GPU stable-fluids solver (semi-Lagrangian advection, vorticity confinement, Jacobi pressure projection) driving a persistent two-pigment dye field: cursor strokes push force and pigment into the fluid, so magenta and cyan inks swirl, fold through violet where they meet, and keep marbling long after the cursor stops. A seeded virtual cursor keeps it alive when idle and hands over to the real pointer with an exponential tween; two pigment blooms are pre-seeded so it is never blank on load. Half-res HalfFloat sim FBOs, adaptive Jacobi budget, DPR-clamped, offscreen-paused, reduced-motion-safe (a frozen ink marbling).
The preview is live. The source is Pro.
One purchase, lifetime access: every pro component's source, CLI install with your own registry token, and all future drops.
Installation
CLI
npx shadcn@latest add @crucible/solventManual — install dependencies, then copy the source
npm install oglProps
| Prop | Type | Default | Description |
|---|---|---|---|
| colors | [string, string, string] | iridescent magenta / cyan meeting through violet | Three ink tones: [pigmentA, pigmentB, midpoint]. Splats alternate slowly between the two pigments, and wherever the inks fold into each other the blend passes through the midpoint — real marbling reads. |
| force | number | Stir strength — how hard cursor strokes push the fluid, 0–3. 1 = default. | |
| splatRadius | number | 0.11 | Splat brush radius as a fraction of the container height. |
| dissipation | number | 0.9 | Fraction of ink kept after one second, 0.5–0.995. Higher holds marbling longer after the cursor stops; lower clears faster. |
| swirl | number | Vorticity-confinement boost, 0–3 — how much the flow curls back on itself into eddies instead of smearing straight. 1 = default. | |
| iterations | number | 20 | Jacobi pressure-solve iterations, 4–40. Higher is a crisper, more incompressible flow. Automatically capped at 12 on high-DPR displays and small viewports. |
| autoDemo | { speed?: number; intensity?: number; resumeDelay?: number } | false | { speed: 1, intensity: 0.85, resumeDelay: 2.5 } | Idle auto-demo: a seeded virtual cursor wanders the canvas and keeps the ink alive when nobody is interacting. speed scales its wander rate, intensity its ink output (both around 1), resumeDelay is the seconds of pointer stillness before it fades back in. Pass false to disable. |
| interactive | boolean | true | Respond to the real pointer. When false only the auto-demo stirs. |
| speed | number | Simulation speed multiplier. 1 = default. | |
| paused | boolean | Freeze the simulation, holding the current frame. | |
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.