Draft. Written against the spec, ahead of the code. The words are the intent; the software is not there yet.
Recording a take
A take is created, cued, and stopped. Creating reserves the paths and writes the manifest before a single frame; starting is the cue.
A take is three calls. The first does everything that can be done before recording — resolves destinations, checks them writable, reserves every file path, writes the manifest — so that by the time the cue comes there is nothing left to decide.
Create, start, stop
| call | does | state after |
|---|---|---|
POST /takes |
snapshots the armed set, reserves paths, writes the manifest | created |
POST /takes/{id}/start |
the cue: every armed stream’s writer starts on the same tick | recording |
POST /takes/{id}/stop |
finalises every writer and the manifest | complete |
{ "id": "tk_7f3a", "state": "created", "files": { "camera:0x2300000fd9009c": "ep12/cam-facetime.mov", "microphone:Scarlett_2i2": "ep12/mic-sm7b.wav", "display:56A96CFC-7F21": "ep12/display-prompter.mov" } }Nothing is recording after create. This is the call Pteroprompter makes to
learn where the footage will live before frame one, so the cue log can name
files that do not exist yet. A created take can sit as long as you like;
start is a separate, deliberate call.
POST /record is create and start in one, and is what the popover’s Record
button does. Use it when you do not need the paths ahead of time.
Destinations
POST /takes takes an optional destination (a folder, relative to the
output root) and files (a map of stream id → relative path) for clients that
want to name things. Omit both and Rheocles names the take folder from name
and the date, and the files from each stream’s kind and name.
The same destination twice is a 409, unless overwrite: true. Rheocles
never silently suffixes a path; a client that named a path meant it, and a
file that quietly became -2 is how a take goes missing.
Disk pre-flight
Create refuses if there is not room. Pass expectedDuration in seconds and
Rheocles estimates the take’s size from the armed set’s measured bitrates;
omit it and the estimate assumes thirty minutes. Short, and create is refused
with the estimate and the free space in the error; tight, and it is created
with a warning alongside.
If a write fails mid-take — disk full, volume unmounted — the take stops
cleanly, every file is finalised as far as it got, and the manifest is marked
incomplete with the reason. Nothing is deleted.
What lands on disk
Rheocles/ ← output root, one field on GET /└── ep12/ ├── manifest.json ├── cam-facetime.mov HEVC, native resolution and rate, timecode track ├── display-prompter.mov ├── mic-sm7b.wav Broadcast Wave, 48 kHz 24-bit, bext time reference └── system-audio.wav| kind | container | codec | carries its time as |
|---|---|---|---|
| camera, display, window | QuickTime .mov, fragmented |
HEVC; ProRes 422 as the one alternative | a tmcd track, time-of-day |
| microphone, system audio | Broadcast Wave .wav |
PCM 48 kHz, 24-bit | bext TimeReference, samples since midnight |
Video files carry no audio track; audio is always its own file. Streams record at native resolution and frame rate — per-stream codec, resolution and rate are deliberately not exposed in the MVP. The codec is one global setting: HEVC by default, ProRes 422 if you ask.
Crash safety
Every MOV is written with a movie fragment interval, so a process that dies mid-take leaves a file that plays up to the last fragment. The manifest is rewritten atomically — temp file, then rename — on every state change, so it is never half-written. A dead process leaves playable files and a truthful manifest; that is a design constraint, not a recovery feature.
Broadcast Wave stops at 4 GB. At 48 kHz, 24-bit, that is 144 kB a second per channel: about 8.3 hours mono, about 4.1 hours stereo. It is the format’s limit and Rheocles does not work around it.
No pause
There is no pause. Stop, and start a new take. A paused file would need either a gap in its timecode or a lie in it, and neither is worth a button.