feat(scoreboard): unit 6 — it is a LAYER (source type, strip geometry, resolver, session hook)

Adds SourceType.Scoreboard with the same per-scene eye toggle, drag and presence as every other
element — 'prominent on BRB, dialled back on Live' is geometry, not a second mechanism. Default
geometry is the strip: 1920 wide, 56 tall, bottom edge.

The output resolver returns the presenter's cached frame exactly like the chat box and alert box do,
and every session start clears the tallies. Preview publication writes one shared WriteableBitmap on
the UI thread (the pump thread must never touch one), refreshed only when a displayed value moves.

Guard: ScoreboardLayerTests pins the enum member, the geometry constants, the resolver case and the
session hook, so the layer cannot quietly become a special widget.
This commit is contained in:
2026-10-30 14:40:31 -07:00
parent 41b0cd6e98
commit deb74529a6
7 changed files with 134 additions and 3 deletions
+3
View File
@@ -85,6 +85,9 @@ public abstract class SceneElement : INotifyPropertyChanged
/// <summary>True only for AlertBox-type sources. Gates stream alerts properties panel.</summary>
public virtual bool IsAlertBox => false;
public virtual bool IsTextOverlay => false;
/// <summary>The scoreboard strip: a per-scene, full-width bar.</summary>
public virtual bool IsScoreboard => false;
public virtual bool IsMediaSource => false;
public virtual bool IsLiveCapture => false;
public virtual bool IsBackground { get; set; }
+5
View File
@@ -13,6 +13,8 @@ public enum SourceType
Countdown,
WebSource,
ChatBox,
/// <summary>The session scoreboard strip: full-width, state not events.</summary>
Scoreboard,
MediaSource,
/// <summary>The designated alert zone: the six monetization events play their
/// unique celebration animations here (OBS alert-box equivalent, native).</summary>
@@ -74,6 +76,7 @@ public class Source : SceneElement
Raise(nameof(DisplaySource));
Raise(nameof(IsWebSource));
Raise(nameof(IsTextOverlay));
Raise(nameof(IsScoreboard));
}
}
}
@@ -88,6 +91,8 @@ public class Source : SceneElement
public override bool IsWebSource => Type == SourceType.WebSource;
public override bool IsTextOverlay => Type == SourceType.TextOverlay;
public override bool IsScoreboard => Type == SourceType.Scoreboard;
/// <summary>The permanent brand logo layer (one per scene, directly above the background).
/// Locked against removal; its image comes from the App Settings brand logo.</summary>
public bool IsBrandLogo { get; set; }