Motion GPU’s material preprocessor supports #include directives for reusable shader code and defines for compile-time constants. Both are expanded before WGSL compilation and tracked with source-line maps for accurate error diagnostics.
Include system
Declaring includes
Includes are named WGSL source chunks declared in the material definition:
Directive syntax
The directive must appear on its own line:
Where name is an identifier matching a key in the includes map. The identifier must follow WGSL naming rules: [A-Za-z_][A-Za-z0-9_]*.
Recursive includes
Includes can themselves contain #include directives, enabling modular shader libraries:
Validation rules
Include expansion order
- The fragment source is scanned line by line.
- Each
#include <name>line is replaced with the full source of that include chunk. - The process is recursive — included chunks can contain their own
#includedirectives. - A line map is built during expansion, tracking which generated line came from which source (fragment line N, include “X” line M, etc.).
This line map is used for diagnostics — when WGSL compilation fails, the error message points back to the original source location (see Error Handling).
Define system
Declaring defines
Defines are compile-time constants injected as top-level WGSL const declarations:
Value forms and emitted WGSL
Validation rules for defines
Expansion order
Defines are sorted alphabetically by key and prepended before the expanded fragment source. This means:
- All
constdeclarations from defines appear first. - An empty separator line follows.
- The expanded fragment (with includes resolved) comes next.
This is deterministic and part of the material signature, meaning changing a define value always triggers a renderer rebuild (unlike uniforms, which only update a buffer).
Defines vs. uniforms: when to use which
Key difference: Defines are baked into the shader source at material definition time. Changing a define requires creating a new material and triggers a full pipeline rebuild. Uniforms are updated per-frame via buffer writes with no recompilation cost.
Source-map diagnostics
When a WGSL compilation error occurs, Motion GPU uses the line map to report the original source location:
- Fragment line errors → reported as
fragment line X - Include errors → reported as
include <name> line X - Define errors → reported as
define "NAME" line X
This means you see meaningful error locations even when your fragment expands to hundreds of generated WGSL lines. See Error Handling and Diagnostics for the full error report structure.
Practical tips
- Keep includes general-purpose — utility functions (noise, SDF helpers, color space conversions) are ideal candidates.
- Name includes clearly — the key is used in error messages and diagnostics.
- Use defines for branch elimination — the WGSL compiler can optimize away dead branches when a bool constant is
false. - Use typed defines for integer loops —
{ type: 'i32', value: N }avoids the defaultf32inference. - Avoid putting
fn frag(...)inside includes — the entrypoint should stay in the main fragment for clarity.