Documents the budget pool activation model, priority-stack brain, ant physics (gravity/collision/surface), unified brush spawning, new config keys (antsStartCount, antBudget, seedWorld), stats overlay active/budget format, worldInit test, and screenWorld.frag color variation.
7.3 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). side-view ant farm with sand/powder physics and material-based world. ants use a fixed budget pool with probabilistic activation; behavior is driven by a priority-stack brain (fall → deposit → navigate → forage → dig → wander).
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)
SandPhysicsScene— Margolus block CA for sand/powder physicsWorldBlurScene— diffuse + decay pheromones (3 channels: toHome, toFood, repellent, blocked by solid cells)- clear
antsPresenceRenderTarget(ant-ant spatial queries, stub) AntsComputeScene— per-ant state via MRT (writes 2 textures simultaneously); gravity pass runs first (ants fall through air), then priority-stack brain for active ants; handles collision displacement out of solid cellsAntsDiscretizeScene— 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, active/budget counts), feeds back as uniformsDrawScene— user painting with material palette; brush tool also spawns ants (key: A,BRUSH_ANTS = 999sentinel,uAntSpawnuniform)ScreenScene— final composited output with side/top camera views (V to toggle); passes ant spawn position to AntsComputeScene
GPU textures
ant state — 2 RGBA Float32 textures per ping-pong target (MRT, count: 2). texture size is Math.ceil(Math.sqrt(antBudget)) — a fixed pool. only antsStartCount ants activate on init; dormant slots sit at pos=(0,0). new ants can be activated via the brush tool (probabilistic activation per frame when spawn is requested):
- texture 0:
[pos.x, pos.y, angle, packed(storage << 1 | isCarrying)] - texture 1:
[personality, cargoMaterialId, pathIntDx, pathIntDy]
world state — RGBA Float32 (worldSize x worldSize):
- R: material ID (0-255), maps to MaterialRegistry entry
- 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.
material system
src/materials/ defines a data-driven material registry. adding a new material requires only a registry entry — no shader changes needed.
MaterialRegistry— 6 built-in materials (ids 0-5): air, sand, dirt, rock, food, home- behavior types:
BEHAVIOR_POWDER(0),BEHAVIOR_LIQUID(1),BEHAVIOR_GAS(2),BEHAVIOR_SOLID(3) - each material has: id, name, behavior, density, hardness, angleOfRepose, color
- lookup textures (256x1 Float RGBA) uploaded as uniforms to shaders:
- properties texture:
[behavior, density, hardness, angleOfRepose]per row - colors texture:
[r, g, b, a]per row
- properties texture:
- material IDs defined in
src/constants.ts(MAT_AIR through MAT_HOME)
sand physics
Margolus neighborhood cellular automata runs as the first render pass each frame.
- world is divided into 2x2 blocks; block offset alternates each frame between (0,0) and (1,1)
- within each block, cells with
BEHAVIOR_POWDERfall downward and slide diagonally, swapping with lighter materials - physics pass writes back to world ping-pong target before pheromone diffusion runs
src/sand/margolus.tscomputes the per-frame block offset (JS side, passed as uniform)
ant physics and brain
ants run a gravity pass before the priority stack each frame:
- gravity: ants in air cells fall downward. steering logic is skipped while falling (
!isFallingguard). - collision displacement: if an ant ends up inside a solid cell, it is pushed out.
- surface constraint: grounded ants follow surface contours.
the priority stack resolves behavior in order, first match wins:
- fall — handled before stack; sets
isFalling, skips steering - deposit — drop food at home tile, or deposit carried powder on surface
- navigate — pheromone-following when carrying food; upward bias when carrying powder
- forage — follow food scent when empty
- dig — bias toward diggable powder below surface (side-view only)
- wander — fallback random movement
key files
src/Renderer.ts— render target creation, pass orchestration, MRT setup, colony stats readbacksrc/Config.ts— simulation parameters (per-channel pheromone configs); ant keys:antsStartCount(default 4),antBudget(pool size, default 512),seedWorld(boolean)src/constants.ts— material IDs (single source of truth for TS + GLSL);BRUSH_ANTS = 999sentinel for ant-spawn brushsrc/ColonyStats.ts— CPU readback of ant texture for colony-level aggregate stats (reports active/budget)src/StatsOverlay.ts— on-screen stats display (cursor position, TPS, colony info); ant count shown as "active / budget"src/__tests__/worldInit.test.ts— tests for world seeding (home/food placement via mulberry32 PRNG)src/materials/types.ts— Material interface and BehaviorType constantssrc/materials/registry.ts— MaterialRegistry with 6 built-in materialssrc/materials/lookupTexture.ts— builds GPU lookup textures from registrysrc/sand/margolus.ts— Margolus block offset calculationsrc/scenes/SandPhysicsScene.ts— sand physics render passsrc/shaders/antsCompute.frag— ant behavior + MRT output (2 render targets via layout qualifiers); gravity, priority stack, spawn activationsrc/shaders/worldBlur.frag— per-channel pheromone diffusion/decay (solid cells block diffusion)src/shaders/world.frag— material ID preservation + pheromone mergingsrc/shaders/sandPhysics.frag— Margolus block CA for powder/sand movementsrc/shaders/screenWorld.frag— final composite; applies per-pixel hash noise (+/-4% brightness) to material colors
planning docs
REALISM-IDEAS.md— research-backed features for more realistic ant behaviorINFRASTRUCTURE.md— data structure analysis mapping features to GPU infrastructure layersdocs/plans/2026-03-11-ant-farm-sand-physics-design.md— sand physics designdocs/plans/2026-03-11-ant-farm-implementation.md— ant farm implementation plan
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.