Patch Notes · Dispatches from the Dungeon

The Chronicle

What we've built, what we've broken, what we've quietly buried on floor 4. Newest first.

◀Page 3 of 11 · v1.20.2 — v1.15.0▶
v1.20.2#September 15, 2026Fix

1.20.2 — Same room, same dungeon

Two people would join one room and end up in two different dungeons. They could see each other — the figures moved across the screen exactly as they should — but one was walking through a crypt and the other through a forest, each fighting monsters the other could not see. The report sounded like a small sync glitch. It was not.

What changed

  • A multiplayer room is now one dungeon for everybody. Multiplayer skips the hub, and the hub is the only place in the game that picks a dungeon and rolls a run seed. So nobody was picking one: every client entered the room on whatever its own last solo run had left in the save. Hence a different biome, a different corridor layout and different monsters for each player. The host now tells the whole party which dungeon this is, which seed, which floor and which difficulty — and joiners take that on board before the game generates anything. A new room starts a fresh run from floor zero; returning to a room already in progress resets nothing and drops you where the party is now.
  • Dying in multiplayer no longer takes the game down. After a restart, teammates' figures stayed in memory as empty shells, and the first attempt to replay their animation brought the whole scene down. The crash only ever happened in multiplayer, and only after a death, which is how it survived so long.
  • A room that no longer exists says so. Following a link into a room that had been cleaned up moments earlier produced a server error instead of an honest "that room is gone".

The map split was quiet enough to play through for a while before anyone worked out what was happening — two people describing the same corridor to each other, from two different dungeons. 🗺️

v1.20.1#September 13, 2026Fix

1.20.1 — When it breaks, someone sees it

Until today, if the game threw an error in your browser, nobody found out. There were two Sentry config files in the repository that made it look like we were watching; they were never loaded — no DSN, no wiring, nothing. Four months of crashes went into the void.

They did not, in fact, go into the void. PostHog had been quietly collecting them the whole time and nobody had ever opened the page. Thirteen open issues were waiting there, the oldest from 7 May.

What changed

  • The multiplayer player list no longer takes the game down with it. It refreshes every second, and it read a joining peer's colour without checking whether their profile had arrived yet. For the first moments after somebody entered your room, it had not. That was the single most frequent error on the project — roughly a third of everything recorded — and it only ever fired in multiplayer, which is why it survived since May.
  • Errors now actually reach us. Browser crashes, pages that fail to render, and API requests that fall over on our side all report in. Server-side reports carry a stack trace and the name of the route that broke — not who you are — and are sent whether or not you accepted cookies, because the players least likely to accept tracking are also the least likely to file a bug report. Analytics stays behind the banner, unchanged. The privacy policy has been updated to say this plainly.
  • Crash reports are readable again. Stack traces used to arrive as a character offset into a minified file, which is worth roughly nothing. Source maps are now uploaded on every production build and deleted straight afterwards, so the game's source does not ship along with them.
  • We get told. A new error, or an existing one suddenly spiking after a deploy, now pings a channel instead of sitting in a dashboard nobody opened.

The eight remaining issues from that backlog are not fixed. Their stack traces point at build artefacts that no longer exist on the CDN, so they cannot be traced to a line — they need to happen once more, now that we can read them. 🔍

v1.20.0#September 9, 2026Fix

1.20.0 — Doors you can walk through

Since every entrance was narrowed to a single door, a doorway has been exactly as wide as the player is. No clearance at all. Two pixels off and an open door behaved like solid wall. That is fixed — along with the single-tile corridors, where it was worse, and with dungeon clears that had been quietly failing to unlock anything.

