Appearance
@carrot/engine-renderer-shaders ​
ts
Shader compilation, caching, and uniform binding for the Carrot WebGL2 renderer.
Installation ​
bash
npm install @carrot/engine-renderer-shadersArchitecture / How It Works ​
This package bridges @carrot/engine-shaders (which defines shader source parsing) and @carrot/engine-renderer (which owns the GL context). It compiles ShaderSource objects into live WebGLProgram instances and provides a typed uniform API.
ShaderProgram ​
Wraps a linked vertex + fragment program. Constructed from a ShaderSource (which provides the GLSL text via renderVertex() / renderFragment()). Uniform locations are lazily cached on first access - subsequent calls skip the GL lookup.
The typed setters (setFloat, setVec3, setMat4, setColor, etc.) accept Carrot math types directly (Vector3Like, Matrix4x4Like, ColorRgbLike), handling the conversion to GL format internally. Matrix4x4 values are packed into column-major Float32Array for WebGL.
ShaderRegistry ​
The single source of truth for compiled programs. On construction, the registry auto-registers the four core shaders (core.sprite.default, core.unlit.color, core.unlit.textured, core.fullscreen.blit) from the coreShaders export - no manual setup required.
Additional shaders can be registered via:
registerXml(xml)- parse a.shaderXML string and register the result in one call.registerGlob(modules)- accepts aRecord<string, string>from Vite'simport.meta.glob(..., { as: 'raw', eager: true })and registers every shader file in one call. Ideal for loading a directory of.shaderfiles at startup.register(source)- compile a singleShaderSource(idempotent).registerAll(sources)- bulk register multiple sources.registerFile(file)- register from a parsedShaderFile.
Other capabilities:
- Prefix queries -
getByPrefix('core.unlit')returns all unlit variants. - Hot reload -
override()disposes the old program and compiles the replacement. - Signals -
onRegisteredfires when a new shader is compiled.
Built-in Shader Library ​
The src/library/ directory contains core shader files in Carrot's XML-based .shader format:
- core.sprite.default - sprite rendering with texture + tint
- core.fullscreen.blit - fullscreen blit using the vertex ID triangle trick (no VBO required)
- core.unlit.color - vertex-coloured geometry with a colour multiplier
- core.unlit.textured - textured geometry with vertex colours and a colour multiplier
All shaders target WebGL2 (#version 300 es) with mediump float precision. These are compiled from pre-baked ShaderSource objects in the coreShaders array, which is also exported for consumers that need the raw sources.
Dependencies ​
| Package | Role |
|---|---|
@carrot/engine-shaders | ShaderSource, ShaderFile types - parsed shader definitions |
@carrot/engine-renderer | Provides the WebGL2RenderingContext for compilation |
@carrot/maths-geometry | Vector2Like, Vector3Like, Vector4Like, Matrix4x4Like for typed uniform setters |
@carrot/colors | ColorRgbLike for colour uniform setter |
Build ​
bash
npm run build # tscOutput: dist/ (ESM + CJS, TypeScript declarations). Note: .shader files in src/library/ are not compiled by TypeScript - they are loaded at runtime by @carrot/engine-shaders.
Usage Guide ​
Shader compilation, caching, and typed uniform API for WebGL2 programs.
Import ​
ts
import { ShaderProgram, ShaderRegistry } from '@carrot/engine-renderer-shaders';Common Patterns ​
1. Create a shader registry ​
Core shaders (core.sprite.default, core.unlit.color, core.unlit.textured, core.fullscreen.blit) are auto-registered on construction - no manual setup needed.
ts
const registry = new ShaderRegistry(gl);
// 4 core shaders already available2. Register shaders from XML strings ​
ts
// Parse and register a .shader XML string in one call
registry.registerXml(myShaderXml);3. Register all shaders via Vite glob ​
ts
// Load every .shader file in a directory as raw strings
const modules = import.meta.glob('./shaders/*.shader', { as: 'raw', eager: true });
registry.registerGlob(modules);4. Register shaders from parsed files ​
ts
import { parseShaderFile } from '@carrot/engine-shaders';
// Register a single shader source
const shaderSource = parseShaderFile(shaderText).source;
const program = registry.register(shaderSource);
// Register from a parsed ShaderFile (convenience)
const file = parseShaderFile(shaderText);
registry.registerFile(file);
// Bulk register
registry.registerAll([source1, source2, source3]);5. Retrieve compiled programs ​
ts
// Get by exact key (throws if not found)
const sprite = registry.get('core.sprite.default');
// Try get (returns undefined if not found)
const maybeLit = registry.tryGet('custom.lit.standard');
// Check existence
if (registry.has('core.unlit.color')) { /* ... */ }
// Get all programs with a prefix
const unlitPrograms = registry.getByPrefix('core.unlit');6. Bind a shader and set uniforms ​
ts
const program = registry.get('core.sprite.default');
program.bind();
// Built-in uniforms (typically set by the render pipeline)
program.setMat4('u_ViewProjection', camera.viewProjection);
program.setMat4('u_Model', entity.transform);
program.setFloat('u_Time', totalTime);
// Material-specific uniforms
program.setColor('u_TintColor', { r: 1, g: 0.5, b: 0, a: 1 });
program.setTexture('u_MainTexture', 0); // texture unit 0
program.setVec3('u_LightDir', { x: 0, y: 1, z: 0 });
program.setFloat('u_Roughness', 0.5);
program.setBool('u_UseFog', true);7. Set matrix and vector uniforms ​
ts
// Matrix from Matrix4x4Like (auto-converts to column-major Float32Array)
program.setMat4('u_Model', modelMatrix);
// Raw Float32Array (already column-major)
program.setMat4Array('u_Bones', boneMatricesFloat32);
// Vectors from Like types
program.setVec2('u_Tiling', { x: 2, y: 2 });
program.setVec3('u_CameraPos', camera.position);
program.setVec4('u_ClipPlane', { x: 0, y: 1, z: 0, w: 0 });8. Check uniform existence ​
ts
if (program.hasUniform('u_NormalMap')) {
program.setTexture('u_NormalMap', 1);
}9. Hot-reload shaders at runtime ​
ts
// Override replaces an existing shader - old program is disposed
const updated = registry.override(updatedShaderSource);10. Listen for shader registration ​
ts
registry.onRegistered.listen(({ key, program }) => {
console.log(`Shader compiled: ${key}`);
});11. Cleanup ​
ts
// Dispose a single program
program.dispose();
// Dispose all registered programs
registry.disposeAll();