Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Playback clock — ED.4

The recorder's player is wall-clock paced and 1× only. The editor needs a clock that is the single authority over time — EditorPlayer: seek to an exact frame, step a frame at a time, play at a chosen rate, honour in/out points, and loop.

stateDiagram-v2
  [*] --> Paused
  Paused --> Playing: play()
  Playing --> Paused: pause() / step()
  Playing --> Paused: reached out-point (no loop)
  Playing --> Playing: reached out-point (loop → in)
  Paused --> Paused: seek(frame) / set_rate(r)

Time is measured in project frames at the project fps. tick(dt) advances the playhead by dt × fps × rate; current_frame() is floor(elapsed × fps), clamped to the playable range [in, out). At the end of the range the clock loops back to the in-point or clamps to the last frame and pauses.

One clock for playhead AND zoom

EditorPlayer wraps wisp_animation::Driver rather than rolling its own timer — and exposes it via driver(). That's deliberate: the zoom animation engine (ED.16) samples its keyframed Tracks against this same Driver, so the playhead and the cinematic zoom advance in perfect lockstep, in realtime preview and in deterministic export alike. A second clock would let them drift.

Realtime vs fixed

EditorPlayer::new builds a realtime clock (the caller injects dt from the render loop). EditorPlayer::fixed advances exactly one frame per tick, ignoring dt — the reproducible stepping the export pipeline (ED.20) uses so every render is bit-stable. Both share the identical frame math, so preview and export agree frame-for-frame.