What changed

  • The player's body is narrower than the gap. The character frame is 32px, a tile is 32px, and the collision body took the frame's size — so the only way through was to hit it to the pixel. Enemies have clamped theirs to 28px since they were first spawned in corridors, with a comment saying "must fit through corridors"; the player never got the same treatment. It is 26px now.
  • Corner correction. Narrowing the body alone buys ±3px of tolerance, which is still not enough to make a door feel like a door. When you walk along an axis and a shoulder catches the jamb while exactly one lane carries on past it, the engine steers you into that lane. A wide passage or a real wall leaves your input alone — it can only fire where you were genuinely snagged. It works on a phone thumbstick too, where nobody is ever exactly on-axis.
  • Single-tile corridors. The same pinch, but their corners did not work at all: a body as wide as the corridor has nowhere to pivot, so turning a moment early put a shoulder on the wall. The correction carries you round the elbow.
  • No more doors to nowhere. Bricking up the spare lanes of an entrance mistook dead-end alcoves for doorways and hung doors on them — locked, key and all, with solid rock behind. A 900-floor sample had 56 of them; there are none now, with nothing stranded behind the change.
  • Clearing a dungeon unlocks the next one again. The bulk sync path — the one your runs take when you log in — gated unlocks on the leaderboard's anti-cheat heuristics, and those legitimately reject endgame characters: four real clears in the database (hellpit and icecastle at level 41–44, sewer at 53, crypt at 37) landed with valid=false and silently lost their unlock. It now uses the dedicated completion check, the same one the single-submit path uses.

Two probes now guard this in the repo: npm run test:passages drives the player through a door, a shaft and an elbow in a real physics engine, and npm run test:dungeon measures the geometry of 900 generated floors. 🚪

v1.19.0#August 23, 2026Polish

1.19.0 — The room you are standing in

The camera has been showing you twice as much room as it was designed to, and the extra half was unexplored black. On a 1080p screen your character sat in the middle of a dark frame with the art too far away to read. That is fixed.

What changed

  • The camera comes in. computeCameraZoom() works out a zoom that keeps about seven and a half tiles in view vertically, then clamped the answer at 2 — which capped every display taller than 480px, which is to say all of them. A 1080p window asked the formula for 4.1 and got 2, so it showed 15.4 tiles instead of 7.5. Rooms are a fixed size, so everything past the room edge was fog. The clamp is now 2.8, which puts a 1080p window at about 11 tiles — the framing a 1280×800 window has always had, and the one the tiles were painted against. Small screens are untouched; they never reached the old ceiling either.
  • Not the literal 7.5. Going all the way there doubles the size of everything on screen and cuts how much warning you get before something reaches you. 2.8 buys back the detail without changing how the fights read.
  • The hub moved with it. The overworld uses the same rule, and if only the floors had changed, walking through a gate would jump scale.

Nothing about the tiles, the props or the lighting changed in this release — this is the same art you already had, at the distance it was drawn for. Gameplay unchanged. 🔍

v1.18.0#August 11, 2026Polish

1.18.0 — The halls, and what stands in them

The ruined halls were the worst-separated pack in the game. Floor and wall sat at 1.26× apart with 43% of the wall's tonal band inside the floor's — so at the foot of a wall there was no line, just stone becoming other stone, and the deepest mortar joints read as holes in the ground you might walk into. This is the pack behind the game's default dungeon, so it is the one most players see first.

Fixing it turned up something older and larger: for most of the game's props, the shadow they were supposed to cast has never been drawn.

What changed

  • The halls came apart into a lit wall and a shaded floor. 1.26× / 43% overlap → 2.16× / 0%, which takes the dungeon from last place in the repainted family to first: dungeon 0%, ice 0%, sewer 22%, crypt 26%, cave 36%, forest 44%. The room is lit from the north-west, so the wall is the surface facing the light and the floor is the half in shadow — the palettes now say so. Floor mean luminance 58 → 37, wall 72 → 87. Nothing was brightened into a haze to get there; the two were simply pulled to opposite sides of the light.
  • The floor gained surface as it lost brightness. A darker floor is an easy way to make a flat floor, so the detail had to come up to meet it: 15 colours → 18–20, flat 2×2 blocks 0.031–0.059 → 0.008–0.02 — the least blocky floor in the pack's history. Slab edges catch the light on their north-west sides and fall away to the south-east, broader blotching breaks up the fill, and there is roughly half again as much grit scattered per tile.
  • The wall stopped being subway tile. Every metric said the old wall was fine, and tiled across a room at 1:1 it was a uniform grid of one grey block, because the per-brick tonal variation was too small to survive being seen next to itself forty times. Each brick's own tone now varies twice as widely, the bevel is cut harder on the shaded sides than the lit ones, there are three spall chips per variant instead of one or two, and water weeps down from the courses in stepped streaks. The four wall variants now differ from each other on 61–80% of their pixels, up from 49–68%.
  • Everything in the game that stands on the ground now has a shadow under it. groundShadow walked its loop from cy - ry, so a fractional radius made every loop variable fractional too, and the canvas then indexed its pixel buffer at a non-integer index. A buffer written at a fractional index takes the write as an ordinary object property and discards it: no error, no pixel, no shadow. 32 of the 42 shadow calls in this repo pass a fractional radius. In the dungeon that was the barrel, the crate, the pillar, the rubble and the sack — five of nine props standing on nothing — plus all three chests, which are shared art and therefore appear in every theme in the game. They are all on the floor now.

