Generator CLI
TypeGPU Generator (tgpu-gen) is a CLI companion tool that transforms WGSL code files into matching TypeGPU definitions. It can be used for integrating TypeGPU into established WebGPU projects, or automating the migration process.
- β¨ Generate TypeGPU definitions from WGSL shaders
- π Continuously watch for changes in WGSL files and update the generated definitions
- π² Specify input and output using glob patterns
- π― Choose the output extension and CJS or ESM format
Installation
You can use it directly through npx
:
npx tgpu-gen path/to/shader.wgsl
Or install it globally:
npm install -g tgpu-gentgpu-gen path/to/shader.wgsl
Example
Letβs assume the following directory structure:
DirectorycomputeBoids
Directoryshaders
- updateSprites.wgsl
- sprite.wgsl
- main.ts
This is a simple project that contains two WGSL shaders (updateSprites.wgsl
and sprite.wgsl
) and a TypeScript file (main.ts
).
The example WGSL shaders can be found on the WebGPU Samples repository.
Here are the contents of the shader files:
Click to see the content
struct Particle { pos : vec2f, vel : vec2f,}struct SimParams { deltaT : f32, rule1Distance : f32, rule2Distance : f32, rule3Distance : f32, rule1Scale : f32, rule2Scale : f32, rule3Scale : f32,}struct Particles { particles : array<Particle>,}@binding(0) @group(0) var<uniform> params : SimParams;@binding(1) @group(0) var<storage, read> particlesA : Particles;@binding(2) @group(0) var<storage, read_write> particlesB : Particles;
// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp@compute @workgroup_size(64)fn main(@builtin(global_invocation_id) GlobalInvocationID : vec3u) { var index = GlobalInvocationID.x;
var vPos = particlesA.particles[index].pos; var vVel = particlesA.particles[index].vel; var cMass = vec2(0.0); var cVel = vec2(0.0); var colVel = vec2(0.0); var cMassCount = 0u; var cVelCount = 0u; var pos : vec2f; var vel : vec2f;
for (var i = 0u; i < arrayLength(&particlesA.particles); i++) { if (i == index) { continue; }
pos = particlesA.particles[i].pos.xy; vel = particlesA.particles[i].vel.xy; if (distance(pos, vPos) < params.rule1Distance) { cMass += pos; cMassCount++; } if (distance(pos, vPos) < params.rule2Distance) { colVel -= pos - vPos; } if (distance(pos, vPos) < params.rule3Distance) { cVel += vel; cVelCount++; } } if (cMassCount > 0) { cMass = (cMass / vec2(f32(cMassCount))) - vPos; } if (cVelCount > 0) { cVel /= f32(cVelCount); } vVel += (cMass * params.rule1Scale) + (colVel * params.rule2Scale) + (cVel * params.rule3Scale);
// clamp velocity for a more pleasing simulation vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1); // kinematic update vPos = vPos + (vVel * params.deltaT); // Wrap around boundary if (vPos.x < -1.0) { vPos.x = 1.0; } if (vPos.x > 1.0) { vPos.x = -1.0; } if (vPos.y < -1.0) { vPos.y = 1.0; } if (vPos.y > 1.0) { vPos.y = -1.0; } // Write back particlesB.particles[index].pos = vPos; particlesB.particles[index].vel = vVel;}
Click to see the content
struct VertexOutput { @builtin(position) position : vec4f, @location(4) color : vec4f,}
@vertexfn vert_main( @location(0) a_particlePos : vec2f, @location(1) a_particleVel : vec2f, @location(2) a_pos : vec2f) -> VertexOutput { let angle = -atan2(a_particleVel.x, a_particleVel.y); let pos = vec2( (a_pos.x * cos(angle)) - (a_pos.y * sin(angle)), (a_pos.x * sin(angle)) + (a_pos.y * cos(angle)) );
var output : VertexOutput; output.position = vec4(pos + a_particlePos, 0.0, 1.0); output.color = vec4( 1.0 - sin(angle + 1.0) - a_particleVel.y, pos.x * 100.0 - a_particleVel.y + 0.1, a_particleVel.x + cos(angle + 0.5), 1.0); return output;}
@fragmentfn frag_main(@location(4) color : vec4f) -> @location(0) vec4f { return color;}
If we wanted to leverage TypeGPUβs type-safe features with these shaders, we could manually create the necessary definitions. However, maintaining these handcrafted definitions in sync with the shaders can be both tedious and prone to errors. Fortunately, we donβt have to do that; we can use the TypeGPU Generator CLI to automatically generate the required TypeScript definitions for us.
Assuming that we are inside the project directory (computeBoids folder), we can run the following command to generate the TypeScript definitions for the shaders:
tgpu-gen "shaders/*.wgsl" -o "definitions/*.ts"
This command will generate the following files:
DirectorycomputeBoids
Directoryshaders
- updateSprites.wgsl
- sprite.wgsl
Directory
definitions- updateSprites.ts
- sprite.ts
The generated TypeScript definitions look like this:
Click to see the content
/* generated via tgpu-gen by TypeGPU */import tgpu from 'typegpu';import * as d from 'typegpu/data';
/* structs */export const Particle = d.struct({ pos: d.vec2f, vel: d.vec2f,});
export const SimParams = d.struct({ deltaT: d.f32, rule1Distance: d.f32, rule2Distance: d.f32, rule3Distance: d.f32, rule1Scale: d.f32, rule2Scale: d.f32, rule3Scale: d.f32,});
export const Particles = (arrayLength: number) => d.struct({ particles: d.arrayOf(Particle, arrayLength),});
/* bindGroupLayouts */export const layout0 = tgpu.bindGroupLayout({ params: { uniform: SimParams, }, particlesA: { storage: Particles, access: 'readonly', }, particlesB: { storage: Particles, access: 'mutable', },});
Click to see the content
/* generated via tgpu-gen by TypeGPU */import * as d from 'typegpu/data';
/* structs */export const VertexOutput = d.struct({ position: d.vec4f, color: d.vec4f,});
These definitions can now be used in our TypeScript code to interact with the shaders in a type-safe manner.
If we wanted to tinker with the shaders, but still have the updated definitions, we could use the --watch
flag to keep the definitions up-to-date.
For specific usage details, check out the following Usage section.
Usage
This section will cover the most common use cases of the TypeGPU Generator CLI and provide short examples.
Generate TypeGPU definitions for WGSL shader files
To generate TypeGPU definitions from a single WGSL shader file, run:
tgpu-gen path/to/shader.wgsl
This will generate a TypeScript file with the TypeGPU definitions in the same directory as the shader.
By default, the generated file will have the same name as the shader, with the .ts
extension.
Directorypath/to
- shader.wgsl
- shader.ts
TypeGPU Generator CLI supports glob patterns for specifying input paths. The following command will generate TypeGPU definitions for all WGSL files inside a given directory:
tgpu-gen "path/to/*.wgsl"
The generated TypeScript files will have the same names as the shaders, with the .ts
extension.
Directorypath/to
- shader1.wgsl
- shader1.ts
- shader2.wgsl
- shader2.ts
Directoryexample
- shader3.wgsl
To specify a recursive search, use the **
pattern:
tgpu-gen "path/to/**/*.wgsl"
This will generate TypeGPU definitions for all WGSL files inside the path/to
directory and its subdirectories.
Directorypath/to
- shader1.wgsl
- shader1.ts
Directoryexample
- shader2.wgsl
- shader2.ts
Specify the output path with the --output
option
By default, the generated TypeScript files are placed in the same directory as the input shaders.
You can specify a different output path using the --output
option:
tgpu-gen "path/to/shader.wgsl" --output "different/path/output.ts"
This will generate the TypeGPU definitions in the different/path
directory with the output.ts
filename.
Directorypath/to
- shader.wgsl
Directory
different/path- output.ts
It also supports glob patterns for specifying the output path:
tgpu-gen "path/to/*.wgsl" --output "output/*.ts"
This will generate the TypeGPU definitions in the output
directory with the same names as the shaders, but with the .ts
extension.
Directorypath/to
- shader1.wgsl
- shader2.wgsl
Directoryexample
- shader3.wgsl
Directory
output- shader1.ts
- shader2.ts
You can also use the -o
shorthand for the --output
option:
tgpu-gen "path/to/shader.wgsl" -o "different/path/output.ts"
Supported extensions and module formats
By default, the generated TypeScript files use the .ts
extension and the ES module format.
You can specify a different extension by just providing the extension in the output path:
tgpu-gen "path/to/shader.wgsl" -o "different/path/output.js"
This will generate the TypeGPU definitions in the different/path
directory with the output.js
filename.
The supported extensions are:
.js
.cjs
.mjs
.ts
.cts
.mts
Using the --keep
and --overwrite
options
When generating TypeGPU definitions, if the output file already exists, the script will fail and not overwrite the existing file.
You can use the --keep
option to skip the generation of the file if it already exists:
tgpu-gen "path/to/*.wgsl" --output "output/*.ts" --keep
This will skip the generation of the TypeGPU definitions for shaders that already have a corresponding TypeScript file in the output directory.
If you want to overwrite the existing files, you can use the --overwrite
option:
tgpu-gen "path/to/*.wgsl" --output "output/*.ts" --overwrite
This will overwrite the existing TypeScript files with the new TypeGPU definitions.
Watch mode
TypeGPU Generator CLI supports a watch mode that continuously monitors the input files for changes and updates the generated definitions.
To enable the watch mode, use the --watch
(or -w
) option:
tgpu-gen "path/to/*.wgsl" --output "output/*.ts" --watch
This will generate the TypeGPU definitions for all WGSL files inside the path/to
directory
and its subdirectories and continuously monitor them for changes.
By default, the watch mode will overwrite the existing files when changes are detected after the initial generation.
You can also use the --keep
and --overwrite
options in the watch mode. They will only affect the initial generation.
Getting help with the Generator CLI
To get a quick overview of the generator, its arguments and options, run:
tgpu-gen --help
You can also use the -h
shorthand for the --help
option.