Files
gramps 318871033f feat(ui): the capture context menu is always available (Ctrl+right-click); wordmark "ty" is YouTube red
1. The preview's right-click handler swallowed every right-click for the zoom box, so the
   element/backdrop context menu could not open at all. Sources and capture windows must be
   changeable AT ANY TIME — a creator swaps a window mid-stream without entering edit mode.
   Ctrl + right-click now bypasses the zoom path and lets WPF open the menu under the cursor;
   plain right-click keeps the zoom box. No menu markup changed.

2. The wordmark's "ty" is YouTube red (#ff0000), permanently. The token sweep had recoloured it
   to the interactive blue because it was a bare literal; DESIGN.md now records "never re-colour
   the wordmark" beside the token, and UiShellTests pins it.

Guard: UiShellTests gains the wordmark rule and the Ctrl+right-click chord.
2026-10-30 11:07:51 -07:00

10 KiB
Raw Permalink Blame History

DESIGN.md — LlamaCasty visual design standard

Status: the standard (decided 2026-10-30). Token values here are normative; Themes/Tokens.xaml is the implementation, and no other file may hardcode a hex once the sweep lands. Two Google Stitch exports feed it (2026-10-26 edit screen, 2026-10-29 audio dock).

The exports' layouts and control drawings are exploratory, not spec. The dock, the four bays, the page-nav sidebar and the skeuomorphic faders are not adopted — the product's design principle is a surface so obvious that a right-brained person can use it without a manual, and hardware cosplay is the opposite of that. Only the colour, type, spacing, radius and elevation system is adopted.

Colour

Surfaces (dark navy scale, darkest to lightest)

Token Hex Use
background #0b1326 App window background
surface-container-lowest #060e20 Deepest recess (scene strip background, canvas housing)
surface-container-low #131b2e Panel background (sidebars, headers)
surface-container #171f33 Card / grouped-section background
surface-container-high #222a3d Hover state, input fields
surface-container-highest #2d3449 Selected/active row background
surface-bright #31394d Lightest surface, rare use (strong hover)
outline #334155 Borders, dividers
outline-variant #1e293b Subtle dividers, inactive meter segments
scrim-soft #22FFFFFF Hover/press wash over a surface (13% white)
scrim-strong #26FFFFFF Stronger wash — selected icon, dimmed image (15% white)
scrim-dark #26000000 Dim strip / shading over the preview (15% black)
scrim-dark-strong #00000080 Heavy overlay — modal veil, poster frame (50% black)

Text

Token Hex Use
on-surface #dae2fd Primary text
on-surface-variant #94a3b8 Secondary / label text
on-surface-disabled #5b6478 Disabled text and icons

Accent — one role each, never mixed

Token Hex Role
tertiary (electric blue) #38bdf8 The interactive accent: selection, focus, sliders, primary buttons, transform handles
on-tertiary #0b1326 Dark ink, for large blue surfaces only
on-accent #ffffff Text/icon on any saturated accent fill — the blue EDIT button, the armed REC/ON-AIR pills. One rule: a coloured fill carries white ink
primary (red) #ff5451 On-air / recording only — LIVE badge, program border, End/Go Live
primary-container #b91a24 Red pressed/hover state
secondary (amber) #ffb95f Game audio channel, Super Chat highlight
secondary-container #ee9800 Amber pressed/hover state
attention (orange) #ff8c3a Dropped frames, the live-screen indicator, blinking warnings
positive #22c55e Status only — connected, applied, healthy. Never an accent, never a button fill
error #ef4444 Error text and icons
error-container #93000a Error surface (health banner, toast) — keeps error visually distinct from on-air red
on-error #ffdad6 Text on an error surface
info-container #3a3b52 Neutral notice surface (info toast)
success-container #1d5c38 Success notice surface (success toast)
warning-container #b8860b Warning surface — health banner, warning toast
test-container #9c6f1c Test-stream chrome: the gold top bar and glow
youtube #ff0000 YouTube-branded surfaces only — Stream Info / YPP rails, the YouTube account row, and the wordmark's "ty" (creator ruling: never re-colour it)

The rule: red means "live or recording" and nothing else. Never a Send button, a delete action, a brand flourish, or a general accent — that was the defect in the first Stitch draft.

#e94560 is retired as the app's general accent (it was in 15 files). Blue takes over every interactive role; red keeps only live/record. The brand/wordmark artwork is unchanged — those assets are the creator's art, not a theme value.

Meter thresholds (both meters, all bays)

Band Range Brush
Nominal −∞ … −12 dB #38bdf8
Caution −12 … −3 dB #ffb95f
Peak / clip −3 … 0 dB+ #ff5451

Meters are measured, never decorative (see docs/ai/output.md): the ladder shows the live level scaled by the current gain, not the gain setting.

Typography

Token Family Use
sans Inter (400/500/600/700) All UI text — labels, buttons, panel titles
mono JetBrains Mono (500/600) Numeric/telemetry values — bitrate, FPS, dB, coordinates, timers. Tabular figures stop digits shifting width as values change

