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.

v0.78.0May 5, 2026Feature

Plate Armor Slows A Mage Down — Soft Class Restrictions Land

Some gear belongs in some hands more than others. Until now, every class wore everything with no penalty — heavy plate looked the same on a Mage as on a Warrior. That changes today.

How it works

Every item can carry a class affinity tag: classes for which it's preferred and classes for which it's penalised. We apply the rule as a stat multiplier:

  • Preferred class: stats scaled +10%
  • Penalised class: stats scaled −30%
  • Every other class: neutral, item works unchanged

Nothing is hard-blocked. Want to put a Mage in plate? Go ahead — the HP bonus just won't carry as far.

What's tagged so far

This release ships the framework + a representative subset of items. We didn't carpet-tag everything; we tagged what's most legible:

  • Heavy plate / chainmail / brigandine — Warrior preferred, Mage penalised
  • Cloth tunics, leather padding, light cloaks — Mage and Archer preferred
  • Steel broadswords, viking axes — Warrior preferred, Mage penalised
  • Daggers, knives, cleavers — Archer preferred
  • Scout's Bow (and ranged signature pieces) — Archer preferred

More items will get tagged in follow-up passes. Untagged gear stays neutral — no surprise nerfs to existing builds.

What you'll see in the UI

When you select an item in the inventory, a new badge appears under the description:

  • Preferred for Warrior (+10%) — green tag
  • Penalised for Mage (−30%) — red tag

So you can see at a glance whether the stats on the card are scaled up or down for your character.

Why soft, not hard

Hard "class can't equip this" blocks frustrate the loot loop — finding a great drop you can't use just feels bad. Soft scaling lets you experiment, keep flavorful builds, and accept the tradeoff. Achievement hunters can still aim for "clear hardcore wearing only preferred items" runs in the future.

v0.77.0May 5, 2026Feature

Whirlwind Blades — Hit Everyone Around You In One Swing

Melee weapons can now have different attack patterns, and the first new pattern is the spin — instead of swinging forward in a 90° wedge, the player sweeps a full 360° circle and lands a hit on every enemy in range.

Two new spin weapons

  • Klinga Wichru / Whirlwind Blade (rare) — +22 ATK, 800ms swing, 220g — the entry-tier rotational sword
  • Karuzelowy Glewia / Carousel Glaive (epic) — +32 ATK, knockback +14, 580g — late-game crowd shredder

Tradeoff

Spin weapons deal 70% damage per target to balance the multi-hit coverage. Against a single enemy, a directional sword still beats them. Against a tight pack of three or more, the math flips — 72×3 = 216% effective output vs the directional swing's 100% on the front-line target.

The visual signal is a yellow ring around the player instead of the usual forward wedge — you can read at a glance which type of weapon you're holding.

Framework

Under the hood, items now carry attackPattern: 'directional' | 'aoe' | 'spin'. Future patterns (cleave cones, thrust lines, bouncing chain) drop in by adding to the union and branching the geometry. Same single performAttack codepath — no engine rewrite per pattern.

v0.76.0May 5, 2026Polish

Each Class Throws Its Own Thing, Spells Push Through Lines, Skill Tree Breathes

Three small but very visible changes.

Class-specific projectiles

Until now every player projectile was the same procedural arrow with a class tint slapped on top. Now each class throws its own shape:

  • Warrior flings a wrapped-grip throwing knife
  • Archer keeps the iconic arrow
  • Mage lobs a glowing fire orb (red ring → orange mid → hot core)

Tints from v0.72 still apply, so the colour signature stays — but the silhouettes are distinct now too. Light shots, charged shots, and the archer volley all use the matching class shape.

Mage projectiles + heavy archer pierce the line

Mage's fantasy is "burn through whoever's in the way." So now both the mage's regular ranged shot and the heavy channeled bolt pass through every enemy in their path until the projectile expires by range. The bolt also keeps its end-of-range AoE explosion — pierce

  • burst, all in one cast.

The archer's heavy charged shot got the same treatment: it used to stop after two enemies; now it pierces every enemy in line. Charge it up, line up the corridor, watch the row collapse.

Light archer / light + heavy warrior shots stay single-target — the class identity still reads.

Skill tree breathes

The skill tree tab had a card-on-card frame: the tree sat in its own bordered scroll container inside the modal's bordered body. Removed the inner frame, kept the scroll behaviour. Tree now uses the full modal width without the visual nesting.

v0.75.0May 5, 2026Polish

Memorial Wakes Up, Heavy Shots Burn Brighter, Ten New Achievements

Three small changes that compound nicely.

Memorial monument actually shows your dead

The memorial in the hub used to draw its list from "hardcore characters who died and weren't deleted yet." Most players don't run hardcore exclusively, so the monument stayed empty even after a long career of dying. It now reads from run_record directly — every fatal run lands on the wall, hardcore or not, even after the character was cleaned up. Forfeits don't count (those are voluntary exits, not falls). Hardcore deaths get a ✝ tag so they still stand out, and each entry shows class, level, floor, and how long ago.

Heavy projectiles burn brighter

Charged shots, channeled bolts, and class active abilities (Volley etc.) now use a brighter shade of the class colour: warrior steel goes pearl white, archer green pops to spring lime, mage red-orange ramps to solar flare. Light shots keep the base shade, so the visual hierarchy reads the moment a heavy lands.

Ten new achievements

  • Beneath the Roots — reach floor 30 in any dungeon
  • Bat Buster / Bone-Picker / Imp Destroyer — 30 kills of each
  • Master Identifier — identify 100 mystery items
  • Gold Baron — earn 50,000 gold lifetime
  • Legendary Hoarder — find 10 legendaries
  • Steady Hand / Iron Constitution — max DEX or VIT (15)
  • Daily Climber — run today's Daily Tower seed
v0.74.0May 5, 2026Polish

Enemies Wind Up, Flinch, And Generally Show They're Alive

Sprint 71 wired up per-direction idle and walk for every enemy in the bestiary. The attack and hurt animations also got generated — they just never played, because no codepath actually called them. That's fixed now.

Hurt flash on every hit

Land a melee hit, an arrow, a charge dash, a fireball, or even splash damage from an AoE — the enemy briefly snaps into the directional hurt pose. ~180ms, just long enough to read as flinch without holding too long. Stacks across all damage sources because every enemy.hp -= site routes through the same helper.

Attack windup before each strike

Ranged enemies now visibly wind up before firing. Cultists, harpies, necromancers, fire elementals, plaguebearers — they all face the target and play the attack anim during the windup window, so you can see the strike coming. Same for melee enemies: when one closes in to hit you, it faces you and plays its attack anim instead of just sliding into your hitbox while playing its walk loop.

The priority is hurt > attack > the AI's normal walk/idle pick, so hitting a windup mid-swing visibly interrupts it.

v0.73.0May 5, 2026Polish

Ten Slots, A Memorial Wall, And A Migration Prompt That Takes No For An Answer

A roster pass on the character-select screen.

Ten slots instead of five

The cap doubled. More room for class experiments, daily-tower attempts, and the inevitable "what if I just made one more archer."

Dead heroes don't count anymore

Hardcore characters who fell in the dungeon used to occupy a slot forever — your roster filled up with tombstones and you had to delete beloved corpses to make room. Now fallen hardcore heroes move to a separate Memorial section under the active list. They don't count toward the slot cap. Active runs only fight for the ten slots.

(Resurrection is, in the loose sense, a future possibility.)

"Main" name fix, take two

Brand-new characters created via legacy paths used to land in the DB named "Main." If you saw a roster full of identical "MAIN" entries, that's why. The fallback now writes "Hero" — same default as the proper character-creation flow uses. Existing rows already named "Main" stay until you rename them (double-click the slot).

Migration prompt won't haunt you

If you played as a guest, then logged in, the screen would offer to import your local characters into your account. Decline once and the prompt would reappear on every visit. Now declining sticks — we remember the choice and don't ask again.

v0.72.0May 4, 2026Polish

Projectiles Pick a Side, Tower Numbers Get a Microscope

Two unrelated polish passes that fit in one shipment.

Class-tinted projectiles

Every arrow / bolt / volley spread that leaves the player's spritesheet now wears the class colour. Mage shoots fireball red-orange, archer shoots forest green, warrior shoots steel grey. Light shots, charged shots, archer's volley — all four spawn paths flow through the same tint helper, so the visual signature is consistent across the whole class kit.

Same procedural arrow texture, just tinted on top — costs nothing on the rendering side and reads cleanly against every dungeon floor. Old hard-coded gold (charged) and lavender (mage bolt) tints are gone; class colour wins everywhere.

Tower funnel — the elite frontier

The Hidden Tower analytics card used to show three numbers (runs, deaths, forfeits). It now also surfaces:

  • Unique climbers (30d) — distinct users who entered, separate from raw run count.
  • Depth percentiles P50 / P90 / P99 — the median floor, the top-10% floor, and the elite-1% floor. P99 reads "where the hardcore live"; one freak run can pump max_floor but it can't budge P99 by much.
  • Average runs per climber — quick read on whether the tower attracts dedicated grinders (>1.5×) or broad one-and-done exposure (≈1.0).

All five numbers come from one extra percentile_cont call in the existing tower query. No new tables, no new indices.

v0.71.0May 4, 2026Polish

Enemies Finally Look Where They're Going

Every enemy in the bestiary has had a four-direction sprite sheet since Sprint 25. The code never used it — every enemy played the "down" row regardless of which way they were actually moving. Slimes chasing left looked like they were sliding sideways. Goblins sprinting up looked like they were moonwalking down.

Enemies now track facing from their velocity vector and play the matching animation row. Down, up, left, right — same four cardinals the player uses. Idle, walk, and (when implemented) attack each have the directional variant; death stays direction-less since the collapse reads the same regardless. Bosses with the bigger 64×64 sheet share the same row layout, so they get it for free.

When an enemy stops moving they hold their last facing, so a slime that just chased you and now stares from a metre away keeps looking at you instead of snapping back to "down."

Mostly cosmetic, but it's the kind of thing you don't notice when it's right and you can't unsee once you do.

v0.70.0May 4, 2026Polish

Mobile Gets the Special Ability Button It Was Missing

If you'd been playing on a phone and wondering why mages had a fireball you could never throw — yeah, the on-screen control cluster just had ATK / SHOOT / GRAB / HEAL plus the dash pill. The class ability ([G] on keyboard) had no mobile button at all. You could unlock Shield Bash / Volley / Fireball in the skill tree and then not have a way to fire it.

A new amber button now sits stacked above the SHOOT button on the right side of the control cluster, mirroring the [G] keybind. Tap to fire your class ability. Same gates as desktop — silent if you haven't unlocked the ability node, silent on cooldown.

The cluster gained a column but the existing buttons stayed in place, so muscle memory carries over.

v0.69.0May 4, 2026Polish

Heavy Shots Aim Themselves, Dead Archers Stop Shouting, And A Few Loose Ends

A grab bag of small things that all add up to "the game stops doing the obviously wrong thing."

Charged shots aim like the regular shot does

The held-attack version of the archer's charged shot and the mage's channeled bolt were still flying in 4-way cardinals — left, right, up, down. Light tap shots got auto-aim back in v0.65; the heavy versions were left behind. Now they use the same logic: cursor angle on mouse-and-keyboard, closest enemy on touch.

Dead ranged enemies stop yelling "!"

When a cultist or imp died mid-windup, the orange warning icon floating above their head stayed in the dungeon as a ghost decoration. The kill path didn't tear it down. Now it gets cleaned up the moment the enemy dies, regardless of which AI state they were in.

Privacy + Terms speak Polish

Both pages used to be EN-only hardcoded JSX. They now load from content/legal/<page>.<locale>.md, render through ReactMarkdown, and swap based on the player's language. PL versions ship today.

Heroes section reads from markdown

The /lore page's "The Three Who Still Descend" block had the hero prose hardcoded next to inline-SVG portraits. Bio + name + role + base stats now live in content/heroes/<class>.<locale>.md so editing a hero's flavour doesn't mean opening JSX. Portraits stay in code (they're SVG, not text).

Five new achievements

  • Among the Clouds — reach floor 100 in the Hidden Tower
  • He Came, He Went — complete the Mysterious Stranger's quest
  • Identifier Apprentice — identify 25 mystery items
  • Merchant's Best Friend — sell 50 items
  • (the fifth was already there waiting for the wiring catch-up)
v0.68.0May 4, 2026Feature

Daily Tower Challenge — Everyone Climbs the Same Tower Today

The Hidden Tower has a new toggle.

What it is

Walk up to the Hidden Tower gate, press E, and the popover now shows a "Daily Challenge" row above Difficulty. Flip it on and:

  • The run uses today's seed instead of a fresh random one. Every player who hits the Daily this UTC day gets the same tower — identical floor layouts, identical mini-bosses, identical loot rolls, all the way up.
  • Difficulty and Hardcore lock to Hard + Hardcore. Daily is meant to be the sharp version of the climb.
  • The card lights up with the ★ DAILY ribbon and the CTA reads "Run Daily" instead of "Enter."

