Creator report: Ctrl+right in edit mode and left-click in preview did nothing when
neither streaming nor recording. The bindings were correct; the action was not.
Two causes, both in the model rather than the handler:
- ActivateZoom opened with `if (!(IsLive || IsRecording)) return;` — the box could not be
created outside a session at all.
- ToggleZoom only ever called DismissZoom, so "toggle" could turn it off and never on.
Now ToggleZoom(x, y) activates at the cursor or dismisses if already open, and the live-only
guard is gone — the magnifier is an editing aid as much as a live one. Both call sites pass
the canvas point, so the box still anchors on the click rather than the frame centre.
Debug 0 warnings; ZoomBox + ZoomMagnifier tests pass (3).
Two event-pairing bugs found by validating every handler instead of trusting the table.
1. Ctrl+right-click opened the context menu in edit mode. Cause: WPF's PopupControlService
opens menus on right-button-UP, and only the DOWN event was being handled — so the zoom
toggled and the menu appeared under it. Both events are now handled when Ctrl is down.
(The creator saw this in edit mode; preview mode had the same latent bug.)
2. The social bar's left-click was dead in preview mode and dragged the layer beneath it in
edit mode. Cause: PreviewGrid handles the TUNNELLING PreviewMouseLeftButtonDown, which
fires before the bar's bubbling handler — and since preview-mode left-click now toggles
zoom, that handler swallowed the bar's click too. The preview handler now steps aside when
the point is inside the bar's bounds (SocialBarElement.RenderSize, translated to canvas).
Audited and left alone because they are correct: left-down → resize handle / element drag /
deselect; move → zoom drag before edit drag (by design); left-up → EndPreviewDrag; right-up
→ zoom-drag release then the Ctrl swallow.
Build Debug 0 warnings, 22 tests pass across ZoomBox, PreviewHistory and SocialBar.
Creator ruling 2026-11-01, and the reason is live-stream ergonomics: no two-handed
chords while a broadcast or recording is running.
- Edit mode: left selects / drags / resizes, right opens the context menu, Ctrl+right
toggles the zoom box. Chords are acceptable here because editing is a stopped activity.
- Preview mode: left toggles the zoom box, right opens the context menu, and Ctrl+right
is swallowed outright — handled rather than left to fall through, so Ctrl+right cannot
open a menu by accident while one hand is on the mouse.
This also removes the old live behaviour where right-click activated the magnifier at the
cursor point (and dismissed it). Zoom in preview is now a plain toggle; if point-zoom is
wanted back it needs a one-button gesture, not a chord.
Build: Release 0 warnings. Debug is currently blocked by the running app holding the exe
(PID 47252) — close it and the Debug build copies normally.
Three creator directives (2026-11-01), done ahead of the surge.
**Gear moved to the preview rail** — first tab, orange (Brush.Attention), gear icon
only. Left-click opens the same app menu the top bar gear owned (Settings / Bug /
Feature / About), right-click goes straight to App Settings; both behaviours moved
with it, so nothing lost an entry point. TopBar keeps the wordmark and EDIT.
**EDIT right edge aligned to the layers panel.** The work area is margin 8 + a 360px
column, the top bar is padding 16, so the shared edge is 352 inside the bar. TopBar
column 0 is now a fixed 352 grid with EDIT right-aligned in it — alignment by
arithmetic instead of by eye.
**Preview undo/redo: Ctrl+Z / Ctrl+Shift+Z.** Models/PreviewHistory snapshots element
REFERENCES plus geometry, visibility, order and membership — a deep clone would mirror
every property of a dozen element subclasses and quietly miss the next one added.
One snapshot per gesture (pushed at drag/resize start, never in the move loop), bounded
at 50, redo survives multiple undos, cleared on layout load. Gated on EditingActive:
undo while the preview shows program output would rewrite a scene nobody is looking at.
Honest scope, in the type's doc comment: layout edits only. Colour/opacity/border/font
edits are not captured yet, so Ctrl+Z after one of those restores the last layout change.
6 tests in PreviewHistoryTests; 19 pass across it and the neighbouring UI classes; Debug
and Release both build at 0 warnings.
The paid delta is output quality, so the rule needs to be measurable rather than a word:
921,600 pixels and 30 fps, fail-closed. Models/OutputProfile.cs is that rule as pure
policy — a permitted tier passes through untouched (Pro, or the free tier's own 720p30),
a disallowed one resolves to the best tier the budget allows and carries ITS bitrate, so
a capped user is never offered an 8 Mbps budget for a 720p frame.
Applied once, in BuildEncoderOptions. That is genuinely one place: the stream and the
local recording are two output blocks of ONE ffmpeg process fed by one EncoderOptions,
so there is no second encoder to forget. (commercial.md claimed "both encoders — never
two checks"; the code is stronger than the doc, and the doc is corrected.)
Developer override, as asked: a "Developer mode — all resolutions" checkbox in App
Settings, bound to MainViewModel.DeveloperMode, which feeds HasProOutput. It is not
hidden in a release build — Controls/DeveloperPanel's Page and Compile items are removed
when Configuration != Debug, and OverlayHost adds it at runtime inside #if DEBUG, so a
shipped exe has no BAML for it at all. The setter also refuses the value when
DevBuild.IsDevelopment is false, which is now the single source for that question (the
scoreboard partial had its own duplicate const).
Two traps worth their lines: a `const bool` dev flag makes `if (!Flag) return;` an
unreachable-code warning in one configuration or the other (CS0162), so DevBuild uses
static readonly; and a Condition on an ItemGroup is invisible to a test reading
item.Attribute("Condition") — read the parent.
Tests: 14 pass across OutputProfileTests, AssemblyIdentityTests and StorePackagingTests.
The invariant test is the one that matters: iterate every shipped tier under a free
entitlement and assert none emits more than the budget, so a future 4K tier fails here
instead of shipping to everyone. App builds Debug and Release at 0 warnings.
Merges the 2026-10-29 Stitch export into the existing 2026-10-26 token sheet and promotes the
file from "redesign exploration" to the normative standard:
- type scale (32→10px), spacing, radii and elevation levels — the three scales the old
DESIGN.md listed as missing
- meter thresholds: cyan ≤ -12 dB, amber -12..-3, red > -3
- interaction rules: focus ring, hover step, 150ms/90ms easing, no springs
Four export tokens rejected as Material-3 warm-seed artifacts (recorded with reasons):
tertiary #4cd7f6 (kept #38bdf8), outline #ab8986, outline-variant #5b403e,
on-surface-variant #e4beba (kept slate #94a3b8).
Product rulings recorded: #e94560 retired as the app's general accent (blue takes every
interactive role, red is live/record only, wordmark artwork untouched); error gets its own
surface (#93000a) so it cannot be mistaken for on-air red.
The export's dock, four bays, page-nav sidebar, CPU/GPU/NVENC readouts and acrylic blur are
explicitly marked exploratory, not spec — the design principle is a simpler surface, not
hardware cosplay. On-stream output styling stays outside this theme.
Falsified facts fixed in the same commit: product.md brand section now points at DESIGN.md for UI
tokens (MARCOM.md stays the marketing palette), and ui-surface.md no longer calls DESIGN.md an
unreconciled exploration.
Docs-only unit: scope-check run, no build.
ai.md 1,308 → 228 lines. No prose rewritten: every block was moved as-is so
nothing could be lost in translation, then replaced by a pointer.
New files:
- docs/ai/environment.md — LAN/SSH + Gitea push recipe, Windows dotnet
build/run, test-suite map, hermetic real-MainWindow test rule
- docs/ai/product.md — brand/naming, AI transparency, GPL licensing
prohibitions, free-forever monetization, auth/account assumptions,
packaging & distribution
- docs/ai/youtube-api.md — go-live ordering, the broadcast-binding fix, the
private-only lock, health parsing, end-stream pre-flight, Test mode,
chat insert shape
- docs/ai/overlays.md — social bar, native alert box (animations, clip,
ticker), chat box conventions
- docs/ai/ui-surface.md — control surface, scene strip, preview rail,
hotkeys, broadcast drawer, toasts, transitions, brand logo, launch
geometry, theme/properties conventions
ai.md keeps the response/derivation rules, the architecture table, the four
existing invariant stubs, and one pointer per moved subsystem.
docs/ai/index.md routes every file with a "read when" column.
References falsified by the move were fixed in the same commit: AGENTS.md
build note → environment.md → Run, and the "Related" footers in
frame-pipeline.md / output.md / capture.md now point at the owning files.
Docs-only unit: scope-check run, no build (no source touched).