Icons: Material Symbols Outlined (bundled, not fetched).

Scale

Token Size / line Weight Tracking Use
headline-lg 32 / 40 700 −0.02em Landing/empty-state titles only
headline-md 24 / 32 600 −0.015em Dialog titles
headline-sm 18 / 24 600 −0.01em Panel and section headers
body-lg 15 / 22 400 — Default body, chat
body-md 13 / 18 400 — Panel rows, form text
body-sm 12 / 16 400 — Secondary text, hints
label-lg 13 / 16 600 0.02em mono — primary telemetry values
label-md 11 / 14 500 0.04em mono — labels, hotkey chips
label-sm 10 / 12 500 0.05em mono — dense telemetry only

Floors and implementation notes

  • 11px is the default label size; 10px is the absolute floor and only for dense readouts that sit beside a larger value. Nothing readable at 100% zoom may be smaller than 10px.
  • WPF has no letter-spacing. Tracking values above are design intent, not a property; implement as-is (no tracking) rather than faking it with padded strings.
  • Mono numerics use Typography.NumeralAlignment="Tabular" so widths stay stable.

Spacing

Token px Use
space-xs 4 Inside a chip, icon-to-text
space-sm 8 Between related controls
space-md 12 Default gap inside a panel
space-lg 16 Panel padding, section separation
space-xl 24 Dialog padding, major separation
gutter 12 Between page columns
margin 16 Window edge to content
margin-docked 8 Edge to content when a rail/drawer is docked

Shape

Token px Use
radius-sm 4 Chips, badges, keycap tags
radius-md 8 Buttons, inputs, cards, scene tiles
radius-lg 16 Preview viewport, drawers, dialogs
radius-full pill Status chips (LIVE, EDIT), toggles

Recessed controls (fader wells, inputs) use the same outer radius as their housing so the seams line up — do not mix a 4px well inside an 8px card.

Elevation

Level Use Implementation
−1 recessed Fader wells, input fields, table headers inset top shadow + surface-container-lowest
0 panel The default chassis surface-container* + 1px outline border, no shadow
1 raised Scene tiles, floating chips, action buttons subtle drop shadow, 0 1px 2px
2 floating Drawers, popups, dialogs larger spread + 1px top highlight

Budget rule: DropShadowEffect is software-rendered in WPF. Shadows on small controls only — never on the preview viewport, the scene strip, or either wing. Depth on large surfaces comes from the surface scale and the 1px border, not from effects.

Interaction

  • Focus ring: 1px #38bdf8 outside a 1px gap — visible against every surface level.
  • Hover: step one surface level up; active: step two. No colour change on hover except for destructive actions.
  • Motion: 150ms CubicEase(EaseOut) for drawers/popovers; 90ms for hover/press. No springs — WPF has no spring easing and hand-rolled overshoot reads as jank at 60Hz.
  • Every action produces a visible outcome. No dead ends, no silent failures.

Not in this standard

  • The audio dock, its four bays, per-bay faders, 24-segment ladders, transport controls, lip-sync slider and master telemetry strip — exploratory. The controls they re-house already exist in the app; whether any of them gets a dock is a separate product decision.
  • The page-nav sidebar (Broadcast Studio / Audio Mixer / Scene Matrix / Telemetry / Hotkeys) — the app is one surface with an EDIT toggle and drawers, not a page router.
  • CPU / GPU / NVENC readouts — no telemetry exists, and none of it changes a live decision.
  • Acrylic/backdrop blur — WPF has no sub-region backdrop blur; panels are solid.
  • On-stream output (chat box, social bar, alerts, brand flash) is styled by its own renderers, not by this theme. Do not apply UI tokens to the broadcast picture.

Rejected from the 2026-10-29 export

The export is a Material-3 dump from a warm seed; four tokens came out tinted by that seed and are rejected in favour of the values above.

Export value Token Why rejected
#4cd7f6 tertiary Neon cyan beside the amber reads "toy"; #38bdf8 is calmer and already used in-app
#ab8986 outline Warm pink borders from the seed — wrong for a navy chassis
#5b403e outline-variant Same seed artifact
#e4beba on-surface-variant Pink secondary text; slate #94a3b8 is legible and neutral

Implementation status

  • Themes/Tokens.xaml exists and is merged first in App.xaml (2026-10-30). Guard: ytLive.Tests/DesignTokensTests.cs — it parses this document and fails if a documented token has no brush, if a value disagrees, or if the retired #e94560 returns as a token.
  • Still to sweep: Themes/Controls.xaml and the dozens of hardcoded hexes in XAML/C# still use the legacy palette. Surfaces convert one at a time; the end state is that every colour, radius and spacing value resolves from Tokens.xaml and a guard fails on any raw #hex outside it.
  • Fonts ship with the app (Assets/Fonts/*.ttf, OFL-1.1) — no installation, no network, no dependence on what the machine happens to have. Notice and license text travel with them (THIRD-PARTY-NOTICES.txt items 13-14).