Project-owned shaders
When the authored material types aren’t enough, import Three.js and create a
THREE.ShaderMaterial directly in project source. Shader code, uniforms, update rules, and
cleanup are game-specific behavior; keeping them together makes their owner and lifecycle
explicit.
Use the Three.js API directly
Section titled “Use the Three.js API directly”The setup function can create the mesh and register its update in a normal engine phase:
import type { GameCleanup, GameContext } from '@engine/runtime/types';import * as THREE from 'three';
export async function setup(ctx: GameContext): Promise<GameCleanup> { const uniforms = { uTime: { value: 0 } }; const material = new THREE.ShaderMaterial({ uniforms, vertexShader: ` uniform float uTime; void main() { vec3 p = position; p.z += sin(p.x * 0.8 + uTime) * 0.25; gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0); } `, fragmentShader: ` void main() { gl_FragColor = vec4(0.04, 0.37, 0.65, 1.0); } `, }); const geometry = new THREE.PlaneGeometry(12, 12, 48, 48); const water = new THREE.Mesh(geometry, material); water.rotation.x = -Math.PI / 2; ctx.scene.add(water);
const animate = (dt: number) => { uniforms.uTime.value += dt; }; ctx.systems.add('gameLogic', animate);
return { dispose() { ctx.systems.remove('gameLogic', animate); ctx.scene.remove(water); geometry.dispose(); material.dispose(); }, };}- The material is a normal Three.js object—there is no vgai shader wrapper or registry.
- Put animation in a phase-ordered system or a
GameComponentattached to the owning mesh. - Remove the update and dispose GPU resources in the cleanup returned by
setup().
For an editor-authored mesh, a project component is often the better ownership boundary: find
or replace its material in init(), update uniforms in update(dt), then restore/dispose in
dispose().
The WaterSurface example
Section titled “The WaterSurface example”Feature-scenes deliberately demonstrates the same ownership rule without a shader-specific
engine abstraction. Its scene uses an ordinary standard material, while the project-owned
WaterSurface component animates native BufferGeometry in Play mode. A shader component
would own a ShaderMaterial through the same lifecycle.
See also
Section titled “See also”- Materials — the built-in material types.
- What’s New / Roadmap — the inline-shader gap and other rendering plans.
- Entities & GameComponents — attach project behavior to an authored Object3D.