The cost, stated plainly. The floor's four variants used to differ from each other on 58–77% of their pixels; they now differ on 42–63%. Pulling the floor down into shadow compresses the distance any two of its variants can be apart, and tightening the crack and grit passes — see below — removed some of the loudest differences between them. The floor is more varied within a tile than it has ever been and less varied between tiles than it was. Of the two, tile-to-tile difference is the one the eye forgives, because the slab joints already break the grid; a flat fill inside one tile is the one it does not. Worth it, but it is a real number moving the wrong way and it belongs here.

One thing the instruments could not see. Every measurement passed while the floor was quietly strewn with daggers. Two separate passes had collided: a crack laid a dark vertical stroke, and the grit scatter — which knew to avoid the slab joints but not the crack — dropped two lit pebble crowns either side of its top pixel. A bright crossbar through a dark stroke is a dagger, and the engine stamps that one variant a few dozen times per room. Each pass was correct alone and the colour counts, block ratios and variant deltas all stayed in band. It was only visible by rendering a roomful and looking at it. The scatter keeps clear of the crack now.

Gameplay unchanged. 🏰

v1.17.1#August 10, 2026Polish

1.17.1 — Slabs and arches

Yesterday's crypt scored well and still had two things wrong with it on a screen. The floor was the darkest in the game — mean luminance 32 against the cave's 38 and the dungeon's 47 — so the slab grid existed in the measurements and nowhere else. And the wall had exactly one opening, repeated: tile a room with it and the arch stops being architecture and starts being a stamp.

What changed

  • The floor came up and the slabs came apart. Mean luminance 32 → 42, which puts the crypt second-darkest in the family instead of darkest, above the sewer and below the cave. The brightness went into the joints rather than the surface: each slab now picks its own tone from a wider spread, the groove is cut deeper, and the stone falls away on its south-east edge where the light doesn't reach. Two slabs of the same grey with a line between them are one surface. Two slabs three ramp levels apart are two stones.
  • Most of the wall is wall now, and no two graves in it are the same. Yesterday's build gave all four wall variants an opening, and the engine picks a variant per tile, so every tile of every room carried a grave. A room walled in that is not an ossuary; it is a bank of filing cabinets. But cutting back to two openings and two plain tiles fixed the density by throwing away the variety — one arch, repeated, is a stamp in exactly the way one arch on every tile was. Both are the same problem: four tiles is not enough to be sparse and varied at once.
  • So the crypt's wall ships eight. Four are plain coursed masonry, two of them fractured, leaning opposite ways. The other four are one grave each: an arched niche with three courses of long bones and two skulls on the pile; the same niche after the stack has let go, bones at angles and the spill caught on the sill; a trabeated loculus with two shelves of skulls facing out; and that same loculus shut with a chiselled slab, because a grave that has been used gets closed and the next one is cut beside it. Half a run is stone, a quarter is a sealed panel, and only a quarter is an open hole. The eight differ from each other on 34–66% of their pixels.
  • The engine only ever allowed four. The per-tile variant was masked with & 3 — written when four frames was the only thing any pack shipped, and quietly a ceiling ever since. It is a modulo against the texture's real frame count now. Nothing else changes: every other pack still ships four frames, and h % 4 and h & 3 are the same number, so every tile in every other theme lands exactly where it did.
  • Correction to yesterday's entry. The 1.17.0 changelog quoted 1.87× and 16% for the floor-to-wall separation. Those came from a reimplementation of the measurement rather than from the committed instrument the rest of the family was measured with; the correct figures for that build are 1.79× and 9%. The colour count was quoted for the whole sheet where every other entry quotes it per variant. Both are fixed in place.

