Skip to content

Record and Replay

greghulette edited this page Jul 28, 2026 · 2 revisions

Record and Replay

Record and Replay ("Clips") captures everything your droid does over a bounded window — Maestro servo moves, HCR / MP3 / WLED / WCB commands, aux‑serial, and continuous knob/gimbal streams — saves it as a named clip, and plays it back on demand. Clips live in a renamable library on the board, and can be triggered from a transmitter control, the config tool, or the serial CLI.

The feature is implemented in firmware in the navirec namespace (navicore_record.h) and surfaced in the config tool as a 🎬 Clips panel with a 📈 timeline editor.


Overview

A clip is a timestamped event list. Recording taps three sources as they happen:

  • Discrete actions — every dispatched WCB (unicast/broadcast), Maestro, aux‑serial, HCR, MP3, and WLED action.
  • Maestro knob keyframes — continuous passthrough knob → servo moves, captured as dense keyframes (one per knob change past the deadband).
  • HCR‑volume keyframes — the post‑gate volume a knob emits.

The lifecycle is record → save → library → replay. You start a capture, perform the moves, stop (which always saves the take), then play the clip back at any time. Replay re‑dispatches the discrete actions through the same code path they took live, and drives Maestro motion with a continuous interpolating curve‑follower — so playback is at least as smooth as the original move.

🚀 Because Maestro motion is re‑interpolated on replay rather than fired keyframe‑by‑keyframe, a clip recorded from jittery knob input plays back smoothly.


Requirements and storage

Persisted clips need the 16 MB custom‑partition firmware. Clips are stored on a dedicated 12 MB clips LittleFS partition (offset 0x400000, size 0xc00000), mounted as a second LittleFS with its own label and base path so its format never touches the config filesystem or /config.json.

Board build Clip behavior
16 MB custom‑partition build Clips are saved to the clips partition and survive reboots.
Old 4 MB (min_spiffs) table Record/replay still works, but clips are in‑RAM only and lost on reboot.

On a board without the clips partition the firmware logs:

[CLIPS] no `clips` partition — clips are in-RAM only (flash the 16 MB partition build)

Enabling persistence requires a full flash of the 16 MB build (the 16 MB custom bootloader + PartitionScheme=custom + FlashSize=16M). An app‑only OTA update does not change the partition table. See Flashing the Firmware.

Clip file format (/<name>.ncr): a small header followed by the raw event array.

