explodorama / files / README.md
README.md
e3384c6b 2026-10-24 Pavel Safronov | 1 | # EXPLODORAMA! |
5551eb37 2026-10-20 Pavel Safronov | 2 | |
b89399da 2026-11-01 Pavel Safronov | 3 | **[▶ Play now!](https://apps.fuzzyworld.net/explodorama/)** — in the browser, on a phone or a computer.\ |
| 4 | **[⏩ Try the next version](https://apps.fuzzyworld.net/explodorama-next/)** — what is coming, built from `main`; may have rough edges. | |
b73dd422 2026-10-20 Pavel Safronov | 5 | |
3321c921 2026-10-27 Pavel Safronov | 6 | A turn-based, mobile-first, rogue-like take on the 1985 NES bomb-laying classic. Every bomb |
5551eb37 2026-10-20 Pavel Safronov | 7 | counts down with *your* moves, so nothing happens until you act — and you can see exactly |
| 8 | what will burn before you commit. | |
| 9 | ||
565a6873 2026-10-25 Pavel Safronov | 10 | Status: **early development.** The board, bombs, lives, seven enemy types, coins, all |
d3e4ed26 2026-10-25 Pavel Safronov | 11 | seven charges (one carried at a time, used when you choose), a hidden gem on every level that offers a choice of power-ups, the shop every 3rd level, the exit, the 20-level run with its ending, sounds and vibration, and saving |
565a6873 2026-10-25 Pavel Safronov | 12 | mid-run work. Curses and the Reaper enemy are planned — |
27f24fed 2026-10-20 Pavel Safronov | 13 | see [PLAN.md](PLAN.md). |
5551eb37 2026-10-20 Pavel Safronov | 14 | |
805e7a9f 2026-11-03 Pavel Safronov | 15 | Version: **0.2.0** (semver; 0.1.0 was the base release). The menu's bottom line shows it with the rules |
5607bea2 2026-10-31 Pavel Safronov | 16 | version and the commit the game was built from (a link to it on GitLab, plus "plus local |
| 17 | changes" in a build with uncommitted changes) and a link to the | |
805e7a9f 2026-11-03 Pavel Safronov | 18 | [source code](https://code.fuzzyworld.net/explodorama/). Tapping the version, or the menu's Changes button, opens the list of |
5607bea2 2026-10-31 Pavel Safronov | 19 | changes in every release, each with its date and, for most, a demo scene. A player who comes |
| 20 | back on a newer version is shown what came after the one they last played (kept in this | |
| 21 | browser's localStorage) when the opening demo ends; a first visit, and a test URL, show nothing. Releases are git tags, made when Pavel decides a batch is ready; between | |
| 22 | them, finished changes collect in `UNRELEASED` in [src/changelog.ts](src/changelog.ts), and | |
| 23 | tagging moves them into a new release there and bumps `version` in package.json. | |
| 24 | ||
bb3823d2 2026-10-31 Pavel Safronov | 25 | **Two copies:** the released game (`/explodorama/`, built from the latest git tag) and the **next** |
| 26 | copy (`/explodorama-next/`, built from `main`: tab title "EXPLODORAMA! (next)"). Deploy the | |
| 27 | released one with `npm run deploy` (the latest git tag) and the next one with | |
b89399da 2026-11-01 Pavel Safronov | 28 | `npm run deploy:next` (needs fuzzyworld-tools with `--as`). The menu opens with a box saying which |
| 29 | version this is (**Official** or **Early adopter**) and a button to switch to the other, with both | |
| 30 | addresses (`homepage` and `nextHomepage` in package.json, through vite.config.ts into | |
| 31 | [src/channel.ts](src/channel.ts)). A released copy only has the button, **Try it early** link and | |
| 32 | teaser once it is built from a tag that includes them (0.2.0 or later). They share an | |
bb3823d2 2026-10-31 Pavel Safronov | 33 | origin, so every localStorage key is per copy (`storageKey` in [src/channel.ts](src/channel.ts)); |
b89399da 2026-11-01 Pavel Safronov | 34 | only `explodorama.earlyRuns` is shared. The released copy also has a |
bb3823d2 2026-10-31 Pavel Safronov | 35 | **Coming next** list; runs finished on the next copy are marked **Early adopter** on its board. |
| 36 | Developer mode is separate and can be switched on in either. | |
| 37 | ||
92cc4ee3 2026-11-02 Pavel Safronov | 38 | Rules version: **43** (`SIM_VERSION` in [src/sim/record.ts](src/sim/record.ts)). It goes up by one |
5607bea2 2026-10-31 Pavel Safronov | 39 | whenever a rule change would make an old run replay differently, independent of the release |
| 40 | version (one release can span several). A run saved under another rules version is not resumed, | |
| 41 | and a seed gives the same dungeon only within one rules version. | |
0b25f1ef 2026-10-24 Pavel Safronov | 42 | |
5551eb37 2026-10-20 Pavel Safronov | 43 |  |
| 44 | ||
| 45 | ## How to play | |
| 46 | ||
52d68b59 2026-10-24 Pavel Safronov | 47 | **The demo:** when the game opens, it first plays a demo — short scenes made up on the spot from |
0bfdc8e6 2026-10-25 Pavel Safronov | 48 | the real rules, each with a caption and an icon. The screen reads top to bottom: the title |
| 49 | **EXPLODORAMA!**, the TV with the scene, then the caption; both the title and the caption go | |
| 50 | once the game starts. Each scene gets to its point quickly: what it is | |
b8849d36 2026-11-01 Pavel Safronov | 51 | about happens 3 to 6 turns in (more for a moment that takes longer to come, like rubble, with a turn or two after it), starting from a calm board (no bomb or flame yet). **A finger shows |
36c5d6a2 2026-10-24 Pavel Safronov | 52 | the controls** as it plays every turn, on the real action bar (it sits right under the board, |
| 53 | apart from the caption at the bottom: what you play on, then what explains it): a tap on a tile (with a ripple | |
| 54 | where it lands), a long press for a bomb (a ring closes in, the bomb's blast is previewed, the | |
| 55 | bomb goes down when the finger lifts), a button and then a tile (Bomb then a tile; Move then two | |
58f1e700 2026-10-24 Pavel Safronov | 56 | tiles away for a Run), Wait, and Go. The player wears a green **"You"** tag over their head throughout, since it isn't otherwise obvious which of the |
| 57 | moving figures is you, and the finger appears beside the player at the start of each scene, so | |
720cc9d3 2026-11-03 Pavel Safronov | 58 | your eye starts where the action is. The top bar shows throughout, as in play (each scene starts at turn 1 with no coins). It starts |
e3384c6b 2026-10-24 Pavel Safronov | 59 | with scenes about the controls alone: stepping, a bomb by long press, a bomb with the Bomb button, |
| 60 | waiting, auto-move (tap a far tile, then Go), **a tour of the top bar** (the finger points at | |
| 61 | each item, ringed, while the caption says what it is: lives, level, enemies left, coins, turn | |
| 62 | and par, bombs / blast / fuse, and the power-ups and charges you hold), and **"What is that?"** | |
| 63 | (the finger taps **?**, then an enemy; the real info dialog opens over the scene, leaving the | |
| 64 | caption undimmed, and the finger taps Got it). The whole demo plays **on an old CRT TV**, as if | |
| 65 | someone were playing on a touch-screen television: scan lines, a vignette, colour fringes and | |
| 66 | faint static, a dark bar rolling down the screen and bright lines sweeping across it, and now and | |
| 67 | then a burst of interference, as if someone switched a vacuum cleaner on nearby, rounded glass in a dark bezel, at most 4:3 wide with black bars beside it on a wide | |
| 68 | screen — and the finger in front of the glass. The rest show every feature on the | |
fa3e81a7 2026-10-24 Pavel Safronov | 69 | board: bombs and their countdown, watching the enemies' arrows to bomb where they're going, a |
565a6873 2026-10-25 Pavel Safronov | 70 | narrow escape, chain reactions, lingering flame, the first three enemy types, drops, the gem, every |
36c5d6a2 2026-10-24 Pavel Safronov | 71 | power-up you can see in action (Bomb +1, Fire +1, Fuse +1, Run, Kick — a tap on a bomb next to |
fcf44f32 2026-10-25 Pavel Safronov | 72 | you —, Throw, Diagonal, Slide, RPG, the Detonator — a tap on your bomb —, Proximity |
| 73 | alert, Wall / Bomb Pass, | |
6c3fcc31 2026-10-26 Pavel Safronov | 74 | Star), every charge (Pierce, Power, Nuke, Acid, Shield, Freeze, Decoy, ICBM, Flame Pass — |
| 75 | the ones you use, with the charge button), **the board's objects** (hiding in a bush, a bush fire | |
1f0038ac 2026-11-01 Pavel Safronov | 76 | creeping on, flame stopping at a metal crate, an oil spill burning all at once, sliding along a spill, crossing spikes |
6c3fcc31 2026-10-26 Pavel Safronov | 77 | while they're down, an oil barrel bursting and going off), **the charge swap** (carrying a |
0bfdc8e6 2026-10-25 Pavel Safronov | 78 | Pierce, the player picks up a Nuke; the choice opens over the scene and the finger taps Take |
| 79 | Nuke), and the exit (walking out once it opens; blasting it lets enemies out). Heart and | |
d5e3ad4d 2026-10-24 Pavel Safronov | 80 | Coin bag only change numbers, so they have no scene; nor does the shop. Every other scene shows |
| 81 | **a way to die**: walking into a blast, not getting far enough, blocking yourself in with your | |
| 82 | own bomb, one bomb setting off another, touching an enemy, and a couple of funny ones (the | |
33a0256b 2026-10-24 Pavel Safronov | 83 | Detonator next to you, a Run into an enemy). The scenes play **in a fixed order** and loop — |
| 84 | the controls first, then the rest, with a way to die after every four — each made new every | |
b8849d36 2026-11-01 Pavel Safronov | 85 | time. The panel shows which one it is (**12 / 56**), with a bar under it that fills as the scene plays and a yellow mark where its moment comes (the same bar sits under every clip in a dialog); **◀ ▶** (or the **← →** keys) go to the |
bb3823d2 2026-10-31 Pavel Safronov | 86 | one before or after, and **↺** back to the first; **the dice button** plays them in a random order instead (lit while on; kept for next time). The demo carries on where it was the next time |
33a0256b 2026-10-24 Pavel Safronov | 87 | it plays, after a reload too. It is |
bb3823d2 2026-10-31 Pavel Safronov | 88 | view-only; **click or tap anywhere else to play** (a key does nothing: Ctrl or Shift used to start the game), and that tap does nothing |
0bfdc8e6 2026-10-25 Pavel Safronov | 89 | else. The menu's **Demo** plays it again; a tap brings you back to your run as it was. |
33a0256b 2026-10-24 Pavel Safronov | 90 | A test URL (`?seed` and the like) skips it; `?demo` shows it anyway, from the first scene. |
52d68b59 2026-10-24 Pavel Safronov | 91 | |
92cc4ee3 2026-11-02 Pavel Safronov | 92 | **With a controller** the demo shows a **virtual controller** under the caption (a line drawing of the pad, d-pad, four |
| 93 | face buttons, shoulders, stick and Start, with the pictures of the pad in use) that lights the | |
| 94 | button for each press (lit for 0.7 s, `PAD_LIT_SECONDS` in `ui/padOverlay.ts`; a d-pad press lets go, then the cursor hops), and a dashed **cursor** on the board that hops between the blue tiles, in | |
| 95 | place of the finger. It has its own scene list: the **cursor** (the d-pad), **Move**, **Bomb**, **Wait**, **L1** | |
| 96 | (back to you), **R1** ("What is that?": the aim jumps to an enemy, Move explains it), the **stick** | |
| 97 | (the view zooms in to twice the size and the stick slides it left, right, up and down, then pressing it brings it back to you), **look** (the | |
| 98 | stick pushed toward an enemy to look at it) and **Start** (the real | |
| 99 | menu opens over the scene, with your run's state in it, and closes again), then the same gameplay | |
| 100 | scenes as the touch demo. A thin **progress bar** of the scene's turns runs along the bottom edge of the TV (inside the glass, above the caption), in every demo. The idle white pictures (d-pad, stick) are white; the face buttons are grey at rest and take their colour while pressed; the pictures lie under the drawing, so its lines stay on top. The touch-only scenes (the long-press bomb, auto-move, the top bar tour, | |
| 101 | "What is that?" by tap) and the charge swap (a dialog's choice) are left out. The pad's demo keeps | |
| 102 | its own saved place, apart from the touch demo's. When the input changes (a pad press, or a mouse, | |
| 103 | touch or key) the demo switches **at the next scene**, never in the middle of one: to the pad's list | |
| 104 | from its first scene, or back to the touch list where it was left. Start or LB ends the demo as ever, but a face button must be **held to play**: **hold the confirm | |
| 105 | button (Cross, or A on an Xbox pad: the bottom button; on a Nintendo pad A is the right-hand button)** until the ring round it on the virtual controller fills: play starts then, and the button, still held, does nothing in the game until you let go of it. The | |
| 106 | last line reads "Hold (the button's picture, A on a Nintendo pad) to play" instead of "Tap anywhere to play"; a short press of any face button does nothing. | |
| 107 | **The input button** under the scene buttons names what the demo is shown for and cycles on each click: **Input: touch** (the finger), | |
| 108 | **Input: mouse** (the same scenes with a pointer instead of the finger; its last line reads "Click anywhere to play"), | |
| 109 | **Input: keyboard** (see below), then | |
| 110 | **Input: controller: ps5**, **xbox**, **switch** and **generic** (the pad's scenes and virtual controller with that | |
| 111 | kind's button pictures, and "Hold (the button) to play"). It overrides what was detected, for this demo only (nothing is | |
| 112 | kept): it stays until the demo ends or a controller is plugged in or unplugged (no click, tap or button press drops it; only holding the confirm button, which ends the demo, leaves it). The scene starts again for the new input. The dialogs' clips follow the real input, not the pick. | |
805e7a9f 2026-11-03 Pavel Safronov | 113 | **The demo's own controls on a controller** (shown as the button's picture on each control while the demo is drawn for a controller): d-pad left / right = the scene before / after, up = shuffle on / off, down = back to the first scene, R1 (RB, R) or View = the next input in the list above. Hold the confirm button to play. |
92cc4ee3 2026-11-02 Pavel Safronov | 114 | **With the keyboard** (pick **Input: keyboard**; the entry cycles after mouse) the demo shows a **key overlay** under the caption instead of the |
| 115 | finger: Kenney's key pictures for the arrows, Alt, Shift, **M B V**, **Space**, **?**, Home, Enter and Esc, white at rest and | |
| 116 | lit for 0.7 s when pressed. Each turn is played with the fewest keys the game accepts: a plain arrow for a step, **B** (or M, V) then an arrow | |
| 117 | for a bomb next to you, **Space** to wait, and for a far tile **Shift + arrows** (the first only wakes the dashed cursor on you, as in play) and then the action | |
| 118 | key. Its scenes: Move, Bomb, Wait, the **Shift cursor**, **?** (then an arrow to the enemy, **Enter** explains), **Alt + arrows** (the view zooms to twice the size and slides, **Home** brings it back) and | |
| 119 | **Esc** (the real menu opens), then the touch demo's gameplay scenes without the touch-only ones and the charge swap, with captions worded for keys. The last line reads | |
| 120 | "Press Enter or Esc to play" (those two end the demo; ← and → change scenes, Tab, Enter and Space work the demo's own buttons, and every other key does nothing). Its place is saved apart from the other lists, and the dialogs' clips follow the real input. | |
| 121 | The Almanac's **Tests** tab (in a Developer run) has a **Demo controller** sample that presses each | |
| 122 | part in turn, on an Xbox, PlayStation and Switch pad. | |
| 123 | ||
36c5d6a2 2026-10-24 Pavel Safronov | 124 | <img src="docs/screenshots/demo.png" alt="The demo: the finger holding on a tile next to the player, a ring closed round it and the bomb's blast previewed; the action bar right under the board, the caption apart at the bottom" width="260"> |
52d68b59 2026-10-24 Pavel Safronov | 125 | |
beb9f2b7 2026-10-21 Pavel Safronov | 126 | You are the green astronaut (animated: it bobs while waiting, hops from tile to tile, crouches |
52d68b59 2026-10-24 Pavel Safronov | 127 | to place a bomb, and walks into the doorway and jumps when a level is cleared; enemies hop between tiles too, and flip over |
ea380ee8 2026-10-22 Pavel Safronov | 128 | when they die). Everything else on the board moves too: bombs pop in, swell as they count down, |
52d68b59 2026-10-24 Pavel Safronov | 129 | slide when kicked and fly when thrown; crates burst; flame fades out; drops and the gem rise |
ea380ee8 2026-10-22 Pavel Safronov | 130 | away when taken. A number in the top bar bumps when it changes, and dialogs pop up and shrink |
| 131 | away. **Goal of each level:** destroy every enemy, uncover the exit door | |
c37a2b0b 2026-10-20 Pavel Safronov | 132 | hidden under one of the crates, and step onto it. |
| 133 | ||
| 134 | Each turn you pick **one** action; then the world takes its turn, in this order: enemies step | |
| 135 | where their arrows pointed, bombs count down and explode, and enemies show their next step. | |
5551eb37 2026-10-20 Pavel Safronov | 136 | |
99869630 2026-10-23 Pavel Safronov | 137 | The action buttons are **icons only** (a game-piece figure = Move, a bomb = Bomb, an hourglass |
52d68b59 2026-10-24 Pavel Safronov | 138 | = Wait). Picking one turns it green and highlights the tiles it can use. There is **no |
| 139 | explanation text during play** (user request): what each power-up and charge does is shown when | |
| 140 | you first get it, and **?** then any button explains that button. Upgrades don't add buttons: | |
| 141 | they make Move and Bomb do more. | |
99869630 2026-10-23 Pavel Safronov | 142 | |
5551eb37 2026-10-20 Pavel Safronov | 143 | | Action | Phone | Keyboard | What it does | |
| 144 | |---|---|---|---| | |
7f242d36 2026-10-25 Pavel Safronov | 145 | | **Move** | Tap a tile next to you, or tap **Move** and then any highlighted tile | **M**, then a direction — or W A S D / arrow keys straight away (Q E Z C diagonally, with Diagonal) | Step one tile up, down, left or right onto an empty tile. **With the Run power-up:** or 2 tiles in a straight line. **With Teleport:** or any empty tile up to 3 steps away (4 with Run too), over anything. **With Kick:** walking into a bomb kicks it. **With Diagonal:** or a diagonal step. **With Slide:** or slide in a straight line until a wall, crate or bomb stops you. | |
d3e4ed26 2026-10-25 Pavel Safronov | 146 | | **Bomb** | Tap **Bomb**, then a highlighted tile — or **press and hold** a tile next to you | **B**, then a direction | Place a bomb on an empty tile next to you. You can have 1 bomb on the board at a time. **With Throw:** or 2 tiles away in a straight line, over a crate, bomb or enemy (not a pillar). **With RPG:** or fired in a straight line, as far as it flies. Always a plain bomb: Pierce, Power, Nuke and ICBM are used with the charge button (see Charges). | |
e3d8dc49 2026-10-27 Pavel Safronov | 147 | | **Wait** | Tap **Wait** | Space | Do nothing; the world takes its turn. (Tapping yourself did the same until 2026-10-26; now it does nothing, since a stray tap could kill you.) | |
| 148 | ||
| 149 | **Deadly moves are marked, and the shortcuts refuse them** (since 2026-10-26). The game plays | |
| 150 | each choice out on a copy of the board, with the real rules, to see whether it would cost you a | |
| 151 | life **this turn** (a Shield or Flame Pass that would take the hit, or an Immortal run, means it | |
| 152 | wouldn't): | |
| 153 | ||
| 154 | - **Wait turns red** when waiting would kill you. It still works when pressed: sometimes there | |
| 155 | is nothing better. | |
| 156 | - With a button picked, a tile that would kill you is **red with a cross** instead of blue. You | |
| 157 | can still tap it, on purpose. | |
| 158 | - The **shortcuts never take a deadly move**: a tap on a tile with nothing picked, W A S D / the | |
| 159 | arrow keys / Q E Z C with nothing picked, a long press for a bomb, and auto-move (Go, or a tap on | |
| 160 | the destination). The tile flashes red (and the phone buzzes) instead. To make such a move | |
| 161 | anyway, pick its button first (Move, then the tile). | |
| 162 | ||
| 163 | It only looks one turn ahead: walking into a dead end that a blast will fill next turn isn't | |
| 164 | marked; the danger overlay shows that. | |
| 165 | ||
| 166 | <img src="docs/screenshots/deadly-move.png" alt="Move picked next to a bomb about to go off: the tile back up into its blast is red with a cross, the safe tile below blue" width="260"> | |
82adee18 2026-10-20 Pavel Safronov | 167 | |
99869630 2026-10-23 Pavel Safronov | 168 | When Move or Bomb can do several things, the tile you tap decides: next to you is a step (or a |
fcf44f32 2026-10-25 Pavel Safronov | 169 | kick, into a bomb), 2 straight is a run, further is where a slide stops. Without picking anything, a tap on the tile where a slide stops slides there; next to you is a bomb, 2 away a throw, further an ICBM while you have launches, otherwise an |
| 170 | RPG bomb. With Diagonal, a diagonal neighbour is a step too — tap it, picked or not. (Teleport is a | |
| 171 | charge, used only from the charge button.) | |
99869630 2026-10-23 Pavel Safronov | 172 | |
ea380ee8 2026-10-22 Pavel Safronov | 173 | **Auto-move:** tap any tile further away that you can walk to — empty floor, the exit, the |
52d68b59 2026-10-24 Pavel Safronov | 174 | gem or a drop. **You take the first step at once**, just as a tap next to you would (if that |
e6bb7c42 2026-10-25 Pavel Safronov | 175 | step is safe). Every tile you will **land on** along the way, including where you're going, is |
fcf44f32 2026-10-25 Pavel Safronov | 176 | highlighted blue — with Run that's only the tiles you land on, not the ones you skip; with |
e6bb7c42 2026-10-25 Pavel Safronov | 177 | Diagonal the way cuts corners with diagonal steps — |
| 178 | with **a line of arrows** through them from you to there, one arrow on each pointing the way that | |
| 179 | move goes (the first in red when it isn't safe), and the **Move** button becomes **Go** (same walk icon, with a green border): each press of | |
52d68b59 2026-10-24 Pavel Safronov | 180 | Go — or each tap on the destination itself — takes **one step** along the way (one turn, as always — the world still |
| 181 | moves between steps). The way is worked out again every turn. Tapping another far tile sets a | |
| 182 | new way. Auto-move ends when you arrive, when you **move somewhere off the blue way** (you | |
720cc9d3 2026-11-03 Pavel Safronov | 183 | changed your mind), when the destination can no longer be reached, when you tap a wall or crate, or on **Esc** (touch: the round **Cancel** button above the action bar's top right, shown while a destination or a picked action is set). The way **never crosses |
52d68b59 2026-10-24 Pavel Safronov | 184 | the open exit** (that would end the level on the way); it only steps onto the exit when the |
| 185 | exit is where you are going. If the only way somewhere is over the open exit, auto-move can't go there. | |
e3d8dc49 2026-10-27 Pavel Safronov | 186 | It **won't take a deadly step**: onto an enemy, onto a tile an enemy's arrow points at, into |
| 187 | flame this turn, or any other move that would cost a life this turn. The next step then shows red, and Go / the destination wait for you to deal with it | |
82adee18 2026-10-20 Pavel Safronov | 188 | (Go falls back to picking Move, so you can step aside yourself). |
92cc4ee3 2026-11-02 Pavel Safronov | 189 | **With a controller or the keyboard cursor**, every tile auto-move can take you to (the same ones a tap would walk to, with a safe first step, not already bright blue) shows as a **faded blue**, next to the bright blue of the single actions. The cursor hops onto them like any other tile, and **Move/Go** there (**M** or Enter on the keyboard) is the same as tapping that tile: the label says "Walk here · N steps" and the first step is taken. With a way already set, the cursor can still hop to every faded tile (Move there sets a new way); on the destination itself the label says "Keep walking · N steps". **The way is previewed** before you confirm: with the cursor on a faded tile, or the **mouse** (not touch) hovering over one with nothing picked, the board shows the route exactly as auto-move would draw it (landing tiles, arrows, the first one red when unsafe) without setting it or taking a step. Tapping, clicking and touch are unchanged. |
00ad7d0a 2026-10-24 Pavel Safronov | 190 | **Once every enemy is gone**, the way needs no more presses: you walk there by yourself, two |
| 191 | steps a second (still one turn per step). | |
28670c3e 2026-10-24 Pavel Safronov | 192 | |
92cc4ee3 2026-11-02 Pavel Safronov | 193 | **Autopilot** (Settings in the menu, "Autopilot", on by default): the moment the last enemy is |
| 194 | gone, a note at the top says **Autopilot: cleaning up**, and after a one-second beat the character | |
720cc9d3 2026-11-03 Pavel Safronov | 195 | walks round by itself, two and a half moves a second, to every coin, charge and gem still lying on the floor, |
92cc4ee3 2026-11-02 Pavel Safronov | 196 | then onto the exit. Every move is an ordinary turn (a Run if you own it), so **gathering costs |
| 197 | turns** and can lose the par bonus. The route is the one that takes the fewest turns in all (the | |
| 198 | exit last; a coin on the way is picked up free). A gem, or a charge that needs a choice (one is | |
| 199 | already carried), opens its dialog on that turn and the walk **waits for your answer**, then goes | |
| 200 | on. If a gem lies under a crate that is still crumbling, the note says **Autopilot: waiting for the | |
| 201 | crates** and it waits; when only the exit is left it says **Autopilot: off to the exit**. The usual | |
| 202 | auto-move safety applies (never a deadly or unsafe step); if it can only wait for many turns, or | |
| 203 | no safe turn exists, it stops with the toast "Autopilot stopped · Your turn". If a coin, charge or gem | |
| 204 | lies behind a bomb that is still ticking (or flame still burning), it waits for that too (**Autopilot: waiting for the bombs**) and then fetches it. No way at all to the | |
| 205 | exit is the existing boxed-in rule (a life). | |
| 206 | *Stopping it* (for that level): **Esc** on the keyboard, **L1** on a controller (its picture is on the note), | |
| 207 | or the small **Stop** button on the note (touch and mouse). Turning "Autopilot" off in the menu stops it at once. | |
| 208 | *While it walks* the board takes no input: taps, clicks, long-press bombs, the action bar (dimmed), | |
| 209 | the keys (WASD, arrows, Q/E/Z/C, action keys, Space, Enter, `?`, Shift + arrows) and the controller's | |
| 210 | cursor and face buttons are ignored, and the controller's cursor is hidden. Still working: its | |
| 211 | dialogs, the menu and Start (opening one pauses the walk), the fullscreen button, the top bar's | |
| 212 | info taps, and looking around (Alt + arrows, Home, the right stick, dragging the board). | |
41566e2d 2026-11-02 Pavel Safronov | 213 | |
28670c3e 2026-10-24 Pavel Safronov | 214 | **How far one move of auto-move goes** (and the first one, when you tap a far tile): a tile next |
fcf44f32 2026-10-25 Pavel Safronov | 215 | to you is always a step. Otherwise it's a **Run** (2 tiles straight along the way) when you have |
| 216 | Run and the way goes straight, or a step — then it works it out again next turn. It only lands on | |
| 217 | safe tiles. Auto-move never spends a charge: a Teleport is yours to use, from the charge button. | |
82adee18 2026-10-20 Pavel Safronov | 218 | |
bb3823d2 2026-10-31 Pavel Safronov | 219 | Tapping an enemy, a bomb, burning flame or a wall does nothing (apart from ending |
| 220 | auto-move; with Kick, tapping a bomb next to you kicks it, with Bomb Pass it walks onto it, and | |
| 221 | with both — or with the Detonator too — a dialog asks which, as it does for an arrow key into | |
| 222 | such a bomb). Tapping a crate walks you to the tile beside it. A tap | |
99869630 2026-10-23 Pavel Safronov | 223 | never walks into an enemy. |
ea380ee8 2026-10-22 Pavel Safronov | 224 | |
99869630 2026-10-23 Pavel Safronov | 225 | **What is that?** Tap the round **?** button at the top right, below the menu on a phone and beside it on a wider screen (or press **?**), |
| 226 | then tap anything on the board — or any action button — to see what it is and what it does: an **enemy** (with its next moves spelled out), a **bomb**, | |
52d68b59 2026-10-24 Pavel Safronov | 227 | burning flame, a wall or crate, the exit, the gem, a drop. The **?** turns green while it is |
ea380ee8 2026-10-22 Pavel Safronov | 228 | on; it works for one tap, and tapping it again or **Esc** turns it off. For things you can walk |
52d68b59 2026-10-24 Pavel Safronov | 229 | to, the dialog has a **Walk there** button that starts auto-move there. The items in the **top |
ea380ee8 2026-10-22 Pavel Safronov | 230 | bar** (lives, level, enemies left, coins, turn / par, bombs, blast, fuse, passes, Star) explain |
32dd53cd 2026-10-25 Pavel Safronov | 231 | themselves with a plain tap. Most of these dialogs **play a short clip** of what they describe, |
| 232 | made on the spot like the demo's scenes and new every loop: a bomb counting down and going off, | |
| 233 | lingering flame, a crate breaking, flame stopping at a pillar, the last enemy dying and the exit | |
| 234 | opening, losing a life, the exit, the gem, coins, each power-up and charge; for the actions (Move, Bomb, | |
fcf44f32 2026-10-25 Pavel Safronov | 235 | Wait) and the power-ups you work yourself (Run, Kick, Throw, Diagonal, the Detonator), |
ac534e57 2026-10-25 Pavel Safronov | 236 | a finger shows how. Enemies have only their picture. With reduced motion turned on, each clip is |
| 237 | a still picture of its moment instead. | |
a4fab0fb 2026-10-21 Pavel Safronov | 238 | |
92cc4ee3 2026-11-02 Pavel Safronov | 239 | **Fullscreen button:** a round button in the top bar, between "?" and the menu, shown only where the browser has fullscreen; it shows |
| 240 | "enter" or "leave" by the state (it follows F11 and Esc too). On a phone's portrait bar, where three round buttons would make the bar taller, all three are a little smaller. With a controller, the menu's **Fullscreen** switch does the same, but a controller press is no browser gesture, so a plain browser may refuse: a note says **Press F11, or use the fullscreen button** (the planned desktop wrapper, Q41, will make it work). | |
| 241 | ||
a4fab0fb 2026-10-21 Pavel Safronov | 242 | **Menu:** the round button at the top right (or **Esc** with nothing picked). It shows the level |
92cc4ee3 2026-11-02 Pavel Safronov | 243 | and seed, the **Sound** and **Vibration** switches (see *Sound and vibration* below), **Fullscreen** (on or off now; where the browser has fullscreen) (the game never goes fullscreen by itself; F11 or Esc leaves it; iPhone Safari has no fullscreen for pages) and **Autopilot**, and its |
0bfdc8e6 2026-10-25 Pavel Safronov | 244 | buttons, kept compact: **Resume** and **New** side by side (New starts a new run and asks first, |
805e7a9f 2026-11-03 Pavel Safronov | 245 | since the current run can't be got back), then two rows of small ones — **Almanac** (every |
6c3fcc31 2026-10-26 Pavel Safronov | 246 | power-up, charge and enemy type, and everything on the board (crates, pillars, bushes, metal |
| 247 | crates, oil, spikes, oil barrels, rubble, with the level each first turns up on), with its picture | |
805e7a9f 2026-11-03 Pavel Safronov | 248 | and what it does, in four tabs, and in a Developer run a fifth, **Tests**: fixed edge-case situations such as a slide over two gems, each with what to expect; the same scenes join the landing demo with `?dev`; an entry with a green ▶ opens its clip; **Demo controller** is a sample of the demo's virtual controller, each tap pressing its next part on an Xbox, PlayStation and Switch pad in turn), **Scores** (the high scores), **Changes** (the list of changes in every release), **Demo** (the demo again) and **Bug** (an |
ba8e4ea0 2026-10-27 Pavel Safronov | 249 | email to the game's bug-report address, which needs no account, filled in with the |
0bfdc8e6 2026-10-25 Pavel Safronov | 250 | game's version, your device and the run, so it can be replayed; a long run's record goes on your |
| 251 | clipboard to paste in). | |
a4fab0fb 2026-10-21 Pavel Safronov | 252 | |
82adee18 2026-10-20 Pavel Safronov | 253 | **Press and hold** a tile next to you (about half a second, with a short buzz on phones that |
| 254 | support it) to arm a bomb there: its blast shows, and letting go places it. Sliding off the | |
| 255 | tile first cancels it. | |
5551eb37 2026-10-20 Pavel Safronov | 256 | |
d3e4ed26 2026-10-25 Pavel Safronov | 257 | **Charges** are things enemies sometimes drop. **You carry one at a time**, and use it **when |
| 258 | you choose**, with the **charge button** beside Bomb (or **V**). It shows the charge's icon and | |
| 259 | how many uses are left, or an empty dashed slot when you carry none (greyed out then); "What is | |
5f066960 2026-10-26 Pavel Safronov | 260 | that?" on it explains charges and the choice below. Every charge is used with it **except the |
| 261 | Shield and Flame Pass, which work by themselves while carried** and are used up by the hits they | |
| 262 | take, leaving the slot empty (user request, 2026-10-25; for a few hours that day they had to be | |
| 263 | raised with the button first) | |
d3e4ed26 2026-10-25 Pavel Safronov | 264 | (since 2026-10-24: until then every charge worked the moment it was picked up, and they |
| 265 | piled up). The top bar shows it too. | |
| 266 | ||
| 267 | - Picking up **the same kind** adds to it (3 more Pierce bombs). | |
| 268 | - Picking up **another kind** asks: **keep** yours and sell the new one, or **take** the new | |
| 269 | one and sell yours (for what is left of it). A charge sells for half its shop price, rounded | |
bb3823d2 2026-10-31 Pavel Safronov | 270 | up. A **Freeze** held can also be **used first**, then the new charge taken (a third button; |
| 271 | charges that need aiming can't be). The choice takes no turn. | |
d3e4ed26 2026-10-25 Pavel Safronov | 272 | - The same goes for a charge chosen from a gem or bought in the shop: with another kind held, it |
| 273 | asks (since 2026-10-25, user report: it used to replace the one held without asking). | |
| 274 | - What you carry goes on to the next level and through a death. The first time in a run you | |
| 275 | pick up each kind, a dialog says what it does. | |
| 276 | ||
52d68b59 2026-10-24 Pavel Safronov | 277 | (Diagonal was a charge until 2026-10-23; it is a power-up now.) |
| 278 | ||
d3e4ed26 2026-10-25 Pavel Safronov | 279 | <img src="docs/screenshots/charge-offer.png" alt="Picking up a Nuke while carrying a Shield: the dialog shows both, with Keep Shield (+3 coins) and Take Nuke (+3 coins)" width="260"> |
| 280 | ||
52d68b59 2026-10-24 Pavel Safronov | 281 | | Charge | Icon | What it does | |
| 282 | |---|---|---| | |
ebcd0a8f 2026-11-02 Pavel Safronov | 283 | | **Pierce** | the Crate Pass icon (crate with ✕) | **3 bombs** whose flame goes **through** crates, burning every one in reach. The charge button puts one down. | |
d3e4ed26 2026-10-25 Pavel Safronov | 284 | | **Power** | the Fire +1 icon | **3 bombs** whose flame reaches all the way to the walls (crates still stop it). | |
| 285 | | **Nuke** | bomb with a skull badge | **3 bombs** that also burn **every tile within 2 steps** (across plus down), through crates and round corners; walls still stand. It can catch you too: get 3 steps away. | | |
5f066960 2026-10-26 Pavel Safronov | 286 | | **Shield** | the Move figure in a ring | **Works by itself while you carry it**, level after level: a ring round you until something hits you. It absorbs that hit (flame, enemy or spikes); under a falling ceiling it **pushes you out** to an empty tile next to you, if there is one, and anything else that hits you that turn. Then it is used up and the charge slot is empty. | |
e6bb7c42 2026-10-25 Pavel Safronov | 287 | | **Freeze** | a padlock | Press the charge button, then tap yourself — or press it again: every enemy freezes in place for **3 turns**, that one included: they turn blue inside a block of ice and thaw a step each turn, then carry on with the moves their (faded, icy) arrows show. | |
d3e4ed26 2026-10-25 Pavel Safronov | 288 | | **Decoy** | three pawns | Press the charge button, then tap where it goes — **up to 3 tiles away in a straight line**, with nothing in the way (a wall, crate, bomb, enemy or flame stops it, as it stops a slide): a pale copy of you. Enemies that chase you (Seekers, Ghosts, Hunters, Sprinters) go after it instead, **until the level ends** — or until an enemy reaches it or flame burns it, which destroys it. It doesn't block anyone. | |
| 289 | | **ICBM** | bomb with a target badge | 3 launches: the charge button fires a bomb as an RPG's (or **I**, then a direction) and it goes off the moment it lands, at any distance. Your bomb limit doesn't count. | | |
5f066960 2026-10-26 Pavel Safronov | 290 | | **Flame Pass** | flame with a shield badge | **Works by itself while you carry it:** flame can't hurt you for the next **3 fire hits** (an orange ring round you; the charge button and the top bar count them), level after level; when they are used the charge slot is empty. Enemies still can. A power-up that worked for good until 2026-10-25, when the balance lab found it won the game alone. | |
92cc4ee3 2026-11-02 Pavel Safronov | 291 | | **Teleport** | the Move figure with an outbox badge | **3 jumps**: press the charge button (or **P**), then tap any empty tile within 3 steps (counting across and down), over anything (with the keyboard: **P**, then **Shift + arrows** to the tile and **Enter**, or a plain arrow for the nearest one that way). **With Run, 4 steps;** **with Diagonal, a square** (a diagonal step counts as one). A power-up until 2026-10-25, for the same reason. | |
e3d8dc49 2026-10-27 Pavel Safronov | 292 | | **Acid** | bomb with a flask badge | **1 bomb** that burns like a Nuke — **every tile within 2 steps** (across plus down), through crates and round corners — and **cracks every pillar** in that area, diagonal ones included (cracks show on it; since 2026-10-26: until then it burned a plain cross and cracked only a pillar an arm of it ran into). It can catch you too: get 3 steps away. **Any later blast** that reaches a cracked pillar **breaks** it: its tile becomes floor, dust trickles from the ceiling over the 8 tiles round it, and **4 turns later** it falls as **rubble**, for good — nothing gets through rubble, not even flame. Whatever is under it is crushed: enemies (a trap to set), drops, bombs, and **you** — unless you carry a Shield, which pushes you out to an empty tile next to you (with none, nothing saves you; a Star doesn't). If the rubble cuts you off from the exit or from an enemy, the level can't be won: that costs a life at once (**trapped**). The outer wall never breaks. Since 2026-10-25. | |
52d68b59 2026-10-24 Pavel Safronov | 293 | |
5f066960 2026-10-26 Pavel Safronov | 294 | A Pierce, Power, Nuke or Acid bomb wears its charge's icon as a small badge. **Bomb** always puts down a |
d3e4ed26 2026-10-25 Pavel Safronov | 295 | plain bomb. |
82adee18 2026-10-20 Pavel Safronov | 296 | |
| 297 | With an action picked, holding or hovering a highlighted tile previews what it will do: where you | |
| 298 | will end up, a faded bomb with its blast, a kicked bomb's stopping place, a changed number. | |
c37a2b0b 2026-10-20 Pavel Safronov | 299 | |
5551eb37 2026-10-20 Pavel Safronov | 300 | - Picking an action highlights the tiles you can choose, in blue. Tapping the action again, |
| 301 | pressing **Esc**, or tapping anywhere else cancels it. | |
| 302 | - **Preview before you commit:** on a phone, press and hold a highlighted tile to see the | |
| 303 | result (for a bomb, its blast in orange); slide to another tile to change your mind; let go | |
c37a2b0b 2026-10-20 Pavel Safronov | 304 | to commit. With a mouse, hovering shows the same preview. For a kick, the preview shows |
| 305 | where the bomb will stop. | |
5551eb37 2026-10-20 Pavel Safronov | 306 | |
| 307 | ### Bombs | |
| 308 | ||
| 309 | - The number on a bomb is **how many more of your actions until it explodes**. A new bomb | |
644cfd0b 2026-10-20 Pavel Safronov | 310 | shows **3**. A bomb showing **1** (flashing white) explodes at the end of your next action. |
5551eb37 2026-10-20 Pavel Safronov | 311 | - The blast is a cross reaching **1 tile** in each direction. It stops at walls; it destroys |
644cfd0b 2026-10-20 Pavel Safronov | 312 | the first soft block (wooden crate) in each direction and stops there. |
5551eb37 2026-10-20 Pavel Safronov | 313 | - A bomb caught in a blast **explodes at once**, whatever its number (a chain reaction). |
82adee18 2026-10-20 Pavel Safronov | 314 | - **Flame lingers for one more turn.** After a blast, its tiles keep burning (orange, with |
| 315 | flickering fireballs) through the next turn: any enemy that walks in dies, and so do you if | |
99869630 2026-10-23 Pavel Safronov | 316 | you wait in it. You can't step or put a bomb into burning tiles — unless flame can't hurt you |
5f066960 2026-10-26 Pavel Safronov | 317 | (a Flame Pass carried, a Star), then you can walk through it like floor (with Flame Pass, using one |
fcf44f32 2026-10-25 Pavel Safronov | 318 | of its hits). It goes out after that turn. |
c37a2b0b 2026-10-20 Pavel Safronov | 319 | - Bombs block movement, for you and for enemies. |
6c3fcc31 2026-10-26 Pavel Safronov | 320 | - **Bombs go on a tile next to you**, not under you as in the original. Both were measured with |
| 321 | the balance lab; see *Measured: bombs under the player* below for how the original rule would | |
| 322 | change the game. | |
c37a2b0b 2026-10-20 Pavel Safronov | 323 | - Bombs can't be placed on an enemy. |
5f066960 2026-10-26 Pavel Safronov | 324 | - Pierce, Power, Nuke and Acid bombs are put down with the charge button (see Charges above); such a |
d3e4ed26 2026-10-25 Pavel Safronov | 325 | bomb wears its charge's icon as a badge. |
5551eb37 2026-10-20 Pavel Safronov | 326 | |
| 327 | ### Danger | |
| 328 | ||
82adee18 2026-10-20 Pavel Safronov | 329 | - **Strong red** tiles will burn at the end of this turn if you wait (including flame still |
| 330 | burning from last turn). | |
| 331 | - **Light red** tiles will burn at the end of the next turn (including flame that will still be | |
| 332 | burning then). | |
5f066960 2026-10-26 Pavel Safronov | 333 | - **A red outline** marks every tile a bomb on the board will hit on a later turn, however long |
| 334 | its fuse (with the chains and spreading fire it will set off, if you wait), and where a ceiling | |
| 335 | will fall: it fills in light red, then strong red, as the moment comes (since 2026-10-25; until | |
| 336 | then a bomb's tiles showed only in its last two turns). | |
| 337 | - Fire that spreads over oil or through bushes, **raised spikes**, and a **ceiling about to fall** | |
| 338 | show the same way (see The board). | |
5551eb37 2026-10-20 Pavel Safronov | 339 | |
c37a2b0b 2026-10-20 Pavel Safronov | 340 | ### Enemies |
| 341 | ||
565a6873 2026-10-25 Pavel Safronov | 342 | <img src="docs/screenshots/enemies.png" alt="Level 19: three Ghosts (green blocks, one inside a crate, see-through), resting ones with a dot among their arrows, and a Wisp (red flame slime)" width="260" align="right"> |
c37a2b0b 2026-10-20 Pavel Safronov | 343 | |
82adee18 2026-10-20 Pavel Safronov | 344 | Every enemy shows its **next 3 moves** as a column of see-through red arrows on the right side |
| 345 | of its tile: the top arrow is its next move (strongest), the ones below are the 2nd and 3rd | |
| 346 | moves (fainter). It makes exactly | |
| 347 | those moves, one per turn, so you can time a bomb for where it will be. No arrows (and closed | |
565a6873 2026-10-25 Pavel Safronov | 348 | eyes): it has nowhere to go and stays put. A **dot** among the arrows is a rest: Ghosts and |
| 349 | Sprinters move only every other turn, with their eyes closed while they rest. **Two arrows one | |
| 350 | behind the other** are a Sprinter's dash: 2 tiles in one turn (a dash through your tile catches | |
| 351 | you there). If you put a bomb on a tile it planned to walk to, | |
52d68b59 2026-10-24 Pavel Safronov | 352 | it stops there and plans a new route. Enemies keep clear of each other: each plans its moves |
| 353 | around where the others will be, so a group (like the 3 let out of a blasted exit) splits up | |
| 354 | instead of moving as one; they only share a tile when there's nowhere else to go. Touching an | |
| 355 | enemy costs a life — walking into it, it walking into you, or the two of you swapping places. | |
| 356 | Flame kills enemies. | |
c37a2b0b 2026-10-20 Pavel Safronov | 357 | |
| 358 | | Enemy | Looks like | Appears from | Moves | | |
| 359 | |---|---|---|---| | |
| 360 | | **Blob** | purple slime | level 1 | Wanders; usually keeps going the way it was heading. | | |
565a6873 2026-10-25 Pavel Safronov | 361 | | **Seeker** | fly | level 4 | Half the time takes the shortest way toward you; otherwise wanders like a Blob. | |
| 362 | | **Drifter** | spinning saw | level 7 | Goes straight until blocked (or another enemy is heading there), then turns. | | |
| 363 | | **Sprinter** | mouse | level 10 | Rests every other turn, then dashes 2 tiles at once, half the time toward you. | | |
| 364 | | **Ghost** | green block slime | level 13 | Moves every other turn, always the shortest way toward you, **through crates**. | | |
| 365 | | **Wisp** | fire slime | level 16 | Wanders like a Blob, **through crates**. | | |
| 366 | | **Hunter** | frog | level 19 | Always takes the shortest way toward you. | | |
| 367 | ||
| 368 | Ghosts and Wisps can be inside a crate (drawn see-through there); flame that burns that crate | |
| 369 | kills them, but flame stopped by a crate in front of them doesn't reach them. Bombs stop every | |
| 370 | enemy. Each level mixes the types met so far. | |
c37a2b0b 2026-10-20 Pavel Safronov | 371 | |
e6bb7c42 2026-10-25 Pavel Safronov | 372 | How many enemies a level has follows its **crowding**: each type counts for how dangerous it is |
| 373 | (a Blob 1, up to a Hunter 2), and they are added until that reaches 1 per 26 open tiles on level 1, | |
fcf44f32 2026-10-25 Pavel Safronov | 374 | rising to 1 per 9 by level 20 — so a bigger board brings more enemies, and later levels are more |
| 375 | crowded. Level 1 has 2; level 20 about ten, on a bigger board. Enemies never start within | |
c37a2b0b 2026-10-20 Pavel Safronov | 376 | 4 tiles of you. |
| 377 | ||
| 378 | ### Drops and coins | |
| 379 | ||
0b63d158 2026-10-25 Pavel Safronov | 380 | A slain enemy often leaves **coins** (bronze = 1, silver = 2, gold = 5: about 1 coin a kill on average) or sometimes a **charge** |
d3e4ed26 2026-10-25 Pavel Safronov | 381 | (see Charges) on its tile. No enemy drops a Decoy, Freeze or Shield while one already lies on |
| 382 | the board. Pierce, Power, Nuke and ICBM add up, so they always can. Drops never share a tile, and never land on the uncovered exit: the new one rolls to the | |
beb9f2b7 2026-10-21 Pavel Safronov | 383 | nearest free floor tile (up to 2 steps away). Walk onto them to collect them. A later flame burns drops lying in the |
e78b7781 2026-10-25 Pavel Safronov | 384 | open, so pick them up soon. Coins are spent in **the shop** (below). |
c37a2b0b 2026-10-20 Pavel Safronov | 385 | |
| 386 | ### The exit | |
| 387 | ||
52d68b59 2026-10-24 Pavel Safronov | 388 | - The exit door (a short arched doorway: orange while locked, dark once open) is hidden under |
| 389 | one of the crates. Burning that crate reveals it. | |
c37a2b0b 2026-10-20 Pavel Safronov | 390 | - The door stays **locked** while any enemy is alive (top-bar enemy count). When the last one |
| 391 | dies, it opens; step onto it to finish the level. | |
| 392 | - **Don't blast the uncovered door:** flame on it lets out 3 more enemies (of the level's | |
52d68b59 2026-10-24 Pavel Safronov | 393 | toughest type). Those drop nothing. They can't be hurt by the flame that let them out (it |
| 394 | lingers a turn), but a new explosion kills them as usual. | |
720cc9d3 2026-11-03 Pavel Safronov | 395 | - **Clearing a level pays 2 coins.** **Par:** the top bar shows the turn you are on (from 1) `/ par`. Finish within par for **5 more**. |
e6bb7c42 2026-10-25 Pavel Safronov | 396 | Par is 10 turns, plus 0.3 a tile of the board (floor and crates), plus 8 per enemy: 41 on level 1. |
c37a2b0b 2026-10-20 Pavel Safronov | 397 | |
27f24fed 2026-10-20 Pavel Safronov | 398 | ### Power-ups |
| 399 | ||
52d68b59 2026-10-24 Pavel Safronov | 400 | Every level hides **one gem** under a crate (never the exit's). Burn the crate to reveal it — it |
| 401 | is in a random colour (the colour means nothing) — then walk onto it. **Don't blast it once it's | |
| 402 | uncovered:** flame on it destroys it and lets out 3 enemies, just like the exit (and, as there, | |
| 403 | those enemies can't be hurt by the flame that let them out). | |
| 404 | ||
| 405 | **Taking the gem offers 5 different power-ups, and you choose one.** The dialog shows each with | |
ac534e57 2026-10-25 Pavel Safronov | 406 | what it does; it can't be closed without choosing, and choosing takes no turn. Choosing takes two |
| 407 | taps: **tap a card** to select it (it turns green, and a clip above the cards shows it in action), | |
e6bb7c42 2026-10-25 Pavel Safronov | 408 | then **Choose** to take it. A card for something with a number shows what it changes from where you are: **Blast 2 → 3** for Fire +1, Bombs, Fuse, Lives, Coins, a Star's turns, or a charge's uses when you carry the same kind (the shop's cards too). The first card is selected to begin with. Heart and Coin bag, which |
ac534e57 2026-10-25 Pavel Safronov | 409 | have nothing to show on the board, show their picture there instead. The 5 are drawn |
52d68b59 2026-10-24 Pavel Safronov | 410 | at random, but not all are equally likely: common ones (Bomb +1, Fire +1) come up far more often |
fcf44f32 2026-10-25 Pavel Safronov | 411 | than rare ones (Proximity alert, Heart). An ability or pass you already hold is never offered. The |
52d68b59 2026-10-24 Pavel Safronov | 412 | offer is fixed by the seed and level, so a retry after a death offers the same. If you die on the turn you take the gem, there |
| 413 | is no choice, and the retry has the gem back. If the same step also reaches the exit, you choose | |
| 414 | before moving on. | |
| 415 | ||
| 416 | | Power-up | Looks like | Effect | | |
| 417 | |---|---|---| | |
e6bb7c42 2026-10-25 Pavel Safronov | 418 | | **Bomb +1** | bomb with a + badge | One more bomb on the board at a time, **up to 5**. | |
| 419 | | **Fire +1** | bomb with an expanding-arrows badge | Blast reaches one tile further, **up to 5**. | | |
| 420 | | **TNT** | fireball with an expanding-arrows badge | Blast reaches **two** tiles further: two Fire +1s in one, up to 5. | | |
| 421 | | **Fuse +1** | bomb with a timer badge | Your bombs start one higher (more time to get away), **up to 5**. | | |
| 422 | ||
| 423 | Each stat has a **limit of 5**, so blasts can't span the board. A power-up with no room left for all | |
| 424 | it gives isn't offered (no Fire +1 at a blast of 5, no TNT at 4), and its card says how far you'd | |
| 425 | go: **Blast 2 → 4 (max 5)**. | |
52d68b59 2026-10-24 Pavel Safronov | 426 | | **Run** | the Move figure with a fast-forward badge | **Move** can run: 2 tiles in a straight line in one turn (or **R**, then a direction). Both tiles must be empty; an enemy on the tile in between is run into. Anything on that tile is picked up. | |
| 427 | | **Kick** | bomb with a right-arrow badge | Walk into a bomb next to you and it slides away until the next tile is blocked (a wall, crate, bomb or enemy), keeping its number. | | |
28670c3e 2026-10-24 Pavel Safronov | 428 | | **Throw** | bomb with an up-right-arrow badge | **Bomb** can also go exactly 2 tiles away in a straight line, over a crate, bomb or enemy in between — but not over a pillar or the outer wall (or **T**, then a direction). | |
a313eb7d 2026-10-25 Pavel Safronov | 429 | | **Diagonal** | the Move figure with a diagonal-arrows badge | **Move** can also step diagonally, where one of the two tiles beside the step is open — not between two blocked tiles (no squeezing since 2026-10-25; the lab found the squeeze was most of its strength) (or **Q E Z C**: up-left, up-right, down-left, down-right); auto-move cuts corners with it. With the Teleport charge, it widens Teleport's reach to a square. A charge until 2026-10-23. | |
7f242d36 2026-10-25 Pavel Safronov | 430 | | **Slide** | the Move figure with a two-way-arrow badge | **Move** can also slide in a straight line until the next tile is a wall, crate or bomb — **tap the tile where it stops** (or **L**, then a direction) — picking up whatever it passes. It can't stop early: an enemy on the way is crashed into (a life lost), and flame on the way burns (unless Flame Pass or a Star). The open exit stops it. | |
| 431 | | **RPG** | bomb with a forward-arrow badge | **Bomb** can also fire a bomb in a straight line (or **F**, then a direction): it flies until the next tile is a wall, crate, bomb or enemy and lands just before it, then counts down as usual. | | |
92cc4ee3 2026-11-02 Pavel Safronov | 432 | | **Detonator** | bomb with a ! badge | Your bombs pulse with a red glow: **tap one** and it goes off this turn (or **X**, then tap it; with the keyboard, **Shift + arrows** to the bomb and **X** or **Enter**). No button. | |
d3e4ed26 2026-10-25 Pavel Safronov | 433 | | **Proximity alert** | bomb with a warning-sign badge | Your bombs go off the turn an enemy is **right next to** one — one that walks up, or one already there when you place it — wherever you are standing. (Until 2026-10-25, anywhere in its reach.) The danger overlay shows it ahead, from the enemies' arrows. | |
ebcd0a8f 2026-11-02 Pavel Safronov | 434 | | **Crate Pass** | crate with an ✕ badge | Walk through crates. | |
52d68b59 2026-10-24 Pavel Safronov | 435 | | **Bomb Pass** | bomb with a shield badge | Walk over bombs. | |
| 436 | | **Star** | star | Nothing hurts you for 8 turns (a gold ring; the top bar counts down); you can walk through flame meanwhile. | | |
| 437 | | **Heart** | heart | One more life. | | |
| 438 | | **Coin bag** | coin | 10 coins. | | |
| 439 | ||
fcf44f32 2026-10-25 Pavel Safronov | 440 | Run, Kick, Throw, Diagonal, Slide and RPG add no buttons — they |
52d68b59 2026-10-24 Pavel Safronov | 441 | make Move and Bomb do more (**?** then the button says how). The Detonator adds none either: |
| 442 | your bombs pulse, and a tap on one sets it off. The top bar shows a small icon for each ability | |
| 443 | and pass you hold. | |
27f24fed 2026-10-20 Pavel Safronov | 444 | |
e78b7781 2026-10-25 Pavel Safronov | 445 | ### The shop |
| 446 | ||
| 447 | After every **3rd level** (3, 6, 9, 12, 15 and 18), going on from the level-cleared banner opens | |
| 448 | **the shop** before the next level. It has **4 items**: power-ups (none you already hold, and no | |
| 449 | Coin bag) and charges, drawn with the gem's rarity weights, each with its **price** — common ones | |
fcf44f32 2026-10-25 Pavel Safronov | 450 | cheap (Bomb +1 and Fire +1 cost 4, most abilities and passes 6), rare ones dear (Proximity alert |
| 451 | 10, Heart 12), charges 3–7. Three levels earn about 12 coins, or about 27 when | |
0b63d158 2026-10-25 Pavel Safronov | 452 | each is cleared within par, so the first shop buys two cheap things, or three or four. Tap an item to select it (a clip above shows it in action), then its **Buy** button |
e78b7781 2026-10-25 Pavel Safronov | 453 | (or, when it's too dear, how many coins you still need); what you buy works at once and lasts for |
0b63d158 2026-10-25 Pavel Safronov | 454 | the rest of the run. **Restock** draws 4 new items for 1 coin, |
| 455 | then 2, 3… in the same shop. **Next level** leaves. Shopping takes no turns. What a shop offers | |
e78b7781 2026-10-25 Pavel Safronov | 456 | comes from the seed, so the same dungeon offers the same things. Nothing carries over between |
| 457 | runs: leftover coins only count on the high-score board. | |
| 458 | ||
0b63d158 2026-10-25 Pavel Safronov | 459 | <img src="docs/screenshots/shop.png" alt="The shop: 9 coins, a clip above the items with their prices, Bomb +1 selected with its own Buy button (4 coins), and Restock and Next level side by side" width="260"> |
e78b7781 2026-10-25 Pavel Safronov | 460 | |
5551eb37 2026-10-20 Pavel Safronov | 461 | ### Lives |
| 462 | ||
5f066960 2026-10-26 Pavel Safronov | 463 | You have **3 lives**. Caught in a blast or touched by an enemy (or on raised spikes, under a |
6c3fcc31 2026-10-26 Pavel Safronov | 464 | falling ceiling, walled in by rubble, or **boxed in** — nowhere to step and nowhere to put a |
| 465 | bomb, with nothing left on the board that could change that, as after a Teleport into a gap | |
| 466 | between two crates), you lose one and the level starts | |
52d68b59 2026-10-24 Pavel Safronov | 467 | again with the same layout and enemies. **You keep everything else**: coins, stats, every |
5f066960 2026-10-26 Pavel Safronov | 468 | power-up (abilities and passes included). **The charge you carry |
fcf44f32 2026-10-25 Pavel Safronov | 469 | drops where you fell** (since 2026-10-25), with what was left of it: walk back over it on the |
| 470 | retry to pick it up again, before a blast burns it. (The original took the passes and the | |
| 471 | Detonator away; since 2026-10-23 a death otherwise costs only the life.) The banner says how and where you died — "Level 3, turn 12: you walked into a Blob." — and so | |
32dd53cd 2026-10-25 Pavel Safronov | 472 | does the game-over banner. Both replay **your own last turns** before the death, over and over, |
| 473 | on the part of the level where it happened, so you can see what went wrong. With none left, the run is over and the seed is shown, so the same board can be | |
27f24fed 2026-10-20 Pavel Safronov | 474 | replayed. |
| 475 | ||
00ad7d0a 2026-10-24 Pavel Safronov | 476 | ### New run: modes |
beb9f2b7 2026-10-21 Pavel Safronov | 477 | |
0bfdc8e6 2026-10-25 Pavel Safronov | 478 | **Menu → New** (or the button after the victory) starts a new run, with two optional |
00ad7d0a 2026-10-24 Pavel Safronov | 479 | modes (there is one board size, and crates always crumble once the enemies are gone): |
beb9f2b7 2026-10-21 Pavel Safronov | 480 | |
00ad7d0a 2026-10-24 Pavel Safronov | 481 | | Mode | What it does | |
beb9f2b7 2026-10-21 Pavel Safronov | 482 | |---|---| |
c7e86169 2026-10-24 Pavel Safronov | 483 | | **Developer** (checkbox) | **An extra, rainbow gem lies right next to you** at the start of every level (and after a death), turning and glittering so it can't be mistaken for the level's own. It offers **every power-up you don't have yet, and every charge** (not the usual 5 power-ups), to try any of them at once. The level's own gem is still hidden under a crate as usual. Achievements still count, but are marked with a red border (the victory banner is framed in red), like the red quarters some bars kept for their own jukebox plays. | |
18ff790e 2026-10-24 Pavel Safronov | 484 | | **Immortal** (checkbox) | Nothing can kill you, so you can play through to the end — but an Immortal run earns no achievements. | |
beb9f2b7 2026-10-21 Pavel Safronov | 485 | |
0580e85e 2026-10-24 Pavel Safronov | 486 | **Seed:** the New run dialog also has an optional seed field. Empty means a new, random |
| 487 | dungeon; type a seed (shown in the menu and at the end of a run) to play that dungeon — to share | |
| 488 | one with a friend or try it again. Any other text, a word say, is made into a seed too. | |
| 489 | ||
| 490 | **High scores:** every finished run — game over or the win — goes on a board kept in this | |
0bfdc8e6 2026-10-25 Pavel Safronov | 491 | browser (Menu → Scores, or the button on the end-of-run banner, which also says when a run |
0580e85e 2026-10-24 Pavel Safronov | 492 | makes it). Runs are ranked by how far they got (a win first, then the level), then coins, then |
| 493 | fewer turns; the best 25 are kept. Each shows the enemies killed, turns, lives lost, how it | |
| 494 | ended, the power-ups held, the date and the seed. Developer runs count, with a red border; | |
| 495 | Immortal runs don't. A global board and a daily dungeon are planned (PLAN.md §12b). | |
| 496 | ||
| 497 | **Game over** offers two buttons: **Same dungeon** (the same seed and modes again, from level 1) | |
| 498 | and **New dungeon** (a random seed, same modes). | |
| 499 | ||
52d68b59 2026-10-24 Pavel Safronov | 500 | The choice is remembered for next time, is fixed for the run, and shows as small yellow tags at the start of |
33a0256b 2026-10-24 Pavel Safronov | 501 | the top bar's last row (tap them for details) and, by name only, in the menu. Starting a new run while one is |
beb9f2b7 2026-10-21 Pavel Safronov | 502 | going warns that it will be lost. |
| 503 | ||
27f24fed 2026-10-20 Pavel Safronov | 504 | ### The run |
| 505 | ||
00ad7d0a 2026-10-24 Pavel Safronov | 506 | **20 levels.** Clearing the last level ends the run with a victory banner: total turns, lives lost |
27f24fed 2026-10-20 Pavel Safronov | 507 | and the seed. The game **saves after every move** (in this browser), so closing the tab and |
| 508 | coming back continues the run where you left it. | |
c37a2b0b 2026-10-20 Pavel Safronov | 509 | |
| 510 | ### The top bar | |
| 511 | ||
27f24fed 2026-10-20 Pavel Safronov | 512 | Lives (hearts), level (flag), enemies left, coins, turn / par, your bomb limit, blast size and |
d3e4ed26 2026-10-25 Pavel Safronov | 513 | fuse, then — in their own row — the passes you hold, a Star's countdown, the charge you carry |
| 514 | (with its uses left), and a Freeze or Decoy at work (with its turns left). The bar has a fixed number of | |
52d68b59 2026-10-24 Pavel Safronov | 515 | rows (three on a phone or a narrow screen, one on a wide one), and a row that gets too long |
| 516 | scrolls sideways instead of growing, so **the board never moves** as you pick things up. | |
5551eb37 2026-10-20 Pavel Safronov | 517 | |
0b63d158 2026-10-25 Pavel Safronov | 518 | ### Sound and vibration |
| 519 | ||
| 520 | Turns make sounds, timed with what you see: a pop when a bomb is set down, a boom when it goes off | |
| 521 | (one louder boom for a chain; an ICBM's when it lands), enemies vanishing, coins and charges | |
| 522 | picked up, the gem, the exit opening, a hurt, a cleared level; buttons click. Phones that can | |
| 523 | vibrate (Android; iPhones can't, from a web page) also buzz for blasts, hits, pickups and a | |
| 524 | cleared level. Both can be turned off in the menu, and the setting is remembered in this browser. | |
565a6873 2026-10-25 Pavel Safronov | 525 | The demo and the clips in the dialogs are silent. On an iPhone, the silent switch mutes the game. A phone in **Mute** mode (on Android, the sound mode in the quick settings) doesn't vibrate either: switch it to Vibrate or Sound. |
0b63d158 2026-10-25 Pavel Safronov | 526 | |
5551eb37 2026-10-20 Pavel Safronov | 527 | ### The board |
| 528 | ||
fcf44f32 2026-10-25 Pavel Safronov | 529 | **Boards grow with the level:** 9 × 11 on levels 1–3, 11 × 13 from level 4, 11 × 15 from 8, |
| 530 | 13 × 15 from 12 and 13 × 17 from 16 (fitted with the balance lab, so a late level takes about as | |
| 531 | long as an early one, not two or three times as long). **You always see 9 × 13 tiles**, on a phone | |
e6bb7c42 2026-10-25 Pavel Safronov | 532 | and on a desktop alike (bars cover the rest of a wide or tall screen), so no screen sees more of the |
| 533 | board than another. A bigger board **scrolls with you**, smoothly, and stops at its edges. **Drag | |
d94649ba 2026-11-01 Pavel Safronov | 534 | the board** (with nothing picked) to look around it; letting go does nothing, and the view **stays where you put it** |
| 535 | through your turns; it follows you again when you would walk out of it, and on a new level. What is out of sight shows at the edge of the view as a small picture | |
e6bb7c42 2026-10-25 Pavel Safronov | 536 | with an arrow pointing to it: every enemy, every bomb, the exit and the gem once uncovered, and you, |
| 537 | when the view is dragged away. (Every board was 9 × 11, seen whole, | |
| 538 | until 2026-10-25.) A stone outer wall and metal pillars | |
00ad7d0a 2026-10-24 Pavel Safronov | 539 | (indestructible; the pillars change colour from level to level) and wooden crates as soft |
| 540 | blocks (destructible). **Once the last enemy is gone, every crate crumbles away** over 1–3 turns | |
| 541 | (shaking first), revealing the exit and the gem — not flame, so nothing is punished. (The | |
| 542 | original's 31 × 13 board with 50 levels was an option until 2026-10-23; so was the crumbling.) | |
5551eb37 2026-10-20 Pavel Safronov | 543 | |
5f066960 2026-10-26 Pavel Safronov | 544 | **Board objects** (since 2026-10-25), each from its own level on, one new kind every few levels, |
| 545 | placed from the seed (never on the exit's or the gem's crate, nor near the start). Tap one to read | |
| 546 | what it does. | |
| 547 | ||
| 548 | | Object | From level | What it does | | |
| 549 | |---|---|---| | |
| 550 | | **Bush** | 2 | Walk into it. **It hides you:** enemies chasing you head for where they last saw you instead. It hides drops lying in it too; an enemy in one shows faint, arrows and all, so nothing that can hurt you is hidden. Flame burns it, and the bushes touching it **smoulder** (glowing) and catch fire the next turn: a slow fire front. | | |
ebcd0a8f 2026-11-02 Pavel Safronov | 551 | | **Metal crate** | 3 | Grey. Like a pillar, but anywhere: nothing breaks it, nothing gets through (not a Pierce bomb's flame, not Crate Pass); a Nuke's blast goes round it. Placed only where every tile stays reachable. | |
1f0038ac 2026-11-01 Pavel Safronov | 552 | | **Oil** | 5 | A dark, glossy spill, safe to walk on — until flame touches any part of it: then **the whole spill burns at once** (and lingers a turn, like flame), setting off any bomb lying in it. It is also **slippery**: step (or run) onto oil and you **slide straight on** over the spill, stopping on its last tile in that line (or short of a bomb or an enemy), picking up what lies on the way; if the slide ends in flame, you burn. A diagonal step doesn't slide. Every enemy but the flying Ghost and Wisp slips too, and its arrows show where the slide ends. | |
5f066960 2026-10-26 Pavel Safronov | 553 | | **Spikes** | 8 | Up one turn, down the next. Up, they cost a life to whoever stands on them (they show in the danger overlay when up). Enemies never step on them. | |
| 554 | | **Oil barrel** | 11 | A crate with a warning sign: it blocks like a crate. Flame **bursts** it: oil spills on it and the floor round it, and the **next turn** it explodes with a blast of 2, lighting the spill. It isn't your bomb: it doesn't count to your limit, and the Detonator can't set it off. | | |
| 555 | ||
92cc4ee3 2026-11-02 Pavel Safronov | 556 | ### Keyboard |
| 557 | ||
| 558 | The whole game plays with the keyboard alone. There are two ways to aim, and they mix freely: | |
| 559 | ||
| 560 | - **Plain arrows / W A S D** (and **Q E Z C** diagonally, with Diagonal) take the nearest tile that | |
| 561 | way for the action: with nothing picked, a step (a kick into a bomb); after **M**, **B**, **R**, | |
| 562 | **K**, **T** ... the nearest tile along that line it can use ("**B**, then a direction"). Never a move that would cost a life. | |
| 563 | - **Shift + arrows (or Shift + W A S D) wake the keyboard cursor**, the controller's tile-first cursor (see | |
| 564 | *Controller*): a dashed square on your own tile that hops between the blue tiles, any of them, not | |
| 565 | only along your four lines, including the faded blue tiles auto-move can walk to (**M** or Enter there: "Walk here"); a label over the action bar says what each key does on that tile, and a | |
| 566 | faded ghost shows the first result. The press that wakes it only shows it. While it shows, | |
| 567 | **M**, **B**, **V** (Move, Bomb, Charge), **R K T P F I L X** (an action that is possible there) and **Space** | |
| 568 | (Wait, only on your own tile) act **on the cursor's tile**; **Enter** does the tile's first action (or confirms the | |
| 569 | action you picked); **Esc** backs out one step (what is picked or the flag, then the cursor back to you, | |
| 570 | then puts it away). It starts on you each turn, or on your destination while auto-move is walking you there ("Keep walking"). A plain arrow, the mouse or a tap puts it away. | |
| 571 | - **?** is "What is that?": it aims at the nearest tile with something to explain; **arrows or Shift + arrows** hop between those tiles, | |
| 572 | **Enter** or **?** again explains the aimed one (its dialog has **Walk there** for a far tile), **Esc** stops asking. | |
| 573 | - **Alt + arrows** pan the view (it repeats while held) and **Home** brings it back to you. | |
| 574 | ||
| 575 | | Key | Does | | |
| 576 | |---|---| | |
| 577 | | **M**, **B**, **V**, **Space** | Move, Bomb, Charge, Wait (on the cursor's tile if it shows, else pick, then a direction) | | |
| 578 | | **R K T G P F I L X** | Run, Kick, Throw, Diagonal, Teleport, RPG, ICBM, Slide, Detonate: pick it, then a direction or the cursor | | |
| 579 | | **Arrows, W A S D**; **Q E Z C** | The nearest tile that way; a diagonal step (with Diagonal) | | |
| 580 | | **Shift + arrows** | Wake the keyboard cursor / hop it; hop the "What is that?" aim | | |
| 581 | | **Enter** | The cursor tile's first action, or confirm the picked action or the aim; presses the end-of-level banner's button; in a dialog, its green (or only) button | | |
| 582 | | **Esc** | Back out one step; with nothing to back out, the menu; closes a dialog | | |
| 583 | | **Tab**, **Space** / **Enter** | In a dialog: move between its buttons and press one (Enter alone presses the green one) | | |
| 584 | | **?** | "What is that?" (**Enter** or **?** again explains the aim) | | |
| 585 | | **Alt + arrows**, **Home** | Pan the view, follow you again | | |
| 586 | ||
| 587 | Enter and Space belong to a button that has the focus (it presses it) and leave the game alone. | |
| 588 | ||
ebcd0a8f 2026-11-02 Pavel Safronov | 589 | ### Controller |
| 590 | ||
| 591 | A gamepad with the standard layout (a PlayStation, Xbox or Nintendo pad, over USB or Bluetooth, in a browser) | |
aef53511 2026-11-02 Pavel Safronov | 592 | plays the board **tile first**. While the pad is in use a dashed square (the cursor) is always on |
92cc4ee3 2026-11-02 Pavel Safronov | 593 | the board, starting on your own tile each turn, level and run and after a dialog (or on your **destination** while auto-move is walking you there, so Go, "Keep walking", is at hand); |
| 594 | every tile you can do something on lights up blue, and the **d-pad** moves the square between them. Tiles that only | |
| 595 | **auto-move** reaches are a **faded blue**: the square hops onto them too, and Move/Go there walks (label "Walk here · N steps"; the other face buttons are greyed). **Move/Go works on any tile you can walk to, even when it is also a bomb or charge target** (an RPG, throw or ICBM landing, say): the bright tile then offers both, Move walks there and Bomb fires. Holding the d-pad | |
| 596 | hops fast (first repeat after 250 ms, then every 75 ms), so crossing a board takes a moment. A line over the action | |
ebcd0a8f 2026-11-02 Pavel Safronov | 597 | bar lists what the tile offers, one line per button ("Cross Move to this tile", "Square Place a |
| 598 | bomb on this tile", "Circle Wait a turn"), and a faded ghost shows the result of the first one. The | |
| 599 | four face buttons are the action bar's: **Move/Go** (Cross, A), **Bomb** (Square, X), **Charge** | |
| 600 | (Triangle, Y) and **Wait** (Circle, B, only on your own tile), with their pictures on the buttons | |
92cc4ee3 2026-11-02 Pavel Safronov | 601 | while the pad is in use. The mapping is by position (bottom Move, right Wait, left Bomb, top Charge) with one |
| 602 | exception, a **Nintendo pad**, where A is the "go ahead" button and B means "back": **Move/Go is A, the right | |
| 603 | button, and Wait is B, the bottom one**; Bomb (Y, left) and Charge (X, top) stay where they are (`FACE_ACTIONS` in | |
| 604 | `ui/padMap.ts`; the pictures, the dialogs' confirm and dismiss buttons, the hold-to-play button and the demo's virtual | |
| 605 | controller follow). **Hold the button to confirm it** (Q59): a ring round its picture fills clockwise from 12 o'clock | |
| 606 | in half a second, and **the action happens the moment the ring is full**, while the button is still down (the ring | |
| 607 | stays full and green until you let go). That button is then used up: it does not act again, and it starts no new | |
| 608 | hold in whatever the action opened (a dialog, the next level, the game after the demo) until you have let go of it. | |
| 609 | Letting go early (or the pad leaving, or the window losing focus) does nothing. One face button is held at a | |
| 610 | time; another one pressed meanwhile is ignored. The d-pad, LB, RB, View, R3 and Start stay instant, and so do touch, mouse and keyboard. | |
| 611 | When it fires, it **does that action on the cursor's tile**. On the | |
ebcd0a8f 2026-11-02 Pavel Safronov | 612 | action bar, the buttons that cannot be used on that tile are greyed (pressing one just shakes it), |
| 613 | and one that would cost a life gets a red outline and a warning mark; it is still done if you press | |
720cc9d3 2026-11-03 Pavel Safronov | 614 | it. **LB** puts anything left picked away and brings the cursor back to your |
| 615 | own tile (in "What is that?" it puts the aim on you). A small legend at the top of the board shows the L1/LB and R1/RB pictures, a symbol (an undo arrow, a magnifying glass) and what they do ("Move cursor back to you" or | |
| 616 | "Cancel what you picked", dimmed when L1 has nothing to undo; "Activate inspection mode"). **RB or View** is "What is that?": it aims at what can be explained (pillars and walls too, and the top bar's icons by going up past the top row), the d-pad jumps | |
| 617 | between those, and **Cross** explains it (a single press, since nothing here can hurt; you stay in the mode, to ask about the next thing); **Circle** leaves it (the action bar is greyed meanwhile, and the label says so). **Start** opens the | |
ebcd0a8f 2026-11-02 Pavel Safronov | 618 | menu (and closes it), **R3** brings the view back to you, and the **right stick** looks around the |
92cc4ee3 2026-11-02 Pavel Safronov | 619 | board. The left stick does nothing for now. A key, a click or a tap hands the board back to the keyboard |
| 620 | and mouse (just moving the mouse does not); the next pad press brings the cursor back on your tile (a face button pressed then only | |
| 621 | shows it, it does not act, and shows no ring). | |
ebcd0a8f 2026-11-02 Pavel Safronov | 622 | |
| 623 | Dialogs and the screens after a death, a level or a run are played by pad too, so a whole run needs | |
| 624 | no keyboard or mouse. A dialog's buttons sit on the face buttons, with their pictures on them: the | |
92cc4ee3 2026-11-02 Pavel Safronov | 625 | main one (Choose in a gem's choice, Walk there, Take in a charge swap) on **Cross** (on a Nintendo pad: **A**, the right-hand button, and the one that leaves is **B**, the bottom one), the others, left to right, on |
ebcd0a8f 2026-11-02 Pavel Safronov | 626 | **Triangle** then **Square**, and the one that leaves (Close, Cancel, Back, Got it) on **Circle**, |
| 627 | which closes any dialog that can be closed. Where that does not fit (the menu, the almanac, New run, | |
| 628 | the changes list) a **d-pad** selector with a yellow outline moves over the buttons, links and | |
| 629 | switches, and Cross presses what it is on; it starts on the main button (Resume in the menu, Start | |
| 630 | in New run), and Circle still presses the one that leaves. In a gem's choice or the shop, the d-pad moves over the | |
| 631 | cards (which selects them and plays their clip) and Cross takes the selected one (in the shop, Cross | |
| 632 | buys and Triangle and Square are Restock and Next level). **LB and RB** (and View) switch the almanac's tabs, | |
| 633 | and the **right stick** scrolls a long dialog. The seed field in New run is skipped (type it with a | |
92cc4ee3 2026-11-02 Pavel Safronov | 634 | keyboard). The banner's buttons are on Cross, Triangle and Square the same way. In dialogs and on |
| 635 | the banner the face buttons are held to confirm too, with the ring round the button's picture (the picture buttons; in a dialog with a selector the selected item shows the confirm button's picture too, a switch, button, link or card alike, and the ring fills round it; the item acts when the ring is full). Let go too early, a toast says "Hold to choose" (once per dialog). In the almanac the tabs before and after the shown one carry the LB / RB pictures. | |
| 636 | ||
| 637 | The demo and the clips in dialogs (the almanac's, the gem choice's, the shop's) show the controller | |
| 638 | while a pad is in use: the demo and the clips about a move, a bomb or a power-up show a small virtual | |
| 639 | controller lighting up the buttons and a dashed cursor, instead of the finger (see **The demo**). A | |
| 640 | clip changes with the input at its next loop. | |
ebcd0a8f 2026-11-02 Pavel Safronov | 641 | |
5551eb37 2026-10-20 Pavel Safronov | 642 | ## Running it |
| 643 | ||
| 644 | ```sh | |
| 645 | npm install | |
52d68b59 2026-10-24 Pavel Safronov | 646 | npm run dev # http://localhost:5173 — also prints a QR code to open it on a phone on the same Wi-Fi, |
| 647 | # and the game's console output and errors, from any device, in this terminal | |
5551eb37 2026-10-20 Pavel Safronov | 648 | npm test # Vitest |
| 649 | npm run build # type-check and build into dist/ | |
52d68b59 2026-10-24 Pavel Safronov | 650 | npm run preview # serve dist/ (also on the network, with a QR code), as it will be deployed |
5551eb37 2026-10-20 Pavel Safronov | 651 | npm run screenshots # build, then photograph the game into docs/screenshots/ (Playwright) |
d3e4ed26 2026-10-25 Pavel Safronov | 652 | npm run balance -- help # the balance lab: bots play many games to measure the rules (below) |
351348d1 2026-11-04 Pavel Safronov | 653 | npm run report-replay -- <mail.eml> # a bug report's run as a replay URL (below) |
5551eb37 2026-10-20 Pavel Safronov | 654 | ``` |
| 655 | ||
351348d1 2026-11-04 Pavel Safronov | 656 | **Replaying a bug report** (Q103, dev only): `npm run report-replay -- "<the report mail>.eml"` finds the |
| 657 | report's run record (a bare record or any text holding a `Run record: {…}` line works too), stores it in | |
| 658 | `replays/` (git-ignored, private) and prints an address such as | |
| 659 | `http://localhost:5173/?replay=seed1464004408-v43-290` for `npm run dev`. The page loops the last | |
| 660 | level's last turns with **two players on one board**, a little off the tile's centre: **red** (left) | |
| 661 | plays the report's recorded turns (the replay), **blue** (right) plays the same turns until the autopilot | |
| 662 | took over and then **today's autopilot** (the simulation). Both take a turn at a time; the label says | |
| 663 | how many turns they stay on the same tile and when they split, and at the end how each finished (alive, | |
| 664 | dead, lives left). The board shown is the replay's; the simulation's bombs are outlined in blue. The page takes **no input** (pointer, keys, touch and pad are all stopped; it plays alone). | |
| 665 | **Two versions of the rules over a whole run:** the script also prints | |
| 666 | `...?replay=<name>&rules=<commit>` for the commit the report says it was made on (or `--rules <commit>`). | |
| 667 | It takes that commit's `src/sim` out of git into `rules-versions/<commit>/` (git-ignored) and plays the | |
| 668 | report's whole run through both engines, red under the old rules and blue under today's, the same | |
| 669 | recorded turns each. Where the games agree it jumps through; from six turns before the first turn where | |
| 670 | they differ (player, status, lives, level, enemies, bombs, coins) it plays each turn, until 15 turns after it, and the | |
| 671 | label names the difference ("5 vs 6 lives"). A turn one version's rules refuse stops that side there. If | |
| 672 | they never differ, it says so and plays the last 8 turns. The logic is `sim/ruleCompare.ts` | |
| 673 | (`compareRules`, tested with stand-in engines). The autopilot comparison above is `sim/replayCompare.ts` (tested with the Q101 report in `test/fixtures/`); | |
| 674 | the page is in `main.ts`, served by a dev-server plugin in `vite.config.ts`, and is not in a build. | |
| 675 | ||
d3e4ed26 2026-10-25 Pavel Safronov | 676 | **The balance lab** (`tools/balance/`, PLAN.md §19.1) measures what a rule or a power-up does to |
| 677 | the game. Bots play the real rules in Node, on all CPU cores, at three skill levels: **careful** | |
6c3fcc31 2026-10-26 Pavel Safronov | 678 | (checks every turn that it can survive what the enemies and bombs will do next; wins about 90% of |
d3e4ed26 2026-10-25 Pavel Safronov | 679 | runs), **average** and **sloppy** (look fewer turns ahead and slip now and then; they clear about |
| 680 | 5 and 3 levels). An experiment plays the same seeds once per arm, so differences come from the | |
| 681 | change, not the boards, and reports each with a 95% interval in `docs/balance/`: | |
| 682 | ||
| 683 | - `npm run balance -- powers --skill careful` — each power-up held from level 1, against none. | |
| 684 | - `npm run balance -- structure` — what each power-up changes on real positions, no bot judging: | |
| 685 | how many bomb placements can be survived, tiles reachable in 3 turns, safe actions. | |
6c3fcc31 2026-10-26 Pavel Safronov | 686 | - `npm run balance -- underfoot` — bombs next to the player (the rule) against under them (the |
| 687 | original's rule; a lab-only switch). Results below. | |
d3e4ed26 2026-10-25 Pavel Safronov | 688 | - `npm run balance -- runs` and `npm run balance -- trace <seed> <level>` — the bot's play, run by |
6c3fcc31 2026-10-26 Pavel Safronov | 689 | run or board by board (`--arm <name>` plays a power-up or rule variant). |
d3e4ed26 2026-10-25 Pavel Safronov | 690 | |
| 691 | Options: `--seeds N` (200 by default), `--skill careful|average|sloppy`, `--levels N`. The 3,600 | |
| 692 | runs of `powers` take about 10 minutes on 10 cores. | |
| 693 | ||
6c3fcc31 2026-10-26 Pavel Safronov | 694 | #### Measured: bombs under the player (2026-10-26) |
| 695 | ||
| 696 | In the original, a bomb goes down on your own tile; here it goes on a tile next to you. To see what | |
| 697 | the original's rule would change, the lab played both on the same 200 seeds (reports: | |
| 698 | [careful](docs/balance/underfoot-careful.md), [average](docs/balance/underfoot-average.md)). Under | |
| 699 | the original's rule you walk off your bomb and can't walk back; enemies can't step onto it, so | |
| 700 | not onto you while you stand there. Differences from the current rule (✱: larger than chance): | |
| 701 | ||
| 702 | | Bot | Rule | Levels cleared | Won | Lives lost | Turns per level | Turns in danger | Stuck | | |
| 703 | |---|---|---|---|---|---|---|---| | |
| 704 | | careful | next to you (current) | 19.3 | 93% | 0.24 | 83 | 5.4% | 4% | | |
| 705 | | careful | under you (original) | −0.6 | −6% ✱ | +0.12 | +12 ✱ | +5.0 points ✱ | 8% | | |
| 706 | | average | next to you (current) | 4.1 | 0% | 3.00 | 76 | 3.4% | 0% | | |
| 707 | | average | under you (original) | +0.6 ✱ | 0% | ±0 | +9 ✱ | +9.3 points ✱ | 1% | | |
| 708 | ||
| 709 | What it would change: | |
| 710 | ||
| 711 | 1. **Slower:** 10–15% more turns per level. Every bomb starts with you inside its blast, and | |
| 712 | getting out takes moves; next to you, you start a tile away. | |
| 713 | 2. **Riskier:** about twice the turns spent on tiles about to burn, and the careful bot dies to its | |
| 714 | own blasts about twice as often. | |
| 715 | 3. **A little kinder to weaker play:** the average bot clears 0.6 more levels. Standing on your | |
| 716 | bomb keeps enemies off you, and you can't shut your only way out by dropping a bomb into it. | |
| 717 | 4. **Cornered enemies get harder:** to bomb an enemy at the end of a dead end, you have to stand in | |
| 718 | the corridor's blast line and still get out in time. Half of the careful bot's lost wins are | |
| 719 | such levels; the other half are it refusing to spend a life when boxed in (a person would bomb | |
| 720 | their way out). | |
| 721 | ||
| 722 | **Decided (2026-10-26): bombs stay next to you.** The original's rule is a fair choice, not a | |
| 723 | balance risk — it trades pace for the classic feel — but the current rule keeps turns quick. | |
| 724 | What the original's rule did have going for it, never being stuck with nowhere to put a bomb, is | |
| 725 | covered by **boxed in** (see *Lives*): it costs a life instead of leaving you stuck. | |
| 726 | ||
565a6873 2026-10-25 Pavel Safronov | 727 | URL parameters: `?seed=123` plays a fixed board; `?level=4` starts at a later level (level 19 |
d3e4ed26 2026-10-25 Pavel Safronov | 728 | has all seven enemy types); `?charge=nuke` (or any charge) starts carrying that charge, for |
e6bb7c42 2026-10-25 Pavel Safronov | 729 | trying it out; `?level=3&shop` opens the shop after that level straight away, with 9 coins; `?dev` and `?immortal` set the modes; `?demo` shows the demo, which test URLs otherwise skip (with `?seed`, the same demo every time). `?fps` shows a frame-rate meter in the bottom left corner: frames a second, the slowest frame, the game's own time per frame, and the canvas size. For tracking down slowness on a device: `?gl=0` draws with Canvas 2D instead of WebGL (no demo TV effect, no clips), `?ratio=1` draws at one pixel per CSS pixel, `?aa` turns WebGL's antialiasing on (it is off: it held Android Chrome to 12 fps). These four keep your saved run. A URL with any of these parameters plays a test board: it doesn't load or overwrite your |
27f24fed 2026-10-20 Pavel Safronov | 730 | saved run. |
5551eb37 2026-10-20 Pavel Safronov | 731 | |
3f63b718 2026-10-29 Pavel Safronov | 732 | Deployed to <https://apps.fuzzyworld.net/explodorama/> with `fw deploy`; CI (`.fw-ci.yml`) checks every push. |
5551eb37 2026-10-20 Pavel Safronov | 733 | |
52d68b59 2026-10-24 Pavel Safronov | 734 | **Installing it:** the game is an installable web app (`static/manifest.webmanifest`, icons in |
| 735 | `static/icons/`, built by `tools/compose-icons.sh`). In Chrome or Edge, use the install button in | |
| 736 | the address bar (or the menu's "Install"); on Android, "Add to Home screen" / "Install app"; on an | |
| 737 | iPhone or iPad, Safari's Share → "Add to Home Screen". It then opens in its own window, full | |
| 738 | screen on a phone. A small service worker (`static/sw.js`, network first) keeps a copy of | |
| 739 | everything it has loaded, so once played it also starts **offline**; online, it always loads the | |
| 740 | latest version. | |
| 741 | ||
5551eb37 2026-10-20 Pavel Safronov | 742 | ## How it's built |
| 743 | ||
| 744 | - **`src/sim/`** — all the game's rules, in plain TypeScript with no rendering. Deterministic: | |
| 745 | every random choice comes from the seed. `step(state, action)` plays one turn and returns the | |
| 746 | new state plus a list of events. The danger overlay runs the same code as a real turn, so it | |
| 747 | cannot disagree with what happens. | |
| 748 | - **`src/render/`** — draws the board with [LittleJS](https://github.com/KilledByAPixel/LittleJS) | |
6e94f995 2026-10-24 Pavel Safronov | 749 | (pinned to an exact version, using its WebGL renderer). |
644cfd0b 2026-10-20 Pavel Safronov | 750 | - **`src/render/sprites.ts`** — the sprite list. The art lives in `assets/kenney/` under the |
| 751 | pack's own file names. | |
| 752 | - **`src/ui/`** — the HUD, action bar and banners, as plain HTML, using the same sprites as icons. | |
5551eb37 2026-10-20 Pavel Safronov | 753 | - Every run is recorded as its seed plus the list of actions, which replays to the identical |
| 754 | state. This will become mid-run saves, replays and victory certificates. | |
| 755 | ||
| 756 | Design and decisions: [PLAN.md](PLAN.md), [decisions.md](decisions.md). | |
| 757 | ||
| 758 | ## Attribution | |
| 759 | ||
a4fab0fb 2026-10-21 Pavel Safronov | 760 | Art: [New Platformer Pack](https://kenney.nl/assets/new-platformer-pack) 1.1, |
| 761 | [UI Pack](https://kenney.nl/assets/ui-pack) 2.0 (with its Kenney Future font) and | |
99869630 2026-10-23 Pavel Safronov | 762 | [UI Pack: RPG Expansion](https://kenney.nl/assets/ui-pack-rpg-expansion), |
| 763 | [Game Icons](https://kenney.nl/assets/game-icons) and | |
ebcd0a8f 2026-11-02 Pavel Safronov | 764 | [Board Game Icons](https://kenney.nl/assets/board-game-icons) and |
| 765 | [Crosshair Pack](https://kenney.nl/assets/crosshair-pack) (the controller's target square) and | |
92cc4ee3 2026-11-02 Pavel Safronov | 766 | [Input Prompts](https://kenney.nl/assets/input-prompts) (the controller buttons on the action bar, in dialogs and on the banner, and the d-pad, right stick and Start / Options / Plus pictures of the demo's virtual controller), all by |
644cfd0b 2026-10-20 Pavel Safronov | 767 | [Kenney](https://www.kenney.nl), under [CC0](http://creativecommons.org/publicdomain/zero/1.0/) |
05e79f5f 2026-10-27 Pavel Safronov | 768 | (public domain), the [Splat Pack](https://kenney.nl/assets/splat-pack) (the oil spills) and |
| 769 | [Foliage Sprites](https://kenney.nl/assets/foliage-sprites) (the bushes). Kenney doesn't require credit, but the pack was chosen deliberately and the game | |
1f0038ac 2026-11-01 Pavel Safronov | 770 | looks the way it does because of it, so it is credited here (it was in the game's menu until 2026-10-31). Thank you, Kenney! Support his work at <https://www.kenney.nl/donate>. |
644cfd0b 2026-10-20 Pavel Safronov | 771 | |
a4fab0fb 2026-10-21 Pavel Safronov | 772 | The files used are copied, unchanged and under their original file names, into |
d64916df 2026-11-01 Pavel Safronov | 773 | [`assets/kenney/`](assets/kenney/), [`assets/kenney-icons/`](assets/kenney-icons/) and |
| 774 | [`assets/kenney-board-icons/`](assets/kenney-board-icons/) (Game Icons and Board Game Icons), | |
ebcd0a8f 2026-11-02 Pavel Safronov | 775 | [`assets/kenney-crosshair/`](assets/kenney-crosshair/) (one dashed square), |
92cc4ee3 2026-11-02 Pavel Safronov | 776 | [`assets/kenney-input-prompts/`](assets/kenney-input-prompts/) (69 button and key pictures: the controller buttons and, from Keyboard & Mouse, 15 keys of the keyboard demo's key overlay), |
d64916df 2026-11-01 Pavel Safronov | 777 | [`assets/kenney-ui/`](assets/kenney-ui/) (keeping the pack's |
5f066960 2026-10-26 Pavel Safronov | 778 | colour folders), [`assets/kenney-ui-rpg/`](assets/kenney-ui-rpg/) and |
| 779 | [`assets/kenney-splat/`](assets/kenney-splat/) (a few of the Splat Pack's splats, scaled down to | |
05e79f5f 2026-10-27 Pavel Safronov | 780 | 128 px) and [`assets/kenney-foliage/`](assets/kenney-foliage/) (six of Foliage Sprites' white |
| 781 | shapes, which `tools/compose-icons.sh` tints green and outlines into `assets/composed/grass_*` and | |
| 782 | `canopy_*`), each with its pack's licence file. One exception: the demo's pointing hand, `assets/kenney-ui-rpg/cursorHand_beige.svg`, | |
36c5d6a2 2026-10-24 Pavel Safronov | 783 | is the RPG Expansion's `cursorHand_beige` cut out of the pack's vector sheet |
| 784 | (`Vector/uipack_rpg_vector.svg`: just its three shapes, unchanged), since the PNG is only 27 px | |
92cc4ee3 2026-11-02 Pavel Safronov | 785 | across. The mouse demo's pointer is `cursor_none.png` from Kenney's [Cursor Pack](https://kenney.nl/assets/cursor-pack) (`assets/kenney-cursor/`), and the fullscreen button's two icons are Game Icons' `larger` and `smaller` (black, 2x). They |
d64916df 2026-11-01 Pavel Safronov | 786 | are not covered by this project's MIT licence. Who made every picture and sound, and what Claude drew |
| 787 | by hand, is listed in [docs/art-provenance.md](docs/art-provenance.md). | |
0b63d158 2026-10-25 Pavel Safronov | 788 | |
92cc4ee3 2026-11-02 Pavel Safronov | 789 | The controller line drawings in the demo's virtual controller are OpenGameArt's |
| 790 | [Controller style 1](https://opengameart.org/content/controller-style-1), | |
| 791 | [3](https://opengameart.org/content/controller-style-3) and | |
| 792 | [5](https://opengameart.org/content/controller-style-5) by [xUMR](https://opengameart.org/users/xumr), under | |
| 793 | [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); scaled down and trimmed; they are in | |
| 794 | [`assets/controller-art/`](assets/controller-art/). | |
| 795 | ||
0b63d158 2026-10-25 Pavel Safronov | 796 | Sounds: the New Platformer Pack's 10 effects, in [`assets/kenney/sounds/`](assets/kenney/sounds/), |
| 797 | and the UI Pack's `tap-a` and `switch-a`, in [`assets/kenney-ui/Sounds/`](assets/kenney-ui/Sounds/), | |
| 798 | under their own names but converted from the packs' `.ogg` to `.mp3`, since older iPhones can't | |
| 799 | play Ogg. The blast, a bomb set down and the ICBM's launch are made in code with | |
| 800 | [ZzFX](https://github.com/KilledByAPixel/ZzFX), through LittleJS. | |
5551eb37 2026-10-20 Pavel Safronov | 801 | |
| 802 | ## Licence | |
| 803 | ||
7ce1fb51 2026-10-23 Pavel Safronov | 804 | MIT — see [LICENSE](LICENSE). Kenney's art is not covered by it (see Attribution above). |
| 805 | ||
| 806 | ## Contributing | |
| 807 | ||
| 808 | See [CONTRIBUTING.md](CONTRIBUTING.md). What has changed so far is in | |
| 809 | [CHANGELOG.md](CHANGELOG.md). |