The cost, stated plainly. Floor-to-wall separation went from 1.79× / 9% band overlap to 1.47× / 26%, which drops the crypt from second-cleanest of the six repainted packs to third — ice 0%, sewer 22%, crypt 26%, cave 36%, dungeon 43%, forest 44%.

Both halves of this release paid into that. A brighter floor sits closer to the wall by definition, and that is the bigger share: the floor's p90 went 0.022 → 0.041, walking its top edge straight up into the wall's band. The rest is the wall's own spread closing in from both ends — with three graves on eight tiles instead of four on four, there is less bone on the sheet and less black hole in it, so the wall's p90 fell 0.124 → 0.091 and its p10 rose 0.012 → 0.024. A narrower wall band means a larger share of it can sit inside the floor's, even though nothing about the masonry face itself moved, and the masonry face is the edge you actually read at the foot of a wall. Real cost, correctly measured, and worth it for a floor that reads as slabs and a wall you can look at twice. Gameplay unchanged. 🪦

v1.17.0#August 10, 2026Polish

1.17 — The Ossuary

The crypt is off the flat list. crypt skins Forgotten Crypt at tier 3 and the crypt zone along the north of the world map, and it held two records nobody wants: the worst wall in the family — two thirds of it perfectly flat 2×2 blocks — and the worst floor-to-wall contrast of any pack, with the two surfaces sitting in the same band of darkness.

Bone, not stone

The dungeon's entry text calls it dry: dust, bone, and a wind that whispers names. So the wall was painted as an ossuary — arched niches with bones stacked inside them — rather than as more cave or more masonry. The palette is pulled from the crypt biome on the world map, which is a cold violet grey, so the bone reads as chilled ivory instead of warm beige.

What changed

  • Floor and wall repainted from scratch. Same painter and the same rules as the hub, Ruined Halls, the forest, the sewer, the cave and the ice fortress: light from the north-west, quiet shading ramps, per-pixel hash grain instead of a regular dither grid, noise fields that wrap at the 32 px seam. floor 3 → 18–20 colours, wall 6 → 26–32. Flat 2×2 blocks on the wall fell from 66% to 3.6% — the pack went from the worst score in the family to the best.
  • Four variants that are actually four. The wall was a single 32×32 tile. The floor claimed four variants but shipped two: #0 matched #3 and #1 matched #2 to three decimal places. Both are now 64×64 sheets whose quadrants differ from each other by 13–17% of their pixels on the floor and 41–54% on the wall.
  • Floor and wall finally separate. The same contrast measurement used on the 1.15.1 fix: 1.17× → 1.79×, and the overlap between their luminance bands dropped from 67% to 9%. The whole family was re-measured with one formula this round, so the packs can be ranked against each other honestly. The crypt lands in the upper half; the dungeon is now the worst and is next in line.
  • Five new props. A headstone, a funerary urn, vault rubble, scattered bones and grave candles join the cobweb, the coffin and the skull pile. Three props to eight. Six reach the world map — the cobweb needs a ceiling to hang from and the candles are a shrine fitting, so both stay indoors.

Two headless dungeon runs, 78 and 70 rooms, all eight props in rotation in both. Prop lists checked against the files on disk across every pack: no dead references. Gameplay unchanged. 💀

v1.16.0#August 10, 2026Polish

1.16 — The Fortress Under The Ice

Ice came off the flat list. ice skins Frozen Reach at tier 3 and the ice biome in the north-east corner of the world map, and it looked worse than the sewer did before the last release: three colours to a floor tile, one single wall tile repeated down the whole corridor, and three props scattered into a room that holds five.

A fortress, not a grotto

The dungeon's entry text has always described a northern fortress overrun by the undead, so the pack was painted as ice-locked masonry rather than a bright ice cavern. The wall is dark slate laid in a running bond, the floor is frozen flagstone with drifts and fractures. The pretty grotto still exists — that's icecastle, a separate pack, untouched.

