From Idea to Game
Every engine demo starts at the finish line. This one starts at line one.
Rich Game Scene
world • entities • rendering • post
A World From Nothing
Four lines. Your game exists.
const world = createWorld();
await world.initialize();
world.start();
World
loop:fixed-timestep (60 Hz)
render:demand-based
visibility:tab-aware pause
lifecycle:entity create / destroy
resources:lazy singletons
What you got for free vs. what you didn't ask for — the engine starts empty.
Defining Your Game's Language
Your components are your vocabulary.
const Position = defineComponent({
name: 'Position',
schema: { x: f32, y: f32, z: f32 },
});
Game Design
"damage with element types"
Component Definitions
Damage
{ amount, element }
The design doc and the code are the same thing.
Components as Memory Layout
Your game design just became your memory layout.
defineComponent(Position)
Type Definition
automatic
ArrayBuffer
x₀
y₀
z₀
x₁
y₁
z₁
x₂
y₂
z₂
...
CPU Memory — contiguous, tightly packed
zero-copy
GPU Buffer
x₀
y₀
z₀
x₁
y₁
z₁
x₂
y₂
z₂
...
GPU Memory — identical layout, no transform needed
Tags are zero-size markers — questions you ask about entities. No storage, just archetype membership.
Entities — Bringing Things to Life
An entity is a number. What makes it real is what you attach to it.
const player = world.entities.create();
world.batch((ctx) => {
ctx.addComponent(player, Position, { x: 0, y: 0, z: 0 });
ctx.addComponent(player, Health, { current: 100, max: 100 });
});
world.tags.add(player, Player);
Archetype Table
one archetype migration via batch
Spawning at Scale
Batch creation — 1,000 entities, one allocation.
const enemies = world.entities.createBatch(1000);
Contiguous Memory
Position[]
1000 entries, aligned
Health[]
1000 entries, aligned
Hierarchy
Player
Weapon
Particle
Particle
Particle
Systems — Making Things Happen
A system is a function that runs every frame. A query is what it cares about.
const MovementSystem = defineSystem({
name: 'movement',
queries: { movers: [Position, Velocity] },
fn: (ctx) => {
ctx.queries.movers.forEach((entity) => {
ctx.write(entity, Position, 'x',
ctx.read(entity, Position)!.x + vel.vx * ctx.dt);
});
},
});
Query
Archetype-matched iteration
No allocation per frame
ctx.write()
~5-10ns per field
Dirty tracking automatic
ctx.dt
Fixed timestep delta
Deterministic
ctx.write() — ~5-10ns per field. No allocation. Dirty tracking notes exactly which bytes changed.
Systems Compose
Dependency graph — systems declare ordering, the engine schedules.
60 Hz Fixed Timestep
input phase
InputPoller
query:[RawInput, DeviceMap]
InputActions
after: InputPoller
query:[RawInput, ActionMap]
PlayerControl
after: InputActions
query:[Player, ActionState]
update phase
Movement
after: PlayerControl
query:[Position, Velocity]
Combat
after: Movement
query:[Position, Damage, Health]
Register everything in the world with a single config object — components, systems, update rate.
Seeing Your World
One import. Your simulation becomes visible.
import { createGPU } from '@omni/gpu';
const gpu = await createGPU({ canvas });
const world = createWorld({ systems: [...], gpu });
ECS / CPU
Components
typed data columns
TypeDescriptors
same schema drives both sides
GPU Pipeline
V-Buffer
visibility rasterize
Lighting
deferred shading
loadGltf(url) → entities with Mesh, Material, Transform
One line loads a 3D scene. Camera is just another entity with a component.
Player Control
Input is data. Actions are queries. Movement is a system.
const bindings = {
[Action.MoveUp]: [{ keyboard: Key.W }],
[Action.Jump]: [{ keyboard: Key.Space }],
[Action.Attack]: [{ mouse: 0 }],
};
Keyboard
Mouse
Gamepad
Touch
InputActions
abstraction layer
ActionState
component on entity
Same code works for every device. No conditionals.
Lighting Your World
A light is a component. Shadows are a flag. The GPU handles the rest.
STAGE 2
Directional Light (sun)
Basic lit
STAGE 3
Point Lights
Multi-color
STAGE 4
Area Lights
Soft emitters
Clustered 3D Light Binning
2
0
5
3
1
0
1
8
6
4
2
0
0
7
3
5
2
1
each cell → light index list
Hundreds to thousands of lights. Per-pixel cost nearly constant.
CastShadow flag activates virtual shadow maps. ReSTIR for massive light counts.
Materials — Defining How Surfaces Look
PBR out of the box. Advanced materials when you need them.
Brushed
Steel
anisotropy 0.7
Not separate shaders. One material model. Pay only for layers you use.
Environment — Sky and Ambient Light
Your world needs a sky. The sky needs physics.
Atmosphere
Rayleigh:scattering
Mie:scattering
Ozone:absorption
Sun:direction vector
Image-Based Lighting
Irradiance Cubemap
diffuse
Prefiltered Cubemap
specular
BRDF LUT
split-sum lookup
Reflection Probes
local IBL overrides for interiors
Planar Reflections
mirrors / water surfaces
Physically-based atmosphere from dawn to dusk. Environment changes → lookup tables recompute automatically.
Volumetrics — Fog, Clouds, and Light Shafts
The space between things matters.
const scene = createScene(gpu, {
volumetricFog: true,
});
Volumetric Fog — Frustum Cross-Section
Froxel Grid (3D voxels)
·
•
·
•
·
·
·
·
•
·
·
•
·
•
·
·
·
•
• light source → in-scattering
· empty voxel
Volumetric Clouds
Ray March
Shape + Detail Noise
Beer-Lambert + Multi-Scatter
Temporal Reproject
Clouds cast shadows. Wind pushes them. Sunset tints them gold.
Post-Processing — The Cinematic Pass
Raw rendering is a photograph. Post-processing is cinematography.
Essential Stack
Auto-Exposure
Bloom
Tone Mapping
TAA
FXAA
Quality Stack
GTAO
SSR
Motion Blur
Depth of Field
Film Effects
optional upscaling
Temporal Upscaling
Render at 50–75%, reconstruct to native. AAA quality on integrated GPUs.
Each effect is independent — add or remove without touching the rest.
Animation — Movement Without the CPU
The GPU animates. The CPU dispatches.
const scene = createScene(gpu, {
animation: { maxSkeletons: 500 },
});
CPU
Dispatch
one call per frame
GPU
Animation Clips
Bone Hierarchy
Vertex Skinning
Morph Targets
Hundreds of animated characters. Load from glTF — it just works.
Decals and Sprites
Paint the world after the fact. Give 2D sprites 3D superpowers.
Decals
Surface Geometry
albedo, normals, roughness
Decal OBB
projected overlay
Modifies Surface Properties
albedo▶blend decal texture
normals▶reorient under decal
roughness▶per-texel override
Sprites
V-Buffer Pipeline (same as 3D)
2D Sprite
rendered as V-Buffer geometry
Inherited Features
lighting▶clustered lighting
shadows▶virtual shadows
AO▶ambient occlusion
bloom▶HDR bloom
DoF▶depth of field
motion▶motion blur
2D and 3D share a pipeline — not a special mode.
Events — Decoupled Communication
Decouple cause from effect.
const DamageDealt = defineEvent({
name: 'combat:damage-dealt',
schema: { target: u32, amount: f32, element: u8 },
pool: 64,
});
Combat System
emit(DamageDealt)
Particle System
spawnHitParticles
UI System
showDamageNumber
Audio System
playHitSound
Add a subscriber, combat never changes. Remove one, nothing breaks. Zero-allocation pooled events.
Scenes and Resources
Games aren't one scene. They're many. Not everything is an entity.
Scene Management
Overlays push onto a stack above the active scene
Resources
Created lazily. No globals. Clean dependency injection.
The Three Tiers of Performance
Start comfortable. Optimize when it matters. Go raw when you must.
Tier 1 — Prototyping
ctx.set(entity, Position, { x: newX, y: newY, z: newZ })
object-style, familiar
Tier 2 — Shipping
ctx.write(entity, Position, 'x', newX)
single-field, ~5-10ns
Tier 3 — Maximum Throughput
pos[base] += vel[base] * dt
raw TypedArrays, SIMD-ready
All three: zero allocation, same dirty tracking, freely mixable.
Debug Visualization
When something looks wrong, make the invisible visible.
Toggle at runtime. Zero cost when disabled. No recompile.
The Full Picture
Every system you added — they all compose.
createWorld
Components
Position
Velocity
Health
Damage
GPU
V-Buffer
Materials
Lighting
Shadows
Environment
Volumetrics
Post
Sprites
Scenes
MainMenu
GameLevel
PauseOverlay
Resources
SpatialIndex
GameConfig
RNG
The Progression
From blank file to AAA-capable game. Each row is additive. No row requires the rows below it.
Step
What You Added
What You Got
World
3 lines
Game loop, lifecycle, scheduling
Components
Schema definitions
Memory layout, GPU compat, dirty tracking
Entities
Create + batch
Lifecycle, hierarchy, pooling
Systems
Functions + queries
Game logic, ordering, phases
GPU
One import
V-Buffer pipeline, GPU-driven rendering
Lights
Components + flags
Clustered lighting, shadows, area lights
Materials
Create + configure
PBR + 6 advanced material models
Environment
Scene config
Atmosphere, IBL, probes
Volumetrics
Flags
Fog, clouds, light shafts
Post
Pipeline config
18 cinematic effects
Animation
loadGltf
GPU skeletal + morph targets
Skip what you don't need. Add what you do. Start building.