Why it matters

The Tower already has a depth leaderboard, but until now your number was meaningless next to anyone else's — different seed, different luck, different difficulty. Daily collapses all of that to a single shared dungeon for the day, so the leaderboard becomes a real ladder. Filter the Tower depth leaderboard with ?daily=true to see only today's attempts.

What stays the same

  • The toggle is off by default. Casual climbers keep the random seed they're used to.
  • Tower key still required. Daily isn't a cheat past the gate.
  • A new tower rolls every UTC midnight.
v0.67.1May 4, 2026Fix

Character Names Stop Turning Into "Main"

If you logged in and noticed every character on the Continue screen was suddenly named "Main" — yeah, that was us. The autosave route took the character's name as optional and, when the autosave didn't include one (it never did), filled the blank with "Main" and wrote that back to the database. One autosave tick was enough to overwrite whatever name the character had.

Now the route looks up the row's existing name when the caller doesn't supply one, and the conflict-update path only writes a name when an explicit one was passed. Renames stick. Autosaves don't touch the name field anymore.

If your characters already got renamed to "Main", their original names are gone — there's no backup to recover from. Double-click a slot on the Continue screen to rename it back.

v0.67.0May 4, 2026Polish

One Hub Map, A Stranger Who Actually Leaves, And Mystery Gear That Stays Mysterious

A handful of fixes that fall into the "of course it should work like this" bucket.

One minimap, whichever floor you're on

The hub used to show two minimaps at once — the actual hub map you'd expect, plus an empty black box where the dungeon minimap would normally live. The dungeon minimap was always mounted; on the overworld it just cleared its canvas to black, which read as "second minimap." It now hides cleanly the moment you step out of a dungeon and reappears the moment you step back in. One minimap, always showing the floor you're standing on.

The Mysterious Stranger only visits once

He was supposed to be mysterious. He kept showing up. Now once you've claimed his quest reward, he packs up his hood and his dagger and doesn't reappear in the hub for that character — that's it, that was the encounter. New characters still meet him fresh.

Equipped gear can't be identified

Identify tab used to list your equipped items alongside everything in the bag, so you could pay 50g to identify the sword you were already swinging. Equipped gear is now hidden from the identify list with a short hint at the top — unequip first, then identify. Companion to the rule below.

Unidentified gear gives basic stats only

Equipping a mystery weapon used to hand you the full hidden stat block, so a 50g identify visit was a curiosity tax rather than a mechanic. Now your character "doesn't know how to use it yet" — unidentified weapons give a baseline (+3 ATK melee, +2 ATK ranged), unidentified armor gives a small HP cushion, unidentified accessories sit inert. Identify the thing and the real stats come online.

v0.66.0May 4, 2026Polish

Shop Gets Filters and the Identify Toast Stops Lying

Two small fixes for the shop trip — one that hits you the moment you walk in with a fat bag, and one you only notice when the merchant has a lot to identify.

Filter and sort in Sell + Identify

Sell tab and Identify tab now wear the same filter pills + sort cycle as the bag — All, Weapons, Gear, Potions, Keys plus a sort toggle that cycles default → rarity → type → name. If you walked into the shop with a stack of mystery weapons and only wanted to identify those, scoping the list now takes one click instead of squinting through everything.

Buy keeps its shelf layout (potions, gear, specials) — there's not enough up there to need a filter, and the shelves already group what matters.

Identify toast stays visible across batches

The toast that pops up after each identify ("you got X — Rare — +stats") was anchored to a single CSS animation. The first identify started the 6-second clock, and the toast quietly faded to invisible when that clock ran out — even if you'd just paid to identify item number five. The text was technically still there, just at zero opacity, so subsequent reveals looked like nothing happened.

The toast now resets cleanly on every identify. Pay for ten in a row and the toast still shows each one, full duration, all the way through the batch.

v0.65.0May 4, 2026Polish

Modals Land in the Middle of the Screen, Fireball Aims Itself

Two small things, both filed under "you'd notice if they weren't there."

The claim modal vertically centers now

It used to drift up against the nav strip on regular pages, and to the top of the play frame in-game. The fix is one of those CSS quirks — the navigation bar applies a backdrop blur, which (per the spec) makes everything inside it the new "reference frame" for position: fixed. The modal thought it was centring on the nav, not the screen.

The modal now mounts directly onto the page body, escaping the nav's blur frame entirely. Wherever you open it from — the top-right pill, the in-game pause menu — it lands centred.

Mage's fireball aims at the closest enemy

When a mage triggered the active ability, the fireball flew in one of four cardinal directions — whichever way the hero was facing. If the closest enemy was diagonally above-left, the fireball would fly straight left and miss. Same problem for the archer's volley spread.

Both now use the same auto-aim the regular ranged shot does. On mouse-and-keyboard, the cursor's exact angle wins. On a phone or with no aim input, the closest enemy in range is the target. The hero still faces in 4-way cardinals (sprite limitation), but the projectile flies at the actual angle.

The warrior's shield bash still uses the cardinal angle — that's a melee-range AOE in front of the sprite, and the cone visual reads cleaner aligned to the facing.

v0.64.0May 4, 2026Polish

The Claim Modal Lives in the Nav Too — and Typing Works Now

Last release lifted the claim form into the game pause menu. The nav bar pill on the rest of the site still bounced unclaimed users out to the dashboard — same chore, different page.

The pill is now consistent with the pause menu. If you've claimed a username, clicking your name jumps to your public profile. If you haven't, clicking it opens the same modal you'd see in-game. Type, claim, modal closes, the pill flips into your profile link without a page reload. Works on every page the nav appears on — landing, lore, changelog, leaderboard, even on someone else's profile page.

And: WASD no longer eats your typing

Pressing W, S, A, or D to type a username (or anything else into a modal in-game) used to move the hero in the world behind the modal — and worse, sometimes the keystroke never reached the input at all. The game's keyboard listener was helpfully intercepting your keystrokes regardless of where focus was.

Now the game pauses its keyboard whenever you're typing into a text field, and re-arms it the moment focus leaves. You can name yourself "Aaaaaa" without sprinting halfway across the meadow.

v0.63.0May 4, 2026Polish

Claim Your Username Without Leaving the Game

Last week the pause menu got a "Claim a username" button. It worked. It also kicked you out of the game and into the dashboard, which felt like getting up to fill out paperwork in the middle of a fight.

Now the button opens a small modal right where you are. Type a name, watch the live availability check (Checking…Available or Taken), hit Claim, the modal closes, the pause menu link flips to "View your profile". The run never left the screen.

If you're already paused, the modal takes over the pause for as long as you need it. Cancel or hit Escape and you're right back where you were. Rename and visibility settings still live on the dashboard — those are once-in-a-while account knobs, not in-game decisions.

v0.62.0May 4, 2026Polish

Find Your Way to Your Own Profile

You could share aot-game.com/u/<you> with your friends. You just had no quick way to get there yourself, short of typing the URL by hand or hunting through the leaderboard for your own row. The site never told you "click your name to see your profile," so most people probably never did.

The username pill in the top-right of the nav bar is now a link. Click it and you land on your public profile. If you haven't claimed a username yet, the same pill takes you to Settings where the claim form lives.

The pause menu inside a run got a matching entry — "View your profile" opens in a new tab so your run keeps ticking while you peek at your stats. Same fallback: unclaimed users get pointed at the claim form instead.

Small thing. Should have been there from the start.

v0.59.0May 4, 2026Polish

Decline Now Actually Declines

The cookie banner at the bottom of the page used to lie. Click "Decline" and it would close itself, save your choice, and then go right on tracking you anyway. Not great.

This week the button does what it says. Decline now means the analytics SDK never wakes up. Accept means it does. There's no secret third option where it pretends to listen. If you've already clicked Accept on a previous visit, nothing changes — your call sticks. If you've never decided, the banner shows up and you actually get a vote.

Apologies to anyone who declined and was tracked anyway. That's fixed now.

v0.57.0May 4, 2026Polish

Shopkeeper Drives a Harder Bargain

The shop used to be a free money laundromat. Pick up a 100g sword, walk to the shopkeeper, sell it back for 100g. Drop a hundred items, sell them all, get rich. The shopkeeper would nod, hand over the gold, and apparently re-shelve the rusted swords next to the legendary ones.

That's done. Sell prices now floor at 10% of an item's value and ramp up with your LCK attribute — about 1.5% per point, capped at 40% for the truly lucky. A 100g sword nets you 12 gold by default, 25 gold if you've invested in luck, 40 gold if you're a Mage who put everything into LCK and did the dance.

The Sell tab shows the actual buyback price now, not the inflated shelf price. No more nasty surprises after you click.

Identify toast — fixed mid-burst

If you handed three rare items to the shopkeeper to identify in quick succession, the first reveal popup would block the next two. You'd see what the first sword was, then nothing for six seconds while the queue waited. Now each new identify replaces whatever's on screen and resets the timer. Hand them all over and read along in real time.

v0.55.0May 4, 2026Feature

Scrolls of Teleport

The Hellpit is twenty floors deep. Halfway down you might run out of potions, your sword might break, and the only options were dying or descending further into a fight you'd already lost. That's not interesting. That's a chore.

Shopkeepers now sell Scrolls of Teleport for around 80 gold. Buy one, carry it. When the floor stops being fun, open your bag and read the scroll. The room dissolves, the run ends cleanly, and you're back at the hub with everything you'd collected so far still in your pockets.

The depth you reached counts on the leaderboard — a 12-floor scrolled-out Hellpit ranks the same as a 12-floor death. Your gear stays equipped. The scroll is gone. Plan the next descent better.

Scrolls show up on the same shelf as potions, roughly one in ten shop slots at the uncommon tier. They work in any dungeon, including the tower. Hardcore characters survive the exit — the scroll ends the run, not the hero.

v0.54.0May 4, 2026Polish

A Bag That Helps You Find Things

The bag has been a static grid since launch. Open inventory, stare at sixteen tiles, hunt for the ring you wanted to swap in. Fine for the first few drops; tedious by the time you've cleared three floors and the bag is full of mystery items.

This release teaches the bag a few small tricks.

Click an empty equipment slot — your unequipped Ring slot, say — and the bag dims everything that's not a ring. The matches get a soft green glow. You spot your candidate, double-click, done. The same trick works the other way: click an item and every other item that fits the same slot lights up alongside it.

A small ↕ Sort button next to the bag header cycles through default order, rarity (legendary first), type (groups weapons, armor, potions), and name. Five filter pills underneath — All / Weapons / Gear / Potions / Keys — narrow the bag down to whatever you're hunting for.

Click an item once to see its details. Click it again to clear the selection. Same for empty slots, same for equipped slots. The bag scrolls cleanly on phone screens too — the details column never gets pushed off.

v0.53.0May 4, 2026Polish

The Tower Gets Mini-Bosses

The tower had a major boss every ten floors and a regular swarm on every other floor. Floors five, fifteen, twenty-five, thirty- five — they were just slightly harder versions of floor four. That's a lot of empty road between landmarks.

Now every fifth floor (skipping the every-tenth boss floors) spawns a mini-boss: a regular tower enemy promoted to elite. Twice the HP, fifty percent more damage, a violet tint that reads from across the room, and a sprite about a third larger than the rabble around it. The mini-boss takes the biggest monster room on the floor — sharing a small chamber with a swarm and a bigger threat made for unfair geometry.

The death screen also got tweaked for tower runs. If you fall on floor twenty-three, the modal now reads "Fell at Floor 23" in violet pixel type instead of the generic "Game Over" kicker. The depth meant something, the screen says so.

Save and quit works mid-tower too — close the game on floor seventeen, come back tomorrow, hit Continue, and the tower picks up where you left it.

v0.52.0May 4, 2026Feature

The Tower Doesn't End

Last week the Hidden Tower opened with five floors and the Lich at the top. We always meant for it to be the endless one. This week it actually is.

The tower no longer has a final floor. Stairs down keep going. Every tenth floor — ten, twenty, thirty — pins a boss in your path: the Stone Golem first, then the Trialmaster, then the Lich. Past floor thirty the rotation cycles, but each round gets harder. Echoes of the same three with fifty percent more HP and damage, then another fifty on the next loop, until you either die or admit you've gone deep enough and pause out.

Enemies get tougher every floor too. Five percent more HP per floor, four percent more damage. By floor twenty-five you'll notice your usual rotation taking longer. By floor forty you'll be playing a different game.

The Forfeit button in the pause menu (tower runs only) lets you bow out gracefully. The depth you reached lands on a new Tower Depth leaderboard, splitting tower runs out from the regular dungeon list so deep tower runs don't crowd out fast Forest clears.

Three new achievements come along: find your first key, reach floor 25, reach floor 50. The Lich is reading patch notes about all this.

v0.51.0May 3, 2026Feature

There Is No Eighth Gate

Or rather: there is one. Most maps disagree.

