Files
gramps d4aa588da0 feat(alerts): TASK 43 — native events & alerts (six unique animations) + chat parity
Replace the external StreamElements feed with NATIVE YouTube events per the creator's
2026-09-23 question.

Chat parity half:
- YouTubeChatService decodes ALL SIX liveChat/messages event types into
  ChatMessage.Kind (superChat/superSticker/newSponsor/membershipGifting/
  giftMembershipReceived/memberMilestoneChat) — the four formerly-empty overlay
  rows are real now — and re-arms its one-shot poll on the server's
  pollingIntervalMillis (streamList connection semantics; clamp 1000-6000ms,
  maxResults=2000). ParsePage internal static seam + ChatPage record for
  deterministic tests; optional HttpClient ctor seam kept; InjectSimulatedMessage
  (TASK 41) preserved.

Alerts half (creator rulings: one celebration zone, six UNIQUE animations, no
menus/polls, sub mention = chat row only, NO viewer count):
- New SourceType.AlertBox 'Stream Alerts' (one per layout, CanAddAlerts gate
  mirroring chat; idle = transparent).
- AlertRenderer: six distinct branded animations (SuperChat slide-up/shine/
  count-up, SuperSticker scale-pop, NewMember drop-in/flash, MemberGift slide-left/
  chip-fan, GiftReceived confetti, MemberMilestone rise/growth-bar), every card
  drawing the 'made with LlamaCasty!' brand line.
- AlertOverlayLayer: true component (Commit-G pattern) — queue (cap 10, drop tail
  never stall), 33ms UI ticker, cache-first RenderFrame + UpdatePreview,
  Advance(double) as the deterministic test clock; ChatEventKind.None rows never
  enqueue.
- Wired: resolver RenderAlertBox, _alertLayer ctor + dispose, LoadLayout previews,
  Add menu item (Controls/LeftPanel.xaml), TestSessionViewModel sims tagged
  (member->NewMember, superchat->SuperChat).

Good Dog ONE integration test: AlertLayerTests (RealApp STA, real WPF raster) —
ParsePage classifies all six kinds + cadence fields; None rows enqueue nothing;
six events play pairwise-distinct moving frames then drain to null.

Gate: clean build 0 warnings; full suite 316/317, the one failure
(LayerReorderPersistenceTests.RealMouseDrag) repros on the clean tree — the
known environmental class (real-mouse-drag no-ops with a game/fullscreen window
focused).

References (OBS/overlay ecosystem):
- streamList semantics: https://developers.google.com/youtube/v3/live/docs/liveChatMessages/streamList
- OBS alert-box pattern (designated celebration zone, idle transparent): creator-chosen model
2026-09-24 08:27:00 -07:00

4.0 KiB

Models — index

Plain data types. No logic beyond what a property can carry. See schema.md for the memory-map conventions.

File Purpose
Scene.cs A scene: Name, IsHidden, IsChatScene, IsEditing, HasBackdrop (Live-only policy flag, default off — only the canonical Live scene has one, see SceneCatalog), Elements collection (images + webcam config), WebcamConfig accessor
SceneCatalog.cs The five canonical scenes (Starting/Live/BRB/Chat/Ending) — the product, by name: All, IsCanonical, Is(name, canonical) (case-insensitive trim), IsChat, HasBackdrop(name) (true only for Live). Drives the empty-DB seed, the "+" missing-scenes menu, and MainViewModel.EnforceBackdropPolicy
Source.cs A source: SourceType enum (DisplayCapture/WindowCapture/Background/Image/TextOverlay/ChatBox/Countdown/WebSource/MediaSource/AlertBox (TASK 43 — the celebration zone, one per layout) — Webcam removed), X/Y/Width/Height, Opacity, IsEnabled, ImageSource (static) / VideoImageSource (live frames), DisplaySource (IsLiveCapture → video, else static), ClipShape enum (Traditional/Round), IsMirrored + MirrorScale, MirrorButtonText/ShapeButtonText, asset identity, IsImageSource (XAML binds this, never Type), backdrop surface: IsBackdrop (permanent bottom layer, never removable), CaptureKey (persisted monitor:<n>/window:<hwnd>/picker:<name>), IsLiveCapture (Type is Display/WindowCapture)
SceneElement.cs Base for anything placeable in a scene: shared layout/clip/mirror/border surface, virtual IsWebcam/virtual IsImageSource; ToggleClipShape + persisted RectWidth/RectHeight (pre-Round rect so round→rect restores after reload)
Webcam.cs Singleton webcam identity: Id, DeviceId, Name (one row app-wide)
WebcamSceneConfig.cs Per-scene webcam placement (subclass of SceneElement): geometry + IsVisible + border (BorderColor/BorderOpacity/BorderWidth/BorderAnimation) + VideoImageSource; WebcamId links to Webcam
QualityOption.cs Resolution tier record (Display, Fps, Bitrate, Width, Height); Label formats as 1080p60 (8Mbps) — drives the bottom-bar dropdown and the output-rect math
StreamConfig.cs StreamConfig (note: TargetBitrate/Resolution defaults are stale — not yet wired to the dropdown), StreamHealth (bitrate/FPS/dropped/duration), StreamStatus enum
MicStatus.cs Footer mic indicator: NotConnected / Connected / Problem — the state behind the MIC button's status dot (red = no device/capture off, green = capturing, yellow = a requested mic failed: in use/unplugged)
YouTube.cs YouTubeChannel and ChatMessage (chat feed) — since TASK 43 every message carries Kind (ChatEventKind None/SuperChat/SuperSticker/NewMember/MemberGift/GiftReceived/MemberMilestone) + event payload fields (SuperChatDisplayString, SuperStickerDescription, GiftNewMembersCount, GifterName, MilestoneMonths)
Socials.cs Social bar (global layer, never a Source): SocialService enum (YouTube/Twitch/X/Instagram/TikTok/Facebook/Discord/Kick/Threads/Bluesky/GitHub/LinkedIn/Pinterest/Snapchat/Reddit/WhatsApp/Telegram/Link/Website/Fediverse), SocialEntry (Service/Handle/ProfileUrl/FediverseSoftware), SocialsConfig (Entries + BarPosition Top/Bottom + BarEnabled on/off — BarJustify dropped, column back-compat), SocialServiceIcons (canonical URL builder + DetectService (URL domain / fediverse @user@domain → Fediverse / bare→Website) + bundled SVG logo path data per service (LogoDataFor) + LogoDataForFediverse(software) mapping nodeinfo software names (mastodon/peertube/pixelfed/misskey/lemmy/pleroma/firefish) to logos with a generic fediverse glyph fallback (FediverseIconData) + LockedIconData/DoNotIconData — initials/colors gone)

Related: ViewModels/index.md consume these; Services/LayoutStore.cs persists Scene/Source.