SIG—17 Signature system
SplitFlap
A mechanical flip display: every character falls forward through the drum to its new value, cell after cell, and lands with a slap.
Live — this one is real
Every character falls forward through the drum, cell after cell, and lands with a slap. Screen readers get the settled text. The timetable is invented.
| Time | Destination | Plat. | Status |
|---|---|---|---|
| 08:42 | KANAZAWA | 4 | ON TIME |
| 08:50 | NAGANO | 11 | ON TIME |
| 09:03 | SENDAI | 7 | DELAYED |
| 09:15 | NIIGATA | 2 | ON TIME |
| 09:21 | HAKODATE | 9 | ON TIME |
Usage
import { useState } from "react";
import { SplitFlap, Button } from "mizu-ui";
export function Example() {
const [n, setN] = useState(0);
const states = ["ON TIME", "BOARDING", "DEPARTED"];
return (
<div style={{ display: "flex", gap: 16, alignItems: "center" }}>
<SplitFlap value={states[n % 3]!} length={8} label="Status" live />
<Button variant="ghost" onClick={() => setN(n + 1)}>
Advance
</Button>
</div>
);
}
This code, running — no configuration beyond the data
Source & setup
Add this component to your project with the shadcn CLI. The command copies its source and styles into your configured UI directory.
npx shadcn@latest add 0xuser64bit/mizu/split-flapFor npm imports, import mizu-ui/styles.css once. Fonts are optional via mizu-ui/fonts.css. Override --mizu-* tokens or use className for local styling. Requires React and Motion.
Inspect signature/SplitFlap.tsx
Source is included in the npm package under src/signature/SplitFlap.tsx.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value / length / align | string / number / left | right | — | The text, padded or trimmed to `length` cells (its own length by default). |
| characters | string | — | The drum in falling order — FLAP_CHARACTERS by default. Characters outside it arrive in one flip. |
| flip / stagger | number | — | Milliseconds for one flap to fall (70) and between neighbouring cells starting (35). |
| label / live | string / boolean | — | Read before the value; live displays announce each new value politely. |
| tone / onSettle | SignatureTone / (value) => void | — | Glyph colour, and a call when every cell has arrived. |
| flapPath() | (from, to, characters, most?) => string[] | — | The flaps a cell passes on its way, for displays of your own. |
Accessibility
The cells are hidden from assistive technology; the value and its label sit beside them as plain text, so a display reads as words rather than letters, inside a table cell or a button alike. A live display announces each new value once, not every flap.
Motion
Each cell falls forward through the drum like the real mechanism: the top leaf folds down and darkens while the next character lands with a small overshoot, and neighbouring cells start a beat apart so a change ripples along the line. Long journeys skip ahead to the last dozen flaps. Reduced motion shows the new value at once.