3.7 KiB
ants-simulation
GPU-accelerated ant colony simulation. ants navigate via pheromone trails, all computed in GLSL fragment shaders rendered to offscreen textures. uses WebGL2 features (MRT, GLSL3).
stack
- three.js (0.173) — WebGL2 renderer, render targets, MRT, shader materials
- lil-gui — runtime parameter tweaking
- vite — dev server and build
- biome — lint + format
- bun — runtime, test runner, package manager
- typescript
commands
just check— lint, typecheck, test (the gate for all work)bun run dev— start dev serverbun run build— production build tobuild/bun test— run tests
architecture
all simulation logic runs on the GPU via ping-pong render targets. no JS-side simulation loop — Renderer.ts orchestrates render passes and manages all WebGLRenderTargets.
render pipeline (per frame)
WorldBlurScene— diffuse + decay pheromones (3 channels: toHome, toFood, repellent, each with independent blur radius and decay rate)- clear
antsPresenceRenderTarget(ant-ant spatial queries, stub) AntsComputeScene— per-ant state via MRT (writes 2 textures simultaneously)AntsDiscretizeScene— maps continuous ant positions to discrete world grid cellsWorldComputeScene— merges ant deposits into world pheromone gridColonyStats— CPU readback of ant texture, computes aggregate stats (foragerRatio), feeds back as uniformsDrawScene— user painting (food, home, obstacles, erase)ScreenScene— final composited output with camera controls
GPU textures
ant state — 2 RGBA Float32 textures per ping-pong target (MRT, count: 2):
- texture 0:
[pos.x, pos.y, angle, packed(storage << 1 | isCarrying)] - texture 1:
[personality, cargoQuality, pathIntDx, pathIntDy]
world state — RGBA Float32 (worldSize x worldSize):
- R: packed cell metadata (bits 0-2: food/home/obstacle, bits 3-5: terrain type, bits 6-13: food quality)
- G: scentToHome
- B: scentToFood
- A: repellent pheromone
discrete ants — RGBA UnsignedByte (worldSize x worldSize):
- R: carrying ant scent deposit, G: non-carrying ant scent deposit, B: cell cleared flag, A: 1
ant presence — RGBA Float32 (worldSize x worldSize), cleared each frame. stub for future ant-ant spatial interaction.
bit layout (world.R)
defined in src/constants.ts, shared between TS and GLSL via defines:
- bits 0-2: cell flags (food, home, obstacle)
- bits 3-5: terrain type (0-7, reserved for substrate-dependent decay)
- bits 6-13: food quality (0-255, reserved for quality-dependent pheromone modulation)
key files
src/Renderer.ts— render target creation, pass orchestration, MRT setup, colony stats readbacksrc/Config.ts— simulation parameters (per-channel pheromone configs)src/constants.ts— cell metadata bit layout (single source of truth for TS + GLSL)src/ColonyStats.ts— CPU readback of ant texture for colony-level aggregate statssrc/shaders/antsCompute.frag— ant behavior + MRT output (2 render targets via layout qualifiers)src/shaders/worldBlur.frag— per-channel pheromone diffusion/decaysrc/shaders/world.frag— cell metadata bit preservation + pheromone merging
planning docs
REALISM-IDEAS.md— research-backed features for more realistic ant behaviorINFRASTRUCTURE.md— data structure analysis mapping features to GPU infrastructure layers
shader files
in src/shaders/. each scene has a matched .vert/.frag pair. loaded as raw strings by the vite glsl plugin in vite.config.ts. all shaders use GLSL3 (#version 300 es via three.js glslVersion: THREE.GLSL3).
textures
in public/textures/ — ant.png and food.png sprites.