Skip to content
Skill Authoring
Skill

/compiling-wgsl

Produces and shrinks WGSL shaders. Converts GLSL (WebGL 1 and 2, Shadertoy mainImage code, Vulkan GLSL 450, compute shaders) to WGSL and checks the port pixel by pixel against WebGL; minifies a WebGPU shader (renaming, dead code, literal and type shortening) and proves the

From plugin
claude-skills
171105 skills1 agent

Claude Code

$ npx -y skills add oaustegard/claude-skills --skill compiling-wgsl --agent claude-code

SKILL.md

compiling-wgsl.SKILL.md
name: compiling-wgsl
description: "Produces and shrinks WGSL shaders. Converts GLSL (WebGL 1 and 2, Shadertoy mainImage code, Vulkan GLSL 450, compute shaders) to WGSL and checks the port pixel by pixel against WebGL; minifies a WebGPU shader (renaming, dead code, literal and type shortening) and proves the result unchanged with naga, Chrome's Tint and bit-identical compute runs; compiles an SVG file or a Python-built scene of circles, rects, paths, gradients and animated transforms into one resolution-independent WGSL fragment shader. Use for convert GLSL to WGSL, port this Shadertoy to WebGPU, WebGL shader to WebGPU, minify this WGSL, shrink my shader, make the shader smaller, WGSL optimizer, turn this SVG into a shader, draw this icon in WebGPU, SDF shapes in WGSL, smooth union shapes, animated vector graphics on the GPU, pretty-print WGSL."
metadata:
  version: 0.5.0

Compiling WGSL

`scripts/forge` is a pure-Python WGSL toolchain (numpy is the only dependency): a parser that follows the spec's template-list rules, a minifier, a shape compiler, and a GLSL front end that rewrites WebGL and Shadertoy GLSL for naga (and glslang) to translate. It came from `oaustegard/experiments/wgsl-forge`, whose RESULTS.md holds the measurements quoted here. Set `SKILL=/mnt/skills/user/compiling-wgsl` (or this directory) and run every command with `PYTHONPATH=$SKILL/scripts`.

When NOT to use this skill

| Situation | Use instead | |---|---| | A raster image (photo, PNG) should become vector shapes | `image-to-svg`, then this skill on its SVG | | The output is a PNG, PDF or SVG file rather than a shader | `drawing-with-pycairo` | | Charts or dashboards | `charting`, `charting-vega-lite` | | HLSL or Metal | not covered; naga reads SPIR-V (`naga in.spv out.wgsl`), so HLSL can go through DXC to SPIR-V first | | GLSL for desktop OpenGL with `#version 330` or older, or code using `iChannel` buffers (multi-pass Shadertoy) | converts, but the multi-pass plumbing (render targets, feedback) is host code you write | | A shader whose host reads names back by reflection (a binding library that matches struct member or function names) | run with `--keep name1,name2`, or do not rename |

Setup

export SKILL=/mnt/skills/user/compiling-wgsl
pip install --break-system-packages numpy pillow          # pillow only for --png
command -v naga || cargo install naga-cli                  # validator; required for GLSL, ~3 min
command -v glslangValidator || apt-get install -y glslang-tools   # GLSL fallback route
node -e "require('playwright')" && echo playwright-ok      # GPU checks need it
python3 $SKILL/scripts/selftest.py                         # ~20 s: every route on bundled fixtures

`selftest.py` prints `missing tools:` first if naga, glslang or node is absent. Every other line must read `ok`.

The GPU checks run headless Chromium on SwiftShader. On claude.ai and Claude Code on the web, Playwright's Chromium is already installed. Elsewhere, point `CHROME_PATH` at a Chromium binary.

Minify a shader

PYTHONPATH=$SKILL/scripts python3 -m forge minify in.wgsl -o out.wgsl       # prints bytes before -> after
python3 $SKILL/scripts/verify.py minify in.wgsl                             # always run this

`verify.py minify` validates the output with naga and compiles both versions in Tint. It then runs every compute entry point that binds only buffers on random typed inputs: the original twice and the minified once. It exits 1 on any failure.

