feat(alerts): TASK 47 — alert box plays a video (built-in/custom clip) + read-time fade + message ticker
TASK 43's alert box grows a real video celebration. Per-alert IAlertClipDecoder
(ffmpeg bgra + f32le pipes, real-time paced, disposed at drain) plays the shipped
Assets/alert-default.mp4 (stamped into the Asset table at startup) unless the
creator picks their own file — path reference only, never stored in the DB; the
six AlertRenderer animations stay the fallback. ~0.3s fade rides the alpha
envelope on straight-source copies (EOF freeze-frames then fades out); audio
forwards to a new AudioMixer alert ring (8s, 48k stereo) drained at unity — no
duck, creator ruling — scaled by volume × fade. An auto-composed marquee ticker
('Funder — Super Chat · $10.00', 140px/s) scrolls top-of-frame via a
FramePump._alertTicker seam through Render/CompositeLayers, mixed into the cache
signature (dynamic overlay, never baked). New Stream Alerts section in LeftPanel.
Derivative-work references (how OBS/Streamlabs alert boxes do per-alert video):
- https://support.streamlabs.com/hc/en-us/articles/217741147-Setting-Up-Your-Streamlabs-Alerts (custom image/video per alert type + variations)
- https://obsproject.com/kb/stream-tutorial-2-alerts (alert overlay as an on-screen zone)
- https://streamlabs.com/content-hub/widgets/alert-box (per-event alert playback)
Good Dog: AlertLayerVideoTests drives a fake IAlertClipDecoder through the whole
lifecycle in one pass (custom path wins, decoder spawns/disposes, fade envelope
0→127→255, audio volume×fade, ticker scrolls, EOF fade-drain to idle). It caught
the clip branch of Advance not clearing _current before AdvanceToNext — the layer
stayed IsPlaying after drain (MyMistakes post-mortem).
Full vstest 319/319; clean build 0 warnings; scope check green.
This commit is contained in:
@@ -62,6 +62,7 @@
|
||||
| 44 | TEST-tab chat fix: resolve liveChatId from snippet (not contentDetails) + poll until the broadcast is live | ✅ Done (2026-09-25); full suite 318/318 | [`TASKS/task-44-test-chat-fix.md`](TASKS/task-44-test-chat-fix.md) |
|
||||
| 45 | TEST-tab chat fix #2: insert body must declare `snippet.type` (400 MISSING_REQUIRED_FIELD) | ✅ Done (2026-09-25) | [`TASKS/task-45-chat-insert-type.md`](TASKS/task-45-chat-insert-type.md) |
|
||||
| 46 | Drawers: click outside the rail closes whichever is open — TEST added to the existing Stream Settings + YPP dismiss behavior | ✅ Done (2026-09-25) | [`TASKS/task-46-drawer-click-outside-close.md`](TASKS/task-46-drawer-click-outside-close.md) |
|
||||
| 47 | Alert box video: built-in/custom alert clip (+ six-animation fallback) with read-time fade in/out + ticker + alert volume in the live mix | ✅ Done (2026-09-26) | [`TASKS/task-47-alert-videos.md`](TASKS/task-47-alert-videos.md) |
|
||||
|
||||
---
|
||||
|
||||
@@ -120,6 +121,17 @@
|
||||
enableAutoStart; YouTube only populates the id on live broadcasts — official GetLiveChatId.java
|
||||
sample lists broadcastStatus=active). Fixed by reading `snippet.liveChatId` and polling with a
|
||||
bounded retry after the frame pump starts; chat stays non-fatal.
|
||||
- **TASK 47 — Alert box video** — **DONE 2026-09-26** (`TASKS/task-47-alert-videos.md`):
|
||||
the TASK 43 alert box now plays a **video** on every alert — a shipped built-in mp4
|
||||
(`Assets/alert-default.mp4`, stamped into the `Asset` table at startup) that the creator can
|
||||
swap for their own file via the new Stream Alerts section (path only, never stored in the DB;
|
||||
six `AlertRenderer` animations remain the fallback). Per-alert decode via a new
|
||||
`IAlertClipDecoder` fx (ffmpeg rawvideo bgra + f32le pipes, real-time paced, disposed at
|
||||
drain); ~0.3s fade-in/out rides the alpha envelope + scales the audio (mixed into the live
|
||||
stream at unity — **no duck**, a per-alert Volume slider instead); an auto-composed message
|
||||
**ticker** ("Funder — Super Chat · $10.00") scrolls along the very top of the frame
|
||||
(never-baked dynamic overlay threaded through SceneCompositor + FramePump). Creator rulings:
|
||||
custom + fallback (not either/or), ticker on top, no ducking.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user