The creator (2026-10-21), on Live -> Layers -> webcam -> Properties: "the Y and H boxes under webcam properties should be the same width as the X and W boxes and those widths should be fixed to accomodate the max number of possible digits providing the geometry values" "also the border color drop drown box content should also include the name of the color next to the hex value as they in the drop-down list box" TASK 61 - one fixed width for the four geometry fields. The row is a DockPanel, and WPF sizes an element to its CONTENT unless it is told otherwise, while the LAST child of a DockPanel fills the remaining space. So X/W (not last) were as wide as their text and Y/H (last) stretched across the row - two widths for the same kind of field. Now all four carry Width="44" and the rows set LastChildFill="False" (without it the last field ignores its own Width and fills anyway). 44px is the measured width of "-1920" in the app's font at 11px (the largest geometry value - the master frame is 1920x1080 - plus a sign) plus the field's padding and border. Docs: https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.dockpanel.lastchildfill The guard MEASURES the widest value with WPF's FormattedText instead of asserting a magic number, so a font change cannot silently make the field too narrow: https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.formattedtext TASK 62 - the border field names its colour. SceneElement.BorderColorName carries the palette's name for the current colour ("Crimson") and is raised when the colour changes; it is EMPTY for a custom hex the creator typed, because "no name" is the honest answer. BorderColorPalette.NameOf changed to match (it used to fall back to the hex itself; the TASK 60 test assertion was updated with it). The hex field keeps a fixed width (60) so the name sits right next to the hex instead of drifting to the row's far edge - the same trap as TASK 61. Guards: ytLive.Tests/GeometryFieldWidthTests.cs, ytLive.Tests/BorderColorNameTests.cs Full suite: 435/435 passed, 0 warnings.
7.7 KiB
7.7 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, 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/virtual IsZoomLayer (TASK 52); ToggleClipShape + persisted RectWidth/RectHeight (pre-Round rect so round→rect restores after reload); TASK 57: the geometry setters (X/Y/Width/Height) are virtual so a derived element can CONSTRAIN every write (the webcam clamps itself into the vertical tier's band) instead of every writer re-implementing the rule; ClipShape + ToggleClipShape() are virtual too, so a derived element can CONSTRAIN the shape (the Chat scene's vertical camera is rect-only); TASK 59: IsRectShape/IsRoundShape — the shape as a CHOICE (the properties panel shows Rect |
VerticalCameraLayout.cs |
TASK 57 (the "vv" feature): the vertical (9:16) tier's camera rules as pure math — TileWidth/TileHeight (270×152 master px = 480×270 in the 1080×1920 output), Inset (32 master px from the band's outer edge), IsVerticalTier(QualityOption) (portrait tier), AreaFor(band, bottom) (the band splits into two 607×540 areas), MaxSizeFor(band), SpotFor(band, w, h, centreX, centreY) (the six spots — the area and column the tile's centre falls in, inset, never outside the band) and DefaultSpot (bottom-right, the corner the 16:9 default webcam uses), FillsArea(band, width) (the camera is wide enough to fill a whole area = "enlarged") and SizeFor(band, requestedWidth) (the Chat camera's TWO sizes - the small tile or one whole 607×540 area — whichever is nearer the requested width, so the resize handle has two detents) |
ZoomSceneElement.cs |
Transient zoom box (TASK 52, creator-corrected 2026-10-08): carries the box rect AND the anchored CaptureX/CaptureY (the fixed box/2 capture window set on ActivateZoom; moving the box never touches it). IsZoomActive flips Kind Static→Dynamic (leaves the baked base while active); never persisted (LayoutStore save skips non-Source/non-WebcamSceneConfig rows), never shown in the layers list or the element template (IsZoomLayer gates both). The compositor SKIPS the active element in every layer loop and draws its 2x content LAST (layer n+1) via ZoomMagnifier. |
Webcam.cs |
Singleton webcam identity: Id, DeviceId, Name (one row app-wide) |
BackgroundEffect.cs |
TASK 51: per-webcam background effect enum None / Remove / Blur, carried by WebcamSceneConfig |
BorderColorPalette.cs |
TASK 60: the colours the webcam's border-colour drop-down offers — NamedColor(Hex, Name) + BorderColorPalette.All (the single source of truth; the picker builds its menu from it) and NameOf(hex) (case-insensitive; empty for a colour outside the palette — "no name" is the honest answer, TASK 62). The creator asked for a colour NAME next to each hex: #e94560 Crimson |
WebcamSceneConfig.cs |
Per-scene webcam placement (subclass of SceneElement): geometry + IsVisible + border (BorderColor/BorderOpacity/BorderWidth/BorderAnimation) + VideoImageSource; WebcamId links to Webcam; TASK 51: BackgroundEffect + BackgroundStrength (0..1, default 0.5) + the radio-pill surface RemoveBackground/BlurBackground (one on turns the other off; both off = None) + HasBackgroundEffect (shows the strength slider); TASK 57 (the "vv" feature): the vertical (9:16) tier's OWN placement per scene — VerticalX/Y/Width/Height/VerticalClipShape/VerticalRectWidth/VerticalRectHeight (persisted, NULL = no vertical placement yet) + the transient VerticalBand/VerticalLayoutLive/LandscapeX…LandscapeRectHeight (the parked 16:9 layout) + BeginVerticalLayout/EndVerticalLayout/CommitLiveLayoutToVertical (the tier swap) and the X/Y/Width/Height overrides that clamp every write into the band; VerticalShapeLocked (the Chat scene's vertical layout is rect-only) overrides ClipShape + ToggleClipShape() so no writer can slip a circle in |
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.