PAXAL
/api/replay-schema
The shape /replay consumes and the SAVE REPLAY chip in pause mode produces. Versioned so consumers can detect older payloads.
TOP LEVEL
version1Schema version. Currently always 1. Future breaking changes will bump this.exported_atISO stringWall-clock at export time (Date.prototype.toISOString()).arena_idstringArena id matching lib/arenas.ts (room | ludlow | la-night | la-night-aerial | …).capture_hznumberFrame capture rate. Currently always 30.window_secnumberLength of the captured window in seconds. Currently always 12.framesFrame[]Pose stream in chronological order. Length is bounded by capture_hz × window_sec.eventsEvent[]Tagged events that happened during the window. Sparse; not aligned to frames.FRAME
atnumberWall-clock timestamp (Date.now()) when the frame was captured.pos[number, number, number][x, y, z] world position. PAXAL uses +Z forward, +Y up.speed_mpsnumberSigned speed in m/s along the heading vector. Negative under reverse.steer_degnumberSteering angle in degrees, signed. Positive turns right.gear'D' | 'R' | 'N' | 'B'Coarse gear state. D=drive, R=reverse, N=neutral, B=hard brake.EVENT
atnumberWall-clock timestamp.kind'impact' | 'gear_shift' | 'ignite' | 'drift_start' | 'drift_end'Discriminator. New kinds may land; consumers should default unknown kinds to no-op.detailnumber | string | undefinedPer-kind payload. impact = normalised force 0-1; gear_shift = target gear number.SAMPLE
{
"version": 1,
"exported_at": "2026-05-16T18:42:11.123Z",
"arena_id": "ludlow",
"capture_hz": 30,
"window_sec": 12,
"frames": [
{
"at": 1747422120000,
"pos": [-4.4, -0.1, -1.3],
"speed_mps": 0,
"steer_deg": 0,
"gear": "N"
},
{
"at": 1747422120033,
"pos": [-4.39, -0.1, -1.28],
"speed_mps": 0.6,
"steer_deg": 2.1,
"gear": "D"
}
],
"events": [
{ "at": 1747422120100, "kind": "ignite" },
{ "at": 1747422121430, "kind": "gear_shift", "detail": 2 },
{ "at": 1747422122871, "kind": "impact", "detail": 0.42 }
]
}NOTES
- ·Frames are captured at 30 Hz wall-clock; render frame rate is independent. A 12-second window holds up to 360 frames.
- ·Events are timestamped against the same wall-clock as frames but don't share indices. The /replay viewer snaps each event to the nearest frame by timestamp.
- ·
posuses PAXAL world coordinates — origin is the arena spawn point in the general case, but the SplatCanvas may centre on the captured scene's AABB centre. Usearena_id+lib/arenas.tsspawnPos to reconstruct a local frame. - ·New event kinds may ship in future versions. Consumers should default-no-op on unknown
kindvalues rather than throw.