Playground

The tools, running
in your browser

A level generator, a world builder that proves its worlds can be finished, and a small game built on the first two. These are the real tools we make games with, rewritten to run in a browser tab. No download, no plugin. Change a number and watch what it does.

A studio site can describe its level generator or it can hand you one. These are the second thing. They are the same algorithms that run in our Unity projects, rewritten in plain JavaScript rather than filmed, and all three together are a 36 KB download, about a tenth of one photograph.

That size is the point as much as the content is. The whole site is hand written flat files with no build step and no dependencies, and a playable page had to arrive without breaking that promise. Everything here loads with the page and works on a phone.

Procedural generation

Wave function collapse

Start with a grid where every square could still be any tile. Pick the square with the fewest options left and commit it to one of them, rule out whatever that choice makes impossible for its neighbours, and repeat. If a square ends up with no options at all, the solver has painted itself into a corner, so it walks the last decision back and takes a different one rather than starting over.

This is an interactive wave function collapse solver. It needs JavaScript, which is currently blocked or still loading.

The rules are data

A tile declares four edge sockets and a weight. Two tiles may sit next to each other when the sockets they present to each other match, and that is the entire constraint system. Switch the tileset and the same solver produces circuitry or dungeons, because neither is written into it.

Backtracking, visibly

Most demonstrations restart on a contradiction and hope. This one snapshots the wave before each decision, and on failure restores it and forbids the tile that led nowhere, so the search takes a genuinely different branch. Turn backtracking off in the panel and watch how quickly a tight grid becomes unsolvable.

Seeds mean something

The generator draws from a seeded pseudorandom stream, not from Math.random. The same seed and the same settings give the same board every time, on any machine. That is what makes a generated level something you can file a bug against.

Progression

Lock and key worlds

A metroidvania is a promise that everything you can see, you can eventually reach. The generator below builds its worlds so that the promise cannot be broken, and then a separate checker, which knows nothing about how the world was built, starts at the entrance with nothing and tries to break it anyway.

This is an interactive world generator and progression validator. It needs JavaScript, which is currently blocked or still loading.

Two halves that do not trust each other

The generator sorts rooms by how far they are from the start, cuts that order into regions, and locks the way into each region behind the ability that sits in the region before it. So each region can only be opened once you have cleared the one before it, all the way back to the start.

The validator ignores all of that. It starts at the spawn holding nothing, walks only the doors it can actually open, picks up whatever it finds, and goes again until it stops making progress. Then it reports what it reached and in what order.

A generator that grades its own homework always passes. Separating the two is what turns "should be reachable" into "was reached, in this order, from a cold start".

What the colours mean

Rooms are tinted by region. Coloured bars across a doorway are ability gates, and they clear as the validator picks the ability up. The circle is where an ability lives, the triangle is the boss, and S is the spawn.

Anything the validator could not reach gets outlined in red. On a world built the way this one is, that outline should never appear, which is exactly why it is worth drawing. Our own 404 page makes a joke about this. The generator really does refuse to build a room the player cannot reach.

Playable

Ember Run

A small platformer whose level is carved out of a collapsed wave. It is not a screenshot of the solver above, it is running the solver above. Change the seed and you are somewhere else.

This is a playable platformer. It needs JavaScript, which is currently blocked or still loading.

Controls

Click the game to give it focus, then arrows or WASD to move, Z to jump, X to attack and Shift to dash. A gamepad works too. Nothing is captured until you click, so the page still scrolls normally.

The air is the point

Hit an enemy standing on the ground and it launches into the air. Hit one already up there and it stays up, a little lower each time. Combos only count while you or your target are off the ground. It is a mechanic from our own game, Sentinels of Gleamwood, and the one small enough to rebuild here properly.

The level is proved, not hoped

Knowing every empty space joins up says something about the map, not about the player, and a level can pass that test while hiding a ledge nobody can jump to. So before a level is handed to you, a checker walks it using only running and jumping, pretending the wall jump and the dash do not exist. The exit goes at the furthest point it could prove you can reach, and a level it cannot mostly get around is thrown away rather than served.

Tooling

The panel beside every demo

None of the three demos above has a control panel of its own. They all declare their tunable values and one shared component builds the interface, which is a port of our Unity package Runtime Debug UI, on GitHub

The claim the package makes is that you should declare a tunable field and have the panel follow, with no interface code written anywhere. Letting you tune three unrelated programs through the same panel is a more convincing demonstration of that than a paragraph would be. Values persist in local storage, saving is debounced so dragging a slider does not thrash it, and Reset puts everything back.

The game's panel uses the declarative path and the solver's uses explicit control configuration, because the solver wants live readouts and ranges that depend on other controls. Both are the same component. That split is deliberate, and porting it here is how the button control type and a fix for a panel that swallowed clicks got proved out before going back into the C# package.

Also on the shelf

Things that do not fit in a browser

The rest of what we build for ourselves. Two published Unity packages and an engine. Both packages install straight from a package manager git URL, and we run them in our own projects every day.

Unity package

Runtime Debug UI

Data driven debug panels for Unity. Tabs, sliders, toggles and readouts declared as configuration rather than built by hand, with values that persist between runs. Installable by package manager git URL. The panels on this page are its port.

View on GitHub, Runtime Debug UI

Unity package

Enhanced Logging

Logging for Unity that compiles out entirely in a release build. Console, file and on screen targets, with the scripting define symbols managed automatically per build type so nobody has to remember to turn it off before shipping.

View on GitHub, Enhanced Logging

C++ engine

Cat Splat Engine

A C++17 runtime on OpenGL 3.3 with a dockable editor, a standalone player and an asset cooker. Cascaded shadows, physically based rendering, swappable physics and scripting backends. There is more about it on the services page.

View on GitHub, Cat Splat Engine

Want this kind of thing built

Procedural generation, tooling and the unglamorous systems work that makes a team faster. That is most of what we do when we are not making our own games.