wgsl.run — VS Code extension
Diagnostics, hover, go-to-definition, references, rename, scope-aware
completions, signature help, outline, folding, quick fixes, canonical
formatting, semantic highlighting — plus a CPU-interpreter kernel
debugger, an optimization advisor, an ML-kernel analyzer, and WGSL→MSL
translation. Every semantic decision flows from a wasm-compiled
libwgsl frontend — the same spec-conformant pipeline that ships as a
C library.
v2.0 status
|
|
| Spec coverage |
W3C WGSL Recommendation §3–§18 — full |
| WGSL spec pin |
CRD-2026-05-07 |
| Unicode |
17.0.0 |
| Engine |
libwgsl wasm via the official bindings/wgsl.js surface (ABI table from wgsl_abi_layout) |
| Re-check model |
incremental wgsl_session_* — byte-identical edits are cache hits, body-only edits skip clean function bodies |
| Positions |
exact: UTF-8 byte ↔ UTF-16 mapping on every wasm boundary crossing |
Design — wasm first, TS minimum
Conventional WGSL extensions ship a TextMate grammar (regex-driven) for
instant offline coloring, then layer LSP semantic tokens on top. This
extension deliberately omits the regex grammar — every coloured
byte, every completion, every quick fix comes from the wasm frontend.
- one source of truth for what every identifier means;
- the engine that produces diagnostics also produces highlights,
completions, and quick fixes, so they can never disagree;
- what you see in the editor is exactly what
wgsl_check reports to
any C / wasm consumer downstream.
language-configuration.json is the only declarative metadata
(bracket pairs, comment markers) — purely editing UX. No grammar.
Architecture
(wasm bundle) (official JS binding)
wgsl_compiler.{js,wasm} + wasm/wgsl.js (ABI-table offsets)
│
▼ WGSL facade (src/client.ts)
│ core: check/diag/hover/def/tokens/format/interp/…
│ extras: sessions, symbols, refs, rename, folding,
│ completions, signature help, code actions,
│ wgslconfig.toml project API
▼
DocumentCompiler ── for each .wgsl document:
│ 1. resolve preamble (wgslconfig.toml or _shared.wgsl)
│ 2. split on `// --- KERNEL: <name> ---`
│ 3. build N synthetic sources:
│ preamble ++ file_preamble ++ section_body
│ 4. one wgsl_session per section →
│ incremental re-check on every edit
│ 5. cache by (uri, version)
▼
{ split, results[] } → providers (all coordinates remapped
synth ↔ original through TextIndex,
UTF-8 bytes ↔ UTF-16 code units)
Kernel-split + preamble injection
Multi-kernel .wgsl files (the WebGPU ML pattern: one resource set
per // --- KERNEL: <name> --- section, helper preamble at the top,
shared utilities in a sibling file) are recognised automatically.
Each section compiles as its own module — exactly how the runtime
engine dispatches them — so cross-kernel n redeclarations and
preamble helpers resolve without false positives.
Preamble resolution
wgslconfig.toml (recommended) — discovered by walking up from
the document's directory; matched by the C-side
wgsl_project_match.
[preamble]
files = [
"_enables.wgsl", # enable subgroups; enable f16;
"_shared.wgsl", # helpers used by every kernel
]
auto_inject_into = ["*.wgsl"]
Legacy _shared.wgsl — a sibling _shared.wgsl, if present,
is prepended when no config matches.
Preamble diagnostics surface in the preamble file itself, never on
dependents. Saving a preamble re-checks every open .wgsl document.
Capabilities matrix
| Feature |
Source |
| Error/warning diagnostics (+ rule codes) |
wgsl_session_check_n + wgsl_diagnostic* |
| Hover: type, signature, builtin docs |
wgsl_hover_at_into |
| Go-to-definition (incl. into preamble files) |
wgsl_definition_at_into |
| Find references (one round-trip) |
wgsl_references_at |
| Rename with validation |
wgsl_prepare_rename + wgsl_references_at |
| Scope-aware completions |
wgsl_completions_at |
| Signature help (active parameter) |
wgsl_signature_help_at_into |
| Outline / breadcrumbs (nested symbols) |
wgsl_document_symbols |
| Folding ranges |
wgsl_folding_ranges |
| Quick fixes (enable-extension, @location, @align, safe-optimize) |
wgsl_code_actions |
| Format document / selection |
wgsl_format / wgsl_format_range_n |
| Semantic-token colouring (22 resolver kinds) |
wgsl_semantic_tokens |
| Debug kernel on the CPU (code lens / command) |
wgsl_interp + wgsl_debug_oracle |
| Module info: entry points, bind group layouts, struct memory layout |
wgsl_module_json |
| Optimization report + safe apply |
wgsl_optimize_json_src / wgsl_optimize_apply |
| ML kernel analysis (patterns, workgroup sweep, advice) |
wgsl_ml_analyze_json_src |
| WGSL → Metal translation |
wgsl_to_msl |
wgslconfig.toml projects |
wgsl_project_open_from_string + wgsl_project_match |
| Incremental re-check |
wgsl_session_* (interface-hash gated) |
Commands
| Command |
What it does |
| WGSL: Debug Kernel in CPU Interpreter |
Runs the selected @compute entry through libwgsl's SIMT interpreter (whole workgroup, barriers, shared memory) — verdict, data races, NaN/Inf anomalies, per-line trace, cost model, divergence, buffer contents. Also available as a ▶ Debug kernel code lens. |
| WGSL: Show Module Info |
Entry points, bind group layouts, resources, struct sizes/offsets/alignment as JSON. |
| WGSL: Show Optimization Report |
Dead code, unused decls, constant branches, CSE, loop findings. |
| WGSL: Apply Optimizations |
Applies the safe subset as one undoable edit (single-kernel documents without injected preambles — whole-unit rewrites are only well-defined there). |
| WGSL: Analyze ML Compute Patterns |
Detects softmax/attention/matmul/…, suggests workgroup-size sweeps, prints advice. |
| WGSL: Translate to Metal Shading Language |
Best-effort MSL preview of the current kernel. |
Settings
| Setting |
Default |
|
wgsl.interp.defaultBufferLength |
16 |
Element count assumed for runtime-sized storage buffers in the interpreter. |
wgsl.codeLens.enabled |
true |
▶ Debug kernel lenses above compute entry points. |
Build
# once: build the wasm bundle in the sibling libwgsl checkout
make -C ../libwgsl wasm
npm run compile # copies wasm + official binding, then tsc
npm run package # vsce package
Limitations
- Cold-start flash: no colour for ~50 ms while the wasm bundle
initialises.
- Formatting refuses lossy runs: the formatter is parse→print, so
on syntactically-broken sources it would silently drop the broken
decls. The extension token-compares input and output and applies
nothing unless the format is lossless — format-on-save can never eat
half-typed code.
- Renaming a preamble decl from a dependent file is refused to
avoid silently missing other dependents — rename in the preamble
file itself.
- MSL output is best-effort: the structured MSL diagnostics API is
not yet exported to wasm, so unsupported constructs yield an empty
translation rather than a detailed reason.
- Interpreter caps: 2M scheduler steps, 256 lanes, 4096 values per
buffer in reports — traces beyond that are truncated and flagged.
License
MIT.
| |