195 lines
12 KiB
Markdown
195 lines
12 KiB
Markdown
|
|
# 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` (Tabler `ti-command`) — opens command palette (also Ctrl+K, Ctrl+P shortcut)
|
|||
|
|
- `☾` / `☀` (Tabler `ti-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.
|
|||
|
|
- `⚙` (Tabler `ti-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 otherwise
|
|||
|
|
- `PART 4 · LIVE 2` — participant count and live-ISO count; "PART" / "LIVE" in Inter 11 SemiBold UPPER tracking 0.06em, numbers in mono
|
|||
|
|
- `DISK 482g` — free disk space on the working volume; coral text if <10GB, hidden if no relevant volume is configured
|
|||
|
|
- `CTRL :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` (also `Ctrl+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 <preset name>… (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 `RenderTransform` and `Opacity` only — 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):
|
|||
|
|
|
|||
|
|
1. **Theme split** — Refactor `WildDragonTheme.xaml` → `Themes/Theme.Tokens.xaml` (styles + key shape) + `Themes/Theme.Dark.xaml` + `Themes/Theme.Light.xaml` (color resources only). Port `ThemeManager` from the deleted WinUI project; wire system app-mode detection via registry (`HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme`).
|
|||
|
|
2. **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.
|
|||
|
|
3. **Participants table redesign** — 5 columns, LED state, instantaneous audio meter, ISO pill.
|
|||
|
|
4. **Settings drawer** — Slide-over from right, dismissable; reuses existing settings view-model.
|
|||
|
|
5. **Command palette** — `Ctrl+K` floating 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
|