Shader module (asset type)
A .shaderModule is a block of WGSL that other shaders include rather than copy — a lighting model, a set of colour-space helpers, one package's shared prelude. It declares no entry point and is never…
Folder shape
<name>.shaderModule/
module.wgsl # the WGSL — helpers, structs, constants (required)
README.md # what THIS module provides (required)
Each file carries a committed .meta sidecar pinning its stable guid, and the
folder carries one of its own.
Including one
A shader names a module by identity, and the identity is what records the dependency — so a shader that is packed, pulled or published carries the modules it includes with it:
#include "~.colour" // a module in the same package
#include "@builtin::shaderModules.pbr_shading" // one from the builtin library
A missing module is a hard error at compile: a shader that names an interface which no longer exists fails loudly rather than compiling against a stale copy. Each module is expanded at most once per shader, so two shaders that both include the same module — or a module that includes another — produce one copy, not a duplicate-definition error.
Writing one
Write only what other shaders need in scope: functions, structs, constants. A module may reference a binding its includers declare, which is how a package's prelude can read that package's uniform block.
const LUMA: vec3<f32> = vec3<f32>(0.2126, 0.7152, 0.0722);
fn srgb_to_linear(c: vec3<f32>) -> vec3<f32> {
let lo = c / 12.92;
let hi = pow(max(c + vec3<f32>(0.055), vec3<f32>(0.0)) / 1.055, vec3<f32>(2.4));
return select(hi, lo, c <= vec3<f32>(0.04045));
}
Answering to another name
A module declares extra names it answers to with @alias lines in the header of
module.wgsl:
// @alias: colour_helpers
// @alias: @mypack::shaderModules.colour
Each becomes an alias on the asset, so the name resolves everywhere an identity
does — asset.resolve, an #include, and the publish gate alike. That is what
lets a module be renamed without breaking the shaders already written against
its old name: content persists the source it was authored with, so a name that
stops resolving is a world that stops publishing.
Only the header is read — the scan stops at the first line that is not a comment, so a directive cannot hide in the module body. A name another asset already holds is refused and reported, since an alias extends the identity namespace rather than taking a name out of another asset's hands.
Registration & hot reload
Writing module.wgsl registers the module under every name the asset answers to
— its guid, its identity, and any alias — so a shader includes it by whichever
name it holds. Saving re-registers it and the shaders that include it recompile,
with no world reload.
Discovery
asset.list("shaderModule")— every registered module.moduleRef:getSource()— the module's WGSL.
Related types
.shader— render-domain shaders (surface, sky, post-process, screen)..computeShader— compute programs.