Personal
Island Generator
A procedural island built tile by tile with wave function collapse. No map is authored and no layout is stored: the entire input is a set of hand-modelled pieces and the rules about which may sit next to which.
Reading about an algorithm is not knowing it
I had read the wave function collapse write-ups and could have described the idea accurately at a whiteboard. Then I tried to implement it and found I understood the idea and none of the engineering, which is a gap that only appears when you build the thing.
The collapse step is easy. Propagation is not: when a cell settles, every neighbour's option set narrows, and theirs after that. Getting that to terminate, stay correct, and run fast enough to watch is the actual problem, and no description had made that clear.
Adjacency is the whole ruleset
The solver takes no map. Its entire input is a set of tiles and, for each, what is allowed on each of its edges. Everything the output looks like is emergent from those constraints.
That is what makes it worth building rather than reading about. The design surface is not the picture, it is the ruleset, and the relationship between the two is not obvious in either direction. Tightening one edge rule changes the character of the whole island, and wanting a particular look means reasoning backwards to the constraints that would produce it.
Three edges, not four
The island is a triangular grid rather than a square one, which is the decision the whole tile set rests on. Three edges instead of four means far fewer unique pieces are needed to cover a surface without a visible seam, and hand-modelling every piece is the expensive part of this kind of project.
The cost is a coordinate system that is genuinely harder to reason about. Each tile has three rotations rather than four, neighbours alternate orientation across a row, and every adjacency rule has to be stated against the right edge of the right rotation. That bookkeeping is where the bugs lived.
Generation is also steerable rather than purely automatic. Clicking any cell forces a specific tile there and re-propagates outward from it, so the solver can be pushed toward a coastline or a cliff and then left to resolve everything the choice implies.
In the app a click does more than advance it: it forces a specific tile into that cell and re-propagates outward from the choice.
Blender to browser
The pieces are modelled in Blender and exported as glTF, then loaded and instanced through react-three-fiber, which lets the scene graph be declarative JSX instead of imperative Three.js calls. That matters more than it sounds for a generator: the solver produces a list of placements and React renders it, so the algorithm never touches the renderer.
Rock and foliage colour is done in custom GLSL vertex shaders rather than baked into the models, which is what keeps a few hand-modelled pieces from reading as the same object repeated across the island.
Grass, four cliffs, water, two beaches, two triangles. That is the whole set.
Constraint propagation, everywhere after
The thing I did not expect is how often this shape turns up once you have built it once. A design system's token layers are a constraint propagation problem wearing different clothes: change a primitive, and the change has to reach every component that depends on it, exactly once, without cycling.
I recognised that faster at work for having written a solver first.