Rust-to-WGSL transpiler using proc macros.
Workspace with wgsl-rs, wgsl-rs-ir, wgsl-rs-macros, example, and xtask crates.
The proc-macro converts a parsed Rust module to an owned IR (defined in
wgsl-rs-ir), then emits a WGSL_MODULE static carrying a constructor
that builds that IR at runtime. The runtime crate (wgsl-rs) renders the
IR to WGSL on demand and supports IR-level type substitution for generic
shader instantiation.
Historical data, insights, affirmations, etc.
A key insight is that wgsl-rs maintains two parallel representations:
- Rust World: The code must compile as valid Rust (design decision #1 in DEVLOG.md) that runs on the CPU.
- WGSL World: The proc-macro transpiles to WGSL that runs on the GPU.
These are fundamentally different execution contexts with different memory models, and yet running a wgsl-rs
program should produce roughly the same results in both "worlds".
Program setup (or preamble, if you will) and the runtime behavior is expected to be different for each world, but the results should match, within reason.
cargo build # Build all crates
cargo test # Run all tests
cargo test -p wgsl-rs-macros # Test specific crate (wgsl-rs-macros in this case)
cargo test -- test_name # Run a single test by name
cargo fmt && cargo clippy # Format and lint
cargo run -p example # Run the example, showing help text about subcommands
cargo run -p example -- show # Show the names of available example modules
cargo run -p example -- source {name} # Validate and print a single example module's WGSL source
cargo expand -p example -- examples::{name} # Expand the example which uses the `wgsl` macro, showing the generated WGSL_MODULEAlways remember to run cargo fmt after making changes.
This repo contains a cargo xtask that provides agents with some
shorthand commands for common development tasks.
cargo xtask wgsl-spec provides access to the WGSL specification without
overwhelming an agent's context window.
cargo xtask wgsl-spec toc # List WGSL spec table of contents
cargo xtask wgsl-spec section <anchor> # Fetch a spec section with subsections
cargo xtask wgsl-spec section --shallow <anchor> # Fetch section without subsections
cargo xtask wgsl-spec section <anchor> <sub> # Fetch a specific subsection- Imports: Standard lib and external crates first, then
use crate::for internal modules - Errors: Use
snafuwith span info for IDE integration (SomethingWrongSnafu { span, note }.fail()?) - Naming: PascalCase types, snake_case functions/modules, SCREAMING_SNAKE_CASE constants
- Patterns:
TryFromfor AST conversions, traits per WGSL builtin, macros for repetitive impls, and useunreachable!when encountering an invariant that is impossible. Similarly use.expect("{reason}")where appropriate. - Spans: Preserve
proc_macro2::Spanon all parsed types for error mapping back to Rust source - Comments: Prefer to split distinct concerns into separate modules with module-level
documentation rather than reaching for
// ===== Section =====headers in a single file. That said,// =====headers are acceptable inside long files (e.g.monomorphize.rs,parse.rs) where splitting into sub-modules would itself be a larger refactor than the organizational benefit warrants. Please document all functions. If parameters are self-explanatory, don't bother writing parameter docs.
The DEVLOG is a set of long-lived development notes. It is a very informal change-log that also contains thoughts about this library's purpose, requirements, and challenges.
Each day of work has an entry with the heading "### YYYY-MM-DD: {description}". If your session is the first of the day, create a new day entry, otherwise append the high-level description of your session to the current day's entry.
An ephemeral session file is maintained at SESSION.md, which you can use as scratch space for your editing session. This file is not checked into git and should be used to persist context between editing sessions. Think of this file as a mini DEVLOG.md, and when the session has ended and goals have been accomplished, update the DEVLOG with a brief, one line summary of the session, then remove the SESSION.md file.