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
InstancedMeshkeeps 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
boundingSphereonce. 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
The 3D layer never feeds back
The browser receives zones and activities and decides everything about bodies: where they walk, which way they face, what gesture they make. Nothing in the rendering layer may write back to the simulation except a click to select.
A closed medieval economy, in real time
Two villages of about 220 people each run a complete production chain, field to mill to bakehouse and pasture to butcher, with floating market prices, daily wages, household purses, tax, tithe, and a winter every twelve days.
Server-sent events for a live simulation
Simulation frames go out over server-sent events, which are one-way, plain HTTP and reconnecting for free, because nothing a watcher does needs a socket and the little that does is an ordinary POST.
Land, building, and a house that grows
The village sells parcels along its lanes, and the ones nearer the green cost more. A family that buys one marks out a site the yard raises, walls first and roof at thirty timber and five stone, from hovel to house to second storey to manor.