Behind the memorial stone at the centre of the hub, on a tile that's been bare grass since the overworld got its biomes, a new gate has started flickering into existence. You won't see it on your first visit. You won't see it on your tenth. It shows up only when you're carrying the right key — and the key only drops from bosses in the seven regular dungeons.

The drop is rare on purpose. One percent on Easy, two on Normal, five on Hard. Featured Dungeon active during the kill adds a small bonus on top. Drops never trigger inside the tower itself, so the loop has a definite end: get a key, walk into the gate, and the key dissolves on entry. Want another run? Earn another key.

What's behind the gate is still small for now — a five-floor descent ending on the Lich. The deeper version is two weeks away. Consider this part one of three.

If you find a key, the gate is in the patch of grass behind the memorial. You can't miss it.

v0.50.0May 3, 2026Polish

Your Profile Looks Better When Shared

Paste your aot-game.com/u/<you> link into Discord, Slack, or anywhere with link previews, and the preview used to be the generic site favicon and a one-line meta description. Not exactly inviting.

Now the preview is a proper share card: 1200×630 pixels of black gradient, your username in oversized type, your featured character's class emblem on the right with their level and deepest floor, and a strip of stats underneath — deepest, top level, character count, hardcore clears. The same numbers your profile page shows, just compressed into a banner.

Profiles that haven't run anything yet still get a clean fallback card. Private and missing slugs render a "Profile not found" card so the share doesn't lie about whether the user exists.

If you've claimed a username, your link looks better today than it did yesterday. If you haven't, claim one in Settings.

v0.49.0May 3, 2026Content

The Bestiary Got Filled In

The bestiary has been a half-empty encyclopedia. Six monsters had a paragraph of backstory; sixteen had nothing but their HP, their attack, and the suggestion that someone would write about them eventually. This is that eventually.

Every enemy in the game now has a write-up. The Bedroom Harpy roosts on a bed she shouldn't have access to, on a floor that shouldn't have beds. The Second-Shift Cultist worships something the dungeon hasn't agreed to. The Lich has read the patch notes. The Intern Necromancer is doing it wrong but doing it. The Retired Mummy still hits hard, but the bandages are coming off in a way they shouldn't be.

Every entry exists in English and Polish. The Polish names lean harder into the bureaucratic-fantasy register — Goblin-Harcerz, Mumia-Emerytka, Licz Ostatniego Patcha — so the prose follows.

Open the lore stone in the hub or visit /lore and read your way through. There are jokes hidden in the longer entries.

v0.48.0May 3, 2026Feature

A Mysterious Stranger

Sprint 44 stretch — the third hub NPC. The Featured Dungeon rotates weekly, the Traveling Merchant shows up to sell, and now a cyan- tinted Mysterious Stranger posts up near the memorial twice a day with a job offer.

How it works

Same deterministic-window pattern as the merchant: two slots a day, 2 hours each, offset 6 h from the merchant so the two NPCs rarely overlap. Walk up, press [E], and pick the offered job — or decline and let it expire.

Three quest types so far, picked deterministically per window:

  • Slay N enemies of type X (8–15 of a specific bestiary entry)
  • Clear N floors (2–4)
  • Spend N gold in shops (100–299)

Reward is gold + a guaranteed rare or epic item. Rare quests pay 100g, epic quests 200g.

Quest UI

Once accepted, a cyan progress panel docks on the right side of the HUD with the task description, a fill bar, and a n / target label.

  • Kills tick when an enemy of the right type drops.
  • Floor clears tick on the existing floor-cleared event.
  • Gold-spend ticks every time useGold succeeds in the shop.

When the bar fills, a yellow Claim reward button appears — click delivers the gold + a random item of the rolled rarity, then the panel disappears.

Persistence

The active quest lives in the save blob — survives floor changes, death, scene-restart, and reloads. autoSave + loadState carry it through the same path that handles the dungeon seed bundle. Old saves without the field default to null.

Banner stack

Hub event banner now shows three rows when everything is up at once:

  • gold strip — Featured Dungeon
  • purple strip — Traveling Merchant
  • cyan strip — Mysterious Stranger

Each row repolls every 30 s so countdowns stay accurate without spamming render work.

Side notes

  • getQuestGiver reuses the merchant's daily-hours derivation (dailyMerchantHours) and just shifts by 6 h, so adding more hub events later is a one-line offset change.
  • Quest rewards filter out potions — only gear pool, so the player doesn't get "+1 minor health potion" as a quest payoff.
  • Dropping a quest mid-run is intentional — the ✕ in the panel header drops it without a confirmation. The next stranger window can offer something fresher.
v0.47.0May 3, 2026Feature

The Hub Comes Alive (Again)

Sprint 37 made the hub a place — biomes, gates, river, memorial, lore stone. Then it sat there. Sprint 44 makes it a place that changes: a featured dungeon every week, a merchant who shows up twice a day for an hour, a banner that tells you what's live.

Featured Dungeon — rotating weekly buff

Every Monday at 00:00 UTC one of the seven dungeons becomes the Featured run for the week. The matching gate gets a pulsing gold ★ FEATURED ★ banner, the gate-card popover sprouts a gold strip explaining the buff, and the run picks up one of:

  • +50% gold — every coin pickup pays out 1.5×
  • +50% XP — every kill levels you faster
  • ×2 legendary drop chance — the rarity slot doubles its weight

Picks are deterministic from an FNV-1a hash of the ISO week — same dungeon and buff for every player on the planet, in MP and SP. The two hashes (dungeon + buff) are independent, so consecutive weeks rarely look identical.

This week (W18): Forest + ×2 legendary.

Traveling Merchant — twice a day, never twice the same

A purple-tinted NPC appears in the hub for two 60-minute windows per UTC day. He stocks 3-4 rare/epic items (~30% of windows include a legendary too) priced 3-5× their normal value. You miss the window, you miss the deal — same windowKey on every client means MP teammates see the same offers.

The merchant rotates between three spots in the hub (memorial side, north path, west path). Walk up, press [E] (or the on-screen button), buy or browse. The modal counts down MM:SS to the window close and auto-shuts when he leaves.

Hub event banner

Top-center on the overworld HUD: a single strip listing what's live right now. Always shows the Featured Dungeon + countdown to next rotation; stacks a purple strip below when the merchant is in town. Repolls every 30 s — ms-precision isn't useful for a once-an-hour event.

