Creator ruling 2026-11-09: finish the queue before the new features, gold pass always last. **Retired (platform's surface, not ours):** - 34 scheduled streams — YouTube owns scheduling *and* the reminder that makes it worth anything. - 50 publish recording — Studio owns upload (resumable, quota-aware, explains rejections), and an in-app uploader would widen the OAuth consent to whole-channel video management for one convenience. The app adds "Show in folder" instead. **New tasks:** 65 replay clips (the creator-side buffer YouTube does not give you), 66 timed ticker messages, 67 per-event alert videos, 68 edit-while-live + first-run On-Air. **TASK 65 spec** is the interesting one: 15 s is a clip (10/15/20, default 15); the ring holds encrypted *encoded* fragments in RAM — raw 1080p frames would be ~7.4 GB for 15 s — so there is no steady disk write and no crash debris; F10 saves; the replay layer plays once then hides in Live and loops the last 1–3 elsewhere; silent by default; three kept; the layer is excluded from its own clip (hall of mirrors). **TASK 14 gains Branch 3:** mic input gain ahead of the gate (table boom mics fall under it), webcam blank hotkey, opacity/geometry parity with a collapsed Geometry disclosure, Show-in-folder. **Decisions recorded:** the replay-buffer reversal (it was retired in 2022-era reasoning as "different product"; the case for it won), the platform-surface rule, and voice triggering deferred — always- listening in a streaming app hears the game, so the content is its own false-positive source. Queue refactored to 56 lines by archiving completed rows and the superseded surge plan; HANDOFF at 40.
66 lines
3.3 KiB
Markdown
66 lines
3.3 KiB
Markdown
# TASK 65 — Replay clips: buffer the last 15 seconds, show it, save it
|
||
|
||
> Catalog: [`TASKS.md`](../TASKS.md) — status and requirements live here.
|
||
> Spec settled with the creator 2026-11-09. **Not a Twitch-clip clone:** the platform owns viewer
|
||
> clips; this is the creator-side replay buffer YouTube does not give you.
|
||
|
||
## The rule
|
||
|
||
**15 seconds is a clip.** Options 10 / 15 / 20, default **15**, no slider, no 30. A clip is a moment,
|
||
not a segment — 3-minute Shorts are the platform's problem, not ours.
|
||
|
||
## Why the ring holds encoded bytes, not frames
|
||
|
||
A 1080p BGRA composite frame is 8.3 MB; fifteen seconds at 60 fps is **~7.4 GB** of raw frames. The
|
||
15 MB figure is *after* compression. So the ring keeps **fragmented MP4** (`frag_keyframe+empty_moov`)
|
||
that ffmpeg writes to a pipe, in a **byte ring in RAM** — never on disk, never raw.
|
||
|
||
- Fragments are **1 s** (not 2): the ring can only hand back whole fragments, so a longer fragment
|
||
means the save can miss the punchline.
|
||
- The buffer is capped **by bytes**, not seconds — bitrate moves. When 15 s would exceed the cap, the
|
||
clip is simply shorter.
|
||
- The ring is a member of the process: it dies with the app, so a crash leaves no debris and needs no
|
||
sweep. **Nothing touches the disk until F10.**
|
||
|
||
## Trigger
|
||
|
||
**F10** saves the clip (F1–F9 are taken; F11 is the fallback if a game steals F10). No focus switch, no
|
||
mouse. Deferred deliberately: **voice triggering** (always-listening in a streaming app is a privacy
|
||
liability, and the game's own audio produces false positives) and **`!clip`** (only for viewers/mods,
|
||
never the creator, who cannot reach a keyboard mid-moment).
|
||
|
||
## The replay layer
|
||
|
||
One layer type, added by the creator to the scenes they want; behaviour comes from the scene:
|
||
|
||
| Scene | Behaviour |
|
||
|---|---|
|
||
| **Live** | plays the new clip **once**, then **hides** — you're there to see it or you're not |
|
||
| Every other scene | loops the last **1–3** saved clips **in order** (highlight reel), configurable |
|
||
|
||
- **Audio off by default**, toggleable per layer. The show's sound design is the creator's; a replay
|
||
should not re-mix it uninvited.
|
||
- **The replay layer is excluded from the clip's own composition.** Otherwise saving while a clip plays
|
||
records a video of a video (hall of mirrors). Viewers still see it live; the clip simply doesn't.
|
||
|
||
## Storage and retention
|
||
|
||
- Saved to `clips\` beside recordings, as a normal `.mp4`.
|
||
- **The three most recent are kept**; the fourth deletes the oldest.
|
||
- **Auto-clip on monetization events** (off by default): a Super Chat / membership / raid saves the
|
||
preceding 15 s hands-free. Same retention, so it cannot accumulate.
|
||
- **Disk discipline:** no steady writes while live (the ring is RAM); the free-space guard that already
|
||
protects REC also disables the ring when space is low — **the recording always wins**.
|
||
|
||
## Privacy
|
||
|
||
Named in `PRIVACY.md`: clips are local only, the three most recent are kept, older ones are deleted
|
||
automatically, and nothing is uploaded. The first save says the same in one line, so the policy is not
|
||
only a document.
|
||
|
||
## Tests
|
||
|
||
- Ring: fragment boundaries respected, byte cap enforced, save emits a playable MP4, oldest pruned.
|
||
- Layer: once-then-hide in Live, in-order loop elsewhere, silent by default, layer excluded from the clip.
|
||
- Failure: save with an empty ring (just started) says so instead of writing a 0-byte file.
|