Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>wgsl.runNew to Visual Studio Code? Get it now.
wgsl.run

wgsl.run

Ugur Toprakdeviren

|
1 install
| (0) | Free
WGSL language support — diagnostics, hover, go-to-definition, semantic highlighting. All semantics from a wasm-compiled WGSL frontend (no client-side regex/grammar fallbacks).
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

WGSL — VS Code extension

Diagnostics, hover, go-to-definition, and semantic highlighting for WGSL. Every semantic decision flows from a wasm-compiled libwgsl frontend (the same pipeline that ships in ../include/wgsl.h).

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 for resolver-aware refinement. This extension deliberately omits the regex grammar — every coloured byte comes from the wasm frontend's wgsl_semantic_tokens walk over the resolved AST.

Tradeoff: until the wasm bundle finishes loading on extension activation (~50 ms cold), the document is uncoloured. In return:

  • one source of truth for what every identifier means;
  • no second classification regex that can drift away from the real spec rules over time;
  • the same engine that produces the diagnostics also produces the highlights, so they can never disagree.

language-configuration.json is the only declarative metadata: it tells VS Code which characters are bracket pairs and what the comment markers look like, purely for editing UX (auto-close-bracket, comment-toggle). No grammar.

Architecture

        (wasm bundle)
   wgsl_compiler.{js,wasm}
            │
            ▼  WGSLClient (FFI wrapper, src/extension.ts)
            │
            ▼
   DocumentCompiler  ── for each .wgsl document:
            │            1. find sibling `_shared.wgsl`
            │            2. split on `// --- KERNEL: <name> ---`
            │            3. build N synthetic sources:
            │                 shared ++ preamble ++ section_body
            │            4. wgsl_check on each → WGSLResult * per section
            │            5. cache by (uri, version)
            ▼
   { split, results[] }
            │
   ┌────────┼─────────┬──────────────┐
   ▼        ▼         ▼              ▼
 diags   hover    definition    semantic-tokens
   │        │         │              │
   ▼        ▼         ▼              ▼
DiagCol  Hover   Location    SemanticTokensBuilder
   │        │         │              │
   └─────── line/col remap: synth → original ─────────────┘

Kernel-split convention

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 _shared.wgsl) are recognised automatically. The runtime engine that ships these shaders prepends _shared.wgsl and splits each section before handing it to the driver; the extension does the same to keep diagnostics in sync.

Example: activation.wgsl declares two kernels (gelu_inplace, swiglu_combine), both reference flat_id from _shared.wgsl, both redeclare n as their own uniform. Without kernel-split, the extension would flag flat_id undeclared and n redeclaration (false positives — those are real WGSL semantics on the fused single-module view, but the engine never compiles it that way). With kernel-split, each section is its own clean compilation.

Diagnostics in _shared.wgsl are surfaced when the user opens _shared.wgsl itself, never on the dependent files.

When _shared.wgsl is saved, every open .wgsl document is re-compiled so its dependents catch any new errors.

Build

The wasm bundle lives in the parent project at ../.build/wasm/. Build the bundle, then the extension:

cd ..               # project root
make wasm           # produces .build/wasm/wgsl_compiler.{js,wasm}
cd extension
npm install
npm run compile     # copies wasm/ + tsc compile → out/extension.js

npm run watch keeps the TypeScript compiler running. Bundle copies happen as part of the build:wasm script every npm run compile.

Run from VS Code

  1. Open the extension/ directory in VS Code.
  2. Press F5 (or Run → Start Debugging) to launch a new Extension Development Host.
  3. Open any .wgsl file — diagnostics appear in the Problems panel, hover shows the resolved type, Cmd-click jumps to declarations, semantic-tokens colour the source according to the resolver's classification.

Capabilities matrix

Feature Status Source
Error diagnostics ✅ wgsl_check + wgsl_diagnostic*
Hover (resolved type) ✅ wgsl_hover_at_into
Go-to-definition ✅ wgsl_definition_at_into
Semantic-tokens colour ✅ wgsl_semantic_tokens
Bracket / comment UX ✅ language-configuration.json
Find references ✅ sweep over wgsl_semantic_tokens + wgsl_definition_at_into
Rename symbol ✅ same sweep + WorkspaceEdit (refused on shared decls)
Code completion ✅ static keyword/type/builtin tables + file-local decls (heuristic)

Limitations

  • Cold-start flash: source has no colour for ~50 ms while the wasm bundle initialises on activation. Acceptable for v1.
  • Position encoding: WGSL columns are 1-based byte distances; VS Code uses UTF-16 code units. ASCII identifiers are exact; non-ASCII XID names land 1–3 code units off. v1.x will switch to positionEncodingKind: utf-8 once VS Code adopts it more widely.
  • No incremental re-check: every edit re-runs the full pipeline. The corpus benchmark says 0.37 ms/Kloc warm, so a 1 KLOC shader is comfortably below the 16 ms frame budget on any modern CPU.
  • References / rename are quadratic-ish per call: each query resolves the cursor's decl and then walks every identifier-like token in the document, calling wgsl_definition_at_into per token. For a 1 KLoc shader that's a few hundred wasm hops — fine for a one-shot user action, but heavy enough that we don't recompute on every keystroke. v1.x: a wgsl_uses_of_decl C export that returns the use list in one round-trip.
  • Completions are heuristic: the resolver doesn't expose scope-at-position, so the suggestion list mixes (a) the static WGSL keyword / type / builtin tables and (b) every named decl the document defines. Function-local lets show up outside their function; a future scope-aware C query removes that noise.
  • Renaming a _shared.wgsl decl from a dependent file is refused to avoid silently missing the other dependents — open _shared.wgsl directly and rename there.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft