- Theme split: Theme.Dark.xaml + Theme.Light.xaml + ThemeManager - New shell: 32px header (mark + wordmark + 3 icons), 40px transport strip, conditional meeting bar, slide-over settings drawer - Removed: 72px rail, 380px permanent settings panel, 6-column footer, custom chromeless title bar buttons - Ctrl+T toggles theme; follows Windows app-mode by default - Shape doc at docs/shapes/2026-05-13-teamsiso-v2-studio-terminal.md
12 KiB
TeamsISO v2 — Studio Terminal (approved shape brief)
Date approved: 2026-05-13
Approver: Zac (operator + product owner)
Host: WPF .NET 8 (src/TeamsISO.App/). WinUI 3 rebuild is abandoned.
Predecessor: the WPF rollback at 1d1ce6a (recording axed, settings pane tab fix, settings button wired).
Why this redesign
The v1 GUI failed the "AI made that" test. Quote from the operator: "its cluttered, screams that AI made it - and relatively inefficient to navigate." The PRODUCT.md anti-references — card-grid-of-icons, always-visible side panel, footer-as-theatre — all describe the current build. v2 commits to a different aesthetic register entirely.
Aesthetic register
Broadcast-engineering instrument. Not a SaaS dashboard. Not Material. Not Fluent default.
Reference proximity: Linear's keyboard-first density × Avid S6 console legibility × Blackmagic ATEM's information hierarchy. The operator mental model is "I'm sitting at an audio mixer; every region has a job, no region is theatre."
What goes away
- The 72px left rail (no actual navigation — there's only one screen)
- The 380px always-visible settings pane (settings change rarely, shouldn't claim permanent real estate)
- The 6-column footer status row (theatre, not information)
- The custom chromeless title-bar caption buttons (look worse than system chrome, break on DPI scaling)
- The "by Wild Dragon" pill and the always-visible "TeamsISO" wordmark as decorative chrome
- The in-call control bar as a permanent strip (only relevant in-call; should appear conditionally)
- The seven identical ghost buttons in the in-call bar (textbook card-grid anti-pattern)
What replaces it
┌─ system Windows title bar [_ □ ✕] ─────────────────────┐
│ 🐉 TeamsISO [⌘K] [☾] [⚙] │ 32px header — mark + wordmark left, 3 icons right
├────────────────────────────────────────────────────────┤
│ ● 02:14:32 PART 4 · LIVE 2 DISK 482g CTRL :9755 │ transport strip — single mono line, replaces footer
├────────────────────────────────────────────────────────┤
│ │
│ ▮ alice ▮▮▮▮ t:5ms alice [LIVE] │
│ ▯ bob ▮▮ t:8ms bob [— OFF]│ participants table = the canvas
│ ▮ carlos ▮▮▮▮▮ t:9ms carlos [LIVE] │ (cyan-tinted row bg = active speaker)
│ ▮ guest 4 -- NO SIG guest_4 [ERROR]│
│ │
├────────────────────────────────────────────────────────┤
│ IN CALL · Daily standup [mute] [cam] [leave] │ conditional — only renders when in call
└────────────────────────────────────────────────────────┘
Header (32px)
Left: Wild Dragon mark (~20px) + "TeamsISO" wordmark in Inter 13 Medium. Click on mark opens About. Right: three icon buttons.
⌘K(Tablerti-command) — opens command palette (also Ctrl+K, Ctrl+P shortcut)☾/☀(Tablerti-moon/ti-sun) — cycles theme dark ↔ light. Tooltip "Theme (System / Dark / Light)" — long-press could open the tri-state, but for v2 just a one-click cycle.⚙(Tablerti-settings) — opens settings drawer
That's all the chrome. No nav rail because there's nothing to navigate to.
Transport strip
Single horizontal line. Mono type (JetBrains Mono 12). Replaces the entire footer.
Fields:
● 02:14:32— green dot + session timer when at least one ISO is live; both hidden otherwisePART 4 · LIVE 2— participant count and live-ISO count; "PART" / "LIVE" in Inter 11 SemiBold UPPER tracking 0.06em, numbers in monoDISK 482g— free disk space on the working volume; coral text if <10GB, hidden if no relevant volume is configuredCTRL :9755— control surface bind; cyan text when active, hidden when off
No icons. No badges. No backgrounds. Just typed status — a console heads-up display.
Participants table — the canvas
Five columns:
| # | Width | Content | Type |
|---|---|---|---|
| 1 | 24px | State LED — 8×8 filled cyan/coral or hollow neutral | hard-edged square, no rounding |
| 2 | * | Name (Inter 13/Medium) + codec/latency caption (Mono 11/Regular, tertiary fg) | "Alice Wong" / "NDIV5 · t:5ms" |
| 3 | 110px | Audio meter — 5 vertical bars, instantaneous level | hard-edged, cyan when LIVE, neutral when OFF |
| 4 | 130px | Output name | Mono 12 |
| 5 | 100px | ISO toggle pill | LIVE = cyan fill / OFF = hollow neutral / ERROR = coral outline |
Row height: 52px (was 56).
Active speaker: full-row background tint bg.active-speaker (cyan-tinted muted neutral). NOT a left-edge stripe — that trips the impeccable "side-stripe border" ban.
Each row reacts to:
- Click anywhere → focuses the row, keyboard-actions apply
- Click the pill → toggle ISO
- Right-click → context menu (preview, custom name, copy NDI source name, save snapshot)
- Hover → reveals a kebab affordance in column 5 right edge for less-frequent actions
Conditional meeting bar
Renders below the table only when TeamsControlBridge.DetectCallState().IsInCall == true. Slides up from below on transition (~120ms ease-out-quart on RenderTransform.Y + Opacity).
Content: IN CALL label (Inter 11 SemiBold UPPER, cyan accent) + meeting title (Mono 12, truncated with ellipsis) + three buttons right-aligned (Mute / Cam / Leave). Share and Notes do NOT live here — they move to ⌘K, where they're invocable any time without the bar fighting for attention.
Width matches the table — not full-bleed; respects the page padding.
Ctrl+K command palette
The redesign's navigation move. Replaces ~80% of what's in the v1 rail + tabbed settings.
Behavior:
Ctrl+K(alsoCtrl+P) opens a centered floating window over the main shell, 560×360px- Search input at the top, results list below
- Empty input → frequent + recent commands
- Typing → fuzzy-matches across command label + category + keywords
- ↑/↓ navigates, Enter invokes, Esc closes
Command categories (each command has icon, label, optional value preview, optional shortcut hint):
- Quick — Enable all online, Stop all ISOs, Refresh discovery, Drop snapshot of all
- Teams — Launch Teams, Hide / show Teams windows, Mute, Toggle camera, Open share, Leave call
- Presets — Apply … (one row per saved preset), Save current as preset, Manage presets
- Output — Framerate 24 / 30 / 60, Resolution 1080p / 720p, Aspect Pillarbox / Letterbox / Stretch
- Network — Apply transcoder topology, Restore default NDI groups, Edit output name template
- App — Theme dark / light / system, Open settings, About TeamsISO, Help (F1)
This is the keyboard-first surface broadcasters with Stream Decks already mentally use.
Settings — slide-over drawer
Triggered from the header gear icon, or from Open settings in the palette, or hotkey , (comma).
- 420px wide, slides in from the right
- 40% canvas scrim behind
- Three tabs: OUTPUT (framerate / resolution / aspect / audio + Reset to defaults), NETWORK (discovery / output groups + Apply transcoder topology + Restore defaults + output name template), APP (theme tri-state, minimize to tray, sort order, Launch Teams on startup, Auto-hide Teams windows)
- Apply Changes button pinned to drawer footer; Esc dismisses; click outside the drawer dismisses
DISPLAY tab from v1 gets renamed APP and absorbs the theme tri-state.
Empty states
- No participants yet: a single centered mono sentence, "no ndi sources yet — open teams and start a meeting", and one tertiary button "Refresh discovery (Ctrl+R)". No illustration, no mascot.
- Not in a call: meeting bar simply doesn't render. No placeholder.
- Discovery degraded: amber dot in transport strip's session timer position, mono text "NDI discovery — restarting". No banner.
Color, theme, motion
Color strategy: Restrained (impeccable product default). Cyan accent earns its place — reserved for LIVE state, focus ring, active speaker tint. Coral reserved for destructive + error. Status amber for warnings. Green NOT used (would compete with cyan for "ok / live" semantics).
Theme default: Follow Windows. Theme persists per-operator via UIPreferences.Theme. Implementation: split WildDragonTheme.xaml into a single style + token-shape file plus two color-only ResourceDictionary files (Theme.Dark.xaml, Theme.Light.xaml). At runtime ThemeManager swaps the merged dictionary entry. WPF analog of WinUI's ThemeDictionary.
Motion:
- 120ms
cubic-bezier(0.16, 1, 0.3, 1)(ease-out-quart) on the meeting bar slide-in/out - 200ms ease-out on the drawer slide
- 180ms cross-fade on theme swap
- 90ms on focus + hover transitions
- No bounce, no elastic, no spring overshoots. Animate
RenderTransformandOpacityonly — never layout properties.
Typography commitments
| Token | Family | Size | Weight | Used for |
|---|---|---|---|---|
text.timer |
JetBrains Mono | 14 | Medium | Session timer in transport strip — instrument-grade |
text.caption |
Inter | 11 | SemiBold (600) | UPPER + tracking 0.06em — transport-strip labels, "IN CALL", "SPEAKING" |
text.display |
Inter | 22 | SemiBold | Settings drawer headings only |
text.title |
Inter | 13 | Medium | Wordmark, table column headers |
text.body |
Inter | 13 | Regular | Participant display names |
text.mono.code |
JetBrains Mono | 12 | Regular | Output names, NDI IDs, meeting title |
text.mono.tech |
JetBrains Mono | 11 | Regular | Latency readouts, codec captions, transport-strip values |
What this is NOT
- Not Fluent-styled. Default Fluent accent integration is generic Windows; TeamsISO is a broadcaster's tool.
- Not minimalism for its own sake. The participants table is dense. Density is the broadcaster's virtue.
- Not chromeless. Default system title bar stays. Chromeless windows break embarrassingly at 4K + DPI scaling.
- Not vanity-branded. The Wild Dragon mark sits small in the header as a quality cue, never as decoration.
Migration path
The view-model surface in src/TeamsISO.App/ViewModels/ is the contract. The redesign rewrites MainWindow.xaml and Themes/* but leaves view-models, the engine, the control surface server, and the OSC bridge untouched.
Order of operations (each step builds clean before the next):
- Theme split — Refactor
WildDragonTheme.xaml→Themes/Theme.Tokens.xaml(styles + key shape) +Themes/Theme.Dark.xaml+Themes/Theme.Light.xaml(color resources only). PortThemeManagerfrom the deleted WinUI project; wire system app-mode detection via registry (HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme). - Main window shell — Replace MainWindow.xaml's outer Grid. Add 32px header, transport strip, full-width content area, conditional meeting bar. Delete the 72px rail, the 380px right pane, the footer.
- Participants table redesign — 5 columns, LED state, instantaneous audio meter, ISO pill.
- Settings drawer — Slide-over from right, dismissable; reuses existing settings view-model.
- Command palette —
Ctrl+Kfloating window with fuzzy command list.
Each step is a self-contained commit so the v1 build remains shippable at any rollback point.
Anti-references — explicit on the "AI made that" failure
These are the failure modes the redesign defends against:
- Card-grid-of-icons (the v1 in-call bar's seven identical ghost buttons)
- Always-visible side panel (the v1 380px settings sidebar)
- Decorative chrome (the v1 "by Wild Dragon" pill, the 72px nav rail, the six-column footer)
- Generic Inter at 13 for everything
- Default WPF DataGrid (Excel)
- Custom chromeless title bars that look generic
- Gradient text, glassmorphism, side-stripe borders (impeccable absolute bans)
- "Hero metric + supporting stats + gradient" SaaS dashboards
- Mascots, "Welcome!" copy, illustrated onboarding cards