Read the result lines:

  • `ok compute main bit-identical`: the minified kernel computes the same bytes.
  • `skip ... original disagrees with itself`: the original has a race for this dispatch

shape. Pass the real shape with `--dispatch 64,1,1`.

  • `skip ... textures or samplers bound`: that shader was compiled, not executed. To prove

a render shader unchanged, render it in its real host before and after and compare pixels.

Options:

  • `--no-aliases` skips the `alias a=vec4f;` pass. Use it for shaders served gzipped: on

the 86-shader corpus that pass saves 1.7% raw bytes but adds 0.9% gzip bytes.

  • `--keep a,b` protects extra names from renaming and removal.

Entry-point names, `override` names, binding numbers and attributes are never changed. Struct members spelled like swizzles (`x`, `rgb`) or like builtin result fields (`fract`, `exp`, `whole`) are never renamed either.

Expect 30–35% of the original bytes on typical shaders (34% on the corpus, against 56% for LucentFlux wgsl-minifier on the files both handle). Shaders that are already terse land nearer 50%: Tilt Rally's nine came out at 51%.

`python3 -m forge fmt out.wgsl` pretty-prints minified code for reading.

Convert GLSL to WGSL

PYTHONPATH=$SKILL/scripts python3 -m forge glsl shader.frag -o shader.wgsl [--minify]
python3 $SKILL/scripts/verify.py glsl shader.frag --png /tmp/port.png               # always run this
PYTHONPATH=$SKILL/scripts python3 -m forge html toy.glsl -o preview.html            # Shadertoy only

The input kind is detected automatically:

| input | detected by | output | |---|---|---| | Shadertoy | `mainImage` and no `main` | the same interface as compiled scenes: uniform `{r, t}` at binding 0, `vs` and `fs` entries; y flipped to Shadertoy's bottom-left origin, alpha forced to 1 | | WebGL 2 (`#version 300 es`) or WebGL 1 (no version) | version line | one WGSL entry point `main`; loose uniforms gathered into one std140 block at binding 0, each `sampler2D` split into a texture and a sampler from binding 1 | | Vulkan GLSL 450 | `#version 450` | passed through as written |

The stage comes from the extension (`.vert`, `.frag`, `.comp`) or from the content (`gl_Position`, `local_size_x`). `--stage` overrides it.

`forge glsl` prints the `binding` lines the host must now supply, with byte offsets. A WebGL program set uniforms by name; WebGPU writes one buffer at those offsets, and std140 puts a `vec3` or `mat3` column on a 16-byte boundary. `note:` line

Read more
@oaustegard
Ships withclaude-skills

A collection of Claude skills distributed as a Claude Code plugin marketplace. Skills are primarily designed for the Claude.ai PaaS skill compute environment; mileage will vary if used as Claude Code Agent Skills.

171105 skills1 agent
Get the whole plugin

Stars on GitHub

Momentum

stars in total
171
Star history of oaustegard/claude-skills on GitHub, a chart by star-history.com

Other skills on claude-skills.

challenging

challenging

Cross-context adversarial review for deliverables before shipping. Use when producing blog posts, technical recommendations,…

More skills from other plugins.

gstack-openclaw-ceo-review

gstack-openclaw-ceo-re…

Use when asked to review a plan, challenge a proposal, run a CEO review, poke holes in an approach, think bigger about scope, or…

gstack12d138k
@garrytan@garrytanInstall Skill
book-to-skill

book-to-skill

Converts books and documents (PDF, EPUB, DOCX, HTML, Markdown, plain text, RTF, MOBI/AZW with Calibre) into structured agent…

@virgiliojr94@virgiliojr94Install Skill
distilly

distilly

Set up the owner profile so a personal agent knows who it works for (first-run setup, \"get to know me\"), or distill colleague,…

@titanwings@titanwingsInstall Skill

Questions about compiling-wgsl.

Which coding agents can use compiling-wgsl?
compiling-wgsl installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.