Angle noise (±12° from wander) caused the ahead-cell pickup check to sample into the sand cell directly below the ant. Ants were grabbing sand on their first frame of existence. Fix: skip powder pickup when the ahead cell equals the cell directly below (the walking surface). Food pickup is still allowed from any adjacent cell. Diagonal dig pickup still works since the DIG priority angles ants at ~40° which targets a diagonal neighbor, not directly below. |
||
|---|---|---|
| docs | ||
| public/textures | ||
| src | ||
| .gitattributes | ||
| .gitignore | ||
| biome.json | ||
| bun.lock | ||
| CLAUDE.md | ||
| index.html | ||
| justfile | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
ants-simulation
GPU-accelerated ant colony simulation built with three.js and GLSL shaders. All simulation logic runs entirely on the GPU — no JavaScript-side physics loop.
How it works
Ants emit two types of pheromones: to-home (left by ants searching for food) and to-food (left by ants carrying food). Ants searching for food follow to-food trails; ants carrying food follow to-home trails.
Each ant carries a limited pheromone inventory. Picking up food or reaching home refills the inventory; each pheromone deposit drains it. This prevents ants that wandered too far from leaving misleading trails — their pheromone runs out, so their trails naturally fade.
Pheromone trails diffuse across neighboring cells and decay over time. The simulation also supports a repellent pheromone channel (independent decay rate and diffusion radius) for future use.
Controls
- Q — paint home
- W — paint food
- E — paint obstacles
- R — erase
- Mouse wheel — zoom
- Click + drag — pan
Architecture
The simulation runs as a chain of GPU render passes using ping-pong render targets:
- Pheromone blur/decay — diffuse and evaporate all pheromone channels
- Ant compute — update each ant's position, direction, and carrying state (MRT: writes primary + extended state simultaneously)
- Discretize — map continuous ant positions onto the world grid
- World update — merge ant deposits into the pheromone grid
- Colony stats — CPU readback of aggregate colony state (forager ratio)
- Draw — user painting input
- Screen — final composited output
Per-ant state (2 textures via MRT)
| Texture | R | G | B | A |
|---|---|---|---|---|
| Primary | pos.x | pos.y | angle | packed(storage, isCarrying) |
| Extended | personality | cargoQuality | pathIntDx | pathIntDy |
World state (RGBA Float32)
| Channel | Data |
|---|---|
| R | packed cell metadata (food/home/obstacle flags + terrain type + food quality) |
| G | to-home pheromone |
| B | to-food pheromone |
| A | repellent pheromone |
Development
Requires bun.
bun install
bun run dev # start dev server
just check # lint + typecheck + test
References
License
MIT
