Compare commits

...

5 commits

Author SHA1 Message Date
150dd3f029 docs(next-steps): refresh — v2 shell + table + palette already shipped
Some checks failed
CI / build-and-test (push) Failing after 26s
The prior NEXT_STEPS.md was written the night the Studio Terminal shell
landed and listed tasks 39 + 40 (table redesign, command palette) as
queued — but they shipped in d282e1b, and several rounds of polish have
landed since (per-ISO overrides, thumbnails, web /ui redesign, gear
glyph swap, ISO toggle corner-radius + column-width fixes).

Rewrite the doc to reflect actual state: what's on main, what's running,
verified-this-session, candidate paper-cuts still to consider, and what
the next real feature pass would look like.
2026-05-16 00:18:35 -04:00
f3e1f50ece docs: refresh participants-table column summary + ISO toggle comment
Some checks failed
CI / build-and-test (push) Failing after 27s
The block comment above the DataGrid still said 'Five columns' and described
the ISO column as a 'pill' at 110px. Both got out-of-date as commits landed:
the table actually has seven columns (preview + CFG were added), the ISO
geometry is a rounded-rect, and the column is 124px now. Bring the comments
in line with the code so future-me reads the right thing first.

No XAML logic changes; comments only.
2026-05-16 00:17:37 -04:00
a98ab811a9 ISO toggle: widen column 110->124, tighten padding so 'Enable' fits
Some checks failed
CI / build-and-test (push) Failing after 31s
After dropping IsoToggle from a full pill to a Radius.M rounded-rect, the
'Enable' label (and the active-state '* LIVE') started clipping at the
right edge of the 110px cell. The pill geometry had visually masked the
tight fit by softening the edges; the squared corners made it obvious.

Widen the ISO column from 110 to 124 (+14px) and tighten the inline button
padding from 14,6 to 10,6. The MinWidth=84 from the IsoToggle style still
covers the OFF state; the column bump gives the active 'LIVE' state room
to breathe without changing the overall row rhythm.
2026-05-16 00:15:26 -04:00
25229bdf1b ISO toggle: square corners to match the rest of the button family
Some checks failed
CI / build-and-test (push) Failing after 27s
Wd.Button.IsoToggle was the only button in the GUI using CornerRadius=999
(full pill). It read as a different control type from the toolbar buttons
around it (Enable all, Refresh, Presets, Stop all, Mute, Cam, Leave —
all Radius.M). The pill shape was meant to make the LIVE state visually
distinct, but the status-coded fill (cyan/coral/amber) already carries
that signal — the geometry was double-duty.

Swap the IsoToggle's CornerRadius from 999 to Radius.M so every button
in the app shares the same shape language. Status read remains via the
fill color.
2026-05-15 16:19:19 -04:00
29f7e56eb9 gear icon: swap Path glyph for U+2699 + bump column to 56px
The custom Path gear with Stroke=Wd.Text.Secondary + StrokeThickness=1.4
rendered as a near-invisible thin grey shape against the dark row
background — users couldn't tell the column was clickable.

Replace with TextBlock rendering U+2699 GEAR from Segoe UI Symbol
at 16px and Wd.Text.Primary foreground. Universally recognized as
'settings', renders crisply at any DPI, and stands out against the
row. Header bumped from empty to 'CFG' so the affordance is
discoverable, column widened from 32px to 56px so 'CFG' fits cleanly.
2026-05-15 16:11:53 -04:00
3 changed files with 138 additions and 96 deletions

View file

