docs(queue): six veggies, then the new work; scheduling and publishing retired
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.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user