Field Value
magic "NCR1"
version 1
mode function‑switch state at record time (clip context)
count number of events that follow
durationMs clip length (derived from the last event's timestamp)

Limits and names:

  • Recording window: 60 s backstop (REC_MAX_MS). A take that runs past 60 s is auto‑stopped and saved so a long take is never lost.
  • Event buffer: 24000 events (RecEvent is 136 B ≈ 3.1 MB of PSRAM). A very dense capture can hit the event cap before 60 s; drop‑if‑full at either the capture queue or the buffer just thins a frame (counted in drops).
  • Clip names: sanitized to [A-Za-z0-9_-] and truncated to 32 characters on save. Non‑matching characters are silently stripped.

Recording from the Clips panel

  1. Connect the board over USB or Via‑WCB (see Connecting).
  2. Click the 🎬 Clips toolbar button.
  3. In the Record row, optionally type a clip name. Leave it blank to auto‑save as rec_1, rec_2, … (lowest unused number).
  4. Click ● Record. The button becomes ■ Stop & Save.
  5. Perform the droid moves.
  6. Click ■ Stop & Save.

The take is always saved — a named clip overwrites that name, a blank name auto‑names rec_N. The library refreshes automatically after a save.


The clip library

The Library section of the Clips panel lists every saved clip. Press ⟳ Refresh to query the board; it shows a storage‑usage bar (from the partition's total/used bytes) and one row per clip with its duration and byte size.

Each clip row has:

Button Action
▶ Play Load the clip from flash and replay it
📈 Open the timeline editor
Rename the clip
🗑 Delete the clip

Renaming or deleting a clip also re‑points any transmitter trigger actions that reference it by name (button tap‑tiers and switch positions, plus an open timeline's actions). Those changes are local until you Save the config to the board.

The Clips panel works over Direct USB or Via‑WCB — over the bridge, commands are relayed to the target board. See Remote Management over WCB.


Triggering from transmitter controls

In the Action Editor and Command Library you can map three record/replay action types onto a button or switch:

Type Behavior
Record (toggle) Fire → start capturing. Fire again → stop and save. Optional clip name (blank → rec_N).
Play clip Fire → load the named clip from flash, then replay. Fire again while playing → stop. Optional Loop checkbox for idle‑animation replay.
Stop Explicit halt — saves an in‑progress recording, aborts an in‑progress replay.

Both Record and Play are toggles: one control starts and stops. Assign the action, then Save the config to the board. The record/play/stop action types are never captured into a clip.

⚠️ Record is toggle‑only in firmware. A matrix button delivers only a debounced tap‑count (no release or hold duration), so toggle is the only matrix‑button‑safe mode — there is no separate hold/level record handler.


Serial CLI reference

All record/replay CLI commands are ?REC sub‑commands (see CLI Commands and Serial JSON Protocol).

Command Effect
?REC,START Start recording
?REC,STOP Abort recording or an in‑progress replay
?REC,PLAY[,name] Load name (if given) and replay
?REC,SAVE[,name] Save the current take; blank name auto‑names rec_N
?REC,LOAD,name Load a clip into the buffer
?REC,LS List clips (emits a [CLIPFS] storage line, then [CLIPLIST] / [CLIPITEM] lines)
?REC,RM,name Delete a clip
?REC,RENAME,from,to Rename a clip (emits `[CLIPUL:RENAME,OK
?REC,CLEAR Clear the in‑RAM buffer
?REC or ?REC,INFO Print state, event count, duration, and drops

The timeline editor uses additional transport verbs: EDITLOAD, EDITBEGIN, EDITEV, EDITEND, and EDITCANCEL.

Typical CLI record/replay session:

?REC,START
… perform moves …
?REC,STOP
?REC,SAVE,wave
?REC,PLAY,wave

How replay works

Replay is deliberately faithful, and it owns the outputs while it runs.

  • Discrete actions are re‑dispatched through the same path as live input, so emotion/verb rewrites and routing re‑apply exactly.
  • Maestro motion is not fired keyframe‑by‑keyframe. A curve‑follower emits a linearly‑interpolated ¼µs position for every active (slot, ch) on every tick. Before the first frame it forces speed = 0 / accel = 0 on every touched channel (so the Maestro's own smoothing can't double‑smooth the interpolated stream), then eases in from the servo's last‑commanded position. The interplay with Maestro speed/accel limits is covered in Maestro Setup.
  • HCR volume replays through a raw SetVolume path that bypasses the live volume‑dedupe cache, so recorded volume ramps aren't decimated. See WLED and HCR Audio.
  • Live dispatch is suppressed during replay — button, switch, knob, and remote input are gated off, except the record/play/stop controls, so a mapped button can still stop a running clip.
  • Loop mode (fn = 1 on a Play action) rewinds cheaply at the end of each lap and eases the loop seam.
  • A 1‑second safety net past the clip's length completes replay even if a bad timestamp would otherwise wedge it, so live control is never locked out indefinitely.

⚠️ A looping Play clip keeps replay active — and therefore keeps live control locked out — until you fire the control again to stop it.

Anti‑snap servo shadow. The firmware keeps a last‑commanded position per slot + ch, written on every real Maestro move. goHome / stopScript and single‑channel auto‑release mark a channel's pose as unknown, so replay re‑anchors and snaps to the next keyframe instead of sweeping the servo up from a stale pose.


Timeline editor (Phase 2)

Click 📈 on a clip row to open the SVG timeline editor. It:

  1. Downloads the clip from the board (?REC,EDITLOAD, streamed as tagged JSON lines).
  2. Shows one draggable‑keyframe polyline per Maestro (slot, ch), HCR‑volume curves, and an Actions row.
  3. Lets you add / select / delete / drag keyframes, add and edit actions, apply easing (which inserts denser synthesized keyframes — the firmware only ever linearly interpolates), Smooth, Undo (Ctrl+Z), and zoom / Fit.
  4. Uploads the edited clip back (?REC,EDITBEGIN → indexed, idempotent ?REC,EDITEV per event → ?REC,EDITEND, which re‑sorts events by time and saves).

⚠️ Editing is best over Direct USB. Download and upload run in the main loop and block SBUS/heartbeat servicing for their duration, so over the WCB bridge the firmware refuses clips larger than 3000 events — connect over USB to edit those.


Limitations and gotchas

  • Persistence requires the 16 MB partition build. On a RAM‑only build, clips are lost on reboot; the persistent clips partition comes only from a full flash, not an app‑only OTA.
  • Clips are not self‑describing. The stored header is only {magic, version, mode, count, durationMs}. Replay depends on the board's current live routing, volume, and servo state — the servo home used for ease‑in is read live at replay start, and volume/destination shadows are not restored. Replaying a clip on a differently‑configured board (or after routing changes) may mis‑route or mis‑anchor.
  • MP3 NEXT / PREV are not deterministic on replay — they advance relative to the module's live track pointer, which NaviCore doesn't shadow. Use absolute "Play track N" in recorded routines.
  • Playing a missing clip does nothing. A named Play that isn't on the board won't fall back to a stale in‑RAM clip.
  • Name sanitization can change targets. Because names are stripped to [A-Za-z0-9_-] and truncated to 32 chars in both the save path and the action editor, a name with other characters can end up pointing a trigger at a different clip than you expect.
  • Event and time caps. 60 s window and 24000 events; a dense capture can hit the event cap first. Dropped frames are counted and reported by ?REC.

See also: Action Editor and Command Library · Maestro Setup · WLED and HCR Audio · CLI Commands · Config Tool Guide

Clone this wiki locally