Public: anyone can read this; the crew can change it.
mobs. make the world come alive #6
Check · Review · Land · Live done — Landed and live in production.
Pushed, tests green (63 pass), app boots and both pages answer in milliseconds.
shipped production is serving it deploy c454002
game is broken and won't load
game is broken
You were right, and the cause was mine: Herd.tick lifted ready off the chunk field and called it detached, so this.blocks was undefined and the frame threw — every frame, starting with the first one where you were standing on a loaded chunk. The loop re-queued itself each time but nothing past the throw ever ran, so the page sat on "carving …" with no rendering and no error visible. It is called through the ground now (this.ground.ready?.(…)), and there is a test with a field whose ready needs its own this that fails without the fix.
I reproduced it before changing anything, by running the real built bundle against a stub canvas and feeding it generated chunks the way the worker does; that reproduction now runs 400 frames with the herd spawning, walking, packing and drawing without throwing. The 64 tests pass and the game page answers in 9 ms.
Two changes so this class of failure cannot be silent again: a frame that throws puts the message on the page and stops the loop instead of throwing forever, and a boot that rejects (a shader that will not compile, say) does the same rather than leaving the loading text up. I could not verify the new mob shader against a real GPU here — there is no WebGL in this sandbox — so if anything is still wrong in the preview, the page will now name it rather than hang, and that message is the thing to send me.
🤖 Generated with Claude Code
Pushed, tests green (63 pass), app boots and both pages answer in milliseconds.
The world now has animals in it.
src/world/mobs.tsis the table of kinds — sheep, pigs, chickens, fish and fireflies — each one a list of boxes with a pivot and a swing, a gait, and a habitat that decides whether it walks, swims or hovers.src/world/herd.tsis what a world is holding right now: a chunk hashes its own creatures out of the seed when it arrives and forgets them when it goes, so nothing new is stored and a world is still a seed plus a list of changed blocks.src/client/mobmesh.tspacks the whole herd into one buffer (20 bytes a vertex) drawn in one call between the solid and the water passes, so stone hides an animal and water tints one. They wander, graze, turn back at cliffs and water, hop a one-block step, keep near where they were born, and bolt when you walk into one or swing near one — a swing shoos rather than hurts, and the block behind still breaks.src/world/physics.tsnow takes aGait, so a sheep is a body the same way the player is. That turned up a real bug in the existing code: the jump impulse never clearedonGround, so a held jump key reapplied it every slice — holding space flew you upward at 8.6 m/s (25 blocks in three seconds, verified before the fix). Jumping is now one impulse per push-off; the existing player tests were unaffected.The terminal got the same world: the map holds the herd of the chunks it is showing, steps it by real seconds and redraws a few times a second, so creatures walk across it while you watch; it keeps the browser's twenty-minute clock, so fireflies come out there too, and the line under the map says what is about. Drawing now homes the cursor and clears per line instead of wiping the screen, which keeps that from flickering.
What I did not do: no combat, no breeding, no feeding or taming, and no multiplayer — two people in one world still see different animals, the same way they do not see each other. Creatures are not persisted and do not survive the chunk they stand in going out of range. In the preview, walk a grassy world at dusk to catch the fireflies, look for a school in deep water, and try
sshto watch the same map move;bun testcovers spawn determinism, footing, the cliff turn, the leash, fleeing, posing, the herd cap, and a 40-creature frame budget (0.5 ms stepped and packed on this machine).🤖 Generated with Claude Code
Closes #5