2. Layers and source tree
The five layers above the line (core, text, layout, render, commands) are webview-safe: they are compiled a second time with tsconfig.webview.json (lib: ["ES2022", "DOM"], types: []), so an acciden…
2.1 Folders#
| Folder | What it holds | Runs in |
|---|---|---|
src/core |
The document model: node, page, style, variable and comment types; ids; events and fold; indexes; drafts and commit groups; property resolution (instances, styles, variables, modes); undo inverses; the selector engine (CLI-001 §6); UDX parse and print (CLI-001 §7); SVG import sanitiser. |
host, script worker, CLI, webview, dev server |
src/text |
The text engine: HarfBuzz binding, ICU4X segmenter binding, font index and loading interface, itemisation, bidi, line breaking, text layout, glyph path cache (§6). | everywhere |
src/layout |
The layout engine: constraints, auto layout (flex and grid), sizing, text auto-resize, incremental relayout, absolute transforms and bounds (§5). | everywhere |
src/render |
The display list builder, the Renderer interface, the Canvas2D renderer, the SVG writer, the PDF writer, the resvg adapter, tiling and LOD planning, the spatial index, hit testing (§7). |
everywhere (Canvas2D in the webview and dev page; resvg on host and CLI) |
src/commands |
The command registry, every command definition by category (commands/node/, commands/text/, commands/layout/, …), the run pipeline, the JSON Schema subset validator, target resolution, transactions (§3). |
everywhere (the webview runs it only to predict, §11.4) |
src/plugin-api |
The Figma Plugin API compatibility layer: the QuickJS loader, the prelude that defines the figma and ud globals inside the sandbox, the member map, value marshalling, ud-plugin-api.d.ts generation (§8). |
host (script worker), CLI |
src/mcp |
The tool table (one row per Figma MCP tool and native ud_* tool), tool handlers, the MCP stdio server, resources and prompts, the Figma schema snapshot comparator, the loopback asset server (§9.6). |
host, CLI |
src/cli |
The ud command: argument parsing generated from schemas, native verbs (tree, inspect, apply, render, …), file and actor resolution, output formatting, exit codes, the terminal shim (§9). |
CLI |
src/headless |
A document opened straight from its file under a lock, with assets folder access, for the CLI when no editor has it open (§9.4). | CLI |
src/bridge |
The socket between ud and a running editor: registry folder, server, client, wire protocol (§9.4). |
host (server), CLI (client) |
src/host/controller |
DesignController and everything an editor host needs that is not VS Code: the command queue, the undo stack, merging external changes, proposals, the script worker, the webview protocol, the Workbench interface (§10). |
host, dev server |
src/host/vscode |
The VS Code host: CustomEditorProvider, document lifecycle, save and backup, file watching, Command Palette and keybinding contributions, settings, status bar, SecretStorage, licensing client, AI runner, LM tools, the terminal PATH (§10). |
host |
src/third-party |
Vendored code that is not edited here: the Soft Forge Payments licensing client, generated Unicode tables (bidi classes and scripts, §6.1). | host, CLI (licensing); everywhere (Unicode) |
src/extension.ts |
activate(): wires src/host/vscode together. |
host |
media/ |
The webview page: custom elements, the canvas, panels, the AppModel replica, the render worker (§11). media/lib/ is generated (§15.1), media/wasm/ and media/fonts/ are copied assets. |
webview, dev page |
dev/ |
The development server (npm run dev): the same controller and webview in a browser, plus test endpoints (PLT-11). |
dev server (Node) |
test/ |
Unit, conformance, golden image, Plugin API, CLI, bridge and integration tests, fixtures and their generators (§14). | Node, VS Code test host, headless Chromium |
scripts/ |
Build and maintenance scripts: copy WASM, generate contributions and typings, refresh the Figma tool snapshot, check the webview and the layer rules. | Node (development only) |
2.2 Which layer may import which#
text
┌───────────┐
│ src/text │ (nothing; WASM and font bytes are injected)
└─────▲─────┘
│
┌───────────┐ ┌─────┴─────┐ ┌────────────┐ ┌──────────────┐
│ src/core │◄────┤ src/layout│◄────┤ src/render │◄────┤ src/commands │
└─────▲─────┘ └───────────┘ └────────────┘ └──────▲───────┘
│ (core is imported by every box below) │
│ ┌───────────────┴──┐
│ │ src/plugin-api │
│ └───────▲──────────┘
│ ┌───────┴──────────┐
│ │ src/mcp │
│ └───▲─────────▲────┘
│ ┌───────────────┐ │ │
│ │ src/bridge │◄─────────┼─────┐ │
│ └───────▲───────┘ │ │ │
│ ┌────────────────┴──┐ ┌───────┴─────┴┐ │
│ │ src/host/controller│◄─────┤ src/cli │ │
│ └──────▲──────▲─────┘ │ src/headless │──┘
│ │ │ └──────────────┘
│ ┌──────────┴───┐ │ ┌──────┐
│ │src/host/vscode│ └─┤ dev/ │
│ └──────────────┘ └──────┘
│
media/ ──► media/lib/{core,text,layout,render,commands} (compiled copies, never src/ directly)| Layer | May import | Must not import |
|---|---|---|
src/text |
nothing in the repository | Node built-ins, DOM globals other than WebAssembly, TextDecoder |
src/core |
src/third-party/unicode |
Node built-ins, DOM, vscode. Randomness only through globalThis.crypto.getRandomValues. |
src/layout |
core, text |
as core |
src/render |
core, text, layout |
as core. The Canvas2D renderer is written against a local Canvas2DLike interface, so it compiles under the Node configuration. |
src/commands |
core, text, layout, render |
as core. Host-only services (raster, file reads, clipboard) come through ctx.services. |
src/plugin-api |
the five above, the QuickJS package | vscode, DOM |
src/mcp |
the above, plugin-api |
vscode |
src/bridge |
core (types), Node net, fs, os |
vscode, host |
src/headless |
core, commands, layout, text, Node fs |
vscode, host |
src/cli |
everything but src/host |
vscode |
src/host/controller |
everything but cli and host/vscode; Node worker_threads |
vscode |
src/host/vscode |
everything but cli |
— |
dev/ |
src/host/controller and below, Node http |
vscode |
media/ |
media/lib/**, its own modules |
anything outside media/ |
The five layers above the line (core, text, layout, render, commands) are webview-safe: they are
compiled a second time with tsconfig.webview.json (lib: ["ES2022", "DOM"], types: []), so an accidental
Node import fails the build. scripts/check-layers.mjs (run by npm run lint) enforces the rest of the table
by parsing import specifiers.
2.3 Where each part runs#
| Process | Runs | Holds a document? |
|---|---|---|
| Extension host (VS Code) | src/host/vscode, DesignController, registry, bridge server, MCP tool handlers for bridged calls, LM tools, licensing, AI runner |
Yes: the authoritative copy of each open document. |
Script worker (a worker_threads worker of the extension host, one per open document, started on first use) |
QuickJS, src/plugin-api, a replica of the document |
A replica that folds every committed event; scripts run on a draft of it (§8.2). |
| Webview (one per editor tab; a split view gets a second one) | media/, media/lib/*; its render worker (a Worker with an OffscreenCanvas, ADR-10) runs shaping, layout and tile rasterisation |
A replica built from the snapshot and the event deltas the host sends (§11.4); the worker holds a second copy fed by the same deltas. |
ud process (terminal, Claude Code, ud mcp) |
src/cli, src/mcp, and either the bridge client or src/headless |
Only headless: the file, under a lock. Through the bridge it holds nothing. |
Dev server (npm run dev) |
dev/, DesignController, the webview page in a real browser |
The authoritative copy, in memory, backed by a file on save. |