Skip to main content

ShaderModule

ShaderModule is the reusable shader feature descriptor used by @luma.gl/shaders. A module may contribute WGSL and/or GLSL source, shader-facing uniform descriptors, resource bindings, dependencies, and defines.

ShaderModules are used by ShaderAssembler and engine classes such as Model and Computation. The assembler resolves dependencies, prepends module source, and returns assembled source plus a combined uniform getter.

For the composition model, see Shader Assembly.

Usageโ€‹

Attach modules through an engine class:

import {Model} from '@luma.gl/engine';

const model = new Model(device, {
source: wgslSource,
vs: glslVertexSource,
fs: glslFragmentSource,
modules: [color]
});

Or pass modules directly to ShaderAssembler.

To define a new shader module, create a descriptor that brings together the source, uniforms, and dependencies that belong to one reusable shader feature:

import type {ShaderModule} from '@luma.gl/shaders';

type MyShaderModuleProps = {
intensity: number;
};

export const myShaderModule = {
name: 'my-shader-module',
source: '...',
vs: '...',
fs: '...',
uniformTypes: {
intensity: 'f32'
},
dependencies: [],
getUniforms: props => ({intensity: props.intensity})
} as const satisfies ShaderModule<MyShaderModuleProps>;

Use source for WGSL, vs and fs for GLSL stage source, or all three when the module supports both backends. uniformTypes declares shader-facing layouts; getUniforms maps application props to the uniforms and bindings consumed by the shader; dependencies brings in other modules first.

Fieldsโ€‹

props, uniforms, bindingsโ€‹

  • props?, uniforms?, bindings? - Type-inference fields. They are not currently used as runtime values.

nameโ€‹

  • name (string) - The name of the shader module.

sourceโ€‹

  • source? (string) - WGSL code contributed by the module.

vsโ€‹

  • vs? (string) - GLSL vertex shader code contributed by the module.

fsโ€‹

  • fs? (string) - GLSL fragment shader code contributed by the module.

uniformTypes (Object) - Uniform shader typesโ€‹

The uniformTypes map describes the shader-facing uniform layout for the module. Primitive uniform leaves use string shader types such as 'f32', 'vec3<f32>', and 'mat4x4<f32>'.

From v9.3

luma.gl also supports composite uniform descriptors:

  • structs use object literals
  • fixed-size arrays use [elementType, length]

See Core Shader Types for the descriptor syntax, TypeScript inference, array handling, and how nested values flow through ShaderInputs and uniform-buffer packing.

propTypes (Object) - Uniform JS prop typesโ€‹

defaultUniforms (Object) - Default uniform valuesโ€‹

getUniforms (function) - Function that maps props to uniforms and bindingsโ€‹

When getUniforms is not provided, shaders validates props using propTypes and returns the matching values.

bindingLayout (Array) - Logical bind-group assignment for bindingsโ€‹

Each entry has name and group. For current bind-group guidance, see Bind Groups and Bindings.

firstBindingSlot (Number) - Preferred WGSL auto-binding start slotโ€‹

This affects module-owned WGSL @binding(auto) relocation.

defines (Object) - Constant defines to be injected into shaderโ€‹

implements (string, optional)โ€‹

Declares an exclusive named shader interface, for example {name: 'project32', implements: 'projection'} or {name: 'project64', implements: 'projection'}. The interface name describes a shared shader contract; it does not verify function signatures or uniform layouts.

Only one distinct module may implement a given interface in an assembly. The assembler checks the complete dependency graph, including default modules and transitive dependencies, and rejects conflicting providers in either input order. Repeated references to the same module object are allowed and deduplicated. Modules without implements keep their existing behavior.

Choose a provider explicitly by including only that implementation. There is no last-module-wins precedence or automatic dependency substitution: dependencies still requires concrete module objects. If a required dependency implements the same interface as another selected module, assembly fails rather than dropping the dependency or leaving its dependent incomplete. Remove a conflicting default module before adding an alternative provider.

This proof of concept supports one interface name per module. Interface-based requirements and provider substitution are future design work.

dependencies (Array) - Shader modules that this module depends onโ€‹

Dependencies are resolved before the module source is assembled.

deprecations (Array) - Deprecated APIs detected during assemblyโ€‹

If deprecations is supplied, assembleShaders will scan shader source code for the deprecated constructs and issue a console warning if found. Each API is described in the following format:

  • type: uniform <type> or function
  • old: name of the deprecated uniform/function
  • new: name of the new uniform/function
  • deprecated: whether the old API is still supported.

instance (Object) - Runtime initialization stateโ€‹

Generated by initializeShaderModule() or shader assembly. Application module descriptors should normally leave this unset.

Statically defining Uniformsโ€‹

If the uniforms of this module can be directly pulled from user props, they may be declaratively defined by a defaultUniforms object:

{
name: 'my-shader-module',
defaultUniforms: {center: [0.5, 0.5], strength: 0.9},
uniformTypes: {center: 'vec2<f32>', strength: 'f32'}
}

At runtime, this map will be used to generate the uniforms needed by the shaders. If either strength or center is present in the user's module props, then the user's value will be used; otherwise, the default value in the original definition will be used.

Dynamically defining Uniformsโ€‹

The shader module may want to perform more complex logic when mapping the user's module props to uniforms. This can be achieved using getUniforms():

{
name: 'my-shader-module',
uniformTypes: {center: 'vec2<f32>', strength: 'f32'},
getUniforms: ({intensity}) => {
return {
strength: Math.sqrt(intensity),
center: intensity > 0 ? [0.5, 0.5] : [0, 0]
};
}
}

Adding Injectionsโ€‹

Use a named ShaderPlugin for target or anchor injections. A plugin can attach this module through its module field and select GLSL or WGSL source for each injection.

Functionsโ€‹

initializeShaderModule()โ€‹

initializeShaderModule(module: ShaderModule): void

Initializes one module's dependencies, parsed deprecations, prop validators, and default uniforms. Assembly calls this as needed.

initializeShaderModules()โ€‹

initializeShaderModules(modules: ShaderModule[]): void

Initializes each module in an array.

getShaderModuleUniforms()โ€‹

getShaderModuleUniforms(
module: ShaderModule,
props?: Record<string, unknown>,
oldUniforms?: Record<string, ShaderModuleUniformValue>
): Record<string, Binding | ShaderModuleUniformValue>

Returns the uniforms and bindings produced for one module update. When the module has getUniforms and props are supplied, shaders calls getUniforms(props, oldUniforms || defaultUniforms). Otherwise it validates and returns matching props through propTypes.

getShaderModuleDependencies()โ€‹

getShaderModuleDependencies(modules: ShaderModule[]): ShaderModule[]

Returns modules and transitive dependencies sorted so dependencies are assembled before modules that use them.

checkShaderModuleDeprecations()โ€‹

checkShaderModuleDeprecations(
shaderModule: ShaderModule,
shaderSource: string,
log: any
): void

Checks shader source against the module's deprecation definitions and logs matching warnings or removals.

sourceLanguage and source-language modulesโ€‹

When sourceLanguage names an application-registered transpiler, source contains reusable code in that language. The assembler combines it with modules' dependencies and the application translation unit before compilation. Set the same sourceLanguage on the application shader. Native shader code and injections continue to use the target GLSL/WGSL language. See application-owned transpilers.