What turns a good card into a family of them: a shell that is the method, a contract that names what varies, members that are data modules plus one figure — and the growth law that legislates on the second instance.
Cross-cutting laws·docs/gallery.md·365 lines
Kit src/components/families/Living example · Explainer family
The law for the gallery — what turns a good card into a family of them. It sits beside card-design-language.md, which governs how ONE card earns its surface, its two fonts and its signature element; this document governs what happens when that card's method survives a second concept. The kit is src/components/families/, one directory per family holding a shell and a contract; the members live under src/app/(app)/labs/gallery/<family>/members/; the living example is /labs/gallery/explainer, one shell worn by every concept on its roster.
01
A family is a methodology with proof attached. A single excellent card proves that its author can make one; it does not prove that anything in it is repeatable. The moment a second concept wears the same anatomy, the card splits into two things that were always there: a SHELL — the parts that did not change — and a CONTRACT — the parts that did. The shell is the method, written as a component whose defaults enforce it. The members are the proof that the method produces more than one card. A family with one member is a card; a family with three is a claim.
The corollary is what a new member costs: a module that satisfies the contract — a data module when the contract is data, a state machine when it is behaviour — plus at most one custom slot. If a third concept needs the shell to change, one of two things is true — the contract has a gap (fix it there, so every member gains the field) or the concept is not a member of this family. There is no third option, and "just this once" is how a family decays back into a folder of similar-looking cards.
02
| Part | Owns | Lives at |
|---|---|---|
| Shell | Anatomy, order, every interaction, motion, the fixed vocabulary (a level ladder, a kicker) | src/components/families/<family>/shell.tsx |
| Contract | What varies, as a zod schema; referential rules between fields; the slot's prop type | contract.ts beside the shell |
| Member | One module satisfying the contract (data, or a state machine), plus one custom slot component | src/app/(app)/labs/gallery/<family>/members/<slug>.tsx |
| Roster | Tab order; the one list every surface reads | members/index.ts |
| Family roster | The family's row on the overview — shape, question, admission test, contract in one line | src/app/(app)/labs/gallery/families.ts |
Three rulings decide which side of the shell/contract line a detail falls on:
03
Every family may grant its members exactly ONE component slot, and it is always the signature element — the figure, the illustration, the thing a reader would remember the card by. Pure data would make it generic, which is the one thing the signature element must not be.
The slot's interface is narrow by law. It is handed the family's colour recipe and the current trace state (stage(key), dim(key), active) and nothing else: no state of its own, no colours of its own, no layout outside its box. A slot that reaches past that interface is a second shell in disguise.
04
/labs/cards stays a card until a second concept can wear its anatomy. Then: extract the shell, write the contract from what differed, turn the original into member one, and register the family. The card keeps its /labs/cards slug — it is the same component, now mounted from a member.memberSchema): the member is values, validated at build time. A BEHAVIOUR contract is the shell's typed props plus a derivation rule (the Status family): the member is a state machine, and what is enforced is that every slot is filled every render and every word is computed from state. Pick data whenever the variation can be written down; reach for behaviour only when what varies is what happens next.05
The first family, extracted from the Concept explainer card when Attention became the second concept to fit it.
Shape: one concept × four levels × one stage system. Question: what is this idea, at my level — and which part of the picture is which part of the formula? Admission: the concept has a formula with named parts and a picture of those parts. A procedure with no formula is a Lineage diagram; a comparison is a Versus.
Method, in the order the reader meets it:
Hues are palette colours by design: stages are categories, not statuses, and the card language's multi-category exception applies. The tip well is amber for every member — an insight, not a warning.
Members are admitted for their SIGNATURE — the one thing the picture shows that the formula only says — and every member declares it in the contract (signature), the way a Status member declares its mechanism and a Run member its shape. "Entropy is an area", "the parent stays skewed, the means become bells", "the third band is the only one that curves": a line like that is the admission test passed in the member's own words, and the public roster prints it beside the name. A concept whose figure has no such line has a diagram, not a signature; a second concept with the same signature is a variant of the member that already proves it.
06
The second family, brought over from yAnimationPlayground's device status card set — twenty cards that already shared one shell there.
Shape: one shell × n state machines. Question: what is this machine doing right now, what happens next, and what can I do about it? Admission: a device with a state machine worth explaining, and a MECHANISM not yet in the roster. A member is admitted for its mechanism (a consumable running out; a fault hijacking the primary button; hysteresis — one reading, two states), never for its device; a new device wearing a mechanism the roster already has is a variant.
Method:
StatusRows or StatTiles) → caption + two pill actions. No slot is optional; a card that cannot fill the anatomy is not a member.useState; calling a second setter inside an updater double-counts under StrictMode, and three cards tripped on exactly that before the rule was written.scenes/, driven by useDeviceClock; the scene never knows who drives it. Pausing when the roll is empty, freezing while a retry waits, parking under prefers-reduced-motion are all the member's operations on the clock, not the scene's.@container and every internal step is @sm:, so the same card sits four across in the grid and opens fully at two-column width on its own page.The roster is the record and the groups are the vocabulary. Each member declares its mechanism in the roster (mechanism), and the roster's STATUS_GROUPS sorts them by the shape of the state machine — Endings, Quantities that turn, Thresholds and windows, Faults and consent, Flows and trade-offs — never by device. A new member joins exactly one group; the public grid shows one group at a time, and the group's one-sentence blurb is what its members have in common.
07
The third family, extracted from the Agent run card when Graph engineering became the second process to wear its anatomy.
Shape: one graph × one clock walk. Question: what is this process doing right now, in what order, and what has it cost so far? Admission: a process with a fixed topology that one clock walks in stages. A topology nobody walks is an Architecture diagram; two topologies compared are a Versus.
Contract: mostly data, with two functions where data cannot carry the meaning. Nodes sit on a 100×100 canvas with a palette hue each; edges carry their SVG path and the PHASES that light them; phases carry the nodes they light, a duration and cumulative counters. The member supplies a meter reading (what this run costs — tokens and dollars, or tasks against wall clock) and the Activity slot — the signature element, what a reader sees the run doing at each stage.
Method:
retry edge is drawn dashed in the error hue — the difference between a fan-out with local retry and a loop with extra boxes.Members are admitted for the SHAPE OF THE WALK they prove, never for the process they depict — the Status rule, one family over. Every member declares its shape in the contract (shape), and the roster is the record:
| Member | Shape of the walk | Where the contract carries it |
|---|---|---|
| Agent run | fan-out / fan-in | three edges out, three back, one phase each |
| Graph engineering | fan-out with local retry | one edge flows twice; a retry edge drawn as a correction |
| ReAct loop | a cycle with an exit | the return edge names three phases; the walk leaves when a thought needs no action |
| RAG chain | a chain with a side store and a falling counter | 24 candidates to 5; two edges converge on the output |
| CI pipeline | a matrix with a critical path | jobs finishing apart is a phase where only the slow one stays lit; compute minutes against wall minutes |
| Saga | a walk that reverses | compensation edges back along the chain to nodes reached only on the way back; the meter returns to zero |
| Two-phase commit | a unanimity barrier | the same edges flow twice with a wait for EVERY answer between; locks held, in lock·seconds |
| Raft election | a majority barrier | the walk moves on at three of five while one vote is still in flight; the late edge lands on a closed door |
| Circuit breaker | a gate that lets one probe through | the edge out of the breaker changes destination when a counter trips; a single edge re-opens it — no fan-out, no reversal, no vote |
| Hedged request | a staggered race with loser cancellation | a second attempt starts before the first finishes; one successful reply releases the caller, then a cancellation edge reaches the unfinished attempt |
A second agent run, a second pipeline, is a variant of the member that already proves its shape. The two barriers are the boundary case: they look alike until the votes come back, and what tells them apart is what opens the door — every answer, or most of them. Two-phase commit was admitted as "a quorum barrier" and re-recorded as unanimity when Raft arrived; the record names the shape precisely enough to refuse the next look-alike.
08
The fourth family, extracted from the Opt-in rate card when Uptime became the second metric to wear its anatomy — and needed a meter that runs from 99% to 100%.
Shape: one share × n windows × one target. Question: where does this rate stand right now — over the window I choose, against my target, against everyone else? Admission: the metric is a SHARE, a numerator over a denominator read in percent over a time window, with a target worth holding and a benchmark worth beating. A count is a stat tile; a series is a chart; a rate nobody judges is a number.
Method, in the order the reader meets it:
direction) and what range the meter shows (domain); the shell normalises the value onto the axis — an opt-in at 62% and a churn at 2.4% both sit to the right of their targets. Without the two fields the family would have needed a second shell by its third member.Members are admitted for the SHARE they read — what over what — never for the department that reports it. Every member declares it in the contract (share), and the public roster prints it beside the name. A second opt-in rate is a variant of the first; a metric that cannot be written as one thing over another is not a rate.
| Member | Share | What it made the contract say |
|---|---|---|
| Opt-in rate | users who said yes over users who were asked | the anatomy itself: windows, delta, target, benchmark, alt view |
| Uptime | minutes up over minutes in the window | domain — a rate that lives between 99 and 100 needs its own meter range |
| Churn rate | customers lost over customers at the start | direction — a rate that is better lower maps onto the same poor → perfect axis the other way |
09
The fifth family, extracted from Meeting Finder when Akash's token-usage interaction supplied the second segmented field. Their common feature is not the pill-shaped tick: it is n lanes × one shared axis × one probe.
Question: what does this coordinate mean in each lane, and what changes when I act? Admission: a segmented field with a common domain, a state-derived probe and an action that changes either the coordinate or the field. A meter alone is a part; unrelated scales do not share an axis. Members are admitted for their mechanism, not the noun on the legend.
Contract: validated metadata plus behaviour. project(state) produces all readings, the summary, tone and button state. locate(state, lane) positions the probe when a lane is selected. act(state) returns a target coordinate and one value per lane. The shell interpolates one atomic state on one clock, locks input during the action, cancels on reset/unmount and jumps directly to the final state under reduced motion. There is no second stored headline or progress counter. The one Lane slot receives its mark data, shell-owned colour and emphasis; it has no local state or chrome.
The visual reference is the original Meeting Finder. All members use its compact two-surface card: title and live coordinate pill → inset panel with left-hand labels, top axis, segmented lanes and right-hand readings → outcome and inverted pill action. The probe is an outlined vertical capsule with a short axis marker and left/right arrows; success turns it green. Row height, spacing, type hierarchy and 24-cell resolution are shared. There is no detached legend or floating tooltip. A new member never changes this anatomy. The capsule encloses one cell: quantity probes share Meter’s rounded fill count and sit on the final lit cell, while hour probes sit on the selected hour. Readouts keep exact values. The marker has its own band below the tick labels, so it never obscures a number; the capsule must not touch adjacent ticks.
Labels select the lane to act on; the overlaid Slider supplies pointer and keyboard scrubbing. The live coordinate pill resets the demonstration. Numeric readings, optional day annotations and active/quiet ink derive from the member's projection. Meeting Finder retains its local-time colours, day shifts and contextual early/late summary; its original card slug and fill prop stay.
Marks follow meaning. Quantity lanes compose feedback/Meter, with its rounded tick skin, rather than inventing a second meter. Availability lanes are a schedule field with non-contiguous intervals, not an ARIA meter. Lane hues are categories; only the inspected lane earns the glow. The moving probe occupies a separate layer. No Recharts canvas is needed: these are inline meter / interval parts with explicit readings, not a new chart engine.
| Member | Mechanism | Proof |
|---|---|---|
| Meeting Finder | move a coordinate through periodic intervals | one UTC hour changes all local readings; the optimum is computed from fixed offsets |
| Token usage | reclaim one endpoint independently | only the selected model loses context; reclaimed tokens equal the difference from the initial fixture |
| Workload balance | transfer a conserved total between endpoints | all three lanes converge while the total stays 1,440 jobs throughout the animation |
These are deterministic demonstrations. Meeting Finder states its fixed UTC offsets rather than claiming live daylight-saving support; token compression is a simulated context reduction, not a provider request.
10
className or render prop on the shell "for this one member" — the shell now has n+1 behaviours and the contract describes n of them.stroke-sky-500 instead of stage("key").stroke. The trace stops reaching it and the binding — the whole method — breaks silently.