What landed

  • lib/hub/events.ts — pure helpers: getFeaturedDungeon(), getTravelingMerchant(), getTravelingMerchantStock(), msUntilNextWeek(), isoWeekKey(). FNV-1a + tiny LCG, no shared state, no server round-trips. Client + server can both call them and never disagree.
  • GameScene getFeaturedMults() stacks the buff into gainXp, the gold-pickup multiplier chain, and pickEquipmentByRarity (legendary slot weight). Non-featured runs see {1, 1, 1}, so SP balance stays unchanged outside the featured dungeon.
  • OverworldScene draws the gold ★ FEATURED ★ text banner above the matching gate, runs a 1 Hz pulse via tween. Spawns / despawns the merchant sprite (npc_shopkeeper tinted #a78bfa) on a 5-second poll so window-edge transitions land cleanly.
  • GateCardPopover gets a .oh-featured-strip band between the accent bar and the header when the dungeon is the week's featured pick — gold gradient with brightness pulse.
  • New <HubEventBanner /> component, mounted on OverworldScene-active state only. Stacks a second strip for the merchant when active.
  • New <MerchantModal /> reuses ModalShell + ShopBuyRow chrome — buy-only, no sell/identify tabs. Live countdown in the accent slot, auto-closes on window expiry, SOLD badge per-purchase.

Side notes

  • Buff stacking: featured XP buff layers ON TOP of class xpMult + difficulty xpMult — a Mage with Mystic Eye on a featured-XP Easy run gets a multiplicative party.
  • Merchant inventory rolls always include a rare and an epic even on unlucky LCG draws (filtered pool fallback). The wildcard slot never duplicates an already-picked item.
  • Future Sprint 44 stretches (hidden 8th dungeon trigger, quest giver NPC) will hook into the same banner — third + fourth strip slots when active.
v0.46.0May 1, 2026Fix

Multiplayer, Patched

A multi-player run surfaced six bugs at once. None of them were giant on their own, but together they made co-op feel like single-player with confused teammates standing around in the dark.

What was wrong

  • The roster in the top-right showed Playroom Kit's auto-generated profile names ("RogueDuck", "PrettyZebra"), not the player's picked class.
  • Killing a single monster credited XP to everyone in the party. The XP-update tick fired locally on every client when the authoritative state showed an enemy at HP 0.
  • Other players cast no light. The lighting recompute ran FOV at the local player only — teammates were invisible flashlights.
  • The minimap and the multiplayer roster both anchored top-right on coarse-pointer devices and painted on top of each other.
  • Remote arrows were invisible. The attack broadcast carried only the melee fields (dir + damage); ranged hits applied damage but no visual.
  • Music started stuttering 1-2 minutes into a session. Each synth SFX call was creating + closing a fresh AudioContext, and Chrome's audio thread fell behind under MP combat load (4 players ⇒ ~10–30 contexts/sec).

What changed

  • Class names ship as displayName. Each peer broadcasts its picked class via setMyState after handleClassConfirm. The game-shell roster + the in-canvas nametag both prefer displayName over the Playroom profile name. Roster also polls every second so it updates as peers finish class-select.

  • XP attribution. New optional awardXpToLocal flag on killEnemy — defaults to true so SP behaviour stays. MP visualisation paths (applyRemoteEnemyState) pass false. When the host's processRemoteAttack lands a kill on a peer's behalf it broadcasts a kill-credit-<peerId> payload; the peer reads it on the next sync tick and adds XP locally. Kills attributed to whoever actually swung.

  • Remote-player FOV in the lighting OR. updateLighting now runs computeFov at each remote peer's tile and ORs the result into this.visibility. Peer crosses a tile boundary → lighting marked dirty so the recompute fires. Bounded by 4 players, so worst case is 3 extra computeFov calls per dirty frame.

  • MP roster moved to the upper-left under the status panel. Top-right column now reads as one consistent stack of icon buttons (📊 stats / 🎒 inventory / ⏸ pause / minimap) instead of competing with the roster chrome.

  • Cosmetic remote arrows. New rangedFire peer state carries spawn xy + velocity + range. Each client reads peer fires and tweens an arrow sprite along the same trajectory — pure visual, no physics, destroys itself after range / speed. Damage stays on the host's authoritative path.

  • Single shared synth AudioContext. Cached per scene and closed only on Phaser.Scenes.Events.SHUTDOWN. The per-call setTimeout(() => ctx.close(), N) everywhere in playSfxSynth is gone; only the connector teardown stays. BGM no longer competes with a churn of short-lived contexts on the same audio thread.

Side notes

  • creditKillsLastSeen is a monotonic counter — re-applying old credit after a reconnect can't double-pay because the host always strictly increases the total.
  • Remote arrow visual reads textures.exists("arrow") defensively so a peer joining mid-floor (asset still loading) silently drops the visual instead of crashing.
v0.45.0April 29, 2026Feature

Pocket Trials

The game shipped a PWA manifest a sprint ago and an Android phone made a fresh point: the rest of the experience wasn't built for a phone. Joystick spawned in the wrong spot. Action buttons slid under the gesture bar. Modals overflowed. Half the time the hero swung in the direction of the joystick instead of at the closest enemy.

This week the mobile build catches up. New dungeons too, and a denser dungeon generator behind both.

Mobile / PWA polish

  • React virtual joystick replaces the rex joystick that was drifting on the overworld (the hub camera zooms 2× and rex's base/thumb GameObjects scale with it, so a tap at screen X=200 spawned the joystick at X=400). New component lives outside Phaser entirely — pointer events caught on the canvas, vector pushed to window.__AOT_JOYSTICK__ for both scenes to read.
  • Auto-aim closest enemy on touch. chooseCombatDir skips the "face the cursor" branch on coarse-pointer devices — the most recent pointer position on a phone is almost always the joystick drag, not an aimed cursor. Melee now lands toward whoever is closest. Ranged got the same treatment with a new free-aim angle helper, so arrows fly at the actual enemy instead of being snapped to a cardinal direction.
  • Tap-collapse HUD. Status panel toggles between full and compact (three thin gauges only — HP / stamina / XP, no text, no badges). Persisted via aot_hud_collapsed localStorage.
  • Tap-toggle minimap. Tapping the minimap collapses it to a 36×36 pin in the same corner; tapping the pin restores it. Reuses the [M] keypress wiring + lost_no_more achievement bridge.
  • Icon HudBtns matched to the pin chrome. STATS / INV / ⏸ render as 36×36 icon pills on any (pointer: coarse) device (was triggering off Tailwind's md: breakpoint, which leaked the labelled desktop variant onto landscape phones).
  • Action button cluster lifted. Bottom anchor is now max(env(safe-area-inset-bottom), 56px) + 24px — Android Chrome reports safe-area-inset-bottom: 0 even when the gesture nav paints over the page bottom, so the 56px floor guarantees ATK and Q stay above the system overlay.
  • Site nav hidden in play phase, PlayWindowChrome bars flattened on coarse pointer, modals clamped to 100dvh, html/body pinned to 100dvh so iOS PWA can't grow the document past the visible viewport mid-load.
  • Overworld now has a joystick — the hub had no movement input on touch after the on-screen D-pad was retired.
  • Mobile-input listener on OverworldScene. Tapping the on-screen E button now opens the gate-card popover; before it only fired in GameScene.

Two new dungeons

  • Mire Warrens (sewer, 5 floors, tier 2) — south-west pocket under the river. Plague swarm bestiary: rats, slimes, plague- bearers, drowned. Brick-arch gate with a 3-frame drip and a green sludge channel at the threshold.
  • Frozen Reach (ice, 10 floors, tier 3) — north-east pocket along the mountain ridge. Undead-knight bestiary: skeletons, wraiths, iron knights, void hounds, cultists. Frosted blue arch flanked by ice columns with a 4-frame shimmer drifting across the tunnel.

Both fill the two themes whose tile / BGM packs were already shipping but had no overworld gate. The hub now has gates for all seven dungeon themes. Two new exploration achievements come along for the ride: cleared_sewer (Plumber) and cleared_ice (Frozen Reach Cleared).

Denser dungeon generation

Sprint 40 doubled the map to 100×80 but the BSP generator still ran with split(root, 4) regardless of map size, capping out at ~12-16 rooms — most of the playable area was bare 30-tile corridor.

  • Split depth scales with map area — aim for ~one leaf per 144 tiles, so a 100×80 plans for ~55 leaves (depth ≈ 6) where it used to cap at 16. Legacy 50×40 still resolves to depth 4, so older callers don't change.
  • Closest-pair connectors. connectTree picks the Manhattan-closest leaf room across each split instead of the first match found in each subtree — top-level connectors stop snaking across half the map.
  • Cross-connection pass. Each room has a 25% chance to carve an extra L-corridor to its nearest non-adjacent room. Adds loops, lets enemies flank, breaks up the linear backbone. Probability is low so layouts stay legible (mostly tree-shaped), not mazey.

A 100×80 boss-test seed produced 36 rooms (32 monster / 1 shop / 1 treasure / 1 boss / 1 start), floor:corridor ratio 2.1:1 — was inverted before this change.

Side notes

  • Status / action panels softened from bg-black/65 to bg-black/40 so the world reads through the chrome. Minimap trim matches.
  • New themes.overworld i18n key (EN: Overworld, PL: Hub) drives the HUD floor chip when the player is in the hub instead of parroting the last dungeon's "P-1 · FOREST".
  • OverworldScene.cleanupBossRoom and the joystick state both live on window.__AOT_* globals — non-React components that need to talk to scenes (or vice versa) keep using the bridge pattern instead of importing through tangled chains.
v0.44.0April 29, 2026Feature

Greater Depths

Every dungeon used to be three floors. Forest, Ruined, Crypt, Void — three floors each. Hellpit got five as a token gesture. Doesn't matter if you're a tutorial player or have cleared the game ten times: same length, same shape, same pacing. Nothing to commit to.

This week the dungeons branch into real tiers. Forest stays at three floors so the tutorial onboard doesn't change. Ruined stretches to five. Crypt is ten. Void is fifteen. Hellpit is twenty — a marathon dive that's an hour-plus session if you finish it. Pick your poison.

To make any of those longer dungeons playable, every floor also doubled in each linear dimension — 50×40 tiles became 100×80 tiles. Four times the explorable area, ten rooms per BSP instead of four, BFS corridors that actually let you wander.

To make a 100×80 floor navigable without losing your bearings, there's now a minimap in the top-right corner. Explored walls go gray, the corridor you can currently see lights brighter, the player's a gold blip with a halo, stairs and chests show as colored dots, and enemies in your line-of-sight turn into red dots. Press [M] to toggle it; the preference sticks across reloads.

What landed

  • Floor counts: Forest 3, Ruined 5, Crypt 10, Void 15, Hellpit 20. DUNGEON_TYPES.floorCount was already the source of truth — anti-cheat, boss-floor detection, and the HUD floor counter all picked up the new values automatically.
  • Map size 2× linear (4× area): 50×40 → 100×80 tiles. BSP generator's minRooms 4→10 and maxRoomSize 14→18 so the bigger canvas fills with rooms instead of empty corridors.
  • Dungeon minimap HUD (DungeonMinimap.tsx): canvas-based, 5 fps poll, reads the live visibility Uint8Array from the scene. Explored / visible / hidden tile states, plus markers for stairs (up green, down blue), chests (yellow/dark yellow), locked doors (red bar), and FOV-visible enemies (red dots). Default visible.
  • [M] toggle: keypress flips minimap visibility, persisted to localStorage.aot_minimap_visible. Toggle count tracked for the new lost_no_more achievement.
  • Cartographer ratio computation: floor-cleared event now carries exploredRatio = touched_walkable_tiles / total_walkable_tiles. Drives the new cartographer achievement.
  • Achievements:
    • marathoner — clear all 20 floors of the Hellpit
    • cartographer — explore ≥95% of a floor's walkable tiles
    • lost_no_more (target 50) — toggle the minimap with [M] 50 times across all your runs

Side notes

  • The chrome-style minimap art (gold rivets, skull/rune endcaps) is queued as Pack A but not blocking — the CSS-rendered border + dark inset reads as part of the same HUD family without a sprite asset.
  • The __ACHIEVEMENT_BRIDGE__ window hook lets non-React components (the minimap's [M] keypress handler) fire achievement unlocks without importing the tracker module through a tangled dependency chain.

Coming soon

  • Sprint 41 — Deep Floor Difficulty Curve is a planning stub for the inevitable balance pass. With Hellpit's 20-floor run live, we need to see how the existing per-floor enemy HP/damage scaling holds up at floor 15-20 — too easy and it's a slog, too hard and it's unreachable. We'll know after a couple of playthroughs.
v0.43.0April 28, 2026Feature

They Shoot Back

Every enemy in this game used to walk up to you and swing. Goblin, skeleton, slime, harpy, imp — all melee, all the time. Player has had a bow and a fireball forever; enemies have had nothing. This week the imps spit fire, the harpies fan three feathers at once, the necromancers lob shadow bolts, and the cultists hurl blood spikes that knock you back two tiles.

Every ranged attack telegraphs. A red ! icon pulses over the enemy's head for 350-600ms before the shot fires — long enough to dash, sidestep, or break line-of-sight by ducking behind a wall. Walls and closed doors block projectiles so cover plays the way it should: walk into the doorway, the boulder hits stone, you walk out and finish them.

Each ranged enemy has its own glass-cannon balance. -30% HP vs the same-tier melee mob, +50% damage per shot, kite-back AI when you close in. Some types are hybrid (imp, harpy) — kite at range but bite if you corner them. The pure-ranged types (necromancer, cultist, plaguebearer) actively run from melee instead of swapping. Mixed encounters force flanking; ranged-only rooms become little puzzle boxes where you have to read the room and pick angles.

The boss-fight pipeline from last week (telegraphs, projectiles, line-of-sight) carried over cleanly — the same raycast util that stops a death beam now also stops a fireball spit, the same projectile spawner serves boss boulders and imp fireballs.

Cast

  • Imp (Forest, Hellpit): fast small fireballs, 1.5s cadence, hybrid — bite if cornered.
  • Harpy (Forest, Hellpit): 3-feather fan in a 30° spread, 2.0s cadence, hybrid.
  • Necromancer (Crypt, Void): heavy slow shadow bolt, 2.5s cadence, pure-ranged. Runs from melee.
  • Cultist (Crypt, Void): blood spike with 80px knockback, 1.8s cadence, pure-ranged.
  • Plaguebearer (Crypt, Hellpit): pus glob, 3.0s cadence, pure-ranged.

Achievements

  • Sniper Supreme (target 5) — kill 5 ranged enemies on a single floor before any of them fires.
  • Out of Range — clear a floor without taking damage from any projectile.
  • Glass Hunter (target 25) — defeat 25 ranged enemies cumulative.
  • Flank Attack — kill a ranged enemy from behind, breaking its line-of-sight on the way in.

Plus the per-dungeon clear achievements (Forest Cleared, Ruined Cleared, Crypt Master, Survived the Void, Hellpit Conqueror) now actually unlock when you complete a themed dungeon — they were defined but never wired to a fire.

What landed

  • lib/phaser/combat/los.ts — shared Bresenham raycast util. Walls + closed doors block. Boss specials (Sprint 38) and enemy ranged paths (this sprint) both call this.
  • lib/phaser/enemies/RangedAI.ts — state machine (idle / chasing / kiting / aiming / shooting / recovering) with mobile windup ×1.3 multiplier and hybrid melee fallback.
  • Per-enemy ranged config — 5 entries (imp, harpy, necromancer, cultist, plaguebearer) wired via resolveRangedAttackForType. Glass-cannon HP scale (-30%) at spawn time.
  • Aim alert sprite — 16×16 ! icon over enemy head during the aim state, 200ms-on/200ms-off frame swap (cheap, no tween).
  • Pack A — Ranged Projectile VFX (6 sprite sheets): fireball / feather / shadow bolt / blood spike / pus glob / alert. Animated at intended fps via existing texture-swap path.
  • 17 Suno SFX — per-enemy charge + release pairs, per-impact flesh hit variants, projectile-on-stone bounce, aim alert ping.
  • Per-dungeon clear achievements wired — Forest Cleared, Ruined Cleared, Crypt Master, Survived the Void, Hellpit Conqueror trigger off the boss-defeated event with the active dungeon snapshot.

Bugs killed

  • Dungeon BGM bled into the overworld — GameScene's SHUTDOWN handler dropped the i18n bridge but never stopped the active BGM Sound instance. After a successful run, the boss theme kept playing into OverworldScene's forest theme — two tracks at once. Now the SHUTDOWN handler explicitly .stop()s the current bgm.
  • Per-dungeon clear achievements never unlocked — the five cleared_* entries were defined in the achievements module but no caller ever called unlock(). Wired into the boss-defeated handler in GameHUD, snapshotting the active dungeon from the store before endActiveRun() clears it.
v0.42.0April 28, 2026Feature

Bosses With Teeth

The three boss types in this game used to fight like every other mob. Bigger HP, bigger numbers, same chase-and-melee AI. The Stone Golem couldn't slam, the Trialmaster couldn't summon phantom blades, and the Lich didn't even cast a fireball. This week each boss becomes its own dance.

Every boss now has 2-3 special attacks, every special is telegraphed 600-1500ms before impact (so a dash window exists), and at half HP each one transitions into a phase 2 with extra moves and a faster tempo. There's a Souls-like HP banner across the bottom of the screen with the boss's name, a damage smear that flashes orange when you take a chunk off, and a phase pip that lights red when the boss enrages. The fight gets an intro stinger + camera shake + zoom punch when you walk in, and a death cinematic with white flash, slow-mo, gold rain, and a guaranteed reward chest when it falls.

The roster:

The Stone Golem (Forest, Ruined, Hellpit) ground-slams a 96px ring around itself, lobs boulders that arc across the room, and at half HP starts erupting earth-spike lines that walk toward you in sequence. The slam has the longest telegraph in the game — a growing red ring you can sprint out of if you read it.

The Trialmaster (Crypt, Void) phases between three quick spectral slashes that fan out 120° each, summons four phantom blades that home onto your last position, and at half HP starts vanishing into purple smoke and reappearing behind you for a heavy strike. The teleport has no telegraph at the destination — only the vanish puff, so you have to predict.

The Lich (Crypt, Void, Hellpit) fans five fireballs in a 90° arc, charges a death beam that takes 1.5s to fire and stretches across the room with a 3s burn DoT on hit, and at half HP starts summoning skeleton minions in pairs (max 4 on the field). The Death Beam telegraph is the most dangerous — line of red, the longest windup, but also the most damage if you eat it.

The hub got a save/resume fix too. If you save mid-run on floor 1 and come back, you can now use the stairs-up to drop your run and return to the overworld. Previously you were stuck in the dungeon until you cleared the boss or died. The new prompt reads "[E] Return to Overworld" — your XP, gold, and gear stay; only the dungeon progress is lost.

Achievement haul: ten new boss-themed unlocks, including Trinity Slayer (kill all three boss types on one character), Boss Master (10 cumulative kills), Untouchable (zero damage from specials in a fight), Lightning Round (60-second clear), Dance of Blades (5 phantom-blade dodges in a Trialmaster fight), Earth-Shaker Survivor (3 ground slams dodged in a Golem fight), Calm in the Storm (zero damage during phase 2), and per-boss slayer entries.

For dev / play-testing, three boss-arena URLs let you skip the overworld and drop straight into a 1v1 with the chosen boss:

  • /game?bossTest=golem
  • /game?bossTest=trial
  • /game?bossTest=lich

Single floor, no minor enemies, full-HP boss in the center room. First load is slow (~15s — the engine pre-fetches all 21 boss SFX

  • 4 BGM tracks + 13 telegraph/special VFX); subsequent fights in the same session boot instantly.

What landed

  • BossController + telegraph helpers + per-boss configs — new lib/phaser/bosses/ module. Controller handles weighted- random scheduling with cooldowns, phase transition at <50% HP, mobile windup ×1.3 multiplier, host-authoritative MP scheduling.
  • Boss HP HUD bannerBossHpBar mounts on boss-engaged via Phaser registry polling (chosen over event-emitter binding to dodge a HMR/StrictMode race that was eating the one-shot setdata emit), three-layer fill composite, lag-bar trails 700ms, damage smear flash, phase pip pulse.
  • Per-boss specials wired — Golem ground slam / boulder / earth spike, Trialmaster triple slash / phantom volley / teleport strike, Lich fireball volley / death beam / summon skeletons. Damage paths reuse the regular dodge + class reduction pipeline.
  • Encounter cinematic — camera shake + zoom pulse + intro stinger on engage, BGM crossfade to per-boss theme, boss-room cleanup despawns minor enemies on engagement.
  • Phase 2 transition — sprite tint shift gold→red, ember aura emitter trailing the boss, BGM rate ×1.15, dramatic synth swell stinger.
  • Death cinematic — white flash, 600ms screen shake, slow-mo (timeScale 0.3) for 800ms, 8-frame radial particle burst, 24-coin gold rain, reward chest spawn 1.2s delay. Skipable via Space/Enter/E/click.
  • 10 new achievementsboss_trinity boss_master untouchable_boss speedrun_boss dance_of_blades earth_shaker_survivor phase2_no_damage plus per-boss slayer trio (already existed). EN+PL i18n.
  • Boss test arena URLs?bossTest=<id> skips menu / character select / overworld, sets warrior default, picks matching themed dungeon for theme + bestiary, forces floor 0 as the boss floor, skips minor enemies.
  • Floor-0 stairs-up exits to overworld[E] Return to Overworld prompt + endActiveRun() flush + scene start. The hand-built escape hatch for "I loaded a save and just want to back out of this run."
  • Pack A — Boss Telegraphs & Specials VFX (9 sheets, public/assets/vfx/{telegraphs,specials,status}/)
  • Pack B — Boss HP HUD Banner (7 layers, public/assets/hud/boss/)
  • Pack C — Boss Encounter Cinematic (6 assets, public/assets/vfx/boss_death/ + public/assets/props/)
  • 4 Suno BGM tracks + 21 SFX files (public/assets/audio/bgm/ + public/assets/audio/sfx/boss/)

Bugs killed

  • Boss specials passing through walls — projectiles (boulder, fireball, phantom blade) had no wall collider; line/cone damage (death beam, earth spike, triple slash) used pure geometry with no LOS check. Projectiles now collide+destroy on wallGroup / doorGroup, line/cone damage uses a Bresenham raycast over the tile grid before applying.
  • Boss HP HUD never appearing — Phaser's setdata-<key> is a one-shot emit on first set; React Strict Mode + HMR mount/unmount cycles meant our listener bound after the registry was already populated, missing the event. Replaced event-emitter subscription with 100ms polling of registry.get — bulletproof but a few cycles slower; latency invisible to the player.
  • Boss test arena spawning random mob enemiesspawnEnemies and loadMap had local isBossLevel calculations that didn't see the bossTestMode override (only the helper did). Routed both through isCurrentFloorBossLevel().
  • Floor-0 save softlock — saving on floor 1 (display) of a themed dungeon and reloading dropped the player back at floor 0 with no way to leave: stairs-up was gated currentFloor > 0, stairs-down only progresses deeper. Fixed via the new floor-0 exit-to-overworld path above.
v0.41.0April 27, 2026Feature

The Hub Comes Alive

The overworld used to be the game's loading screen with a person on it. Procedural canvas tiles in five flavours of green, props painted with fillRect, and a shopkeeper outpost that was nothing more than an [E] prompt floating in empty grass. This week the hub got a texture pass and the merchant actually showed up.

Each biome zone now skins itself with the matching dungeon theme's PNG floor pack — forest tiles in the meadow and woods, dungeon stone in the ruined zone, crypt withering in the north, void cracks in the east, and cave scorch in the southeast. Four 32×32 variants per theme rotate per tile by xy hash, so the surface looks varied instead of repeating in obvious rows. Prop scatter pulls from the same packs: mushrooms / logs / vines in the forest, barrels and dropped swords in the ruins, coffins and skullpiles in the crypt, runes and spikes in the void, crystals and stalagmites in the hellpit. Trees stay canvas-painted (no PNG art for them) and layer in front of the PNG ground props for canopy depth.

The shopkeeper outpost now has a building. Closed wood door in the middle, hand-lettered sign hanging above, two flanking brass lanterns flickering on a 3-frame loop, and a softly breathing additive halo behind each lantern so the shop reads as warm even from across the meadow. The merchant himself stands in front of the door with the same idle animation his dungeon counterpart uses, and the [E] prompt now hangs over him instead of the door so the approach feels like greeting a person, not opening a building.

Pressing [E] opens the actual shop UI — Buy / Sell / Identify tabs, gold bar, the same per-floor stock generator the dungeon merchant uses. Floor 0 stock is mostly potions and low-tier gear, which fits "hub merchant" perfectly. Sell and Identify tabs work against your full inventory, so the hub is now where you offload junk between runs.

Water and lava picked up some atmosphere. The river drifts white sparkles westward at 90ms cadence, additive-blended so they catch against the dark water. The hellpit lava strip exhales orange-to-red embers rising at 70ms cadence with random horizontal sway. Two particle emitters total — single GameObjects, GPU-accelerated, no per-tile sprite churn.

Lanterns no longer pulse in lockstep — every animated prop (path lanterns, magma vents, void shards, shop lanterns) carries a per-sprite phase offset so a row reads as separate flames instead of one ticking metronome.

All five dungeons unlock by default. The unlock-on-clear chain (Forest → Ruined → Crypt → Void → Hellpit) is gone — pick whichever gate matches the run you're in the mood for.

What landed

  • Asset-driven overworld bakebakeOverworldMap(scene) reads PNG floor + prop textures from the scene's cache. Biome → theme map: meadow/forest = forest, ruined = dungeon, crypt = crypt, void = void, hellpit = cave. Water / mountain / shore stay procedural (no PNG art).
  • Shop outpost dressing — door (frame 0, closed) + sign tile + two prop_shop_lantern sheets (3-frame flicker, 6fps, per-sprite phase offset) + two prop_shop_lantern_glow halos (additive blend, alpha-tween 0.55↔0.85 over 1.2s).
  • Overworld shopkeeper NPCnpc_shopkeeper sprite with a 4-frame idle-down animation, positioned 1.1 tiles in front of the door so the player approaches him head-on.
  • Shop UI hooked up — pressing [E] near the merchant calls setShopOpen(true) directly, opening the same Buy / Sell / Identify modal the dungeon shopkeeper uses. Closing the modal emits gate-card-closed so the proximity lock releases for the next [E] press.
  • Ambient particles — single river-spanning sparkle emitter (90ms drift west) + single lava-strip ember emitter (70ms rise with horizontal sway, tint cycle yellow→orange→red). Both additive-blended.
  • Lantern desync — every animated prop carries a phase data value derived from its position; the update-loop frame index uses (time + phase) * fps. Path lanterns, magma vents, void shards, shop lanterns all desync independently.
  • All dungeons unlocked by default — every entry in DUNGEON_TYPES now has unlockRule: { kind: "default" }. The cleared-prerequisite chain is removed.

Bugs killed

  • Shopkeeper missing from Crypt / Void / Hellpit — the spawn gate read level.bossLevel from the LEVELS theme table, where Cave / Crypt / Void are flagged bossLevel: true for the legacy 17-floor rotation. Themed dungeons gate-skipped on every floor. Replaced with isCurrentFloorBossLevel() which reads dungeon.floorCount - 1 from the active dungeon definition.
  • Trees disappeared in the forest — the texture-pass swap replaced canvas-painted trees with PNG mushroom / log / vines, but the PNG pack ships no tree art so the canopy went flat. Trees come back via the canvas painters; PNG props layer underneath as ground-level dressing.
  • Shop tile was empty — the shop position only rendered the [E] prompt floating in air; no door, no sign, no merchant. Replaced with the full outpost dressing + NPC sprite.
  • "Coming soon" stub on shop press — the shop variant of HubFurnitureModal showed placeholder copy. Replaced with a short-circuit that opens the real shop modal directly.
v0.40.0April 27, 2026Feature

The Run Has an End

A themed dungeon used to descend forever. You'd kill the Forest's boss on floor 3, step on the stairs down, and find yourself on floor 4. Then 5. Then 6. The "completion" never registered, the next gate never unlocked, and there was no way back to the hub short of dying. This week the run actually ends.

Stairs down on the boss floor of a themed dungeon now check whether the boss is dead. Alive — the descent is gated with "Defeat the boss first." Dead — the screen fades, the run record posts as complete, and you're back at the meadow with the next-tier gate now lit. The unlock travels through the leaderboard pipe, so the Hall of the Fallen and the next dungeon's gate state both update.

The hub frame got bigger. The whole game window now fills the viewport (still inside the double golden border), the Phaser canvas renders at 1:1 to the screen instead of envelop-scaling a 640×480 letterbox, and the camera zooms 2× so sprites stay the chunky size they were. Net effect: the same hero, way more of the world visible at once.

Stamina has weight now. Sprint drains the bar twice as fast as before — the full pool empties in two seconds of running, not four. Heavy attacks cost 25 stamina, so you can't spam them in a sprint+heavy combo and never run dry. The exhaustion lockout that was supposed to gate sprint until 25% recovery actually works now (a threshold off-by-one let stamina bounce around 1 and re-engage sprint forever). And the cap itself now scales with VIT — every point of vitality adds 10 max stamina on top of a 50 base, so an endurance build can sustain more sprint windows + more heavy chains than a glass cannon.

The character sheet expanded — the stats / skill tree / trophies modal now stretches up to 1100 px or 80% of the viewport (whichever is smaller) so the trophy grid doesn't crush itself into a column of two on widescreen.

What landed

  • Run completion + unlock chain — themed dungeon final-floor stairs gate on boss death, fade-back-to-overworld submits the run as completed: true, leaderboard's recordDungeonClear registers the next-tier unlock.
  • Anti-cheat completion gate fixed — the legacy 17-floor rule flagged every themed-dungeon clear as invalid (Forest=3, Hellpit=5). Now reads floorCount - 1 from the dungeon definition; legacy / endless runs keep the 17-floor rule.
  • Scale.RESIZE + camera zoom 2× — game canvas matches its parent in real pixels, camera zoom keeps sprites visually 2× their native size; growing the chrome reveals more world, not bigger sprites.
  • Full-viewport chromePlayWindowChrome switched to flex column with the gameplay area as flex-1; the page itself is h-[100dvh] overflow-hidden. Decorative torch backdrop + PlayHeader + PlayFooter dropped — /game is just the nav and the game window.
  • HUD transparency — main status panel + multiplayer badge
    • HUD buttons dropped from bg-black/90 to bg-black/65; minimap from 0.85 to 0.55 with a 6px backdrop blur.
  • Character sheet width — modal grows to min(1100px, 80vw) instead of the old 560px cap.
  • Stamina drain doubled + heavy attack cost — sprint at 50/s (was 25/s); heavy attacks cost 25 stamina and gracefully fall back to a light swing when the pool is too dry.
  • maxStamina from VITbaseMaxStamina = 50 + vit * 10, recomputed on level-up and skill-unlocks; current stamina scales proportionally so a level-up bump doesn't snap the bar to "exhausted."
  • Save in overworld — new endActiveRun store action clears the dungeon tag + seed cache and flushes the save. Continue on a hub-state save now boots into Overworld instead of trying to resume a finished run.
  • Menu polish — WSAD navigation alongside arrows, Space + F confirm alongside Enter, and a session-pending gate kills the brief "Sign In" flash that appeared before the auth check resolved on returning logged-in users.

Bugs killed

  • Forest doors latched closed on revisit / forever-descending Forest — both downstream of the missing run-end. Floors past the declared depth were freshly generated each time with no cache; the player would assume "doors I opened are now closed." With the run actually ending at the boss floor, the issue doesn't surface in normal play.
  • Bridge stuck the player — the river-crossing gap is one tile wide and the player physics body was the same size, zero tolerance for diagonal drift. Body shrunk to 20×20 with a (6,6) offset.
  • Death modal was unclickable — the rank-reveal scrim inherited pointer-events: none from the GameHUD root and never opted back in. Same fix as gate cards last week — pointer-events: auto on .rr-scrim.
  • Sprint never actually exhaustedwantsSprintMove had a stamina > 1 threshold; stamina drained to ~0.7, sprint disengaged for one frame, regen ticked back to ~1.3, sprint re-engaged. Bounced forever, never hit 0, exhaustion flag never latched. Threshold is now > 0; exhaustion is set atomically when sprint drain clamps at 0.
  • Page crash returning to the hub — OverworldScene's class fields (gates / furniture / animSprites) only initialize on new, not on subsequent scene.start("OverworldScene"). The second hub entry was pushing new sprites onto stale-handle arrays. Game-level event listeners (enter-dungeon, gate-card-closed) were also stacking — anonymous handlers with no detach. Both fixed with explicit reset at the top of create() and named listeners that detach on SHUTDOWN.
  • Cross-run state bleed in dungeonsfloorCache + doorSprites weren't cleared on GameScene.create(), so a second run inherited the previous run's open-door / opened- chest snapshots on floors with the same numeric index.
v0.39.0April 26, 2026Feature

Walk the Shardrealm

The hub introduced last week was a flat green floor with five billboards. This week it's an actual place. Three times the size, nine biome zones, an east-west river you cross on plank bridges, mountain ridges along the north and west, ocean lapping at the south and east edges, a magma stream feeding the Hellpit's eastern bend.

You spawn in a meadow clearing. Walk south through long oak shadows lit by lanterns to reach the Forest Gate. West through stone rubble and rust-streaked boulders to the Ruined Halls. North past skull cairns and dead trees stitched with fog patches to the Crypt. East across cracked ground glittering with cyan-violet shards to the Void Rift. Far southeast, beyond a basalt-strewn plain that breathes ember haze, the Hellpit Caverns. The dirt path always points the way.

Your hero is normal-sized now. The gates are doorways instead of billboards. The map's about three times what it was, so you can't see all five from the spawn — finding them is part of the journey.

The hub furniture started doing things. Walk up to the memorial monument and press [E] to see your Hall of the Fallen — every hardcore character whose run ended badly. The lore stone pulses softly; press [E] and it tells you about the Shardrealm in your own language. The shopkeeper outpost is still empty — that's a future patch.

A minimap sits in the corner now. It paints the same biome washes as the world below, the five gates as theme-tinted dots, your position as a gold blip. The gate you're closest to pulses so you don't have to wait for the [E] prompt to know which dungeon you're about to commit to.

What landed

  • Overworld v2 — 96×72-tile map (~3× Sprint 36), nine biome zones, river, mountain ridges, ocean periphery, dirt paths, bridges, lava stream, prop scatter (trees / boulders / cairns / dead trees / shards / vents). All baked once into a single map texture so frame budget stays in dungeon territory.
  • Animated hub props — lanterns flicker (8fps), magma vents ember (8fps), void shards pulse cyan↔violet (4fps).
  • Terrain collision — water, mountain, lava, and ocean block movement; bridges punch walkable holes in the river and lava barriers so the dirt paths actually function.
  • Hub minimap HUD — top-right corner, biome-tinted, player blip with glow, last-visited gate highlighted.
  • Memorial / lore / shop interactions — [E] near each opens a popover. Memorial pulls your hardcore deaths from the run history. Lore stone reads the intro chapter inline. Shop is a stub for the cosmetics system.
  • Player + gate scale at 1× — Sprint 36 had everything at 2×, which made the hub feel like a billboard yard. The smaller hero in the bigger world reads as exploration.
  • Hub BGM — the forest theme plays in the meadow, fades out cleanly when you commit to a gate.

Bugs killed

  • Couldn't enter dungeons — the gate card popover sat outside the game frame because of how the modal scrim was anchored. Fixed; modal slides up inside the canvas now.
  • Modal was un-clickable — the same popover ignored mouse input on first ship because GameHUD's root overlay opts out of pointer events. Modal now opts back in explicitly.
  • Player stuck on the path to the Forest Gate — collision rectangles built from default-origin sprites were shifted 16 px and collapsed the bridge gaps over the river. Rebuilt with explicit (0, 0) origin so the bridges open properly.
  • Sprint never ran out — stamina ticked from 0 → 1 every frame, which immediately re-engaged sprint and effectively gave infinite stamina. There's now an exhaustion lockout: drain to zero and you have to recover to 25% before the bar lets you sprint again.
v0.38.0April 26, 2026Feature

Pick Your Descent

For 35 sprints, every run started the same way: hit New Game, pick a class, watch a random dungeon roll out underneath you. This week the meta-loop changed. After Class Select you now spawn in an Overworld hub — a peaceful forest clearing with five themed dungeon gates around it. You walk up to one, press E, and a card slides up showing the dungeon's name, difficulty stars, bestiary preview, your personal best, plus the difficulty + hardcore picker. Confirm and you drop into that dungeon's themed run.

Five dungeons, each one a coherent identity:

  • Emberwood Grove (T1) — easy entry, friendly bestiary, +20% gold drop. The starter.
  • The Ruined Halls (T2) — abandoned keep, balanced. Unlocks once you clear the Grove.
  • Sunken Ossuary (T3) — undead-heavy, +20% rare drop. Bones, dust, and a dry wind that whispers names.
  • Void Rift (T4) — caster-heavy, +30% epic drop. A tear in the world. Things still live here.
  • Hellpit Caverns (T5) — five floors, +50% legendary drop. Magma seeps from the walls. The trials end here.

Themes used to be a hidden randomness — different floor = different theme, no continuity. Now they're a strategic choice. Crypt run? Skeletons / mummies / necromancers, every floor. Void run? Wraiths and casters all the way down.

Each themed clear unlocks the next tier and grants an achievement (Cleared the Grove / Cleared the Ruins / Master of the Crypt / Survived the Void / Hellpit Conqueror). The leaderboard now scopes by dungeon too — every category you see can be filtered to just one dungeon's runs.

The death loop changes too. Used to be: die, restart same dungeon. Now: die, return to the hub, pick a different dungeon for the next attempt. The hub is your post-run home — a memorial monument tracks your fallen heroes, a lore stone hints at the world (more here in a future sprint), a shopkeeper outpost is a stub for cosmetics that'll come with their own sprint.

Multiplayer keeps its existing flow — room codes still drop parties straight into a run with random theme, no hub. The hub is single-player only.

What landed

  • Overworld scene at hub-entry — forest backdrop, 5 themed dungeon gates radiating from a center clearing, WASD walk, E approach prompt. Memorial monument + lore stone furniture. Animated gates: forest pulses 8fps, void rift swirls 12fps, hellpit embers 8fps, crypt haze 4fps, ruined static.
  • Gate Card popover — pixel-art header, theme accent, difficulty stars, bestiary preview, personal best, daily- challenge ribbon when applicable, run modifier picker, locked state with prereq hint. Esc closes; Enter confirms.
  • Themed dungeons — every floor of a themed run uses a single theme + curated bestiary + forced final boss. No more theme rotation per floor.
  • Per-account unlocks — clear a dungeon (any class, any difficulty) to unlock the next tier. Forest is unlocked by default. Anonymous players get every dungeon unlocked client-side; logging in syncs back to the server.
  • 5 new achievements for clearing each dungeon.
  • Leaderboard dungeon filter/leaderboard?dungeon=void scopes any per-run category to a single dungeon's runs.
  • Schema migration 0008_dungeon_typesrun_record gains dungeon_type_id; user_dungeon_unlock table tracks per-account progression.
v0.37.0April 26, 2026Feature

Plant Your Torch on the Wall

Every run you finish now lands on a global leaderboard. Eleven categories, four classes, four time windows, and a daily challenge where everyone runs the same dungeon. The deepest descent, the fastest clear, the biggest crit, the meanest hardcore death — there's a niche on the wall for whatever your play style is.

The new home is /leaderboard. Eleven category pills across the top — Deepest Floor / Fastest Clear / Longest Run / Kill Count / Gold Earned / Highest Level / Legendaries Found / Biggest Crit plus three per-account aggregates (Achievements, Total Boss Kills, Total Runs). Filter by class, flip on Hardcore Only, scope by time bucket (All-Time / This Month / This Week / Today). Top 3 sit on a podium with tier-tinted glow — gold for #1, silver for silver, bronze for bronze — and ranks 4–50 fill the table below. Every filter combo lives in the URL, so sharing a deep-link is just copy-paste.

Your public profile page at /u/<you> got a new section called Best Ranks, slotted between Featured Character and Stats. It shows your top 3 strongest categories — class-tinted card per rank, big pixel rank number with a rarity tier dot, "Top 50"-style badge in the body. Hover lifts the border to gold and reveals a "View on leaderboard →" CTA. If you haven't ranked anywhere yet, the section folds into a single dashed CTA pointing back to /game.

Right after every run — death or victory — a modal slides in showing where you placed. Run summary on top (floor, level, kills, duration), then the rank reveal block tinted by tier: gold for top 3 with a Trophy podium glyph, silver for top 10, bronze for top 50, no glow past 50. #1 specifically fires a one-shot gold flash overlay the frame the rank lands. Auto- dismisses after 8 seconds; hover or focus pauses the timer; Esc closes immediately. Anonymous players see a "Sign in to claim this rank" CTA instead — the run is cached locally and back-ranked at first login, so nothing is lost.

And the Daily Challenge — a deterministic seed derived from today's UTC date. Click "Play Today's Daily" on the leaderboard and you'll start a run with the same dungeon every other player gets today. Toggle "Daily Only" to scope the leaderboard to runs that used today's seed. Resets at UTC midnight; live countdown on the tile.

What landed

  • /leaderboard page — 11 categories × 4 class filters × 4 time buckets × hardcore on/off. Sticky filter bar, podium top-3 with tier-tinted glow, table 4–50 with zebra rows + class accents
    • "YOU" badge for your row. Public — no login required to browse.
  • Profile rank widget at /u/<slug> — top 3 best ranks card grid between Featured and Stats. Class-accent borders, tier dots (legendary / epic / rare / uncommon / common), placeholder cards fill empty slots, full-width empty state with /game CTA when no ranks claimed.
  • End-of-run rank reveal modal — slides in over the death / victory screen, summary stats + tier-tinted rank reveal + Beats X% subtitle. Auto-dismiss in 8s, Esc closes, hover pauses.
  • Daily Challenge — deterministic seed-of-the-day, "Play Today's Daily" CTA, "Daily Only" filter, live UTC-midnight countdown. Same dungeon for every player, every day.
  • Anonymous run capture — runs played without login still get cached locally and submit on next sign-in, so anyone who plays before signing up doesn't lose their first wall-plant.
  • Privacy mask on rankings — players with profile visibility off appear as (private) in the leaderboard. Their rank still counts; only the link to /u/<slug> is suppressed.
v0.36.0April 26, 2026Feature

Your Name on the Wall

We've spent a sprint giving every player a public address. You can now claim a username, point people at aot-game.com/u/<you>, and the page that loads will pull together everything you've earned — your active run, your fallen hardcore characters, your trophy shelf, your class breakdown.

Claim happens in Settings → Profile. Pick a name (3–20 chars, letters / digits / underscore), watch it light up green when it's free, hit Claim. You can rename later — the URL changes immediately, the old slug becomes available for someone else, and that's fine. There's a switch right under it for "Show publicly" if you'd rather keep the page off the open web; flipping it off turns /u/<you> into a 404 for visitors but leaves your username in the lobby intact.

The profile page itself is built like a torch-lit memorial: header with the @username in pixel font, a Featured Character card showing your deepest live run with class-tinted accents, a stats row (total characters, deepest floor, highest level, hardcore falls), the trophy grid sorted by category with rarity-tinted borders and hover descriptions, your time-per-class breakdown if you've played more than one, and finally a Hall of the Fallen collecting your hardcore deaths as cards — names, levels, deepest floor, in death-order. Hardcore deaths are wins on this page; that's the deal.

Discovery loops back through the multiplayer browser. Every host nick in the lobby with a public profile is now clickable — opens the trophy hall in a new tab so you don't lose your place in the room list. Anonymous hosts and private profiles render as plain text, same as before.

What landed

  • Public profile pages at /u/<username> — server-rendered, pulls aggregate stats + achievement unlocks across all your save slots, plus a Hall of the Fallen for past hardcore characters.
  • Username claim flow in Settings — live availability check (300ms debounced), bilingual EN+PL validation messages, optimistic visibility toggle. Rename allowed (URL changes; old slug freed).
  • Lobby linking — host nicks in the room browser link to the host's public profile when they have one. Privacy switch on the host side hides the link cleanly.
  • Reserved usernames — system routes (admin, api, dashboard), brand words (adventure, trials, aot), and a small set of generic noise (null, system, support, etc.) won't claim. Class names are fair game — Warrior_42 is yours if you want it.
v0.35.0April 26, 2026Feature

Mouse Is Now Optional

The previous patch landed heavy attacks on hold-LMB only — which quietly meant Sprint 33's whole keyboard-first push fell apart the moment you wanted to charge a swing. Mouse mandatory, just for the heavy. Fixed.

Hold Space for heavy melee. Hold F for charged ranged shots. The 200ms threshold cleanly separates a tap (light attack) from a hold (class heavy — warrior cleave / archer charged shot with a 2-enemy pierce / mage channeled bolt with 40px AoE). Mouse LMB still works for players who prefer it; nobody loses anything.

We also caught up the onboarding so the new verbs are actually discoverable. The chrome footer under the canvas now shows Shift / F / G alongside the WASD / Space row it had since v0.30. The first-run tutorial got the same treatment — the cheat-sheet modal lists Shift (dash / sprint), G (class ability), and Space / F now read "hold = heavy" inline. Existing players will see the updated tutorial again on next session, since we bumped the "already seen" gate.

And one corner-case fix: the camera used to clamp flat against the map edge, which meant if you walked into the top-left corner of a floor your character ended up directly under the HP / stamina HUD cluster. The camera now keeps panning a little past the map rect when you reach an edge, exposing the dungeon-black void where the HUD lives instead of hiding tiles you actually need to see.

What landed

  • Hold-Space / Hold-F for heavy attacks — 200ms threshold, same dispatch as hold-LMB (per-class heavy variant). Tap behaviour unchanged: Space still fires the regular swing, F still fires the regular shot.
  • Tutorial cheat-sheet refreshed — added Shift, G rows; folded the heavy-attack hint into the Space / F labels. Tutorial gate bumped so existing players see the new sheet on next login.
  • Chrome footer keys updated — added Shift, F, G to the desktop keybind row. Inventory pill dropped from the row to keep it from spilling on narrower windows (Inventory still in the in-game button cluster).
  • HUD-safe camera padding — camera bounds extended 6 tiles beyond the map rect on every side. Walking into a corner no longer parks tiles behind the HP / stamina overlay. Physics world stays at the real map size — entities can't actually leave the playable area.
v0.34.0April 25, 2026Feature

Now It Looks Like You Mean It

Last patch gave you dash, sprint, heavy attack, and a stamina bar. This patch finally makes them look like the things they are.

Sprint used to mean "the walk anim, but faster." It now plays a dedicated 12fps run cycle per class — bigger stride apex, real forward lean, an air-frame where both feet are off the ground, plus the kind of class flair the rest of the game has been carrying: warrior dust puffs at the rear foot, archer hood flick + quiver bounce, mage robe billow with a violet glimmer trailing the back foot. You'll see the difference the moment you hold Shift.

Dash and heavy attack got the same treatment. Each class sheet grew eight new frames per direction: three for the dash burst, two for the heavy wind-up loop, three for the release follow-through. Warrior shoulders into the dash with sparks. Archer's body shifts opposite to the bow, hood trails behind. Mage briefly dissolves into a dithered ghost of itself before re-forming. The heavy back-cock visibly pulses while you hold LMB — release fires the swing / loose / bolt as a real animation, not the regular attack swap-out.

The stamina bar also stopped being inert. It now reads what it's actually doing — a soft 1.5s shimmer band sweeps when you're refilling, a backward wind-flicker streams past the trailing edge while sprinting, the whole bar warm-pulses to amber under 25%, and hitting zero flashes the frame red for 400ms before settling into a striped lockout pattern. A boot sigil on the left, a dash-ready pip on the right, and tick marks at 25 / 50 / 75% reveal as the fill recedes past them.

A few mechanical follow-ups landed quietly alongside the art:

What landed

  • Run cycle sprites — three new sheet_sprint.png files (one per class), 4 directions × 4 frames at 12fps. Walk stays at 8fps for non-sprint movement.
  • Dash + heavy attack sprites — base sheets extended from 320×128 to 576×128. Cols 0–9 unchanged (idle / walk / attack / hurt); cols 10–17 add dash burst (10–12), heavy wind-up loop (13–14), heavy release (15–17).
  • Stamina HUD polish — boot sigil, dash-ready pip, threshold ticks, and four animated states (refill shimmer, sprint flicker, low pulse, exhausted lockout) all driven from live values, no per-frame JS.
  • Dash on Shift release, not press — first version dashed the moment you tapped Shift, which meant every "I want to sprint" burned 35 stamina on an unwanted dash. Now: tap (under 200ms) = dash; hold past 200ms = sprint engages. Quick double-tap still chains two dashes.
  • Sprint actually drains stamina now — the throttle gate on the stamina setState was 0.5, and per-frame sprint drain at 60fps is 0.42. Every frame of drain was getting filtered out, so sprint visually engaged but the bar never moved. Drop the gate, sprint drains as designed.
  • Closed doors finally stop arrows — the projectile-vs-door check was checking the wrong grid (pathfinding 0/1 instead of the TILE enum), so doors never registered as solid. Walls were fine by coincidence (TILE.WALL === 1). Read door state from the actual sprite map. As class flavour: archer's volley sails through closed doors, normal arrows don't.
  • Hydration error squashed — mute button + stamina bar were both reading state set from localStorage / performance.now() on first render, which mismatched server vs client.
v0.33.0April 25, 2026Feature

Dodge, Run, Hit Harder

Combat used to have one verb: attack. You walked toward the thing, you hit the thing, you walked away. We've spent this patch giving the player more verbs.

Shift is the big one. Tap it and you dash — a quick burst in the direction you're moving, with i-frames so the slime that was about to land a hit ends up biting air. Hold Shift and you sprint at 1.5× speed. Both pull from a new stamina bar that sits between HP and XP, refills while you stand still, refills slower while you walk, and empties faster than you'd like when you panic-spam Shift in a corner.

Each class flavours their dash differently. Warrior charges — 50% weapon damage on the first thing your shoulder meets, plus a stagger they need a moment to recover from. Archer backsteps — always opposite the way you're facing, with a +30% range buff on the next arrow so you can keep your distance. Mage blinks — longer, faster, hungrier in stamina cost. Worth it.

Hold left-click for a heavy attack. Warriors cleave a 90° arc and hit up to three enemies at once. Archers charge a shot that does double damage and punches through two enemies in a line. Mages channel a bolt that detonates with a small splash on impact. The trade is movement — while you're charging, you're at 60% speed, and anyone with a ranged attack will use that against you.

And finally, the mouse is now optional. Movement-based facing was forcing keyboard players to think about cursor position they couldn't see. Now offensive actions auto-target the nearest enemy in range unless you've moved the mouse in the last second — meaning a keyboard-only run finally plays like a keyboard-only run instead of "WASD plus invisible aim".

What landed

  • Dash + sprint on Shift — tap dashes 96px (3 tiles) in the movement direction with i-frames; hold sprints at 1.5× base speed.
  • Stamina bar — green slim bar between HP and XP. 100 cap, 30/s regen while moving, 60/s standing still, 25/s drain while sprinting.
  • Class-flavored dashes — Warrior shoulder charge (+50% ATK on contact + stagger), Archer backstep (always opposite of facing
    • 0.6s focus window for +30% arrow range), Mage blink (4 tiles in the same window, costs 1.5× stamina).
  • Heavy attack on hold-LMB — 400ms charge, 1.5s cooldown, 60% movement speed during wind-up. Class variants:
    • Warrior cleave — 90° arc, hits up to 3 enemies, 1.5× ATK.
    • Archer charged shot — 2× ATK, pierces 2 enemies in line, longer range.
    • Mage channeled bolt — 1.8× ATK, 40px AoE on impact.
  • Aim-decoupled facing — sprite faces cursor (or auto-target) for 500ms after each offensive action, so you can WASD-backpedal and keep arrows aimed at the enemy chasing you.
  • Auto-target nearest enemy — keyboard-only players: SPACE for melee, F for ranged, G for ability now all dispatch toward the nearest enemy in 250px without needing the cursor. Mouse still wins when you've moved it in the last second.
  • Character sheet tabs — Stats / Skill Tree / Trophies split into three tabs (1/2/3 to switch, Tab cycles, Esc closes). Skill tree finally has the modal width to itself.
v0.32.1April 25, 2026Hotfix

The Shopkeeper Remembers He Has a Shop

It turns out the shopkeeper was only really committed to the first shop he opened. After that, the dungeon kept generating his shop room — counter, rug, shelves, the whole setup — but the man himself wasn't there. Walk back to a floor where he greeted you ten minutes ago? Empty. Descend to a brand new shop floor? Also empty.

Fixed. The spawn was tied to the enemy spawn pass, which gets skipped when you re-enter a floor you've already cleared. So the shop room loaded, the props loaded, and then the part that places the shopkeeper quietly didn't run. He now spawns on every entry to a shop floor — first visit, tenth visit, doesn't matter.

What landed

  • Shopkeeper present on every shop floor — both first-time visits to new shop floors and revisits to cleared shop floors. He's also back where you left him on a floor you already cleared.
v0.32.0April 24, 2026Feature

The Dungeon Starts Talking

This patch doesn't change how the game plays. It changes what the game knows about itself.

We finally wrote down the Shardrealm. There's a proper intro chapter at /lore now — the Rift, the seventeen floors, the shop that's always open whether or not its keeper has been home. It's short, on purpose. The dungeon explains more of itself the deeper you go, and we don't want to ruin that on page one.

We also wrote the first handful of bestiary entries. Slime, Goblin, Skeleton, Imp, the Stone Golem on floor three, the Trialmaster on six. Each one is one paragraph of what this is and one line of what the dungeon wants you to learn from it. Sixteen more entries to go; they'll keep showing up.

Quietly, in the same patch: every public release from v0.19 to v0.26 has a Polish translation now. The last three already did. Full backfill closes the gap, so a Polish reader opening /changelog on release day gets the whole timeline in their language.

And then on top of everything else, the enemy death animations landed. Every kill now plays a three-frame stagger → collapse → dust sequence before the sprite fades. It's a tiny change per kill, and genuinely a big one over a whole run.

What landed

  • Lore intro chapterThe Shardrealm / Kraj Odłamków at /lore, both languages.
  • Bestiary entries — six enemies with proper flavour prose (Slime, Goblin, Skeleton, Imp, Stone Golem, Trialmaster), EN + PL each.
  • Polish changelog backfill — every public release v0.19 → v0.26 now ships a .pl.md alongside the .en.md.
  • Enemy death animations — 22 enemies + 3 bosses each get a three-frame death sequence (stagger → collapse → dust) before the sprite fades.
v0.31.0April 24, 2026Feature

One Life, One Keyboard

Two kinds of players asked for this patch. The ones who want the run to matter more. And the ones who, on principle, refuse to touch a mouse.

For the first group: Hardcore mode is a new toggle on the New Game screen. Flip it and your character gets one life. Die in a hardcore run and the slot turns into a tombstone — a Permanent chip, greyed-out tile, Continue disabled. The save stays in your slot list as a record of how that one ended, which is either a trophy or a note for next time. Both useful.

For the second group: every menu in the game is keyboard-driven now. Character select responds to arrow keys, Enter, Del, F2 (rename), N (new), and Esc. The class / difficulty / hardcore picker cycles the full ladder with ↑↓. The shop modal switches tabs with 1 / 2 / 3 or Tab and closes with Esc. Inventory closes with Esc. The main menu already knew the trick — Sprint 27 taught it. Now everything else matches.

Two quieter wins came in the same patch:

  • You can rename slots now. Rename button, F2, or double-click the name. 24-character cap.
  • Anonymous saves migrate to your account on login. Sign in with characters in your browser and you'll get a one-shot prompt: import them or not. We ask before we touch anything.

What landed

  • Hardcore mode — per-save permadeath toggle on New Game; dead hardcore slots get a Permanent chip and Continue locks them out.
  • Full keyboard navigation — character select, class picker, shop, inventory, all responsive to arrow keys, Enter, Esc, and context hotkeys (F2, N, Del, H, 1-3, Tab).
  • Slot rename — inline editing on every character tile, with matching server + localStorage validation (1–24 chars).
  • Anon → account promotion — one-shot confirm prompt on login imports your browser-local characters into your cloud account.
v0.30.0April 24, 2026Major

Three Spells and an Actual Tree

The skill tree was a tree the way three potted shrubs in a row are a forest. We've planted a real one.

Every class now branches from a shared root into three gateways, and tier 2 forces an either/or — Berserker or Duelist, not both. Two Warriors in the same party will no longer look identical. Capstones demand points spent in the branch. The grand capstone at the top of each tree wants two of three branch capstones and the active ability. Specialists and generalists finally reward differently.

Speaking of: every class has an active ability now, bound to G. Warriors get Shield Bash — 90° cone, 2× damage, guaranteed knockback and a short stun. Archers get Volley — three arrows in a 30° fan. Mages get Fireball, which does exactly what you'd hope, on a 64px radius.

The ability node has cross-branch prerequisites. You can't blitz one branch and grab the spell on the way through. Warriors need offense AND defense; Archers need precision AND volley; Mages need elemental AND arcana. The spell is a hybrid build's reward.

A few notes for the eagle-eyed:

  • Old saves carried their unlocked nodes over wherever the ids matched. Anything that didn't match came back as a free skill point. Call it a mid-patch respec, on us.
  • The new dial next to your XP bar is the cooldown. Pie fills while cooling, glows gold when it wants to be cast.

What landed

  • Skill tree rebuilt — root → gateways → XOR choices → capstones → ability → grand capstone. Every class now has ~15 nodes laid out as a real graph, not three stacked lists.
  • Three active abilities — Shield Bash, Volley, Fireball, on G, one per class, all gated behind the cross-branch ability node.
  • Cooldown HUD dial — class-themed icon plus a radial fill that pulses gold on cast-ready.
  • Cross-branch build incentives — abilities want two specific gateways; the grand capstone wants two of three branch capstones plus the ability. Pure-branch sprints stop paying off here.
v0.29.0April 24, 2026Major

The Chronicle Itself

You're reading it. This page used to be a big JSX file we edited by hand every release, which worked fine until we realised we'd been writing patch notes in TypeScript. We've demoted it to a pile of markdown files, and, while we were at it, gave it a voice.

The entries you're scrolling through are all freshly rewritten. Same facts, less "we added an active character ID field to the zustand store", more "scrap your save, cry, start over." We also taught the page Polish — hit the PL toggle in the nav and everything adapts.

Behind the scenes, a little script ferries our internal sprint notes through Claude to produce a public draft we then edit into shape. So next time we ship a patch, the note will be this voice without one of us staying up to hand-craft it.

What landed

  • Markdown-driven changelog — entries live as files under content/changelog/ so we (and contributors) can write in prose instead of JSX soup.
  • Fresh voice pass — every historical entry rewritten in the new register. Same facts, more personality.
  • Polish translations — for the last two releases so far, more coming as we backfill.
  • Drafting helper — internal tool that converts Sprint notes into public drafts. We still edit. Claude just gets us to 60%.
  • Lore scaffold — the infrastructure for a future lore + bestiary pass is in place. Doesn't change anything you see today, but the next world-building patch won't need a refactor to ship.
v0.28.0April 24, 2026Feature

The Shop, Fully Open

Our shopkeeper used to be a gold-tinted copy of the player. He didn't move. He didn't blink. He sold you potions in grim silence. We've intervened.

He now has his own sprite, his own robe, and a part-time job: wandering between the counter, the shelves and the potted plant, stopping to inspect each one as if he forgot something. He also waves when you walk up, which is either charming or deeply unsettling depending on how long you've been in the dungeon. The shop itself finally looks like a room someone works in — counter, shelves, barrel, iron-bound chest, a warm brass lantern that actually flickers, and a rug so he has something to stand on.

The door got upgraded too. Heavy oak, brass kick-plate, OPEN banner hanging over it. Monsters can't follow you in any more — the barrier holds whether the door is open or not, which, yes, we know, makes no physical sense.

What landed

  • A proper shopkeeper — idle breathing, faces whoever walks up, waves on approach, strolls between decor when you're not looking.
  • Shop interior — counter, shelves, barrel, chest, rug, potted plant, lantern with a warm additive glow. Same glow now lights wall torches everywhere too, because it turns out we could have been doing that all along.
  • Enemy barrier at the door — goblins try, goblins fail.
  • Identification reveal toast — a properly-sized card tells you what you just bought, what it does, and why you paid 50 gold for the privilege. Replaces the previous "silently mutate the item in your bag" experience.
  • Stable shop modal — Buy / Sell / Identify tabs no longer trampoline the modal height when you switch between them.
  • Dedicated shop BGM + SFX — a cozy tavern-style loop fades in when you cross the threshold. Door swings have a proper creak and a bell.
v0.26.0April 23, 2026Balance

Pick Your Pain

We shipped the audio pass, ran a playtest, and immediately noticed half of you were dying on floor 1. Not a difficulty curve, a vertical wall. So the dungeon now asks before you start: Easy, Normal, or Hard.

Easy adds 30% HP and cushions incoming damage by 20% while enemies hit back for less — "a bit of a holiday". Normal is what we originally tuned for. Hard sharpens enemy hits and cuts your gold and XP by 10% — for the repeat customers who'd decided Normal was comfortable.

You can change difficulty mid-run in Options too. Your HP ratio is preserved, so a Hard → Easy swap at 20/100 stays proportional on the new max.

What landed

  • Three presets on New Game: Easy, Normal, Hard — each affects player HP, damage taken, enemy HP + damage, and gold/XP gain.
  • HUD chip — a coloured badge next to your level shows the current preset (Normal hides it — you're in the baseline).
  • Live switch — change difficulty from the pause-menu Options without quitting the run.
v0.25.0April 23, 2026Major

Something to Listen To

The dungeon sounded like a synthesiser for most of its life. In this patch we commissioned 8 original BGM tracks (one per theme plus boss music), 39 SFX one-shots, and a dedicated menu loop. Every swing of a sword, every potion gulp, every footstep — rendered properly instead of the placeholder bleeps.

Footstep volume is attenuated because Suno mastered them hotter than everything else and you could hear the Warrior coming from three rooms away. Separate music / effects sliders landed in Options too, saved per device.

What landed

  • 8 themed BGM tracks + alt takes + menu theme — dungeon, sewer, cave, forest, ice, crypt, void, boss. Triggered from theme keys so the right track plays on the right floor.
  • 39 new SFX across hits, picks, UI, and combat — pooled with random variants so rapid attacks don't sound like one sampler.
  • Music / SFX split sliders — Options → Pause menu. Device- scoped localStorage, 0.5 default.
  • Multiplayer fix (while we were in there) — classes and sprites finally sync between clients. Pause Escape twice no longer keeps you paused forever.
  • Torches rework — every lantern hangs on a wall now (no more torches floating in the middle of rooms), and decorative torches no longer spawn as random dungeon props.
v0.24.0April 23, 2026Feature

Knockback and Shareable Seeds

Two small things that nobody explicitly asked for and everyone started using immediately.

First: enemies now fly backwards when you hit them. Weapon classes and Strength scale it, bosses resist it, slimes travel surprising distances. It turns melee from "clicking until dead" into a little physics conversation.

Second: run seeds are shareable. Every New Game now rolls a seed, and the pause menu has a Copy Link button that packages your current dungeon into a URL. Send it to a friend and they get the same floors. Nice for races, co-op, or bragging about the legendary you found on floor 2.

What landed

  • Knockback — new weapon stat, scales with Strength, resisted by elites/bosses at 0.3–0.8×. Hits now have weight.
  • Run seeds — rolled on New Game, persisted through the run, visible in the pause menu.
  • Seed share — Copy Link button bundles the current run into a ?seed= URL. Paste in the browser, same dungeon spawns.
  • URL seed pre-load — visit a shared link and the dungeon is already waiting for you on New Game.
v0.27.0April 22, 2026Feature

One Hero Isn't Enough

You rolled a Warrior, got to floor 5, then wondered — reasonably — how an Archer would play the same dungeon. The old answer was: scrap your save, cry, start over. We have prepared a more dignified answer.

Up to 5 save slots per account. One per class, per difficulty, per mood. Continue now opens a grid of little character cards — class emblem, level, difficulty chip — and you pick which run you're in the mood for. New hero? "+ New Character" tile, same screen.

Guest runs get slots too, stored on this device. Log in whenever you feel like making them permanent.

What landed

  • 5 save slots — per-character saves with class emblem + level + difficulty on the card.
  • Character picker — Continue opens the slot grid; pick one or start a new hero from the same screen.
  • Anonymous slots — guest runs get local slots on your device. Login migration coming.
  • Autosave routing — switching characters no longer overwrites your other hero's progress, which, yes, used to happen.
v0.23.0April 22, 2026Major

Three Ways to Die

Before this patch, every hero was the same person wearing a different hat. We've introduced Warrior, Archer, Mage — three actual classes with distinct starting attributes, different weapons, and a skill tree each.

Warrior is bulky and hits hard; starts with a rusty sword. Archer is fast and precise; starts with a bow. Mage is fragile but ferocious; starts with a wand. Each class has its own icon, its own player sprite (freshly commissioned pixel art), and 12 skill nodes you can unlock with level-up points across three branches per class.

Also: new tile pack landed, so the dungeon visually reads better — seven themed floor textures with matching wall tiles and scattered props (mushrooms, coffins, pipes, crystals, depending on the theme).

What landed

  • Three classes — Warrior, Archer, Mage — with unique starting attributes, starting gear, and per-class skill trees.
  • Player sprites — proper pixel-art class spritesheets replacing the placeholder knight everyone used.
  • Skill tree — 12 nodes per class across three branches. Spend your level-up points, respec isn't a thing (yet).
  • Tile pack v2 — 7 themed floor + wall sets with procedural props. The dungeon no longer looks like one beige room 17 times.
v0.21.0April 22, 2026Feature

Gold Stars for Dying Creatively

Achievements are in. 26 of them to start. A toast pops in the top of the HUD when you unlock one — First Blood, Level Five, Full Gear Set, Full Strength Build, and more specific ones we won't spoil here.

They sync between devices for logged-in players and fall back to local storage for anon runs, same pattern as saves. No badges to show off yet — that's on the roadmap — but the system tracks everything so the profile showcase is ready whenever we ship it.

What landed

  • 26 achievements across progression, gear, combat, and exploration milestones.
  • Toast notifications — top-center slide-in with the unlock name, auto-dismissed after 4s.
  • Cross-device sync for logged-in players; localStorage for guests.
v0.22.0April 20, 2026Feature

Seven Dungeons' Worth of Wallpaper

The dungeon used to be one tileset with the hue swapped. This patch brings a proper 7-theme rotation: Dungeon, Sewer, Cave, Forest, Ice, Crypt, Void. Each theme has its own floor texture, wall texture, atmospheric palette, and themed props (mushrooms in the forest, skulls in the sewer, ice crystals where you'd expect).

Boss floors still land every three floors, but now they use the matching theme's boss variant — so the Cave boss fights in a cave, not in a generic dungeon box.

Props are procedural scatter: each room gets a random-but-bounded selection so two adjacent floors don't look identical.

What landed

  • 7-theme rotation — Dungeon → Sewer → Cave → Forest → Ice → Crypt → Void, cycling every floor % 7.
  • Themed props — per-theme prop pool (forest has mushrooms, crypt has coffins, sewer has pipes, etc.). Scattered per procedural seed so re-running the same seed reproduces the layout.
  • Boss themes — boss floors inherit the current theme's palette and prop set. No more Crypt boss in a Dungeon room.
v0.20.0April 20, 2026Major

Turning Out the Lights

The dungeon got dark. Properly dark. Every floor now runs a field- of-view pass — you only see what your hero can see, with the rest gradually dimming into black. Lanterns hang on walls and cast actual light, each with its own pre-computed FOV so closing a door containes the glow to its room.

On top of that we ran the HUD v5 pixel-vocabulary rewrite — the top bar, the shop modal, the inventory, the character sheet, all redone in a consistent pixel aesthetic. The menu got a matching upgrade. Everything now looks like it belongs in the same game.

Content also got a fresh pass: more items, more enemies, more floor layouts, and translations for the whole interface (English + Polish so far, more to come).

What landed

  • Lighting / FOV — per-player shadowcast, per-lantern FOV bitmap, darkness overlay as a render texture.
  • Lantern placement — generator hangs one on every shop + boss room guaranteed; other rooms get them by chance with wall- adjacent placement.
  • HUD v5 — full pixel-art reskin of every HUD surface (top bar, modals, menus, tooltips).
  • Content expansion — more items, more enemies, more room variety.
  • i18n — EN + PL throughout the UI, with a locale switcher in the navigation.
v0.19.0April 18, 2026Launch

Everything That Came Before

We've been making this for a while. Before we started the public changelog, nineteen sprints had already landed — everything from "can a goblin walk" to a working level editor with community maps.

Rather than backfill each one individually, here's the consolidated story of the first nineteen sprints. The game you're looking at existed, in some form, by April 18th 2026 — that's when the public design pass finished and we started writing these notes properly.

What came before

  • Core game loop (Sprints 1–9) — player movement, enemies, inventory, shop, items, procedural floors, keys, stairs. The dungeon-crawler bones.
  • Boss fights + deploy (Sprint 10–11) — every third floor ends on a themed boss; game goes live at aot-game.com.
  • Multiplayer (Sprints 12–14) — up to 4 players in the same dungeon, lobby + room browser, sync polish. Drop-in, drop-out, cross-device.
  • Attribute system (Sprint 15) — STR/DEX/VIT/PER/LCK, points from level-ups, derived stats on equipment.
  • PWA (Sprint 16) — installable on phones and tablets, works offline after first load.
  • Virtual joystick (Sprint 17) — touch controls for mobile players. The on-screen thumb pad.
  • Level editor (Sprint 18) — build your own dungeons in the browser, share them with other players.
  • Community maps (Sprint 19) — browse + rate + report custom maps built in the editor. Moderation queue for admin.

Every release from here on has its own entry.