From b4420f6212fecb9054bb78ecc922481b9da4730d Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Wed, 13 May 2026 02:36:46 -0700 Subject: [PATCH 1/5] winui: window sizing rubric, screenshot validation, anti-self-delegation Three connected improvements to the WinUI dev skills, motivated by repeated failure modes when building small apps: 1. winui-design SKILL.md - new Step 4 'Size the Window to the App' WinUI 3 has no SizeToContent, so apps default to ~1024x768 regardless of content - which makes utilities feel oversized. Adds an 8-step reasoning rubric (inventory rows, derive widest-row width, sum heights, round up, sanity-check ranges, prefer compact-but-not-clipping, aspect-ratio follows content, validate after running) and a worked example. Old 'Step 4: Design Anti-Patterns' renumbered to Step 5. 2. winui-ui-testing SKILL.md - new Step 3.5 'Look at the Screenshots' UIA assertions can't see clipping, overlap, cramped layout, or theming bugs. Adds explicit guidance to capture screenshots at multiple states (initial, post-interaction, per mode), view them after each run, and apply a visual checklist. Test-script template now creates a screenshots/ directory and captures intermediate state, not just a single final shot. 3. winui-dev.agent.md - 'Do The Work Yourself' section Agents kept re-delegating user requests to a fresh winui-dev sub-agent, wasting context and hiding progress. Adds an explicit prohibition against self-delegation while still permitting narrow helpers (explore for unfamiliar codebases, rubber-duck for plan critique). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- plugins/winui/agents/winui-dev.agent.md | 11 +++ plugins/winui/skills/winui-design/SKILL.md | 82 ++++++++++++++++++- .../winui/skills/winui-ui-testing/SKILL.md | 43 ++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/plugins/winui/agents/winui-dev.agent.md b/plugins/winui/agents/winui-dev.agent.md index b2a8a57..39532e4 100644 --- a/plugins/winui/agents/winui-dev.agent.md +++ b/plugins/winui/agents/winui-dev.agent.md @@ -4,6 +4,17 @@ description: "Builds WinUI 3 desktop applications using Windows App SDK, XAML, a user-invocable: true --- +## You Are The WinUI Developer — Do The Work Yourself + +**You are `winui-dev`. The user already selected you. Do the work directly using your own tools.** + +- ❌ **Do NOT** delegate this task to another `winui-dev` agent via the `task` tool. You are that agent — delegating to yourself is a redundant hop that wastes a context window, hides progress from the user, and adds latency. +- ❌ **Do NOT** spawn a `general-purpose` or `winui:winui-dev` sub-agent for the WinUI build itself. The user picked this agent specifically so they get *your* execution. +- ✅ **Do** use the `task` tool for narrow, parallelizable sub-questions where it genuinely helps — e.g. an `explore` agent to map an unfamiliar codebase in parallel, or a `rubber-duck` critique of a non-trivial plan before implementing. These are scoped helpers, not full-task handoffs. +- ✅ **Do** load the `winui-dev-workflow` and `winui-design` skills and execute the build yourself: scaffold, edit files, run `BuildAndRun.ps1`, fix errors, iterate. + +If you catch yourself about to call `task` with `agent_type: "winui:winui-dev"` or with a prompt that re-states the user's original request, stop — you're the one who should be doing it. + ## Process You build WinUI 3 desktop apps following this process: understand requirements → design and plan UI → scaffold if needed → write code → build & run. The user might ask you to use other steps defined by skills such as `winui-ui-testing` for UI validation or `winui-code-review` for quality checks if desired only. diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index 09f2d8f..7fe8dec 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -40,7 +40,87 @@ description: "WinUI 3 UI design and XAML correctness — layout planning, contro - Sidebar: fixed 300-360px width; main content: `Width="*"` with 24px padding - Status bar: `Grid` row at bottom; toolbar: `CommandBar` or title bar buttons -#### Step 4: Design Anti-Patterns +#### Step 4: Size the Window to the App + +> **WinUI 3 has no `SizeToContent`.** A `Window` is a Win32 `HWND` and, if you don't set a size, Windows hands it a generic ~1024×768 default — which makes utilities and forms look comically oversized (unlike SwiftUI, which auto-fits). **Every new app must explicitly size its main window** in `MainWindow`'s constructor. **Do not skip this step**, and **do not fall back to the OS default** "to be safe". + +**Reason from the layout you just designed — don't guess, and don't reach for a generic number.** You just chose the anchor control, the columns, the rows, and the typography. Use them. + +**Sizing rubric:** + +1. **Inventory every row of your layout.** Before estimating, list every row that will appear in the window: title bar, mode selector, hero element, action buttons, expander rows, toggle rows, status text, etc. Sizing is driven by the **widest row** and the **sum of all row heights** — not the "average" or the "main" content. + +2. **Estimate width from the widest row.** The window must comfortably fit the widest single row without truncation. For each row, sum: + - Fixed sidebars / nav panes (e.g. `NavigationView` left pane ≈ 320) + - Inline labels + controls + value text on the same row (e.g. "Auto-start next session" label + `ToggleSwitch` + "On/Off" state text ≈ 280–340; three `NumberBox`es side-by-side with labels ≈ 360–440; a 3-option `RadioButtons` row ≈ 320–400 depending on label length) + - Hero controls (timer ring ≈ diameter + 64; chart ≈ its natural width) + - Outer padding (24 on each side is typical) + Take the **max across all rows**, not the average. If you're unsure a label will fit, add 40px headroom — clipped text is a far worse failure than a slightly-too-wide window. + +3. **Estimate height by summing every row.** Title bar (~32) + each content row's natural height + spacing between rows (8–16 each) + outer padding (24 top + 24 bottom). For a hero element like a timer display, give it its full intended height (don't let it overlap the row above). For scrollable lists, pick a height that shows ~6–10 rows without scrolling. + +4. **Round up to the nearest 20.** Always round **up**, never down — rounding down is how content clips. Multiples of 20 (or the 4px grid × 5) feel intentional. + +5. **Sanity-check against scale anchors** (these are ranges, not targets — derive your own from steps 1–3): + - Single-purpose utilities (one job, one screen) → typically **~440–560 wide** + - Forms, dialogs, single-page tools → typically **~600–800 wide, ~640–800 tall** + - Multi-pane apps (nav + content, list + detail, tabs) → typically **~1100–1300 wide, ~720–840 tall** + - Document/canvas/media editors → as wide as your default canvas needs, often **1280+** + If your derived number is well below these ranges, you probably missed a row in step 1 — go back and re-check. + +6. **Compactness vs. clipping — pick clipping-free every time.** A utility should feel utility-sized, but **not at the cost of truncated labels, cropped controls, or content overflowing the window**. Between two sizes, prefer the smaller — but only if both fit the content with breathing room. If in doubt, add 20–40px on the side you're uncertain about. + +7. **Aspect ratio follows the layout.** Tall content (lists, timers, forms) → portrait-ish. Wide content (tabs, code, media, multi-column) → landscape-ish. Don't default to landscape out of habit. + +8. **Validate after running.** After `BuildAndRun`, look at the running window (capture a screenshot via the `winui-ui-testing` skill and view it). If you see **any** of these, the window is too small — go up by 40–80px on the affected axis and rebuild: + - Text labels ending with `…` that shouldn't be (mode names, settings labels, toggle descriptions) + - Hero elements clipped at the top or bottom (timer digits sliced, ring cropped) + - Controls cut off at the right edge (NumberBox values, RadioButton labels) + - Status/footer text overlapping content above it + - Any unintended scrollbar appearing + This validation step is **mandatory**, not optional. The rubric is an estimate; the running app is the source of truth. + +**Worked example** (illustrative — derive your own, don't copy): +A focus-timer app with: mode `RadioButtons` row (Focus / Short Break / Long Break ≈ 380 wide), 320px timer ring, Pause/Reset button row (≈ 260), an `Expander` "Customize durations" containing three labeled `NumberBox`es side-by-side (≈ 380), and an "Auto-start next session" toggle row (≈ 320). Widest row = mode selector at ~380 → +48 padding → ~430 → round up → **460 wide**. Height: titlebar 32 + mode row 48 + ring 320 + buttons 48 + expander collapsed-or-expanded ~240 + toggle 48 + status 32 + padding 48 + spacing ~40 ≈ 856 → round up → **860 tall**. Result: **460 × 860**. If validation shows the mode labels clipping, bump to 500 × 860. + +**Anti-pattern — what NOT to do:** designing the same focus timer at **440 × 720** because "utilities are small" — this clips "Long Break", crops the timer digits, truncates the toggle label, and overlaps the status footer. Compactness is good; clipping is a bug. + +**Pattern — apply the size you derived (DPI-aware):** +```csharp +// MainWindow.xaml.cs constructor, AFTER InitializeComponent() +using Microsoft.UI.Windowing; +using Windows.Graphics; + +public MainWindow() +{ + InitializeComponent(); + ExtendsContentIntoTitleBar = true; + SetTitleBar(AppTitleBar); + + // Scale DIPs → physical pixels so size is consistent across DPIs. + var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this); + var dpi = (uint)PInvoke.User32.GetDpiForWindow(hwnd); + var scale = dpi / 96.0; + AppWindow.Resize(new SizeInt32( + (int)(460 * scale), // ← width in DIPs from the rubric + (int)(860 * scale))); // ← height in DIPs from the rubric +} +``` + +Simpler fallback if `PInvoke.User32` isn't available (ignores DPI; fine for prototypes): +```csharp +AppWindow.Resize(new SizeInt32(460, 860)); +``` + +**Anti-patterns:** +- ❌ Leaving `MainWindow` without an `AppWindow.Resize(...)` call → app launches at OS default ~1024×768 regardless of content +- ❌ Setting `Width`/`Height` on the root `Grid` to "force" a window size — it doesn't size the window, just clips/letterboxes content +- ❌ Reaching for a generic "safe" size instead of deriving from the layout +- ❌ Defaulting to landscape when the content is clearly portrait (or vice versa) +- ❌ Picking the smallest size that "probably fits" — clipped labels/controls are a bug, not a style choice +- ❌ Skipping the post-build validation in step 8 — the running app is the source of truth, not your estimate + +#### Step 5: Design Anti-Patterns | ❌ Don't | ✅ Do Instead | |----------|--------------| | Centered floating card on background | Content fills window with padding | diff --git a/plugins/winui/skills/winui-ui-testing/SKILL.md b/plugins/winui/skills/winui-ui-testing/SKILL.md index f47b2da..c036e31 100644 --- a/plugins/winui/skills/winui-ui-testing/SKILL.md +++ b/plugins/winui/skills/winui-ui-testing/SKILL.md @@ -101,6 +101,11 @@ if ($missingId.Count -eq 0) { $results += @{ name = "AutomationId coverage"; status = "FAIL"; detail = "Missing: $names" } } +# ─── State Screenshots (capture each meaningful state for visual review) ─── +New-Item -ItemType Directory -Force -Path "screenshots" | Out-Null +winapp ui screenshot -a $AppPid -o "screenshots/01-initial.png" 2>$null +# ...take more screenshots after key interactions above (mode switches, dialogs opened, etc.) + # ─── Final Screenshot ─── winapp ui screenshot -a $AppPid -o "test-screenshot.png" 2>$null @@ -140,6 +145,44 @@ Write tests for **every requirement** from the user's prompt: Read `test-results.json` for structured pass/fail. Only fix code if tests fail. +### Step 3.5: Look at the Screenshots — Don't Skip This + +UIA assertions tell you if an element **exists** and what its **value** is. They tell you **nothing about how the app actually looks**. Clipped labels, cramped layout, overlapping rows, content cut off at the window edge, wrong colors, broken theming, controls bleeding past their container — UIA will happily report `PASS` while the app is visually broken. + +**Always capture screenshots and view them yourself.** This is the single highest-leverage thing you can do to catch the bugs your test script misses. + +**At minimum, capture and view:** +1. **Initial state** — app just opened, default mode. Look for clipping, oversized/undersized window, broken theming, mis-aligned controls. +2. **After main interactions** — after switching modes, opening expanders, toggling state, navigating to a secondary page. Look for layout shifts that overflow, controls that didn't update visually, flyouts that render off-screen. +3. **Any state mentioned in the user's prompt** — if they asked for "colorful modes with different accents", screenshot each mode and verify the colors actually changed. + +**How to capture inside the test script:** +```powershell +winapp ui screenshot -a $AppPid -o "screenshots/01-initial.png" +winapp ui invoke "ShortBreakModeRadio" -a $AppPid; Start-Sleep -Milliseconds 300 +winapp ui screenshot -a $AppPid -o "screenshots/02-short-break.png" +winapp ui invoke "ExpanderCustomize" -a $AppPid; Start-Sleep -Milliseconds 300 +winapp ui screenshot -a $AppPid -o "screenshots/03-expanded.png" +``` + +**How to view them after the run:** use your image-viewing tool on each PNG path — it returns the image as inspectable data so you can actually see the app. Do this **after every test run**, not just at the end of the task. + +**What to look for in each screenshot — a visual checklist:** +- [ ] Window size fits the content — no scrollbars where you didn't intend any +- [ ] No text ending in `…` that shouldn't be (labels, button text, mode names, toggle descriptions) +- [ ] Hero elements (timer rings, large displays, charts) fully visible — not sliced at top, bottom, or sides +- [ ] Controls at the right edge are fully visible (last NumberBox value, last RadioButton label, toggle state text) +- [ ] No overlapping text or controls between rows +- [ ] Spacing looks intentional — not cramped, not unintentionally vast +- [ ] Theming is right — backgrounds, accent colors, gradients match what the user asked for +- [ ] Light/Dark/HighContrast all render (capture under each theme if relevant to the task) +- [ ] Focus states, hover states, error states render if the test exercised them + +**If a screenshot reveals a visual bug that UIA tests missed:** that's a bug, not a "minor polish issue". Fix it before declaring the task done. Common fixes: +- Content clipped at edges → window too small → grow `AppWindow.Resize` per the sizing rubric in `winui-design` Step 4 +- Controls overlap → missing `RowSpacing`/`ColumnSpacing` or wrong row definitions +- Labels truncate with `…` → fixed `Width` on a parent that should be `Auto`, or `TextTrimming` set unnecessarily + ### Step 4: Fix and Rerun (if the user asked for it) If tests fail: From 45d15d3460f30f405c2650a4b0358893546ef898 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 19 May 2026 15:41:44 -0700 Subject: [PATCH 2/5] winui-design: replace PInvoke.User32 with framework DllImport; drop misleading fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DPI-aware snippet in Step 4 had two real correctness issues that surfaced in PR review and were confirmed by an empirical two-monitor test: 1. PInvoke.User32.GetDpiForWindow is a third-party NuGet not in the default WinUI 3 scaffold; agents copying the snippet hit "type or namespace PInvoke not found". Replace with a one-line [DllImport("user32.dll")] — no NuGet, no CsWin32 source-generator plumbing, works in the constructor. 2. SetTitleBar(AppTitleBar) referenced an XAML element the snippet never declares; orthogonal to sizing anyway. Removed. Also drop the "Simpler fallback if PInvoke.User32 isn't available (ignores DPI; fine for prototypes)" block — the empirical test showed AppWindow.Resize takes physical pixels, so Resize(new SizeInt32(460, 860)) on a 1.25-scale monitor (the default on many Windows laptops) produces only ~368x688 DIPs of usable space and guarantees the clipping the rubric is designed to prevent. The "fallback" was actively misleading. Replaced with a one-line "Why this shape" explaining why XamlRoot.RasterizationScale (the managed WinUI 3 API) isn't viable here (null in ctor, stale after AppWindow.Move). Strengthened the "Pattern" header with the concrete failure mode so future readers see why the DPI math is needed, not just that it's needed. Also fixes a small bug in winui-dev.agent.md: "rubber-duck" was named as if it were a real agent_type. Rephrased to "a general-purpose agent for a rubber-duck critique" so the named agent_type is valid. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- plugins/winui/agents/winui-dev.agent.md | 2 +- plugins/winui/skills/winui-design/SKILL.md | 42 +++++++++++----------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/plugins/winui/agents/winui-dev.agent.md b/plugins/winui/agents/winui-dev.agent.md index 39532e4..95f9bc7 100644 --- a/plugins/winui/agents/winui-dev.agent.md +++ b/plugins/winui/agents/winui-dev.agent.md @@ -10,7 +10,7 @@ user-invocable: true - ❌ **Do NOT** delegate this task to another `winui-dev` agent via the `task` tool. You are that agent — delegating to yourself is a redundant hop that wastes a context window, hides progress from the user, and adds latency. - ❌ **Do NOT** spawn a `general-purpose` or `winui:winui-dev` sub-agent for the WinUI build itself. The user picked this agent specifically so they get *your* execution. -- ✅ **Do** use the `task` tool for narrow, parallelizable sub-questions where it genuinely helps — e.g. an `explore` agent to map an unfamiliar codebase in parallel, or a `rubber-duck` critique of a non-trivial plan before implementing. These are scoped helpers, not full-task handoffs. +- ✅ **Do** use the `task` tool for narrow, parallelizable sub-questions where it genuinely helps — e.g. an `explore` agent to map an unfamiliar codebase in parallel, or a `general-purpose` agent for a rubber-duck critique of a non-trivial plan before implementing. These are scoped helpers, not full-task handoffs. - ✅ **Do** load the `winui-dev-workflow` and `winui-design` skills and execute the build yourself: scaffold, edit files, run `BuildAndRun.ps1`, fix errors, iterate. If you catch yourself about to call `task` with `agent_type: "winui:winui-dev"` or with a prompt that re-states the user's original request, stop — you're the one who should be doing it. diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index 7fe8dec..1efef56 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -85,32 +85,34 @@ A focus-timer app with: mode `RadioButtons` row (Focus / Short Break / Long Brea **Anti-pattern — what NOT to do:** designing the same focus timer at **440 × 720** because "utilities are small" — this clips "Long Break", crops the timer digits, truncates the toggle label, and overlaps the status footer. Compactness is good; clipping is a bug. -**Pattern — apply the size you derived (DPI-aware):** +**Pattern — apply the size you derived.** `AppWindow.Resize` takes **physical pixels**, not DIPs — on a 1.25× monitor (the default scale on many Windows laptops), `Resize(new SizeInt32(460, 860))` without scaling becomes only ~368 × 688 DIPs of usable space, guaranteed to clip a 460-DIP-wide rubric. Multiply your DIP-based rubric numbers by the monitor's DPI scale: + ```csharp -// MainWindow.xaml.cs constructor, AFTER InitializeComponent() -using Microsoft.UI.Windowing; -using Windows.Graphics; +// MainWindow.xaml.cs — framework-only, no third-party NuGet, works in the constructor. +using Microsoft.UI; // for Win32Interop +using Microsoft.UI.Windowing; // for AppWindow +using System.Runtime.InteropServices; +using Windows.Graphics; // for SizeInt32 -public MainWindow() +public sealed partial class MainWindow : Window { - InitializeComponent(); - ExtendsContentIntoTitleBar = true; - SetTitleBar(AppTitleBar); - - // Scale DIPs → physical pixels so size is consistent across DPIs. - var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this); - var dpi = (uint)PInvoke.User32.GetDpiForWindow(hwnd); - var scale = dpi / 96.0; - AppWindow.Resize(new SizeInt32( - (int)(460 * scale), // ← width in DIPs from the rubric - (int)(860 * scale))); // ← height in DIPs from the rubric + [DllImport("user32.dll")] + private static extern uint GetDpiForWindow(IntPtr hWnd); + + public MainWindow() + { + InitializeComponent(); + + var hwnd = Win32Interop.GetWindowFromWindowId(AppWindow.Id); + var scale = GetDpiForWindow(hwnd) / 96.0; + AppWindow.Resize(new SizeInt32( + (int)(460 * scale), // ← width in DIPs from the rubric + (int)(860 * scale))); // ← height in DIPs from the rubric + } } ``` -Simpler fallback if `PInvoke.User32` isn't available (ignores DPI; fine for prototypes): -```csharp -AppWindow.Resize(new SizeInt32(460, 860)); -``` +Why this shape: `XamlRoot.RasterizationScale` (the managed WinUI 3 API for DPI) is `null` in the constructor, stale after `AppWindow.Move`, and only correct post-layout — so it doesn't fit a "set the size before first paint" use case. The single-line `[DllImport]` works at construction time, on any monitor, with no NuGet dependency. **Anti-patterns:** - ❌ Leaving `MainWindow` without an `AppWindow.Resize(...)` call → app launches at OS default ~1024×768 regardless of content From cae0fe7a86fc7a65561dd80e8af36621dcc2b6f0 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 19 May 2026 15:46:17 -0700 Subject: [PATCH 3/5] winui-design: extract worked example to references/, dedupe visual checklist with winui-ui-testing M2: The focus-timer walkthrough (460 x 860 derivation + 440 x 720 anti-pattern) moves out of SKILL.md prose and into references/window-sizing-examples.md, with SKILL.md keeping only a 1-line schematic of the rubric and a pointer to the reference. Concrete worked numbers stay out of every loaded skill payload but remain on-demand when an agent wants a full example to anchor against. M6: Step 4 step 8's bulleted symptom list (5 bullets that were a strict subset of the 9-item visual checklist in winui-ui-testing Step 3.5) collapses to a 1-paragraph pointer with inline symptom hints. The authoritative checklist lives in winui-ui-testing, which is the skill that owns 'look at screenshots'. Net: -11 / +50 (the +50 is the new on-demand reference file, not loaded by default), with no change in covered guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- plugins/winui/skills/winui-design/SKILL.md | 14 ++---- .../references/window-sizing-examples.md | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 plugins/winui/skills/winui-design/references/window-sizing-examples.md diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index 1efef56..03d303f 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -72,18 +72,9 @@ description: "WinUI 3 UI design and XAML correctness — layout planning, contro 7. **Aspect ratio follows the layout.** Tall content (lists, timers, forms) → portrait-ish. Wide content (tabs, code, media, multi-column) → landscape-ish. Don't default to landscape out of habit. -8. **Validate after running.** After `BuildAndRun`, look at the running window (capture a screenshot via the `winui-ui-testing` skill and view it). If you see **any** of these, the window is too small — go up by 40–80px on the affected axis and rebuild: - - Text labels ending with `…` that shouldn't be (mode names, settings labels, toggle descriptions) - - Hero elements clipped at the top or bottom (timer digits sliced, ring cropped) - - Controls cut off at the right edge (NumberBox values, RadioButton labels) - - Status/footer text overlapping content above it - - Any unintended scrollbar appearing - This validation step is **mandatory**, not optional. The rubric is an estimate; the running app is the source of truth. +8. **Validate after running.** After `BuildAndRun`, capture a screenshot via the `winui-ui-testing` skill and apply the visual checklist in `winui-ui-testing` Step 3.5 — if any symptom appears (clipped labels, cropped hero elements, controls cut off at the edge, overlapping rows, unintended scrollbars), grow on the affected axis by 40–80px and rebuild. This validation step is **mandatory**, not optional. The rubric is an estimate; the running app is the source of truth. -**Worked example** (illustrative — derive your own, don't copy): -A focus-timer app with: mode `RadioButtons` row (Focus / Short Break / Long Break ≈ 380 wide), 320px timer ring, Pause/Reset button row (≈ 260), an `Expander` "Customize durations" containing three labeled `NumberBox`es side-by-side (≈ 380), and an "Auto-start next session" toggle row (≈ 320). Widest row = mode selector at ~380 → +48 padding → ~430 → round up → **460 wide**. Height: titlebar 32 + mode row 48 + ring 320 + buttons 48 + expander collapsed-or-expanded ~240 + toggle 48 + status 32 + padding 48 + spacing ~40 ≈ 856 → round up → **860 tall**. Result: **460 × 860**. If validation shows the mode labels clipping, bump to 500 × 860. - -**Anti-pattern — what NOT to do:** designing the same focus timer at **440 × 720** because "utilities are small" — this clips "Long Break", crops the timer digits, truncates the toggle label, and overlaps the status footer. Compactness is good; clipping is a bug. +**Schematic:** widest row `W` → `+48` padding (24 each side) → round up to nearest 20 = **window width**. Σ(row heights) + Σ(spacing between rows) + 32 (titlebar) + 48 (top/bottom padding) → round up = **window height**. See `references/window-sizing-examples.md` for a fully worked focus-timer derivation (460 × 860) plus a same-app anti-pattern walkthrough. **Pattern — apply the size you derived.** `AppWindow.Resize` takes **physical pixels**, not DIPs — on a 1.25× monitor (the default scale on many Windows laptops), `Resize(new SizeInt32(460, 860))` without scaling becomes only ~368 × 688 DIPs of usable space, guaranteed to clip a 460-DIP-wide rubric. Multiply your DIP-based rubric numbers by the monitor's DPI scale: @@ -260,3 +251,4 @@ ToolTipService.SetToolTip(btn, "Save the current document"); | `references/typography-and-spacing.md` | Detailed type ramp, spacing grid, and sizing examples | | `references/colors-and-materials.md` | Theme brush catalog, Mica/Acrylic surface pairings, material usage | | `references/iconography-and-motion.md` | Icon guidelines, animation patterns, connected animations | +| `references/window-sizing-examples.md` | Fully worked applications of the Step 4 sizing rubric | diff --git a/plugins/winui/skills/winui-design/references/window-sizing-examples.md b/plugins/winui/skills/winui-design/references/window-sizing-examples.md new file mode 100644 index 0000000..057ce04 --- /dev/null +++ b/plugins/winui/skills/winui-design/references/window-sizing-examples.md @@ -0,0 +1,47 @@ +# Window Sizing — Worked Examples + +This file holds concrete, end-to-end applications of the sizing rubric in `SKILL.md` Step 4. The rubric itself is the authoritative algorithm; the examples here are illustrations — **derive your own numbers from your own layout, don't copy these verbatim**. Each example follows the same structure: list rows → derive width → derive height → state result. + +## Example 1: Focus-timer utility (single-purpose) + +A simple Pomodoro-style timer with mode switcher, hero ring, action buttons, and an optional settings expander. + +**Layout (rows top to bottom):** +- Title bar (~32 tall) +- Mode `RadioButtons` row: Focus / Short Break / Long Break (~380 wide, ~48 tall) +- 320px-diameter timer ring (320 wide, 320 tall) +- Pause / Reset button row (~260 wide, ~48 tall) +- `Expander` "Customize durations" containing three labeled `NumberBox`es side-by-side (~380 wide, ~240 tall when expanded) +- "Auto-start next session" toggle row (~320 wide, ~48 tall) +- Status text row (~32 tall) + +**Width derivation:** +- Widest row = mode selector at ~380 +- + 48 padding (24 each side) → ~430 +- Round up to nearest 20 → **460 wide** + +**Height derivation:** +- Titlebar 32 + mode row 48 + ring 320 + buttons 48 + expander 240 + toggle 48 + status 32 = 768 +- + 48 padding (24 top + 24 bottom) + ~40 cumulative spacing between rows = 856 +- Round up to nearest 20 → **860 tall** + +**Result: `460 × 860`** (DIPs — multiply by `RasterizationScale` before passing to `AppWindow.Resize`, per the Step 4 snippet). + +If post-build validation shows the mode labels clipping (`"Long Break"` cut off), bump to `500 × 860` and rebuild. + +### Anti-pattern for the same app + +Sizing the focus-timer at **440 × 720** because "utilities are small" — this clips `"Long Break"` in the mode selector, crops the timer digits at the top and bottom of the ring, truncates the auto-start toggle label, and overlaps the status footer with the toggle row. The rubric forces 460 × 860; cutting to 440 × 720 reintroduces every symptom the rubric is designed to prevent. Compactness is good; clipping is a bug. + +--- + +## Adding more examples + +Add a new `## Example N: ` section using the same structure (layout → width → height → result → anti-pattern). Good candidates if you find yourself sizing one of these from scratch: + +- A settings dialog (form-shaped, single column of labeled inputs) +- A multi-pane app (left nav + content) +- A canvas/media editor (wide-format with a toolbar) +- A login / first-run window (small, centered, tight) + +Each new example reinforces that the rubric generalises across app shapes — the more concrete examples on file, the less an agent has to extrapolate from the focus-timer in isolation. From 35994f87ef85c1a0e3f0c43c2b485e48b130c005 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 19 May 2026 16:03:44 -0700 Subject: [PATCH 4/5] winui: ultra-lean rewrite of window-sizing + screenshot-validation + anti-self-delegation prose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the Team Lead Test more aggressively across all three files. Cuts redundant enforcement, scenario-specific filler, and restated rubric positives. Preserves every operational imperative. winui-dev.agent.md (anti-self-delegation): 11 → 2 lines. The two banned sub-types collapse into one parenthetical; the scoped-helpers ✅ shrinks to one clause; the redundant closing 'if you catch yourself' paragraph drops (the rule above it already says it). winui-ui-testing/SKILL.md (Step 3.5): 33 → ~16 lines. Drops the duplicate script example (the State Screenshots block in the script template above already shows the pattern), the 3-bullet 'what counts as a state' list (one sentence covers it), and the 'How to view' paragraph (tool-agnostic: the agent picks its own view tool). Visual checklist trimmed from 9 → 9 items but with one merged pair (right-edge + overlap kept as separate bullets after all) and one new item added: 'Content uses the available width — no asymmetric dead zones' covers the bug where content gets pinned to one edge with empty space on the other. winui-design/SKILL.md (Step 4): 76 → ~30 lines. The 8-step rubric collapses to one paragraph + a sanity-check list — the formula Sigma(row heights) forces enumeration without needing a dedicated 'inventory' step, 'widest row' encodes max-not-average, and 'round up' speaks for itself. Drops the aspect-ratio step (tall→portrait is obvious), the 'compactness vs clipping' step (subsumed by 'round up — clipped is worse'), and the 6-bullet Anti-patterns section (5 of 6 restated the rubric's positives; the one novel trap — Width on root Grid clips, not sizes — folds into a one-line note after the snippet). The 3-line 'Pattern — apply the size you derived' intro collapses to one line. Snippet using-statement comments removed. Closing line goes tool-agnostic: 'Validate visually after build via winui-ui-testing Step 3.5' (no longer says 'capture a screenshot' — that's a layering violation, design owns the rubric, testing owns the validation mechanism). 'Iterate the size or layout' covers both grow-the-window and fix-asymmetric-padding failure modes. Net for default-loaded payloads: -58 lines on top of the previous M2+M6 commit, total PR addition shrinks from +176 to +88 lines (-50%). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- plugins/winui/agents/winui-dev.agent.md | 9 +-- plugins/winui/skills/winui-design/SKILL.md | 62 +++++-------------- .../winui/skills/winui-ui-testing/SKILL.md | 47 +++++--------- 3 files changed, 30 insertions(+), 88 deletions(-) diff --git a/plugins/winui/agents/winui-dev.agent.md b/plugins/winui/agents/winui-dev.agent.md index 95f9bc7..9d1a9ba 100644 --- a/plugins/winui/agents/winui-dev.agent.md +++ b/plugins/winui/agents/winui-dev.agent.md @@ -6,14 +6,7 @@ user-invocable: true ## You Are The WinUI Developer — Do The Work Yourself -**You are `winui-dev`. The user already selected you. Do the work directly using your own tools.** - -- ❌ **Do NOT** delegate this task to another `winui-dev` agent via the `task` tool. You are that agent — delegating to yourself is a redundant hop that wastes a context window, hides progress from the user, and adds latency. -- ❌ **Do NOT** spawn a `general-purpose` or `winui:winui-dev` sub-agent for the WinUI build itself. The user picked this agent specifically so they get *your* execution. -- ✅ **Do** use the `task` tool for narrow, parallelizable sub-questions where it genuinely helps — e.g. an `explore` agent to map an unfamiliar codebase in parallel, or a `general-purpose` agent for a rubber-duck critique of a non-trivial plan before implementing. These are scoped helpers, not full-task handoffs. -- ✅ **Do** load the `winui-dev-workflow` and `winui-design` skills and execute the build yourself: scaffold, edit files, run `BuildAndRun.ps1`, fix errors, iterate. - -If you catch yourself about to call `task` with `agent_type: "winui:winui-dev"` or with a prompt that re-states the user's original request, stop — you're the one who should be doing it. +You are `winui-dev` — don't call `task` with `agent_type: "winui:winui-dev"` (self-hop). `task` is fine for scoped helpers (`explore` for parallel codebase mapping, `general-purpose` for rubber-duck critique), not for the build itself. ## Process diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index 03d303f..9dbafaa 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -42,48 +42,25 @@ description: "WinUI 3 UI design and XAML correctness — layout planning, contro #### Step 4: Size the Window to the App -> **WinUI 3 has no `SizeToContent`.** A `Window` is a Win32 `HWND` and, if you don't set a size, Windows hands it a generic ~1024×768 default — which makes utilities and forms look comically oversized (unlike SwiftUI, which auto-fits). **Every new app must explicitly size its main window** in `MainWindow`'s constructor. **Do not skip this step**, and **do not fall back to the OS default** "to be safe". +> **WinUI 3 has no `SizeToContent`.** Without an explicit size, Windows defaults the main window to ~1024×768 — oversized for most utilities. **Size the window in `MainWindow`'s constructor; derive from the layout, not a generic.** -**Reason from the layout you just designed — don't guess, and don't reach for a generic number.** You just chose the anchor control, the columns, the rows, and the typography. Use them. +**Rubric.** Width = widest row + 48 padding (24 each side), rounded **up** to nearest 20. Height = 32 (titlebar) + Σ(row heights) + Σ(spacing) + 48 padding, rounded up to 20. Round up — clipped content is a worse failure than a slightly-wide window. -**Sizing rubric:** +**Sanity check** (ranges, not targets — derive yours from the rubric): +- Single-purpose utility → ~440–560 wide +- Form / single-page tool → ~600–800 wide, ~640–800 tall +- Multi-pane (nav + content) → ~1100–1300 wide, ~720–840 tall +- Document / canvas / media editor → 1280+ wide -1. **Inventory every row of your layout.** Before estimating, list every row that will appear in the window: title bar, mode selector, hero element, action buttons, expander rows, toggle rows, status text, etc. Sizing is driven by the **widest row** and the **sum of all row heights** — not the "average" or the "main" content. +If your derived number is well below its range, you missed a row — re-check. -2. **Estimate width from the widest row.** The window must comfortably fit the widest single row without truncation. For each row, sum: - - Fixed sidebars / nav panes (e.g. `NavigationView` left pane ≈ 320) - - Inline labels + controls + value text on the same row (e.g. "Auto-start next session" label + `ToggleSwitch` + "On/Off" state text ≈ 280–340; three `NumberBox`es side-by-side with labels ≈ 360–440; a 3-option `RadioButtons` row ≈ 320–400 depending on label length) - - Hero controls (timer ring ≈ diameter + 64; chart ≈ its natural width) - - Outer padding (24 on each side is typical) - Take the **max across all rows**, not the average. If you're unsure a label will fit, add 40px headroom — clipped text is a far worse failure than a slightly-too-wide window. - -3. **Estimate height by summing every row.** Title bar (~32) + each content row's natural height + spacing between rows (8–16 each) + outer padding (24 top + 24 bottom). For a hero element like a timer display, give it its full intended height (don't let it overlap the row above). For scrollable lists, pick a height that shows ~6–10 rows without scrolling. - -4. **Round up to the nearest 20.** Always round **up**, never down — rounding down is how content clips. Multiples of 20 (or the 4px grid × 5) feel intentional. - -5. **Sanity-check against scale anchors** (these are ranges, not targets — derive your own from steps 1–3): - - Single-purpose utilities (one job, one screen) → typically **~440–560 wide** - - Forms, dialogs, single-page tools → typically **~600–800 wide, ~640–800 tall** - - Multi-pane apps (nav + content, list + detail, tabs) → typically **~1100–1300 wide, ~720–840 tall** - - Document/canvas/media editors → as wide as your default canvas needs, often **1280+** - If your derived number is well below these ranges, you probably missed a row in step 1 — go back and re-check. - -6. **Compactness vs. clipping — pick clipping-free every time.** A utility should feel utility-sized, but **not at the cost of truncated labels, cropped controls, or content overflowing the window**. Between two sizes, prefer the smaller — but only if both fit the content with breathing room. If in doubt, add 20–40px on the side you're uncertain about. - -7. **Aspect ratio follows the layout.** Tall content (lists, timers, forms) → portrait-ish. Wide content (tabs, code, media, multi-column) → landscape-ish. Don't default to landscape out of habit. - -8. **Validate after running.** After `BuildAndRun`, capture a screenshot via the `winui-ui-testing` skill and apply the visual checklist in `winui-ui-testing` Step 3.5 — if any symptom appears (clipped labels, cropped hero elements, controls cut off at the edge, overlapping rows, unintended scrollbars), grow on the affected axis by 40–80px and rebuild. This validation step is **mandatory**, not optional. The rubric is an estimate; the running app is the source of truth. - -**Schematic:** widest row `W` → `+48` padding (24 each side) → round up to nearest 20 = **window width**. Σ(row heights) + Σ(spacing between rows) + 32 (titlebar) + 48 (top/bottom padding) → round up = **window height**. See `references/window-sizing-examples.md` for a fully worked focus-timer derivation (460 × 860) plus a same-app anti-pattern walkthrough. - -**Pattern — apply the size you derived.** `AppWindow.Resize` takes **physical pixels**, not DIPs — on a 1.25× monitor (the default scale on many Windows laptops), `Resize(new SizeInt32(460, 860))` without scaling becomes only ~368 × 688 DIPs of usable space, guaranteed to clip a 460-DIP-wide rubric. Multiply your DIP-based rubric numbers by the monitor's DPI scale: +`AppWindow.Resize` takes **physical pixels**, not DIPs — multiply by the monitor's DPI scale: ```csharp -// MainWindow.xaml.cs — framework-only, no third-party NuGet, works in the constructor. -using Microsoft.UI; // for Win32Interop -using Microsoft.UI.Windowing; // for AppWindow +using Microsoft.UI; +using Microsoft.UI.Windowing; using System.Runtime.InteropServices; -using Windows.Graphics; // for SizeInt32 +using Windows.Graphics; public sealed partial class MainWindow : Window { @@ -93,25 +70,16 @@ public sealed partial class MainWindow : Window public MainWindow() { InitializeComponent(); - var hwnd = Win32Interop.GetWindowFromWindowId(AppWindow.Id); var scale = GetDpiForWindow(hwnd) / 96.0; - AppWindow.Resize(new SizeInt32( - (int)(460 * scale), // ← width in DIPs from the rubric - (int)(860 * scale))); // ← height in DIPs from the rubric + AppWindow.Resize(new SizeInt32((int)(460 * scale), (int)(860 * scale))); } } ``` -Why this shape: `XamlRoot.RasterizationScale` (the managed WinUI 3 API for DPI) is `null` in the constructor, stale after `AppWindow.Move`, and only correct post-layout — so it doesn't fit a "set the size before first paint" use case. The single-line `[DllImport]` works at construction time, on any monitor, with no NuGet dependency. +`XamlRoot.RasterizationScale` is null in the ctor and stale after `AppWindow.Move`, so `[DllImport]` is the cleanest path. Don't try to size the window by setting `Width`/`Height` on the root `Grid` — that clips content, not the window. -**Anti-patterns:** -- ❌ Leaving `MainWindow` without an `AppWindow.Resize(...)` call → app launches at OS default ~1024×768 regardless of content -- ❌ Setting `Width`/`Height` on the root `Grid` to "force" a window size — it doesn't size the window, just clips/letterboxes content -- ❌ Reaching for a generic "safe" size instead of deriving from the layout -- ❌ Defaulting to landscape when the content is clearly portrait (or vice versa) -- ❌ Picking the smallest size that "probably fits" — clipped labels/controls are a bug, not a style choice -- ❌ Skipping the post-build validation in step 8 — the running app is the source of truth, not your estimate +Validate visually after build via `winui-ui-testing` Step 3.5; iterate the size or layout until the checklist passes. See `references/window-sizing-examples.md` for a worked focus-timer derivation. #### Step 5: Design Anti-Patterns | ❌ Don't | ✅ Do Instead | diff --git a/plugins/winui/skills/winui-ui-testing/SKILL.md b/plugins/winui/skills/winui-ui-testing/SKILL.md index c036e31..fd2a49f 100644 --- a/plugins/winui/skills/winui-ui-testing/SKILL.md +++ b/plugins/winui/skills/winui-ui-testing/SKILL.md @@ -145,43 +145,24 @@ Write tests for **every requirement** from the user's prompt: Read `test-results.json` for structured pass/fail. Only fix code if tests fail. -### Step 3.5: Look at the Screenshots — Don't Skip This +### Step 3.5: Look at the Screenshots -UIA assertions tell you if an element **exists** and what its **value** is. They tell you **nothing about how the app actually looks**. Clipped labels, cramped layout, overlapping rows, content cut off at the window edge, wrong colors, broken theming, controls bleeding past their container — UIA will happily report `PASS` while the app is visually broken. +UIA assertions don't see clipping, overlap, wrong theming, or controls bleeding past their container — UIA returns `PASS` while the app is visually broken. **Capture screenshots with `winapp ui screenshot` and view each PNG.** -**Always capture screenshots and view them yourself.** This is the single highest-leverage thing you can do to catch the bugs your test script misses. +Capture the initial state and any state after a major interaction (the State Screenshots block in the script template above handles this). -**At minimum, capture and view:** -1. **Initial state** — app just opened, default mode. Look for clipping, oversized/undersized window, broken theming, mis-aligned controls. -2. **After main interactions** — after switching modes, opening expanders, toggling state, navigating to a secondary page. Look for layout shifts that overflow, controls that didn't update visually, flyouts that render off-screen. -3. **Any state mentioned in the user's prompt** — if they asked for "colorful modes with different accents", screenshot each mode and verify the colors actually changed. +**Visual checklist — fail the run if any item is `no`:** +- [ ] No unintended scrollbars +- [ ] No text ending in `…` that shouldn't be +- [ ] Hero elements fully visible (not sliced) +- [ ] Right-edge controls fully visible +- [ ] No overlapping rows +- [ ] Content uses the available width — no asymmetric dead zones (e.g. content pinned to one edge leaving empty space on the other) +- [ ] Spacing intentional — not cramped, not unintentionally vast +- [ ] Theming matches the user's ask (Light/Dark/HighContrast if relevant) +- [ ] Focus/hover/error states render if tested -**How to capture inside the test script:** -```powershell -winapp ui screenshot -a $AppPid -o "screenshots/01-initial.png" -winapp ui invoke "ShortBreakModeRadio" -a $AppPid; Start-Sleep -Milliseconds 300 -winapp ui screenshot -a $AppPid -o "screenshots/02-short-break.png" -winapp ui invoke "ExpanderCustomize" -a $AppPid; Start-Sleep -Milliseconds 300 -winapp ui screenshot -a $AppPid -o "screenshots/03-expanded.png" -``` - -**How to view them after the run:** use your image-viewing tool on each PNG path — it returns the image as inspectable data so you can actually see the app. Do this **after every test run**, not just at the end of the task. - -**What to look for in each screenshot — a visual checklist:** -- [ ] Window size fits the content — no scrollbars where you didn't intend any -- [ ] No text ending in `…` that shouldn't be (labels, button text, mode names, toggle descriptions) -- [ ] Hero elements (timer rings, large displays, charts) fully visible — not sliced at top, bottom, or sides -- [ ] Controls at the right edge are fully visible (last NumberBox value, last RadioButton label, toggle state text) -- [ ] No overlapping text or controls between rows -- [ ] Spacing looks intentional — not cramped, not unintentionally vast -- [ ] Theming is right — backgrounds, accent colors, gradients match what the user asked for -- [ ] Light/Dark/HighContrast all render (capture under each theme if relevant to the task) -- [ ] Focus states, hover states, error states render if the test exercised them - -**If a screenshot reveals a visual bug that UIA tests missed:** that's a bug, not a "minor polish issue". Fix it before declaring the task done. Common fixes: -- Content clipped at edges → window too small → grow `AppWindow.Resize` per the sizing rubric in `winui-design` Step 4 -- Controls overlap → missing `RowSpacing`/`ColumnSpacing` or wrong row definitions -- Labels truncate with `…` → fixed `Width` on a parent that should be `Auto`, or `TextTrimming` set unnecessarily +If the checklist fails, it's a bug — fix before declaring done. Window too small → grow per `winui-design` Step 4. ### Step 4: Fix and Rerun (if the user asked for it) From 8ed4d3d25956aa007595f89e9f2336c81665fc65 Mon Sep 17 00:00:00 2001 From: Nikola Metulev <711864+nmetulev@users.noreply.github.com> Date: Tue, 19 May 2026 16:08:43 -0700 Subject: [PATCH 5/5] winui-design: drop window-sizing-examples reference, make ui-testing validation user-opt-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reference file was 47 lines of one focus-timer instantiation of a 2-line formula. An LLM agent given the formula can derive any layout without seeing a worked example first — 'see one, do one' is human pedagogy, not LLM pedagogy. A single example also risks anchoring toward focus-timer-shaped solutions. Drop the file, drop the references-table row, drop the trailing 'See references/...' sentence in Step 4. The rubric stands on its own. Also reframe the Step 4 closing line: instead of prescribing 'validate visually after build' (which would auto-trigger the ui-testing pipeline — spawn the app, capture UIA, take screenshots, run the checklist), make it user-opt-in: 'If the user asks for UI validation, see winui-ui-testing Step 3.5'. This matches the policy already stated in winui-dev.agent.md that the user might ask for ui-testing 'if desired only'. The ui-testing skill is expensive to run; it shouldn't be the default follow-up to every window-sizing exercise. Net: -49 lines of repo (47 file + 2 default-loaded payload), no loss of operational guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- plugins/winui/skills/winui-design/SKILL.md | 3 +- .../references/window-sizing-examples.md | 47 ------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 plugins/winui/skills/winui-design/references/window-sizing-examples.md diff --git a/plugins/winui/skills/winui-design/SKILL.md b/plugins/winui/skills/winui-design/SKILL.md index 9dbafaa..461a834 100644 --- a/plugins/winui/skills/winui-design/SKILL.md +++ b/plugins/winui/skills/winui-design/SKILL.md @@ -79,7 +79,7 @@ public sealed partial class MainWindow : Window `XamlRoot.RasterizationScale` is null in the ctor and stale after `AppWindow.Move`, so `[DllImport]` is the cleanest path. Don't try to size the window by setting `Width`/`Height` on the root `Grid` — that clips content, not the window. -Validate visually after build via `winui-ui-testing` Step 3.5; iterate the size or layout until the checklist passes. See `references/window-sizing-examples.md` for a worked focus-timer derivation. +If the user asks for UI validation, see `winui-ui-testing` Step 3.5 to verify the rubric against the visual checklist. #### Step 5: Design Anti-Patterns | ❌ Don't | ✅ Do Instead | @@ -219,4 +219,3 @@ ToolTipService.SetToolTip(btn, "Save the current document"); | `references/typography-and-spacing.md` | Detailed type ramp, spacing grid, and sizing examples | | `references/colors-and-materials.md` | Theme brush catalog, Mica/Acrylic surface pairings, material usage | | `references/iconography-and-motion.md` | Icon guidelines, animation patterns, connected animations | -| `references/window-sizing-examples.md` | Fully worked applications of the Step 4 sizing rubric | diff --git a/plugins/winui/skills/winui-design/references/window-sizing-examples.md b/plugins/winui/skills/winui-design/references/window-sizing-examples.md deleted file mode 100644 index 057ce04..0000000 --- a/plugins/winui/skills/winui-design/references/window-sizing-examples.md +++ /dev/null @@ -1,47 +0,0 @@ -# Window Sizing — Worked Examples - -This file holds concrete, end-to-end applications of the sizing rubric in `SKILL.md` Step 4. The rubric itself is the authoritative algorithm; the examples here are illustrations — **derive your own numbers from your own layout, don't copy these verbatim**. Each example follows the same structure: list rows → derive width → derive height → state result. - -## Example 1: Focus-timer utility (single-purpose) - -A simple Pomodoro-style timer with mode switcher, hero ring, action buttons, and an optional settings expander. - -**Layout (rows top to bottom):** -- Title bar (~32 tall) -- Mode `RadioButtons` row: Focus / Short Break / Long Break (~380 wide, ~48 tall) -- 320px-diameter timer ring (320 wide, 320 tall) -- Pause / Reset button row (~260 wide, ~48 tall) -- `Expander` "Customize durations" containing three labeled `NumberBox`es side-by-side (~380 wide, ~240 tall when expanded) -- "Auto-start next session" toggle row (~320 wide, ~48 tall) -- Status text row (~32 tall) - -**Width derivation:** -- Widest row = mode selector at ~380 -- + 48 padding (24 each side) → ~430 -- Round up to nearest 20 → **460 wide** - -**Height derivation:** -- Titlebar 32 + mode row 48 + ring 320 + buttons 48 + expander 240 + toggle 48 + status 32 = 768 -- + 48 padding (24 top + 24 bottom) + ~40 cumulative spacing between rows = 856 -- Round up to nearest 20 → **860 tall** - -**Result: `460 × 860`** (DIPs — multiply by `RasterizationScale` before passing to `AppWindow.Resize`, per the Step 4 snippet). - -If post-build validation shows the mode labels clipping (`"Long Break"` cut off), bump to `500 × 860` and rebuild. - -### Anti-pattern for the same app - -Sizing the focus-timer at **440 × 720** because "utilities are small" — this clips `"Long Break"` in the mode selector, crops the timer digits at the top and bottom of the ring, truncates the auto-start toggle label, and overlaps the status footer with the toggle row. The rubric forces 460 × 860; cutting to 440 × 720 reintroduces every symptom the rubric is designed to prevent. Compactness is good; clipping is a bug. - ---- - -## Adding more examples - -Add a new `## Example N: ` section using the same structure (layout → width → height → result → anti-pattern). Good candidates if you find yourself sizing one of these from scratch: - -- A settings dialog (form-shaped, single column of labeled inputs) -- A multi-pane app (left nav + content) -- A canvas/media editor (wide-format with a toolbar) -- A login / first-run window (small, centered, tight) - -Each new example reinforces that the rubric generalises across app shapes — the more concrete examples on file, the less an agent has to extrapolate from the focus-timer in isolation.