Use physics when movement carries a data claim: a body is delayed, blocked, sorted, sampled, counted, or settled because of the data. If movement only makes a static chart feel active, use ordinary chart animation or no motion.
For process HOCs (Gauntlet vs ProcessFlow), capacity queues, body marks, and the example checklist, see thePhysics process guide.
Rule of thumb: every physics chart needs a settled projection that is still a useful chart when the animation is paused, skipped, or rendered for reduced motion.
Pick the Mode
Pick the mode before picking the component. Most confusion comes from putting texture-style particles on a layout chart and asking readers to infer meaning from motion that does not actually encode anything.
| Mode | Readout | Use it for | Semiotic starting point |
|---|
| Layout | Read at rest | Collision relaxation, swarms, piles, and packed bodies where motion is how the layout finds a stable position. | CollisionSwarmChart |
| Process | Read the transition and the result | The simulation mirrors the system being explained: sampling through bins, late-event barriers, backpressure, or settling into categories. | EventDropChart |
| Uncertainty | Read the settled distribution | Posterior samples or scenario draws fall through a process and rest as a quantile dotplot or histogram — motion frames frequency, not network topology. | GaltonBoardChart |
| Texture | Read the base chart | Particles decorate flow direction or activity. Keep this in the host chart unless the bodies carry data, collisions, or state. | Realtime Encoding |
Settled Projection
The accessible object is the settled or aggregated chart, not the path each body took. Motion may teach the process, but the chart still owes readers a stable answer: bins, totals, intervals, late counts, sediment, or an explicit projection table.
- Stakeholder Journey lets competing cohorts move through process stages and settle into accessible stage-level projections.
- Watermarks, Made Physicalanimates event arrivals, then exposes settled window counts and late counts.
- UnitPileCharttreats bodies as unitized value carriers, then reads the piled result by category.
- CollisionSwarmChartuses collisions to separate overlapping dots while preserving their x-axis position.
- ProcessFlowChartmoves work items through capacitated stages and reads stage counts plus feature completion.
Displacement Ledger
A displacement ledger names what moves, why it moves, and what state change the movement represents. Write this before building a custom physics scene. If you cannot fill in displacement, projection, and accessibleReadout, the chart probably does not need physics.
JS
const displacementLedger = { source: "arrivalTime and eventTime", body: "one event body per row", displacement: "body falls into the event-time window bin", barrier: "watermark closes old windows", sensor: "late bodies cross into the late gutter", projection: "window totals and late counts", accessibleReadout: "settled table + live milestone observations", }
Settled Ledger
The displacement ledger above is an authoring discipline. The settled ledger is how the finished chart proves it kept that promise at runtime.
Every physics chart shares one deep structure: a chargeenters, an apparatus routes it, and it comes to rest indestinations. Balls into bins, units into category piles, arrivals into windows and a late gutter, properties into a socket or a graveyard, components into reason-labelled outlets. So they all owe the same invariant: every charged body is accounted for in exactly one place. That invariant is this family'sbars start at zero — it is what makes a settled projection an auditable reading rather than a claim about a movie.
Declare the charge and the evidence checks it. Omit it and no ledger is reported — the total is never guessed.
JS
import { unstable_buildPhysicsSettledEvidence } from "semiotic/experimental" const evidence = unstable_buildPhysicsSettledEvidence(store.snapshot(), { bodies, projectionRows, charge: rows.length, // what the chart claims entered }) evidence.ledger // { charge: 60, live: 60, queued: 0, sedimented: 0, // unaccounted: 0, balanced: true } evidence.warnings // [] — or ["PHYSICS_QUEUE_UNDRAINED"] when the apparatus never // received bodies the projection already counted, and // ["PHYSICS_LEDGER_MISMATCH"] when bodies simply vanished.
Why it matters: a projection overlay is drawn from your data, while the bodies come from the simulation. When those two numbers disagree, the chart is stating a total it is not showing. The ledger is the only thing that notices.
Terminal State
Some physics charts are driven by an authored event tape — gates that strip a property, phases that form a product, a completed task that releases its dependents. Those charts owe one more thing:
The end state must be computable from the authored inputs alone. If the outcome only exists as the residue of a simulation, then reduced motion, server rendering, snapshot export, anddescribeChart cannot state it — and the chart is a movie, not a reading.
Tape-driven charts satisfy this in the shape that suits each one. The pure result is what a non-visual reader receives, so it is not an optimization — it is the accessible object.
JS
// CrucibleChart — compiles both ends of the run as data const plan = compileCruciblePlan({ data, phases, products, outlets, events }) plan.initialState // before the tape plan.terminalState // after the tape, no clock advanced plan.terminalSpawns // ChainReactionChart — derives task state at a clock position const runtime = initialRuntime(machine, "snapshot", currentTime, true) runtime.completed / runtime.blockers / runtime.armed // GauntletChart — folds the authored tape over the initial states const terminal = resolveGauntletTerminalStates({ projects, events, layout, positiveProperties, negativeProperties, }) // Caveat: with crashDetection armed, physics can still override the // outcome. The pure fold is "what the plan earns on paper".
This is also the sharpest test when you are designing a new physics chart. Ask: Can you state its ledger in one sentence?(No → it is an animation.)Does its terminal state exist without simulating? (No → it is a movie.) Would a reader who has never seen it guess the reading protocol from the apparatus? (No → the name is wrong.)
Stage Geography
The charge → apparatus → destinations structure is also a layout you can build with. Every shipped physics chart names the zones differently — Gauntlet has startX/socketX/graveyardX, Crucible has chamber/mouth/outlets, and Galton and Pile independently wrote the same lane formula. Naming it once gives subsequent physics charts a common starting point.
JS
import { physicsStageGeography, physicsStageColliders, physicsChargePoint, describePhysicsStageGeography, } from "semiotic/physics" // also from semiotic/recipes const stage = physicsStageGeography({ size: [700, 420], flow: "down", // or "right" for process lanes destinations: 21, // or [{ id, label }, …] destinationExtent: 0.55, channelRatio: 0.7, // < 1 leaves gutters (tubes, not bins) }) stage.charge // where bodies enter stage.apparatus // pegs / gates / phases / stages / barriers stage.destinations // [{ id, label, order, centerX, centerY, … }] stage.projection // strip reserved for the settled reading physicsStageColliders(stage) // floor + one divider per boundary physicsChargePoint(stage, i, count) // spread a burst, don't co-locate describePhysicsStageGeography(stage, { charge: "Events", apparatus: "a watermark barrier", destination: "windows", }) // → "Events enter at the top, travel downward through a watermark // barrier, and come to rest in 21 windows: 0, 1, 2, …"
This is authoring vocabulary for a new chart or aPhysicsCustomChartlayout — the existing charts keep their own layouts, and a regression test pins the builder to their lane math so anything you build on it lands in the same visual family.
Motion Budget
Motion should clarify the state transition once, then get out of the way. Budget it the same way you budget labels and annotations: what does it cost, and what does the reader learn that the settled chart cannot show alone?
| Budget item | Requirement |
|---|
| Autoplay | Short enough to understand in one pass; provide pause and replay when motion continues. |
| Reduced motion | Handled by the frame: a reduced-motion reader gets the settled end state in one pass — every paced arrival admitted and every authored event applied — with no animation. Verify it with the settled ledger rather than assuming. |
| Time scale | Use replay time scale for arrival pacing, not to slow gravity or the physics clock. |
| Body count | Keep live bodies within a readable range; aggregate, evict, or sediment long streams. |
| Accessibility | Expose the settled chart, aggregate rows, and milestone observations as the accessible object. |
JSX
<EventDropChart data={events} timeAccessor="eventTime" arrivalAccessor="arrivalTime" windows={{ size: 12 }} watermark={{ delay: 18 }} timeScale={0.08} // replay pacing only paused={prefersReducedMotion} frameProps={{ onTick: (result, controls) => setRuntime(controls.snapshot()), onBodyPointerDown: (body) => setSelectedEvent(body?.datum), }} />
Choose The HOC
| Component | Use when | Settled projection |
|---|
| GaltonBoardChart | Posterior samples, uncertainty, binned outcomes, and Plinko-style explainers. | Histogram or quantile-dotplot projection. |
| EventDropChart | Event time versus arrival time, watermarks, lateness, queueing, and windows. | Window counts, late counts, and closed/open state. |
| UnitPileChart | Unitized counting, category bins, sedimented totals, and materialized denominators. | Category totals and represented value. |
| CollisionSwarmChart | Dot strips and grouped distributions where collisions reveal local density without hiding the quantitative axis. | X-axis distribution with optional group lanes and counts. |
| ProcessFlowChart | Multi-body workflows with capacitated stages, rework portals, and feature groups that complete only when every member is absorbed. | Stage occupancy counts and group completion ledger. |
| GauntletChart | One compound plan degraded by timed gate effects (lift balloons and drag particles). | Property inventory, viability, and outcome state. |
| PacketFlowChart | Packets on authored routes where throughput stays readable as a static layer. | Route throughput and node totals. |
| PhysicsCustomChart | The scene needs custom colliders, sensors, spawn rules, or overlays that the HOCs do not expose. | Your layout must return the projection evidence explicitly. |
Reach for PhysicsCustomChartonly after the HOCs fail on geometry or state. If the custom scene does not need colliders, sensors, spawn timing, or sediment, it is probably an ordinary custom chart.
Do Not Use Physics For
- Decorating a bar, line, or Sankey chart with particles that do not carry data.
- Replacing a readable axis, legend, or summary with a body path.
- Hiding uncertainty behind randomness without showing the sample or interval.
- Long-running streams that never aggregate, evict, sediment, or pause.
- Any chart where reduced motion would remove the only meaningful readout.