Drawing four hundred people

The valley is a handful of instanced meshes, three for people and five for houses by tier and one for trees, with frustum culling off, world-sized bounding spheres set once, and clicks landing on invisible fat capsules.

Three gotchas, each found by a screenshot

  • Frustum culling must be off. An InstancedMesh keeps its base geometry's tiny bounding sphere at the origin, so once the river leaves the view three.js culls the entire mesh and everybody loses their bodies.
  • Set a world-sized boundingSphere once. Otherwise the mesh computes its sphere from wherever the instances happened to be on the first raycast and never again, and clicks miss after people move with nothing to show for it.
  • Pick with fat invisible capsules. Raycasting thin bodies and heads means a click that misses by two pixels selects nothing, in a scene where everything is moving.

Nothing is fetched

No models, no textures, no fonts on the critical path. Geometry is primitives and everything else is computed, which keeps the Docker build hermetic and means the valley renders on a cold cache in one round trip.

A sun that is a function of the hour, windows that come on at dusk, fields that turn gold in autumn and white in snow, a mill wheel that turns, fires that flicker: all of it is arithmetic over the frame, not assets.

The crowd is jostled, not carried

Nobody walks the exact centreline. Each person keeps their own side of the lane, a stable offset from their id, at their own pace, and a separation pass nudges anyone standing closer than a shoulder's width. Doors gather a loose knot instead of a queue.

People who have stopped are leashed to where they stopped. Without the leash, a baker at a busy door was shoved two hundred units across the river over one day, could not path home, and starved beside a full larder. If somebody is ever a long way from their village, the leash is what broke.

Read next

More on the build