WESL Logo

#wgsl-edit

Web component for editing WESL/WGSL with CodeMirror 6. Features syntax highlighting, linting, multi-file tabs, and light/dark themes out of the box.

#Installation

npm install wgsl-edit

#Usage

<script type="module">import "wgsl-edit";</script>

<wgsl-edit></wgsl-edit>

#Inline Source

Include shader code directly via <script> tags. Multiple tags create a multi-file editor with tabs:

<wgsl-edit>
  <script type="text/wesl" data-name="main.wesl">
    import package::utils;
    @fragment fn main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
      return vec4f(utils::gradient(pos.xy), 1.0);
    }
  </script>
  <script type="text/wesl" data-name="utils.wesl">
    fn gradient(uv: vec2f) -> vec3f { return vec3f(uv, 0.5); }
  </script>
</wgsl-edit>

#With wgsl-play

Link an editor to a player for live shader preview:

<wgsl-edit id="editor" lint-from="player" theme="auto">
  <script type="text/wesl">/* shader code */</script>
</wgsl-edit>
<wgsl-play id="player" from="editor"></wgsl-play>

The play component reads sources from the editor and live-previews the shader.

#Programmatic Control

const editor = document.querySelector("wgsl-edit");

editor.source = shaderCode;           // set active file content
editor.addFile("helpers.wesl", code); // add a file
editor.activeFile = "helpers.wesl";   // switch tabs

#Autosave (dev mode)

Edits can be persisted back to the source file on disk during Vite development. Add the wgslEditAutosave() plugin alongside wesl-plugin and set autosave on the editor:

// vite.config.ts
import wgslEditAutosave from "wgsl-edit/autosave";
import { linkBuildExtension } from "wesl-plugin";
import viteWesl from "wesl-plugin/vite";

export default {
  plugins: [
    viteWesl({ extensions: [linkBuildExtension] }),
    wgslEditAutosave(),
  ],
};
// app.ts
import shaderConfig from "./shader.wesl?link";

const editor = document.querySelector("wgsl-edit");
editor.project = shaderConfig;
editor.autosave = true;

shader-root is picked up automatically from the ?link import, so edits land in the right file on disk. Production builds never include the middleware, so the same code is safe to ship.

#Using with wesl-plugin

For more control, use wesl-plugin to assemble shaders and libraries at build time.

import shaderConfig from "./shader.wesl?link";

editor.project = {
  ...shaderConfig,
  conditions: { MOBILE: isMobileGPU },
  constants: { num_lights: 4 }
};

#API Reference

#Attributes

Attribute Values Default Description
src URL - Load source from URL
theme light dark auto auto Color theme
readonly boolean false Disable editing
tabs boolean true Show tab bar
lint on off on Real-time WESL validation
lint-from element ID - Element ID of a wgsl-play to receive compile errors from
line-numbers true false false Show line numbers
shader-root string - Root path for shader imports
autosave true false auto-detect Save edits to disk via dev server (requires shader-root)

#Properties

Property Type Description
source string Get/set active file content
project WeslProject Get/set full project config (weslSrc, conditions, constants, packageName, libs)
activeFile string Get/set active file name
fileNames string[] List all file names

#Methods

Method Description
addFile(name, content?) Add a new file
removeFile(name) Remove a file
renameFile(oldName, newName) Rename a file

#Events

Event Detail Description
change WeslProject Any edit or conditions change
file-change { action, file } File add/remove/rename

#CLI

Edit a shader file in the browser with live reload:

npx wgsl-edit path/to/shader.wesl
npx wgsl-edit shader.wgsl --port 3000 --no-open

#Bundle Size

~136 KB brotli for the full bundle with all dependencies.

Component Brotli
CodeMirror ~104 KB
lezer-wesl (grammar + lezer runtime) ~26 KB
wesl linker (powers live linting) ~14 KB