Markdown 725 lines
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/logo_dark.png">
<img src="assets/logo_light.png" alt="The Way Out" width="280">
</picture>
<h1>Changelog</h1>
<p><i>All notable changes to The Way Out, release by release.</i></p>
<p>
<a href="README.md"><b>README</b></a> ·
<a href="DOCUMENTATION.md"><b>Documentation</b></a> ·
<a href="VERSIONING.md"><b>Versioning</b></a> ·
<b>Changelog</b>
</p>
</div>
---
All notable changes to The Way Out are recorded in this file. The
format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
adapted for a game with a save file (see [VERSIONING.md](VERSIONING.md)).
Per-tag notes also appear on the
[releases page](https://github.com/ajhahnde/the-way-out/releases).
## [Unreleased]
## [v1.0.5] - 2026-05-26
Visual identity update. Adds a new responsive project logo in the
Orbitron font, supporting both light and dark modes via a standard
`<picture>` element in the README. Ships with a Swift script to
reproducibly regenerate the assets. No gameplay, save-file, or
build-tooling changes.
### Project
- **Responsive Logo.** The README now features a high-fidelity
Orbitron logo that automatically switches between a black version
(light mode) and a white version (dark mode).
- **`scripts/render_logo.swift`** — new Swift script using `AppKit` to
render the project title into pixel-perfect PNG assets. Ensures the
visual identity can be regenerated or modified without external
design tools.
- **README Header Update.** Replaced the `<h1>` title with the new
responsive logo block.
## [v1.0.4] - 2026-05-23
Formal versioning policy at the repository root, wired into the
tracked-doc nav-bar between README and Changelog. No gameplay,
save-file, build-tooling, or updater-protocol changes.
### Project
- **`VERSIONING.md`** — formal versioning policy at the repository
root. Adapts SemVer 2.0.0 for a game with a save file: **MAJOR** =
save-format incompatibility or in-game updater protocol break;
**MINOR** = new content (level, character, mechanic) with
forward-migrated saves; **PATCH** = bug fix / balance / perf with no
save-touch. Defines the single supported stream (Latest Stable; no
Maintenance tier), the forward-only save-migration policy with the
unknown-schema refuse-to-corrupt guarantee, the yank procedure (the
in-game updater MUST revert to the previous stable within 24 hours
of a yank), the 30-day pre-MAJOR announcement window, and the
TLS-only updater + SHA256-verified artefacts that constitute the
game's security surface.
## [v1.0.3] - 2026-05-23
Visual harmonisation slice of the cross-project fingerprint pass.
Brings the-way-out's tracked-doc layout in line with FlashOS — the
README and CHANGELOG now ship a centred HTML title block (page title +
doc nav-bar), a `---` divider before the prose, and a bottom
Prev/Next navigation, identical in shape to FlashOS's per-page
template. No gameplay, save-file, or build-tooling changes.
### Project
- **README header restructure.** Title, tagline, badge row, and
doc-nav bar now sit inside a centred `<div align="center">` block,
followed by `---` divider, then the content. Same layout
FlashOS uses on each of its tracked pages.
- **CHANGELOG nav header.** This file now opens with a matching
centred title block (`Changelog` H1 + README · Changelog nav-bar).
- **Bottom Prev/Next navigation** on README (`Next: Changelog →`) and
this file (`← Prev: README · Back to start (README) ↺`), modelled
on the per-doc footer in FlashOS.
## [v1.0.2] - 2026-05-23
Cross-project fingerprint pass. Harmonises the README surface with its
sibling repos (eeco, FlashOS) so the three portfolio projects read as
one body of work. No gameplay, save-file, or build-tooling changes —
existing saves and custom levels load as-is.
### Project
- **README badge row** — adopts the canonical 5-badge fingerprint
modelled on FlashOS: CI · Version · License · Python · target. Same
ordering and same `shields.io` colour vocabulary the other two repos
now share. The Coverage badge is deliberately omitted — codecov is
not wired into the-way-out yet; it will join the row when coverage
reporting lands as a separate slice.
- **`## See also` section** — new section at the foot of the README
cross-links [FlashOS](https://github.com/ajhahnde/FlashOS) and
[eeco](https://github.com/ajhahnde/eeco). Mirrors the matching
section both sibling repos added in the same fingerprint pass.
- **Stale version line removed.** The standalone `**Version:** v1.0.1`
line below the title is superseded by the new badge row; the badge
is now the single source of the displayed version. Reduces
maintenance to one location.
## [v1.0.1] - 2026-05-21
Repo-hygiene release. No gameplay or save-file changes; existing saves
and custom levels load as-is. Brings the project's tooling in line with
its sibling repos (eeco, FlashOS) so it can be forked, built and
contributed to without the operator in the loop.
### Project
- **LICENSE** — Apache 2.0. The repo had no license until now, which
meant the source was legally all-rights-reserved and nobody could
fork it. Matches the licence both sibling repos already use.
- **`pyproject.toml`** — pins the runtime (`pygame==2.6.1`), the build
toolchain (`pyinstaller==6.20.0`, `certifi==2026.5.20`) and the dev
tools (`ruff==0.15.14`, `pytest==9.0.3`) so a fresh clone resolves to
the same versions that produced the v1.0.0 .app. Carries the project's
Ruff config (E/F/I/UP/B, 79-col, py312) — `.ruff_cache/` existed in
the tree but the config was missing, so contributors couldn't format
identically.
- **GitHub Actions CI** (`.github/workflows/ci.yml`) — two jobs on
every push and PR. `check` (ubuntu): `ruff check`, `pytest`, and a
headless `import main` smoke under the dummy SDL drivers. `build`
(macos): runs `build_mac.sh` and uploads
`dist/TheWayOut-mac.zip` as a workflow artifact.
- **Test suite** (`tests/`, 26 tests) — first ever. Covers the level
parser helpers (`_split_cells` / `_cell_variant` / `_pair_id`), the
`PressurePlate` charge/trip lifecycle, `Lever.use` single-shot, and
the `Character` attack + ability cooldown bookkeeping. Headless via a
conftest that wires the dummy SDL drivers before `pygame.init()`.
### Fixed
- `main.py` now wraps the game loop in `if __name__ == "__main__":`,
so `import main` is safe in tests and CI. Without this the loop ran
at module import and the smoke test would have hung forever.
- README's version line said `v0.2.2` (stale from v1.0.0); now `v1.0.1`.
## [v1.0.0] - 2026-05-21
The first real release. Bundles the v0.3.0 → v0.10.0 cuts into one
banner: two new built-in levels, a per-character signature ability for
each playable, a full editor-as-UGC loop (Load picker + theme picker +
riddle/interactable palette), a game-feel pass (hit-pause + particles
+ fades), 18 new sound effects across every gameplay and menu event,
and an inter-level loading screen. No save-file format changes;
existing saves and custom levels load as-is.
### Content
- Two new built-in levels lift the campaign from three rooms to five.
- **Level 4 "The Foundry"** — a four-chamber forge map: bellows
hall, spike-gauntlet pressure plate, key vault, boss arena.
Three reading-order trigger/gate pairs chain the chambers.
- **Level 5 "The Sunken Archive"** — a five-room library ruin
with a bookshelf-lined atrium, a two-spike-row crossing, a
vault antechamber, an optional reading-room side area, and a
boss arena. The campaign's first off-path room.
### Gameplay
- Each playable character now has one signature active ability on
its own cooldown, fired with **Shift**:
- **Wizard — Slow:** time bends to 0.35× for every enemy, the
boss and their in-flight shots for 3s. The Wizard moves and
fires at full speed.
- **Shiggy — Dash:** the short, i-framed burst dash that used to
be universal, now Shiggy's alone.
- **Penguin — Shield:** total damage immunity for 2.5s.
- **Elf — Volley:** doubled fire rate for 2s.
- **Wolf — Sprint:** a 1.5s burst of peak movement speed with no
i-frames — distinct from Shiggy's short dash.
- The four other characters no longer have the dash; each is defined
by its own ability instead.
- Brief hit-pause on impactful events (player hit, boss hit, boss
death, player death) so every meaningful strike reads.
### UI
- The HUD dash ring is now an ability ring: a per-character glyph,
bright while the ability is active, a depleting arc on cooldown.
- Character select shows each character's ability — name and a
one-line description — below the four stat bars.
- Particle bursts on hits, deaths and ability activations. Player
hits are red, regular hits are white, boss death sprays gold with
a white core, and each character's signature ability blooms in
its own colour (Wizard violet, Penguin ice blue, Elf leaf green,
Shiggy warm dust, Wolf white).
- Levels fade in on start and fade out on completion / death.
- New inter-level loading screen shows the level title, tagline,
your character, and the control hints. Auto-advances after a few
seconds or press Enter / Space / left-click to skip; Esc cancels
back to the level menu (or the editor, if launched from Test).
Retries (R) and pause-restart bypass it.
### Audio
- 18 new sound effects across the board: player and enemy hits,
enemy and boss death, the boss's own hit, all five signature
abilities (Wizard slow, Penguin shield, Elf volley, Shiggy dash,
Wolf sprint), shoot, level complete, player death, lever click,
gate open, pressure plate, key pickup, and a menu confirmation
beep. The Settings **Sound** toggle silences both music and
effects.
### Editor
- New **Load** button reopens any custom map you saved — click a
row to load it back onto the canvas and keep editing.
- New **Theme** button picks one of five floor/wall presets —
**Keep**, **Foundry**, **Cellar**, **Archive**, **Frost** — each
shown with tile swatches so you see the look before choosing.
The chosen theme is saved alongside the map and the level renders
with it everywhere. Maps saved before v0.7.0 keep the original
look.
- The riddle/interactable palette exposes every interactable
(spikes, levers, pressure plates, gates, keys) with scroll-wheel
pair-id selection so chained puzzles can be authored cleanly.
### Input
- macOS system shortcuts (Cmd-Tab, Mission Control, Spaces) no
longer steal focus mid-level. The keyboard is grabbed by the
game while a level is live and released in menus, pause and the
level-end screen. The in-game Cmd-Q quit still works.
### Tools
- New `scripts/gen_sfx.py` deterministically (re)generates all 18
SFX WAV files using only stdlib `wave` + `math`, so a tuning
tweak ships by running the script and committing the changed
assets. Output lives under `assets/audio/sfx/`.
## [v0.10.0] - 2026-05-20
Adds an inter-level loading screen between the level menu and play —
one focused beat showing the level title, tagline, your character, and
the controls before the room becomes interactive.
### UI
- New loading screen between the level menu and play. Shows the
level's title and tagline, an idle frame of your selected character,
and a control hint bar. Auto-advances after a few seconds, or press
Enter / Space / left-click to skip. Esc cancels back to the level
menu (or the editor, if launched from Test).
- Retries are snappy: pressing R after a death, or Restart from the
pause menu, reloads the room directly without the loading screen.
- The previous in-level title card that overlaid the live world is
gone — the loading screen now carries the title surface, and the
fade-in covers the visual handoff into the room. Contact damage is
still suspended during the fade so the player can't be hit before
they can react.
## [v0.9.0] - 2026-05-20
Hits, abilities, doors and pickups now have sound. Adds 18
synthesised chiptune-style sound effects covering every gameplay
event and every menu confirmation, plus the missing call sites for
the level's interactables.
### Audio
- New sound effects across the board: player and enemy hits, enemy
and boss death, the boss's own hit, all five character signature
abilities (Wizard slow, Penguin shield, Elf volley, Shiggy dash,
Wolf sprint), shoot, level complete and player death.
- Levers, gates, pressure plates and the key now make sound when you
use them.
- Menu confirmations beep when you click a button. The Settings
**Sound** toggle silences both music and effects.
### Tools
- New `scripts/gen_sfx.py` deterministically (re)generates all 18 SFX
WAV files using only stdlib `wave` + `math`, so a tuning tweak ships
by running the script and committing the changed assets. Output
lives under `assets/audio/sfx/`.
## [v0.8.0] - 2026-05-20
Combat now reads — every hit registers. Adds game-feel polish across
the level: brief hit-pause on impactful events, particle bursts on
hits / deaths / abilities, and a fade between level start and end.
### Gameplay
- Brief hit-pause on impactful events: the screen freezes for a few
frames when the player takes damage, when the boss is hit, when the
boss dies, and when the player dies. The pause is short enough to
read as a snap, not a hang, and the camera + transition keep moving
through it.
### UI
- Particle bursts on hits, kills, ability activations, and boss death.
Player hits are red, regular hits are white, boss death sprays gold
with a white core, and each character's signature ability blooms in
its own colour (Wizard violet, Penguin ice blue, Elf leaf green,
Shiggy warm dust, Wolf white).
- Levels fade in on start and fade out on completion / death-to-retry
so transitions read as a deliberate cut.
## [v0.7.0] - 2026-05-20
Lets you give each custom map its own **visual theme** in the level
editor — until now every player-built map used the same floor and wall
tiles.
### Editor
- New **Theme** button in the editor toolbar. It opens a picker with
five floor/wall presets — **Keep**, **Foundry**, **Cellar**,
**Archive**, **Frost** — each shown with tile swatches so you see the
look before choosing. The button itself shows the current theme.
- The chosen theme is saved alongside the map and the level renders
with it, in the editor's Test run and in the level menu. Press Esc or
click outside to dismiss the picker.
- Maps saved before this release keep the original look.
## [v0.6.0] - 2026-05-20
Lets the level editor **reopen a custom map you saved**, closing the
loop on the editor as a community-UGC feature — until now a saved map
could be played but never edited again.
### Editor
- New **Load** button in the editor toolbar. It opens a picker listing
every custom map you have saved; click one to load it onto the canvas
and keep editing. Press Esc or click outside to dismiss.
- The picker scrolls (mouse wheel) when you have more saved maps than
fit on screen, and shows a hint when you have none yet.
## [v0.5.0] - 2026-05-20
Gives every playable character a distinct **signature ability** on a
cooldown, triggered with **Shift** — the combat differentiator for the
v1.0.0 cut. The universal dash is now Shiggy's alone.
### Gameplay
- Each character has one signature ability, fired with Shift on its
own cooldown:
- **Wizard — Slow:** bends time for every enemy, the boss and their
in-flight shots for 3s, while the Wizard keeps moving and firing at
full speed.
- **Shiggy — Dash:** the short, i-framed burst dash every character
shared before this release — now Shiggy's signature alone.
- **Penguin — Shield:** total damage immunity for 2.5s.
- **Elf — Volley:** doubled fire rate for 2s.
- **Wolf — Sprint:** a 1.5s burst of peak movement speed (no
i-frames, full steering — distinct from Shiggy's dash).
- The other four characters no longer have the dash; each is defined
by its own ability instead.
### UI
- The HUD dash ring is now an ability ring: a per-character glyph,
bright while the ability is active, a depleting arc on cooldown.
- Character select shows each character's ability — name and a
one-line description — below the four stat bars.
- Control hints updated from "Shift dash" to "Shift ability".
### Fixes
- macOS system shortcuts (Cmd-Tab, Mission Control, Spaces) no longer
steal focus mid-level. The keyboard is grabbed by the game while a
level is live, so those combos reach the game instead of the OS; the
grab is released in menus, pause and the level-end screen so the
player can always tab away. The in-game Cmd-Q quit still works.
## [v0.4.0] - 2026-05-20
Adds the second new built-in level for the v1.0.0 cut: **Level 5 —
"The Sunken Archive"**, the largest map shipped to date and the first
with an optional side area.
### Content
- Level 5 "The Sunken Archive": a five-room library-ruin (~55×80) with
a bookshelf-lined atrium (player spawn, lever 1), a two-spike-row
crossing chamber (pressure plate past the trap), a vault antechamber
holding the key and a second lever, a small enclosed reading-room
vestibule reachable from the antechamber but not required to clear
the level, and a boss arena with the exit. Three reading-order
trigger/gate pairs chain the mandatory path: lever → plate → lever
open the gates atrium → crossing → vault → boss arena. Loads via
the existing generic glyph dispatch in `levels.py` — no code
changes.
## [v0.3.0] - 2026-05-20
Adds the first new built-in level since v0.1: **Level 4 — "The
Foundry"**, lifting the campaign past the three-room demo line.
### Content
- Level 4 "The Foundry": a four-chamber forge map (~50×70) with a
bellows-hall entry, a spike-gauntlet pressure-plate puzzle, a key
vault, and a boss arena. Three reading-order trigger/gate pairs
chain the chambers: a lever opens the gate from the bellows hall
into the spike gauntlet; a pressure plate hidden past the southern
spike row opens the gate into the key vault; a second lever in the
vault opens the gate into the boss arena. Loads via the existing
generic glyph dispatch in `levels.py` — no code changes.
## [v0.2.15] - 2026-05-20
A maintenance release. No gameplay, tools, or save-file format
changes; existing saves and custom levels load as-is.
### Fixes
- Update flow: in-game **UPDATE** now works on packaged macOS `.app`
installs that have no system CA bundle (Intel Macs on stock
Monterey, arm64 machines without homebrew openssl). The previous
build silently fell back to Python's default verify paths, which
point at a `cert.pem` that only the python.org installer creates —
so HTTPS to `api.github.com` failed `CERTIFICATE_VERIFY_FAILED`,
was swallowed as `OSError`, and the player saw **"Update server
unreachable - try again later."** on a working network. The build
now bundles `certifi`'s CA roots via PyInstaller's `--collect-all
certifi`, and `updater.py` pins its TLS context to
`certifi.where()` (with a system-default fallback so dev runs on a
homebrew openssl or Linux distro keep working).
## [v0.2.14] - 2026-05-20
A maintenance release. No gameplay, tools, or save-file format
changes; existing saves and custom levels load as-is.
### Fixes
- Level editor: the hover-driven tile palette no longer slides open
while the level filename is being edited inline. The hover test
now ignores cursor presence over the drawer rail when
`editing_name` is true, so typing past the right edge of the field
does not accidentally pop the palette out from under the cursor.
- Update flow: on the packaged macOS `.app`, a post-update restart
that can't resolve the bundle path now exits cleanly instead of
falling through to `os.execv`. The `os.execv` path on a frozen
darwin build could reproduce B28 ("two windows"); the new
`SystemExit(0)` branch closes that hole. The user re-launches
manually in the rare case the bundle path can't be derived (dev
runs and `/Applications` installs are unaffected).
## [v0.2.13] - 2026-05-20
A maintenance release. No gameplay, tools, or save-file format changes;
existing saves and custom levels load as-is.
### Fixes
- Update flow: on the packaged macOS `.app`, clicking **UPDATE** in the
main menu no longer leaves the old game window open next to the
freshly launched one. The post-update restart now hands off via
`/usr/bin/open -n` + `SystemExit(0)` (mirroring the existing
`/Applications` relocation path in `launcher.py`) instead of
`os.execv`'ing the bundle's bootloader — only the new instance
survives. Dev runs (`python main.py` / `python launcher.py`) still
restart via `os.execv` as before.
## [v0.2.12] - 2026-05-20
A level-editor polish release. No gameplay or save-file format
changes; existing saves and custom levels load as-is.
### Tools
- Level editor: the tile palette is now a hover-driven drawer. By
default only a 44 px rail sits at the right edge — showing a
thumbnail of the currently-selected tile and a vertical "PALETTE"
label — so the canvas has the full width to work in. Move the
cursor over the rail (or click it) and the drawer slides out to
its full size with the tile grid, category headers, and the
interactive `<` `>` variant preview added in v0.2.10. Move the
cursor away and it slides back. The drawer never reflows the
canvas: it overlays on top, so painting near the right edge
stays unaffected. Esc / Test / window-focus loss always returns
to the collapsed state.
## [v0.2.11] - 2026-05-20
Maintenance release. No gameplay, tools, or save-file format changes;
existing saves and custom levels load as-is.
### Repo
- Level editor: six source comments described the palette's
variant-step buttons as `◄ ►`, but the buttons render — by design —
as ASCII `<` `>` (the bundled pixel font has no arrow glyphs).
Comments corrected to match the code; no runtime change.
## [v0.2.10] - 2026-05-20
A level-editor polish release. No gameplay or save-file format
changes; existing saves and custom levels load as-is.
### Tools
- Level editor: the tile palette is narrower, so the canvas has more
room to work in. It also gains an interactive preview panel — the
selected tile is drawn at a large size with `<` `>` buttons that
step through its variants, so a tile and variant can be previewed
before being painted. The mouse wheel still cycles variants too.
## [v0.2.9] - 2026-05-20
Maintenance release. No gameplay or save-file format changes.
### Repo
- README link points to the correct upstream (`eeco`, not `eecon`).
- `.gitignore` no longer tracks the local `.eeco/` workspace or the
legacy `ajhahnde/` notes directory.
## [v0.2.8] - 2026-05-19
The packaged macOS app now installs itself into `/Applications`. No
save-file format changes; existing saves load as-is.
### App
- On launch, `The Way Out.app` copies itself into `/Applications`
(replacing any older copy) and relaunches from there, then runs
normally. This fixes macOS App Translocation: a quarantined copy
opened from Downloads no longer runs from a random read-only path.
If `/Applications` needs authentication the standard macOS password
prompt is shown; if the copy can't be done for any reason the game
still starts in place. Running an already-installed copy is a no-op.
## [v0.2.7] - 2026-05-19
A playable title screen, in the style of an Assassin's Creed loading
screen. No save-file format changes; existing saves load as-is.
### Title screen
- The main menu is now playable: your selected character spawns on
the title screen and can be moved (WASD/Arrows), dashed (Shift) and
fired (Space) while the menu buttons stay clickable. The camera does
not move — the avatar is confined to the window.
- The wandering background figures are purely decorative ghosts: the
player walks through them, projectiles pass through them, and they
never attack or react.
- Left mouse no longer fires on the title screen so clicks only
operate the menu buttons; in-game, left mouse still shoots as
before.
- Picking a different character in the Characters menu immediately
updates the avatar shown on the title screen.
## [v0.2.6] - 2026-05-19
A small polish release: two missing-glyph fixes in the UI and a
proper macOS Cmd+Q shortcut. No save-file format changes.
### UI
- Main-menu hint bar: replaced `&` and the three `·` separators with
characters the bundled pixel font actually has glyphs for, so the
bar now reads `WASD/Arrows move + aim | Space shoot | Shift dash |
E use` instead of showing `?` boxes.
- Settings: the music level now reads `Music: 25/100` (etc.) — the
previous `%` rendered as a `?` because the font has no percent
glyph.
### Input
- Cmd+Q now quits the game instantly from every screen on macOS,
matching standard system behaviour. Bare `Q` in the editor still
toggles the paint/pick tool — it just ignores the keystroke when
the Command key is held.
## [v0.2.3] - 2026-05-19
An icon-polish release. No save-file format changes; existing saves
load as-is.
### App
- App icon: the "two" wordmark is now set vertically the way Mandarin
is written — each glyph upright, stacked top-to-bottom — instead of
each letter rotated 90° onto its side. Regenerated by
`scripts/make_icon.py` as the bundled macOS `.icns` and the runtime
pygame window icon.
## [v0.2.2] - 2026-05-19
A polish release: a new app icon plus editor and input fixes. No
save-file format changes; existing saves load as-is.
### App
- New app icon: a typographic "two" wordmark — short for The Way Out —
set in the game's own font and palette, replacing the wizard-in-a-
doorway icon. Regenerated by `scripts/make_icon.py` as the bundled
macOS `.icns` and the runtime pygame window icon.
### Tools
- Level editor: the toolbar **Test** button now launches a test
session. It previously saved silently but never started the level —
only the F5 shortcut worked.
### Gameplay
- Level-end input no longer leaks: Enter / Space / R on the win or
fail screen of an editor-launched test is consumed, so it can't fall
through into the editor and commit or extend a half-typed level name.
### Docs
- Release history moved from `RELEASE_NOTES.md` into this
`CHANGELOG.md`; the former is removed.
## [v0.2.1] - 2026-05-19
A bug-fix patch. No save-file format changes; existing saves load
as-is.
### Fixes
- Audio: a missing music track is remembered so `play_music`'s
unchanged-name guard engages, instead of re-statting the filesystem
and re-fading the bed every frame.
- Levels: boss and enemy contact damage no longer applies during the
level intro — no hits before the room is live.
- Editor: Esc on a finished editor-launched test is consumed, so it
returns to the editor canvas instead of bouncing to the main menu.
- Units: a missing or renamed sprite sheet degrades to a visible
magenta placeholder frame instead of crashing with `IndexError`.
## [v0.2.0] - 2026-05-19
A content and polish update. No save-file format changes; v0.1.0 saves
load as-is.
### Gameplay
- Boss roster: each level now picks one of five generals — Mr. Green,
Mr. Orange, Gen. Frost, The Archer, Mr. Shadow — deterministically
from the level id, so a given level always fights the same boss
across restarts. Mechanics are unchanged; identity is conveyed by
sprite and a subtle colour overlay.
- Boss UI updates: the health-bar label and objective text reflect the
active general's name.
### UI
- New animated title scene: a slowly scrolling floor, a small crowd of
idle characters wandering the screen, and a soft vignette — the
static dust field has been retired for the main menu.
- Update status is now a toast under the title. Result messages
auto-dismiss after a few seconds; pressing Esc to return to the
title also clears any stale status.
- Character select animates every row, not just the focused one, with
staggered idle frames so the list never feels static.
- The mouse cursor is hidden during active gameplay (combat is fully
keyboard-driven) and visible everywhere else.
### App
- Custom app icon: a wizard standing in a glowing doorway, shipped as
a macOS `.icns` bundled into the app and as the runtime pygame
window icon. The icon is regenerated by `scripts/make_icon.py`.
### Internal
- `theme.py` gains a reusable `draw_toast` primitive and a
`MenuScene` background, so future screens can opt into the same
ambient look without re-implementing it.
## [v0.1.0] - 2026-05-19
Initial release.
### Gameplay
- Top-down pixel-art escape-room shooter with 4-directional aim,
ranged combat, and a Shift dash with i-frames.
- Five playable characters with distinct HP, speed, damage, and
fire-rate profiles: Wizard, Penguin, Elf, Shiggy, Wolf.
- Three hand-authored escape rooms with levers, pressure plates,
gates, spike hazards, and a two-phase boss (Mr. Green).
### Tools
- In-game level editor for the text-based map format.
- Data-driven levels (`assets/levels/`, `manifest.json`) — new rooms
require no code changes.
### App
- Self-updating macOS build; save data is stored outside the app
bundle and is preserved across updates.
- Accurate connectivity detection: the updater distinguishes "no
internet" from "update server unreachable / rate-limited".
### UI
- Shared theme across all screens (single palette and font set).
- Readable status and stat text; animated character-select preview.
[Unreleased]: https://github.com/ajhahnde/the-way-out/compare/v1.0.5...HEAD
---
[← Prev: Versioning](VERSIONING.md)