What changed

  • Floor and wall repainted from scratch. Same painter and same rules as the hub, Ruined Halls, the forest, the sewer and the cave: light from the north-west, discrete shading ramps, per-pixel hash grain instead of a repeating dither lattice, noise fields wrapping at the 32px boundary. floor 3–4 → 15–20 colours, wall 4 → 16–20. Flat 2×2 blocks on the wall fell from 42% to 2–3%.
  • Four variants instead of one. Floor and wall were both single 32×32 tiles; both are 64×64 sheets now, quartered into four variants dealt by an (x,y) hash. The masonry bond runs on 16px blocks over 8px courses, so any variant abuts any other without a broken joint.
  • The floor finally reads apart from the wall. Same contrast measure as the 1.15.1 fix: 1.59× → 4.87×, with luminance band overlap down from 14% to zero. In a dark corridor you can now see where the floor ends and the wall begins.
  • Five new props. A snow drift, fallen masonry, a dead brazier, a garrison banner and a rack of spears join the crystal, the fracture and the skeleton. The pack goes from three to eight. Six of them reach the world map — the brazier and the spears are garrison fittings and stay indoors.

The dungeon was walked on the running game twice with all eight props in rotation, and the hub bake stamps the full outdoor set with no missing textures. Gameplay is untouched. ❄️

v1.15.1#August 9, 2026Hotfix

1.15.1 — Where the wall ends

Yesterday's repaint gave the sewer and the cave hundreds of colours each, and then hid the one line that matters. Floor and wall were painted in the same tone, so from a top-down camera the corridor read as one continuous surface — beautifully textured, and you couldn't tell where you were allowed to walk.

Both packs now sit apart. The sewer's brick is lit stone above dark water; the cave's wall is the dark the magma floor glows against. Nothing moved, nothing was rebuilt — the two surfaces just stopped pretending to be each other.

What changed

  • Sewer. The floor sank and the wall came up. Where the two used to share three quarters of the same tonal range, they now share barely a fifth, and the brightness gap between them went from 1.09× to 1.74×.
  • Cave. The worse of the two, as it turned out — 93% of the wall's range sat inside the floor's, which is as close to invisible as a wall gets. The crust was lifted off the bottom of the ramp and the wall was given its own darker one, landing at 36% overlap and a 1.45× gap.
  • Props are untouched. Every crystal, column, ore vein and pile of scree carries the colours it shipped with yesterday. Only the two surfaces moved.

Both packs now separate more cleanly than Ruined Halls and the forest, which were the ones that looked right all along. Gameplay is untouched. 🧱

v1.15.0#August 9, 2026Polish

1.15 — The Sewer Runs Deep, The Cave Runs Hot

Two more tile packs came off the flat list: the sewer (tier 2, the second dungeon a player descends into) and the cave (tier 5, Hellpit Caverns and the Hell floors). Both looked exactly like the forest did before the last release — five colours a tile, a single wall variant repeated down the whole corridor, and three props scattered into a room that holds five.

What changed

  • Floors and walls repainted from scratch. Same painter and same rules as the hub, Ruined Halls and the forest: light from the north-west, discrete shading ramps, per-pixel hash grain instead of a repeating dither lattice, noise fields wrapping at the 32px boundary so floors tile seamlessly. Sewer: floor 5 → 28–31 colours, wall 5 → 25–33. Cave: floor 4–5 → 21–26, wall 6 → 14–20. Flat 2×2 blocks fell from 19–33% to 0.4–2%.
  • Four variants instead of one. Both walls were a single 32×32 tile; they are 64×64 sheets now, quartered into four variants dealt by an (x,y) hash, the same way the floors work. A corridor is no longer one tile stamped in a grid.
  • The cave is volcanic, not cold. cave serves Hellpit Caverns at tier 5 and the Hell floors of Hell & Heaven, so it is basalt with magma veins and glowing fissures rather than a grey grotto. Wet brick, algae and standing water stayed with the sewer.
  • Ten new props. Sewer: valve, sludge, flotsam, ladder, puddle. Cave: scree, column, ore vein, magma, remains. Both packs go from three to eight, so a full room isn't the same set as the last one.

Two bugs caught along the way

Both fell out of measuring what the map bake actually stamps, rather than reading the layout code.

  • The hub was dropping five forest props. The theme list in the hub scene never learned about the props added in 1.14, and the stamping helper returns quietly when a texture failed to load — no console error, no hole in the map. 19 stamps went nowhere on every bake.
  • Cave crystals never appeared at all. The scatter belt thinned on every third index while picking its prop with that same index, so position zero was skipped every single time. Thinning now runs off its own hash and all six are in rotation.

Both dungeons were walked on the running game, with all eight props appearing in each. Gameplay is untouched. 🕳️

▼ Older dispatches · Page 4