Realtime and physics charts both move marks, but motion means different things in each. Semiotic factors out a shared motion core -- identity, a clock, placement, velocity, process, and evidence -- that both runtimes read from the same records. Each runtime then layers its own policies on top:
- Realtime -- pulse, decay, transition, staleness, and buffer policy (seeRealtime Encoding)
- Physics -- mass, force, collision, constraints, and controllers (seePhysics Encoding)
Two runtimes, one dataset
The same records drive both panels below. The left panel treats motion as streaming recency and presentation; the right treats the same arrivals and vectors as initial conditions in a physical world. Pick a clock before reading age -- "now" is part of the encoding.
Event time0.0s
Realtime interpretationpulse + age + trailPhysics interpretationspawn + velocity + settle Resolved rows0 visible / 6
| Record | Arrival | Age | Lifecycle | Speed | Process |
|---|
| Permit event | 0.6 | future | not arrived | 16.1 | arrived |
|---|
| Sensor batch | 1.3 | future | not arrived | 25.0 | queued |
|---|
| Schema update | 2.8 | future | not arrived | 20.1 | working |
|---|
| UI patch | 4.1 | future | not arrived | 30.1 | working |
|---|
| Quality check | 5.2 | future | not arrived | 18.0 | observed |
|---|
| Release signal | 7.4 | future | not arrived | 24.0 | settled |
|---|
The shared channels
Every channel in the core resolves once, from the same datum, into a value both runtimes can use. What differs is the interpretation, not the data:
- Arrival -- one value read through a named clock. Realtime may use event or ingest time; physics maps a simulation-basis arrival to
spawnAt. - Placement --
x, y, and lane only align when the author states a coordinate space (data, world, or screen). - Velocity -- a derived cue in realtime (direction from successive points), but causal state in physics (it changes the next position).
- Age -- decay can measure age by buffer rank or by elapsed time, but the two can't share thresholds without an explicit adapter.
- Lifecycle --
fresh → stale is temporal classification;queued → armed is domain process state. Both survive, never conflated. - Evidence -- named analytical values (arrival, stage, wait, settled position) stay readable when motion is paused or removed.
Choosing a clock
Age is meaningless without a clock, so the encoding names one. now,arrival, and any TTL must share a single basis and unit -- buffer rank is useful, but it is not wall-clock age. Four clocks plus an ordinal rank are available:
- Event time (
event / seconds) -- When the represented event occurred. - Ingest time (
ingest / seconds) -- When the runtime received the record. - Simulation time (
simulation / seconds) -- When a body enters a modeled world. - Presentation time (
presentation / seconds) -- When a transition or pulse is shown. - Buffer rank (
buffer-index / index) -- Ordinal recency, not elapsed duration.
Cause, cue, and evidence
Keeping these three apart is what stops motion from becoming an attractive but unreadable model:
- Cause -- changes what happens: velocity, force, mass, collisions, constraints, and explicit state transitions.
- Cue -- changes what is shown: pulse, trail, interpolation, highlight, and age-to-opacity.
- Evidence -- records what happened: arrival, delivery, occupancy, wait, throughput, completion, and settled outcome.
Composing the encoding
The shared compiler (compileMotionEncoding) resolves records once into the neutral core. Runtime adapters extend that core with their own policies instead of re-reading the data.
JS
const motionEncoding = { id: "id", time: { arrival: "arrivedAt", basis: "event", unit: "seconds", }, placement: { x: "x", y: "y", lane: "lane", space: "data", }, kinematics: { velocityX: "vx", velocityY: "vy", space: "world", }, process: { stage: "stage", target: "target", work: "remaining", }, evidence: { value: "value", observedAt: "observedAt", }, }
Age helpers normalize a named clock without deciding whether the source is a ring buffer or a simulation. Keep the inputs commensurate:
JS
resolveMotionAge({ now, arrival, ttl, }) // now, arrival, and ttl must share one basis and unit. // Buffer rank is useful, but it is not wall-clock age. opacityFromAge({ age, extent: ttl, type: "exponential", halfLife: ttl / 2, })
Reduced motion
A reduced-motion view settles physics to a valid state and removes realtime pulses and trails, while still exposing arrival, lifecycle, process stage, target, and outcome through semantic items and tables. A frozen mid-animation frame is not a reduced-motion alternative.
- Realtime Encoding -- presentation policies for arriving and aging data
- Physics Encoding -- causal dynamics, constraints, process, and settled evidence
- Merge Pressure -- dependency delivery, staged review, and process claims in a full example