Examples
generic shadertoy-plasma.ts
Plasma
The classic sum-of-sines plasma folded through an RGB palette — the "hello shader". One DSL source, animated by a single time uniform.
Live
0.0s
One source, compiled every way
The DSL source below, compiled to WebGPU (WGSL), WebGL2 (GLSL ES 3.00 — two stages), and a reflection JSON the host binds from. Nothing but the DSL tab is hand-written.
// ═══ @xgis/shader-dsl example — a ShaderToy plasma, authored in the DSL ═══//// Ports the classic ShaderToy plasma (sum-of-sines → palette) to the DSL: a// fullscreen-triangle vertex stage + a fragment stage driven by a {time,// resolution} uniform. One DSL source emits WGSL (WebGPU) AND GLSL ES 3.00// (WebGL2) plus its pipeline Reflection — the metadata a host needs to build the// bind-group layout + pack the uniform. The /shader-dsl site page renders this live.
import { fn, module, vec3, vec4, sin } from '../src/index.ts'import { VsOut, vs, fullscreenUniforms } from './_fullscreen.ts'import type { ShaderExample } from './_shared.ts'const U = fullscreenUniforms()
// `vo` (vertex-out), NOT `in`: `in` is a reserved keyword in GLSL, so naming the// fragment param `in` would emit `vec4 fs_impl(VsOut in)` — a hard WebGL2 compile error.const fs = fn( 'fs', { vo: VsOut }, ({ vo }) => { const t = U.field.time const uv = vo.uv // sum-of-sines plasma field const v = sin(uv.x.mul(10).add(t)) .add(sin(uv.y.mul(10).add(t))) .add(sin(uv.x.add(uv.y).mul(10).add(t.mul(0.7)))) // map the field through an RGB palette const col = vec3(sin(v), sin(v.add(2.094)), sin(v.add(4.188))) .mul(0.5) .add(0.5) return vec4(col, 1) }, { stage: 'fragment', retAttr: '@location(0)' },)
const plasmaModule = module({ structs: [U.struct, VsOut.decl], bindings: [U.binding], funcs: [vs, fs],})
export const plasma: ShaderExample = { id: 'plasma', title: 'Plasma', blurb: 'The classic sum-of-sines plasma folded through an RGB palette — the "hello shader". One DSL source, animated by a single time uniform.', category: 'generic', file: 'shadertoy-plasma.ts', module: plasmaModule, renderable: true, controls: { time: { kind: 'time' }, resolution: { kind: 'resolution' } },}struct Uniforms { time: f32, resolution: vec2<f32>,}
struct VsOut { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32>,}
@group(0) @binding(0) var<uniform> U: Uniforms;
@vertexfn vs(@builtin(vertex_index) vi: u32) -> VsOut { let _cse0 = ((f32((vi & 1u)) * 4.0) - 1.0); let _cse1 = ((f32((vi >> 1u)) * 4.0) - 1.0); return VsOut(vec4<f32>(_cse0, _cse1, 0.0, 1.0), vec2<f32>(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));}
@fragmentfn fs(vo: VsOut) -> @location(0) vec4<f32> { let _cse0 = ((sin(((vo.uv.x * 10.0) + U.time)) + sin(((vo.uv.y * 10.0) + U.time))) + sin((((vo.uv.x + vo.uv.y) * 10.0) + (U.time * 0.7)))); return vec4<f32>(((vec3<f32>(sin(_cse0), sin((_cse0 + 2.094)), sin((_cse0 + 4.188))) * 0.5) + 0.5), 1.0);}#version 300 esprecision highp float;precision highp int;
struct VsOut { vec4 pos; vec2 uv;};out vec2 uv;
VsOut vs_impl(uint vi) { float _cse0 = ((float((vi & 1u)) * 4.0) - 1.0); float _cse1 = ((float((vi >> 1u)) * 4.0) - 1.0); return VsOut(vec4(_cse0, _cse1, 0.0, 1.0), vec2(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));}
void main() { VsOut _out = vs_impl(uint(gl_VertexID)); gl_Position = _out.pos; uv = _out.uv;}#version 300 esprecision highp float;precision highp int;
struct VsOut { vec4 pos; vec2 uv;};layout(std140) uniform Uniforms { float time; vec2 resolution;} U;in vec2 uv;layout(location = 0) out vec4 _ret;
vec4 fs_impl(VsOut vo) { float _cse0 = ((sin(((vo.uv.x * 10.0) + U.time)) + sin(((vo.uv.y * 10.0) + U.time))) + sin((((vo.uv.x + vo.uv.y) * 10.0) + (U.time * 0.7)))); return vec4(((vec3(sin(_cse0), sin((_cse0 + 2.094)), sin((_cse0 + 4.188))) * 0.5) + 0.5), 1.0);}
void main() { VsOut vo; vo.pos = gl_FragCoord; vo.uv = uv; _ret = fs_impl(vo);}{ "bindGroups": [ { "group": 0, "entries": [ { "group": 0, "binding": 0, "name": "U", "space": "uniform", "resourceKind": "uniform-buffer", "structName": "Uniforms" } ] } ], "uniforms": [ { "name": "Uniforms", "size": 16, "align": 16, "fields": [ { "name": "time", "type": "f32", "offset": 0, "align": 4, "size": 4 }, { "name": "resolution", "type": "vec2<f32>", "offset": 8, "align": 8, "size": 8 } ] } ], "storage": [], "entries": [ { "name": "vs", "stage": "vertex", "inputs": [ "u32" ], "output": "struct:VsOut" }, { "name": "fs", "stage": "fragment", "inputs": [ "struct:VsOut" ], "output": "vec4<f32>" } ], "overrides": []}
Run it locally:
npx tsx examples/print.ts plasma
— prints the WGSL, GLSL, reflection. Source:
GitHub.
New to the IR? See Concepts; the full authoring + emit surface is in the API reference.