microsoft / microsoft/WinAppVSCE
[Feature]: XAML Visualizer
@chiaramooney is already working on this.
Since Jul 20, 2026.
- Dominant language
- TypeScript
- Stars
- 13
- Forks
- 3
- Avg merge
- 6d 1h
- Merged PRs (30d)
- 11
Description
1. Summary
A read-only, real-time preview of a XAML page/control rendered next to the editor. As the developer edits XAML, a preview pane updates live to show the rendered UI, with light/dark/high-contrast theme switching, device/size presets, and zoom.
2. Problem / motivation
WinUI 3 XAML has no live preview in VS Code — you must build and run to see layout, and even VS's XAML Designer for WinUI 3 is limited. Iterating on spacing, styles, and control composition means a build-run-look-repeat loop measured in tens of seconds. A live visualiser collapses that to instant feedback, which is the highest-frequency inner-loop activity in UI work. This is table stakes for Avalonia and Uno in VS Code today; WinUI needs parity.
3. Similar Products
| Tool | Approach |
|---|---|
| Avalonia Previewer (VS Code) | Out-of-process design-time host renders the control in isolation with design-time data; editor streams XAML deltas. |
| Uno Hot Design / Hot Reload (VS Code) | Renders inside the running app on any target; editor is a relay. |
| VS XAML Live Preview | Shows the running app's UI in an IDE pane. |
| VS XAML Designer (WPF/UWP) | Design-time render surface; weak/absent for WinUI 3. |
Takeaway: two industry patterns — design-time isolated render (Avalonia) vs running-app render (Uno/VS Live Preview). Does it make sense to do both?
4. Goals / non-goals
Goals
- Live preview pane (side-by-side or separate tab) that re-renders on XAML edit, debounced.
- Theme toggle: Light / Dark / High Contrast. Size presets.
- Zoom / pan; DPI-accurate rendering; background/checkerboard for transparency.
- Graceful error surface: when XAML can't render, show the parse/runtime error in the pane, keep last-good render.
- Works in VS Code / Cursor / Windsurf (webview-based host; no editor-proprietary rendering).
Non-goals
- Editing via the preview (drag/drop, selection→XAML) — that's C4.
- Inspecting a running app's live tree — that's C6.
- Pixel-perfect guarantee for every third-party/custom-drawn control (best-effort via the engine).
5. Proposed implementation
VS Code Webview (preview pane) ◀──img/stream── C3 host (extension)
│ theme/size/zoom UI │ spawns + supervises
│ error overlay ▼
└──────────────── XAML text + context ──▶ B4c design-time render engine
(renders control/page → frames/bitmap,
resolves types/resources/themes)
- Render source (B4c): the engine loads the XAML in a design-time context, resolves the project's types/resources/styles (shared with C1's type system), and produces rendered output — either a bitmap per change or a lightweight frame stream. C3 does not render XAML itself.
- Transport: the engine runs as a child process; communicate over a local socket/stdio JSON protocol (send: XAML doc + project context + theme/size; receive: image + hit-test metadata + errors). Metadata (element bounds) is optional for C3 but forward-compatible with C4.
- Host/UI: a VS Code webview shows the image with a toolbar (theme, size, zoom, refresh). The extension watches the active XAML doc, debounces edits (~150–300 ms), and forwards them.
- Project context: obtain refs/resource dictionaries/TFM from the winapp CLI project model (B); reuse restore output so custom controls and
StaticResources resolve.
6. API / contribution surface
"contributes": {
"commands": [
{ "command": "winapp.xaml.openPreview", "title": "WinApp: Open XAML Preview", "category": "WinApp" },
{ "command": "winapp.xaml.openPreviewToSide", "title": "WinApp: Open XAML Preview to the Side", "category": "WinApp" }
],
"menus": { "editor/title": [{ "command": "winapp.xaml.openPreviewToSide", "when": "resourceExtname == .xaml", "group": "navigation" }] },
"configuration": {
"winapp.xaml.preview.theme": { "enum": ["light","dark","highContrast"], "default": "dark" },
"winapp.xaml.preview.defaultSize": { "type": "string", "default": "1280x720" },
"winapp.xaml.preview.autoRefresh": { "type": "boolean", "default": true },
"winapp.xaml.preview.refreshDebounceMs": { "type": "number", "default": 200 }
}
}
Design-time render protocol (host ↔ B4c), illustrative:
// → render request
{ "op":"render", "uri":"MainWindow.xaml", "text":"<Grid…", "project":"CounterApp.csproj",
"theme":"dark", "size":{"w":375,"h":720}, "dpi":1.25, "wantHitTest":false }
// ← render result
{ "op":"frame", "png":"<base64|shared-mem handle>", "width":375, "height":720,
"diagnostics":[{ "severity":"error", "message":"Cannot find resource 'TitleStyle'", "line":7 }] }
7. Design tradeoffs & alternatives
- Design-time render vs running-app preview. Design-time (this spec) gives feedback with no build/run and no identity/cert friction, but can diverge from runtime for code-driven UI. Running-app preview is truest but slow to start.
- Bitmap-per-change vs frame stream. Bitmaps are simplest and plenty for a preview; a stream enables animations/interaction later (C4). Start with debounced bitmaps; design the protocol to allow streaming.
- Isolation scope: control vs whole window. Rendering a single
UserControl/Pageis fast and matches Avalonia; whole-window may need app resources. Support page/control first.
8. Dependencies & risks
- Hard dependency on B4c. Without the design-time render engine, C3 cannot exist; C3's timeline is gated by B4c. This spec covers only the host/UI/protocol side.
9. Open questions
- What exactly does B4c emit — bitmaps, a retained visual tree, or a frame stream — and what's its API/timeline?
- Page/control isolation vs full-window preview for v1?
- Does implementing both hot reload and a visualizer make sense? Is there business need for both?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.