Interface components whose micro-interactions are physically simulated.
The physics lives in the 200 milliseconds nobody consciously notices: the press that compresses, the ring that settles, the knob that carries momentum into its snap. Not decoration.
See DESIGN.md for the philosophy and DECISIONS.md for the reasoning behind the architecture.
| Path | What it is | Licence |
|---|---|---|
packages/fluid |
Engine. Maths, simulation loop, interaction primitives. | MIT |
packages/fluid-react |
React bindings for the engine. | MIT |
registry/ |
The copy-paste components themselves. | MIT |
apps/fluid-demo |
Showcase, rendering the registry files directly. | MIT |
fluidis a working name.
v0.1 is an engine with a small set of reference components, each proving a distinct physics rather than adding a shape.
| Component | What it proves | Status |
|---|---|---|
| Button | Press asymmetry, ripple, content morph | done |
| Switch | Drag momentum, droplet trail, landing ring | done |
| Checkbox | A mark drawn along its own path | done |
| Slider | Constrained drag, elastic bounds | next |
| Input | Focus settling, validation as a damped oscillator | next |
Anything beyond this waits until a real application asks for it. See DECISIONS.md.
The engine is installed. The components are copied.
npm install @quirelabs/fluid @quirelabs/fluid-react
npx fluid add button # planned; copies registry/ui/button.tsx into your repoThe physics is versioned and fixable centrally, and one shared frame loop drives every component on the page. The markup and styling belong to whoever copied it.
Simulations never emit class names or decide appearance. They write named scalars as CSS custom properties, and CSS decides what those drive.
.fluid-button {
transform: scale(calc(1 - var(--fluid-press) * 0.035));
}Restyling cannot break motion, and retuning motion cannot break styling.
Comes from Base UI. We add motion and never reimplement a
menu. prefers-reduced-motion is honoured at the simulation level: simulations
settle and stop stepping, so reduced-motion users get the final state with no
work being done.
Requires Node >= 20 and pnpm 9.
pnpm install
pnpm --filter fluid-demo dev # http://localhost:5180
pnpm test
pnpm typecheck
pnpm check # biome lint + formatMIT. See LICENSE.