@ -1,89 +1,107 @@
# Where we left off — v2 "Studio Terminal" shell landed (2026-05-13 night) # Where we left off — Studio Terminal shell shipped, paper-cuts being chipped (2026-05-16 morning)
## What's done (uncommitted on local main) ## State of main right now
**v2 redesign shape:** Approved brief at `docs/shapes/2026-05-13-teamsiso-v2-studio-terminal.md`. Aesthetic register is "broadcast-engineering instrument" — Linear's keyboard-first density × Avid console legibility. Goes hard against the "screams AI" failure mode. Origin tip: `f3e1f50` — *docs: refresh participants-table column summary + ISO toggle comment*
**PRODUCT.md + DESIGN.md** updated to reflect WPF as the host (WinUI 3 lines removed), v2 IA decisions absorbed, recording references softened, theme implementation rewritten for WPF DynamicResource swap. Recent commits on `origin/main`, newest first:
**Theme system split:** ```
- `src/TeamsISO.App/Themes/Theme.Dark.xaml` — color brushes only, dark variant f3e1f50 docs: refresh participants-table column summary + ISO toggle comment
- `src/TeamsISO.App/Themes/Theme.Light.xaml` — color brushes only, light variant a98ab81 ISO toggle: widen column 110->124, tighten padding so 'Enable' fits
- `src/TeamsISO.App/Themes/WildDragonTheme.xaml` — styles + control templates (no color brushes anymore; uses `DynamicResource` for every brush ref) 25229bd ISO toggle: square corners to match the rest of the button family
- `src/TeamsISO.App/Services/ThemeManager.cs` — singleton that swaps the merged dictionary at runtime, reads `HKCU\...\AppsUseLightTheme` for System mode, subscribes to `SystemEvents.UserPreferenceChanged`, persists via `UIPreferences.Theme`. 29f7e56 gear icon: swap Path glyph for U+2699 + bump column to 56px
- `App.xaml` merges Theme.Dark.xaml + WildDragonTheme.xaml by default; `App.xaml.cs.OnStartup` calls `ThemeManager.Current.Apply()` before MainWindow shows. 5a43c9c feat: per-ISO framerate/resolution/aspect/audio overrides + thumbnail BMP
- `UIPreferences.Prefs` record gets a new `Theme = "System"` field (forward-compatible — old json files still load). 647deec feat(web): topology + thumbnail endpoints, redesigned /ui control panel
- New brush key: `Wd.Accent.CyanText` (Dark `#97EDF0` / Light `#0E7C82`) for cyan-as-text contrast on light canvas. The existing `Wd.Accent.Cyan` stays bright in both modes for fill use. 4944de5 feat(wpf): v2 - restore live thumbnail preview column in participants table
209b643 fix(wpf): MainViewModel subscription via direct Subscribe + Dispatcher marshal
d282e1b feat(wpf): v2 task 39+40 - studio table redesign + Ctrl+K command palette
c271303 feat(wpf): v2 'Studio Terminal' shell - theme system, header, transport strip, drawer
1d1ce6a feat(wpf): rollback to WPF host, axe recording, fix settings pane
```
**v2 main window shell:** The v2 "Studio Terminal" shell, the v2 participants table redesign (task 39),
- Default Windows title bar (no more custom chromeless caption buttons — they looked generic and broke on DPI scaling). the Ctrl+K command palette (task 40), per-ISO overrides + thumbnails, and the
- 32px header: Wild Dragon mark + "TeamsISO" wordmark left; three icon buttons right (⌘K command palette, theme toggle, settings gear). The mark is small (20px) as a quality cue — click opens About. redesigned `/ui` control panel are **all shipped**. The previous NEXT_STEPS.md
- 40px transport strip: mono-typed single line. `● 02:14:32 PART 4 · LIVE 2 CTRL :9755`. Cyan dot + timer only when at least one ISO live. CTRL cluster right-aligned in a Grid column. listed 39 + 40 as queued — that's stale.
- Body: alert banner + update banner + action toolbar (Enable / Refresh / Presets / Stop all + Teams launch/hide icons) + participants DataGrid.
- Conditional meeting bar at bottom — appears only when `IsTeamsInCall == true`, with Mute / Cam / Leave.
- 72px left rail: **gone**.
- 380px permanent settings panel: **gone**.
- Six-column footer: **gone**.
- Settings: slide-over drawer overlay (420px from right) triggered by the header gear; OUTPUT / NETWORK / APP tabs (DISPLAY renamed to APP); same bindings as v1. Scrim click dismisses; Esc dismisses.
**Hotkeys preserved + new:** ## What's running
- F1 help, Ctrl+R refresh, Ctrl+Shift+S panic stop, 19 / NumPad 19 toggle Nth participant — all preserved.
- **Ctrl+T toggle theme (NEW)** — cycles dark ↔ light. Hooked through `MainViewModel.ToggleThemeCommand``ThemeManager.Toggle()`.
- **Ctrl+K command palette (placeholder)** — currently opens the help dialog. Task 40 replaces this with a real fuzzy-search palette window.
**View-model additions (MainViewModel):** A fresh Release build (PID changes each session — current one is `7928`,
- `ParticipantCount` and `LiveCount` — feed the transport strip's "PART N · LIVE N" readout. Updated on the 1Hz stats tick. started 2026-05-16 00:17). Source: `src/TeamsISO.App/bin/Release/net8.0-windows/TeamsISO.exe`,
- `ToggleThemeCommand` — wraps `ThemeManager.Current.Toggle()`. last write 23:50ish after the comment-refresh rebuild.
**MainWindow code-behind cleanup:** ## Verified this session
- Removed `OnMinimize`, `OnMaximizeRestore`, `OnClose`, `OnWindowStateChanged`, the maximize-icon swap logic (no more custom title bar).
- Added `OnCommandPaletteClick`, `OnSettingsScrimClick`, `OnPreviewKeyDown` (Esc to close drawer).
- `OnSettingsToggleClick` now toggles `SettingsDrawerOverlay.Visibility` (the slide-over) instead of toggling the v1 right-column width.
## To build, push, and demo - `dotnet test src/tests/TeamsISO.Engine.Tests/`**104 passed / 0 failed**.
- `dotnet build src/TeamsISO.App/TeamsISO.App.csproj -c Release` → 0 warnings, 0 errors.
- Pushed three new commits to forgejo: `5a43c9c..f3e1f50`.
## Candidate paper-cuts I noticed but didn't touch
These are the same shape of fix as the ones in `25229bd` / `29f7e56` /
`a98ab81` — small, single-file, low-risk — but I want you to sign off
before they ship:
1. **Header gear button still uses the thin-Path glyph.** `MainWindow.xaml:149`.
The exact same near-invisible 1.4px stroke that drove the per-row swap to
`U+2699` in `29f7e56` is still on the header settings gear. Same fix
probably applies — swap Path → `TextBlock` with `U+2699` from Segoe UI
Symbol, drop the size hack.
2. **Header theme-toggle button.** `MainWindow.xaml:137`. Hand-rolled
crescent-moon Path with 1.4px stroke. Reads as a vague grey blob in dark
mode. Candidates: `U+263D` (☽), `U+263E` (☾), or `U+2600` / `U+263C`
(☀ for light), with a `DataTrigger` swapping by `ThemeManager.Current.Mode`.
3. **Launch-Teams / Hide-Teams icon buttons in the toolbar.**
`MainWindow.xaml:388` and `:400`. Custom Path glyphs at 1.4 / 1.5 stroke
thickness — same legibility complaint, just less load-bearing because
the buttons also have tooltips.
4. **Per-row gear column** (`CFG`, 56px wide). Was widened in `29f7e56`
from 32 → 56 specifically to fit the "CFG" header. The gear glyph
inside is centered and only ~16px wide, so 56px is generous; could
probably go to 48px and reclaim 8px for the flex `*` column without
losing anything.
## What's queued for an actual feature pass
Nothing committed-against. Conversation has danced around:
- **Real command palette content.** The `Ctrl+K` window exists (commit
`d282e1b`) — actions feed from `CommandPaletteCommands.cs`. Worth a pass
to make sure every toolbar action and settings tab is mirrored there,
and that the keyboard shortcut hints render right.
- **Settings drawer copy.** The OUTPUT / NETWORK / APP tabs were rewritten
during the v2 shell pass. Some of the help text is still v1-era and
refers to controls that aren't there anymore. Worth a sweep through
`MainWindow.xaml` around the drawer body.
- **Onboarding window.** `OnboardingWindow.xaml` exists. Last touched
before the v2 shell. Probably out of date visually.
## Build, push, demo cheatsheet
```powershell ```powershell
cd "C:\Users\zacga\Documents\Claude\Projects\Teams ISO" cd "C:\Users\zacga\Documents\Claude\Projects\Teams ISO"
# Clear the corrupt local index from the earlier session # Clear a stale index lock if you hit one
Remove-Item .git\index -Force -ErrorAction SilentlyContinue Remove-Item .git\index.lock -Force -ErrorAction SilentlyContinue
git reset
# Build the WPF host # Stop any running instance (release the DLL locks)
Stop-Process -Name TeamsISO -Force -ErrorAction SilentlyContinue
# Build + run
dotnet build src\TeamsISO.App\TeamsISO.App.csproj -c Release dotnet build src\TeamsISO.App\TeamsISO.App.csproj -c Release
Start-Process .\src\TeamsISO.App\bin\Release\net8.0-windows\TeamsISO.exe
# If the build is clean: # Push when ready
.\src\TeamsISO.App\bin\Release\net8.0-windows\TeamsISO.exe git add -A
git commit -m "your message"
git push origin main # forge.wilddragon.net
``` ```
In the running app, test: If anything regresses the v2 shell, the v1 entry point is preserved in git
1. **Theme toggle** — press `Ctrl+T`. Should swap dark ↔ light without restart. Header colors, surfaces, and text foregrounds all repaint. history at `1d1ce6a` — rollback with `git reset --hard 1d1ce6a` then publish.
2. **System theme follow** — open Windows Settings → Personalization → Colors → "Choose your mode" → flip between Dark and Light. TeamsISO should track the OS automatically (default preference is `System`).
3. **Settings drawer** — click the header gear icon. 420px drawer slides in from the right with OUTPUT / NETWORK / APP tabs. Esc or click-scrim dismisses.
4. **Transport strip** — should show the session timer when at least one ISO goes live, and the PART/LIVE counts always.
5. **Conditional meeting bar** — only appears when Teams is in a call.
If anything regresses, the v1 shell is preserved in git history at `1d1ce6a` — easy rollback with `git reset --hard 1d1ce6a` then publish.
## Commit + push when ready
```powershell
git add -A src/TeamsISO.App/ docs/ PRODUCT.md DESIGN.md
git commit -m "feat(wpf): v2 'Studio Terminal' shell — theme system, header, transport strip, drawer
- 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"
git push origin HEAD
```
## What's still queued (tasks 39 + 40)
- **Task 39** — Participants table redesign. The DataGrid columns in the v2 shell are still v1-style (Name / Source / ISO toggle). v2 wants: 5 columns (state LED, name+codec, audio meter, output name mono, ISO pill), 52px rows, full-row active-speaker tint instead of left stripe, hard-edged 8px state LED.
- **Task 40** — Real Ctrl+K command palette window. Floating 560×360 dialog, fuzzy search across categories (Quick / Teams / Presets / Output / Network / App). Replaces the current placeholder that opens the help dialog.
Both are scoped commits and depend on the v2 shell being confirmed working first. After this lands and you've verified the theme swap + drawer + transport strip render correctly, ping me and we'll knock those out.

View file

@ -410,23 +410,36 @@
<!-- <!--
Participants table — v2 "Studio Terminal" layout. Participants table — v2 "Studio Terminal" layout.
Five columns: Seven columns (left → right):
1. State LED 24px — 8×8 hard-edged square. Filled cyan 1. State LED 24px — 8×8 hard-edged square. Filled cyan
when LIVE; filled coral on ERROR; when LIVE; filled coral on ERROR;
filled amber on NO SIGNAL / STARTING; filled amber on NO SIGNAL / STARTING;
hollow neutral when OFF. hollow neutral when OFF.
2. Name + caption * — DisplayName (Inter 13/Medium) plus 2. Preview thumb 106px — 96×54 (16:9) WriteableBitmap fed
from the engine's most recent
ProcessedFrame at the 1Hz stats
tick. Em-dash placeholder when
no pipeline is running.
3. Name + caption * — DisplayName (Inter 13/Medium) plus
source machine + state label below source machine + state label below
in JetBrains Mono 11/Tertiary. in JetBrains Mono 11/Tertiary.
3. Audio meter 110px — five vertical hard-edged bars, 4. Audio meter 110px — five vertical hard-edged bars,
each lit when DisplayedAudioLevel each lit when DisplayedAudioLevel
crosses its threshold (0.2, 0.4, crosses its threshold (0.2, 0.4,
0.6, 0.8, 1.0). No averaging. 0.6, 0.8, 0.95). No averaging.
4. Output name 150px — JetBrains Mono 12 — the NDI source 5. Output name 150px — JetBrains Mono 12 — the NDI source
name TeamsISO broadcasts as. name TeamsISO broadcasts as.
5. ISO toggle pill 110px — LIVE = cyan-muted fill with cyan 6. CFG (gear) 56px — U+2699 glyph button; opens the
text; OFF = hollow neutral; ERROR per-participant override editor
gets the existing trigger swap. (framerate / res / aspect / audio).
7. ISO toggle 124px — rounded-rect Radius.M button. LIVE
= cyan-muted fill with cyan text;
OFF = hollow neutral; ERROR gets
the existing trigger swap. Width
124 chosen so 'Enable' and
'● LIVE' don't clip at the right
edge after the corner-radius
change in 25229bd.
Row height 52 (down from 56). Active speaker = full-row Row height 52 (down from 56). Active speaker = full-row
bg.active-speaker tint set by the global DataGridRow style bg.active-speaker tint set by the global DataGridRow style
@ -615,36 +628,43 @@
</DataGridTemplateColumn> </DataGridTemplateColumn>
<!-- Col 5a — Per-row gear: opens the ISO override editor for this <!-- Col 5a — Per-row gear: opens the ISO override editor for this
participant. Narrow (32px) so the table still fits inside a participant. We use the Unicode gear glyph (U+2699) instead
1280px window after the toggle column. --> of a custom Path — it renders cleanly at any size, doesn't
<DataGridTemplateColumn Header="" Width="32" IsReadOnly="True"> disappear against dark rows the way 1.4px strokes do, and
reads as "settings" at a glance. Header is "CFG" so the
affordance is discoverable even when the row hover state
isn't active. -->
<DataGridTemplateColumn Header="CFG" Width="56" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Button Style="{StaticResource Wd.Button.Ghost}" <Button Style="{StaticResource Wd.Button.Ghost}"
Click="OnIsoOverrideClick" Click="OnIsoOverrideClick"
Padding="6,4" Padding="6,2"
VerticalAlignment="Center" VerticalAlignment="Center"
HorizontalAlignment="Center" HorizontalAlignment="Center"
ToolTip="Override output settings for this participant"> ToolTip="Override output settings for this participant (framerate, resolution, audio)">
<Path Data="M 8,1 L 8,3 M 8,13 L 8,15 M 1,8 L 3,8 M 13,8 L 15,8 M 3,3 L 4.5,4.5 M 11.5,11.5 L 13,13 M 3,13 L 4.5,11.5 M 11.5,4.5 L 13,3 M 8,5.5 C 9.4,5.5 10.5,6.6 10.5,8 C 10.5,9.4 9.4,10.5 8,10.5 C 6.6,10.5 5.5,9.4 5.5,8 C 5.5,6.6 6.6,5.5 8,5.5" <TextBlock Text="&#x2699;"
Stroke="{DynamicResource Wd.Text.Secondary}" FontSize="16"
StrokeThickness="1.4" FontFamily="Segoe UI Symbol"
Fill="Transparent" Foreground="{DynamicResource Wd.Text.Primary}"
Width="14" Height="14" VerticalAlignment="Center"
Stretch="None"/> HorizontalAlignment="Center"/>
</Button> </Button>
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<!-- Col 5 — ISO toggle pill. LIVE = cyan-muted fill + cyan border + cyan text. <!-- Col 7 — ISO toggle. LIVE = cyan-muted fill + cyan border + cyan text.
OFF = hollow neutral. Error states use the existing IsoToggle style. --> OFF = hollow neutral. Error states use the existing IsoToggle style.
<DataGridTemplateColumn Header="ISO" Width="110"> Width 124 (was 110) so the "Enable" / "● LIVE" content has breathing
room inside the rounded-rect — 110 was clipping the label at the
right edge once the IsoToggle stopped being a full pill (25229bd). -->
<DataGridTemplateColumn Header="ISO" Width="124">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Button Command="{Binding ToggleIsoCommand}" <Button Command="{Binding ToggleIsoCommand}"
Margin="0,0,12,0" Margin="0,0,12,0"
Padding="14,6" Padding="10,6"
VerticalAlignment="Center"> VerticalAlignment="Center">
<Button.Style> <Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource Wd.Button.IsoToggle}"> <Style TargetType="Button" BasedOn="{StaticResource Wd.Button.IsoToggle}">

View file

@ -319,7 +319,11 @@
</Setter> </Setter>
</Style> </Style>
<!-- ISO toggle: pill, status-coded --> <!-- ISO toggle: rounded-rect (Radius.M) to match the rest of the button
family, status-coded background (LIVE cyan / ERROR coral / NO SIGNAL
amber). Previously a full pill (CornerRadius=999); pill made the LIVE
indicator visually distinct from the toolbar buttons in a way that
read as "different control type" rather than "different state". -->
<Style x:Key="Wd.Button.IsoToggle" TargetType="Button"> <Style x:Key="Wd.Button.IsoToggle" TargetType="Button">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/> <Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="11"/> <Setter Property="FontSize" Value="11"/>
@ -340,7 +344,7 @@
Background="{TemplateBinding Background}" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="999"> CornerRadius="{StaticResource Radius.M}">
<ContentPresenter HorizontalAlignment="Center" <ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"/> Margin="{TemplateBinding Padding}"/>