| name | lvt |
| description | Inspect running Windows application UIs using the lvt (Live Visual Tree) CLI tool. Use this skill when you need to understand a Windows app's visual tree structure, capture annotated screenshots, detect UI frameworks, or find specific UI elements for verification or interaction planning.
|
Inspect Windows application UI with lvt
When to use
Use lvt whenever you need to understand the visual content or structure of a running Windows application. Common scenarios:
- UI verification — confirm that a UI change was applied correctly (e.g. a button label changed, a dialog appeared)
- Finding UI elements — locate a specific control, menu item, or text field in an app's visual tree
- Screenshot capture — take an annotated screenshot of an app with element IDs overlaid
- Framework detection — determine which UI frameworks an app uses (Win32, ComCtl, XAML, WinUI 3, WPF, Chromium)
- Automated UI interaction planning — get element IDs and bounds to plan mouse clicks or keyboard input
Prerequisites
Before using lvt, ensure lvt.exe and lvt_tap_{arch}.dll are available. If they are not already on PATH or in the current directory, download and extract them automatically:
# Download the latest release zip (matching host architecture) and extract to ~/.lvt
$lvtDir = "$env:USERPROFILE\.lvt"
if (-not (Test-Path "$lvtDir\lvt.exe")) {
New-Item -ItemType Directory -Path $lvtDir -Force | Out-Null
$arch = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "arm64" } elseif ($env:PROCESSOR_ARCHITECTURE -eq "x86") { "x86" } else { "x64" }
$release = Invoke-RestMethod "https://api.github.com/repos/asklar/lvt/releases/latest"
$asset = $release.assets | Where-Object { $_.name -like "lvt-*-$arch.zip" } | Select-Object -First 1
$zip = "$env:TEMP\lvt.zip"
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip
Expand-Archive -Path $zip -DestinationPath $lvtDir -Force
Remove-Item $zip
}
# Run lvt from the install directory
& "$lvtDir\lvt.exe" --help
Once downloaded, lvt.exe persists in ~/.lvt/ and does not need to be downloaded again.
Usage
Target an application
You must specify exactly one target. Pick the most convenient option:
# By process name (most common — omit .exe extension if you like)
lvt --name notepad
# By window title substring
lvt --title "Untitled - Notepad"
# By PID
lvt --pid 1234
# By HWND (hex)
lvt --hwnd 0x1A0B3C
Get the visual tree
# JSON output (default) — best for programmatic parsing
lvt --name notepad
# XML output — more compact, easier to read
lvt --name notepad --format xml
# Write to a file instead of stdout
lvt --name notepad --output tree.json
Capture a screenshot
# Screenshot only (no tree output)
lvt --name notepad --screenshot out.png
# Screenshot + tree output together
lvt --name notepad --screenshot out.png --dump
Screenshots are annotated with element IDs (e0, e1, …) overlaid on each element, making it easy to correlate visual positions with tree nodes.
Scope to a subtree
When the full tree is too large, scope to a specific element:
# Only show element e5 and its descendants, up to 3 levels deep
lvt --name myapp --element e5 --depth 3
Detect frameworks only
lvt --name notepad --frameworks
Interpreting the output
Element IDs
Every element gets a stable ID like e0, e1, e2, etc., assigned in depth-first order. These IDs are consistent within a single invocation — use them to:
- Reference specific elements in follow-up commands (
--element e5)
- Correlate screenshot annotations with tree nodes
- Identify click targets by combining element ID with its
bounds
Key element properties
| Property | Description |
|---|
id | Stable element ID (e.g. e0) |
type | Element type name (e.g. Window, Button, TextBlock) |
framework | Which framework owns this element (win32, comctl, xaml, winui3, wpf, chromium) |
className | Win32 window class name (Win32/ComCtl elements) |
text | Visible text content or window title |
bounds | Screen-relative bounding rectangle {x, y, width, height} |
children | Nested child elements |
JSON example
{
"target": { "hwnd": "0x001A0B3C", "pid": 12345, "processName": "Notepad.exe" },
"frameworks": ["win32", "winui3"],
"root": {
"id": "e0",
"type": "Window",
"framework": "win32",
"className": "Notepad",
"text": "Untitled - Notepad",
"bounds": { "x": 100, "y": 100, "width": 800, "height": 600 },
"children": [ ... ]
}
}
XML example
<LiveVisualTree hwnd="0x001A0B3C" pid="12345" process="Notepad.exe" frameworks="win32,winui3">
<Window id="e0" framework="win32" className="Notepad" text="Untitled - Notepad" bounds="100,100,800,600">
<ContentPresenter id="e1" framework="winui3" bounds="108,140,784,552" />
</Window>
</LiveVisualTree>
Recommended workflow
- Start the target app if it isn't already running
- Run
lvt --name <app> --format xml to get a quick overview of the UI tree
- Take a screenshot with
lvt --name <app> --screenshot ui.png to see the visual layout with element IDs
- Drill into a subtree with
--element <id> --depth <n> if the tree is large
- Use element IDs and bounds to plan any UI interactions (clicks, keyboard input)
Tips
- Use
--format xml for human-readable output and --format json for programmatic parsing
- If the tree is very large, use
--depth to limit traversal depth first, then drill deeper with --element
- Element IDs change between invocations if the UI structure changes — always re-query before acting on stale IDs
- The tool requires no special permissions beyond being able to read the target process (same user session)
- For XAML/WinUI 3 apps, lvt injects a helper DLL into the target — this is safe and non-destructive but means
lvt_tap_{arch}.dll must be next to lvt.exe
- For WPF apps, lvt injects
lvt_wpf_tap_{arch}.dll and the managed LvtWpfTap.dll — both must be next to lvt.exe
- lvt.exe must match the target process architecture (x64, x86, or ARM64) — a clear error is shown on mismatch. Use
lvt-x86.exe for 32-bit WPF apps.
Chrome/Edge DOM inspection (optional one-time setup)
lvt can dump the DOM tree of web pages in Chrome and Edge. This requires a one-time setup:
$lvtDir = "$env:USERPROFILE\.lvt"
# 1. Register the native messaging host for Chrome and Edge
& "$lvtDir\plugins\chromium\lvt_chromium_host.exe" --register
# 2. Load the browser extension in Chrome or Edge:
# - Open chrome://extensions (or edge://extensions)
# - Enable "Developer mode"
# - Click "Load unpacked" → select the extension folder:
Start-Process "$lvtDir\plugins\chromium\extension"
After setup, lvt --name chrome or lvt --name msedge will include the DOM tree of the active tab. If the extension is not installed, lvt still works for all other frameworks — it just won't show web content.