Current Architecture Snapshot
The prototype is organized around a lightweight game loop, a compact ECS layer, and a rendering pipeline that feeds GLSL shaders through a centralized shader library. The engine intentionally keeps subsystems small and composable so each system can evolve independently.
- Engine Core: schedules a consistent update loop that feeds delta time into every system. Neccessary for consistent behaviour across varying frame rates.
- ECS World: manages entity IDs, component storage, and ordered system updates.
- Render Stack: bridges ECS data with Three.js meshes and WebGL2 shader materials.
- Shader Workflow: loads named shader pairs and caches them for reuse.
Engine Loop & System Scheduling
The engine core owns a single animation loop. All systems are
registered once and receive a dt value every frame to
keep motion and animation deterministic.
const engine = new Engine();
engine.addSystem(RotationSystem);
engine.addSystem(TransformSystem);
engine.addSystem(ShaderSystem);
engine.addSystem(RenderSystem(renderer, scene, camera));
engine.start();
Entity Component System Foundation
Entities are given simple numeric IDs, while components are stored in maps by name. This keeps lookups fast and lets the systems focus solely on behavior.
const entity = engine.world.createEntity();
engine.world.addComponent(entity, "Transform", Transform());
engine.world.addComponent(
entity,
"Rotation",
Rotation(new THREE.Vector3(0.5, 1.0, 0))
);
engine.world.addComponent(entity, "Mesh", Mesh(cube));
engine.world.addComponent(entity, "Shader", Shader(material));
The ECS systems currently include a rotation updater, transform syncer, shader time uniform updater, and a render dispatcher.
Rendering Pipeline & Scene Integration
Rendering is driven by a WebGL2-backed Three.js renderer. Geometry is constructed using standard Three.js methods, then attached to ECS entities so the engine can update transforms before each frame.
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
material
);
scene.add(cube);
const entity = engine.world.createEntity();
engine.world.addComponent(entity, "Transform", Transform());
engine.world.addComponent(
entity,
"Rotation",
Rotation(new THREE.Vector3(0.5, 1.0, 0)),
);
engine.world.addComponent(entity, "Mesh", Mesh(cube));
engine.world.addComponent(entity, "Shader", Shader(material));
Shader Library & Material Factory
Shader files are referenced by name rather than by path, making it
easy to swap or expand shader sets without changing game code. A
small material factory creates RawShaderMaterial
instances with consistent defaults.
const material = await MaterialFactory.raw("prototype3d", {
uniforms: {
uTime: { value: 0 },
uResolution: {
value: new THREE.Vector2(canvas.clientWidth, canvas.clientHeight),
},
},
});
The shader library caches loaded shader text, so repeated materials reuse the same shader strings without additional network requests.
Prototype Capabilities
- Realtime rotating geometry driven by ECS systems.
- Shader uniforms for time and resolution updates.
- Responsive resizing that keeps camera aspect accurate.
- WebGL2-only pipeline to support GLSL 300 ES shaders.
Next Development Targets
The next target is to expand the engine's ability to handle custom models through obj support, and to build out additional ECS systems for input handling.
- Input and camera control systems.
- Asset loading utilities for models and textures.