With wgsl-rs you write a subset of Rust code and it automatically generates WGSL shaders and wgpu runtime linkage.
Rust code written this way is fully operational (it can be run on the CPU) while the transpiled WGSL is isomorphic and
should generate the same results on the GPU.
In short, with wgsl-rs, you can unit test and run your code on the CPU in Rust, and use the generated WGSL on the GPU,
while sharing the same type definitions between the two.
Procedural macros are provided by the wgsl-rs-macros crate.
This project is funded through NGI Zero Commons, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program. Learn more at the 2025 NLnet project page.
This work will always be free and open source. If you use it (outright or for inspiration), please consider donating.
There is a project plan for getting to beta here
Yes! See the example, which transpiles the shader from Tour of WGSL.
wgsl-rs validates WGSL using naga.
The #[wgsl] macro auto-generates #[test] fn __validate_wgsl() for every
non-template module — running cargo test will surface any validation failures.
| Module Type | Auto-generated validation test? |
|---|---|
| Non-template module (with or without imports) | Yes — __validate_wgsl |
| Template module (with type parameters) | No — instantiate first, then validate |
#[wgsl(skip_validation)] |
No |
All non-template modules get an auto-generated validation test because their
full WGSL source (including any imports) is assembled at runtime.
Template modules contain unresolved placeholders and must be instantiated before
they produce valid WGSL; use validate_with_instantiation_types(T1, T2, ...)
to specify concrete types for validation.
// Non-template module - auto-validated at test time.
#[wgsl]
pub mod constants {
pub const PI: f32 = 3.14159;
}
// Module with imports - also auto-validated at test time.
#[wgsl]
pub mod shader {
use super::constants::*;
pub fn circle_area(r: f32) -> f32 {
PI * r * r
}
}
// Skip all validation
#[wgsl(skip_validation)]
pub mod experimental {
// ...
}You can also validate modules at runtime using Module::validate():
use wgsl_rs::wgsl;
#[wgsl]
pub mod my_shader {
// ...
}
fn main() {
// Validate manually (requires "validation" feature)
my_shader::WGSL_MODULE.validate().expect("WGSL validation failed");
}To disable validation entirely, disable the validation feature:
[dependencies]
wgsl-rs = { version = "...", default-features = false }When the validation feature is disabled, Module::validate() and
validate_wgsl_source() are unavailable, and the #[wgsl] macro does not
generate auto-validation tests.
Maybe — it depends on your needs.
- Lower barrier to entry: No custom Rust compiler backend required.
- Works with stable Rust: No need for nightly or custom toolchains.
- Editor support: The
#[wgsl]macro makes supported syntax explicit, so your editor (via rust-analyzer) can help you write valid code. - Immediate WGSL output: Use, inspect, and debug the generated WGSL anywhere WGSL is supported, including browsers and non-Rust projects.
- Human readable WGSL output: The WGSL that
wgsl-rsproduces is very close in structure to the Rust code you write, including binding names and types. - Easy interop: Generated WGSL can be used in any WebGPU environment.
- WGSL only: Only works on platforms that support WGSL.
- Limited to WebGPU features: No support for features not present in WGSL (e.g., bindless resources).
- Subset of Rust: Only a strict subset of Rust is supported.
- No traits
- No borrowing
- Very restricted module support
Note: wgsl-rs and Rust-GPU are not mutually exclusive! You can start with wgsl-rs and switch to Rust-GPU when you need more advanced features. I'm working on making them co-habitable.
The project is split into a few parts:
wgsl-rs-macrosProvides thewgslprocedural macro for writing WGSL modules in Rust. Handles parsing and code generation for the supported Rust subset.wgsl-rsProvides theModuletype,wgsl::std, and exports thewgslmacro.
There's also a devlog that explains some of the decisions and tradeoffs made during the making of this library.
Contributions, feedback, and questions are welcome!
