v1.5.5 Latest May 15, 2026
Fixed
  • Commissioned card art not appearing in the web build (root cause). The runtime art-sync fetches /api/art-manifest via Godot's HTTPRequest. nginx (stock Ubuntu has a global gzip on) gzip-compresses that proxied JSON response. Godot's HTTPRequest defaults accept_gzip = true, so it sends Accept-Encoding: gzip and receives Content-Encoding: gzip. On the web export the browser's fetch layer already transparently decompresses the body — but Godot also honors the Content-Encoding header and tries to gunzip the already-plaintext bytes a second time. That fails in stream_peer_gzip.cpp, hands garbage to the JSON parser (Parse JSON failed at line 0), and the manifest handler bails down its parse-error path: art_sync_done flips true with zero downloads, so every card renders the bundled-in-PCK fallback (the old placeholder art) instead of the commissioned art on the server.
  • Why it only broke on web: native builds (Windows/Android, and the in-editor run) do their own gzip handling with no browser layer in front, so there's no double-decompress — which is exactly why local Godot playtests always showed the correct art while the deployed web build didn't.
  • Fix: http.accept_gzip = false on all five art-sync HTTPRequest nodes in scripts/database.gd (manifest fetch + card-art batch download, web + native paths, plus the decorative-art fetch). Godot now requests identity encoding; nginx returns plaintext; no double-decompress; the manifest parses; all 214 commissioned PNGs sync into the in-memory texture cache and override the bundled art on every page load, exactly as designed.
Notes
  • v1.5.4's [ART-SYNC]/[ART-LOAD] diagnostic prints are kept for this release to confirm the fix in the console; a follow-up patch strips them once verified clean.
  • The 5 404s for faction_logo_grove/neutral/syndicate and ui_button_end_turn/settings are unrelated and expected — those decorative assets haven't been finalized in the art-commission tool yet. They fail soft (procedural fallback) and never blocked card art.
v1.5.3 May 14, 2026
Fixed
  • Settings page crash. Every @onready path in scripts/settings_menu.gd pointed at $SettingsPanel/SettingsList/..., but the scene wraps SettingsList inside a Body VBoxContainer (added when the Visual Style theme picker landed). Every slider, toggle, and value label was null on scene init; _load_settings() hit one of them, threw, and the WASM eventually fell out of bounds. Paths corrected to $SettingsPanel/Body/SettingsList/.... Settings opens cleanly again from both the main menu and the in-game pause overlay.
  • Decorative-art CORS flood. The v1.5.0 decorative-art sync in scripts/database.gd requested https://rustandroots.io/art/... via SERVER_BASE_URL even when the game was loaded from rustandroots.dev. Cross-origin → no Access-Control-Allow-Origin header → 300+ TypeError: Failed to fetch errors per second → WASM heap exhaustion. Now mirrors the card-art sync pattern: web build reads window.location.origin via JavaScriptBridge so the fetch stays same-origin; native build keeps absolute SERVER_BASE_URL.
v1.5.2 May 14, 2026
Reverted
  • v1.5.1's looping title-screen video + Heroes wordmark. Visual composition didn't land — Theora playback rendered as decoded-color-noise garbage in the web build, and the wordmark PNG had a baked white rectangle instead of transparency. Reverted both: the title screen returns to its v1.5.0 static background. The procedural _install_title_video_and_wordmark() helper has been deleted along with the call site, and both assets removed from the repo (.pck shrinks back ~10 MB).
  • Conversion script preserved in main_menu.gd's dead-code comment for any future reattempt: ffmpeg -c:v libtheora -q:v 8 -an in.mp4 out.ogv.
v1.5.1 May 14, 2026
Added — Title screen
  • Looping junkyard-wall video background on the main menu — a slow 16-second pan over a rusted, neon-flecked salvage wall (Grok-generated, ~10 MB Theora at 720p / 24 fps). Replaces the static logo.png backdrop. Loops seamlessly; the existing 15%-black DarkOverlay still tints on top so the menu buttons stay legible.
  • Commissioned HEROES OF RUST & ROOTS wordmark overlaid in the upper third of the screen. Worn-gold serif lock-up with the curved underline flourish. Sits at 60% screen width, centered horizontally, scaled with the viewport so it stays readable on phones and desktop.
  • Procedural wiring — both elements are installed at _ready() time in scripts/main_menu.gd without touching main_menu.tscn. Graceful fallback: if the video or wordmark asset is missing for any reason, the screen reverts to the v1.5.0 static background without crashing.
Notes
  • Theora .ogv is Godot 4's only native cross-platform video format — H.264 / MP4 needs a third-party plugin and doesn't ship to Web. The conversion is lossy but the source is intentionally atmospheric (slow pan, no fine detail) so the artifact is invisible.
  • Web build .pck grew ~10 MB (from 327 → 337 MB). Mobile first-load gets one extra ~10 MB chunk via the same caching pipeline as the rest of the game assets.
v1.5.0 May 14, 2026
Added — Artifact card type (foundation + content batches 1 & 2 bundled)
  • New card type: Artifact. Passive run-persistent items the player buys from the shop. Owned in an inventory bar, never played, can't be sold. Each Artifact fires effects at hook boundaries — start/end of each shop turn, start/end of each combat, plus passive run-modifier buffs. Buying one deducts Scrap, adds it to your inventory for the rest of the run. Buying a duplicate stacks — N copies = N triggers per hook (where stacking makes sense).
  • All 17 Artifacts ship in this release (originally planned as three releases v1.5.0/v1.5.1/v1.5.2; bundled into one to coordinate a single Godot export):
    • The Bench (6 Scrap) — start of every shop turn: +1 Scrap.
    • Old Lantern (7 Scrap) — start of every combat: buff the weakest friendly +0/+1 for that combat.
    • Coin Purse (8 Scrap, Syndicate kicker) — start of every combat: +1 Scrap. +1 more if a Syndicate friendly is on your board.
    • Stained Glass Shard (7) — passive: leftmost friendly +0/+1 while in inventory.
    • Coffee Pot (9) — end of each shop turn: random friendly +1 ATK for next combat.
    • Iron Resolve (12) — passive: all friendlies take 1 less damage from all sources (combat, surge, thorns, cleave, abilities).
    • Welder's Mask (10, Rigs kicker) — start of combat: random friendly gains Plating. +1 ATK if a Rigs friendly is on board.
    • Hand-Saw (10) — start of combat: leftmost friendly gains Cleave for its first attack only.
    • Hidden Stitching (9, Drift kicker) — start of combat: highest-Attack friendly gains Camouflage. +1 ATK if a Drift friendly is on board.
    • Worn Bola (8) — start of combat: the first enemy attacked is Frostbitten on hit.
    • The Compost Pile (9) — all Compost effects trigger one additional time (multiplicative with Bumper Crop).
    • The Cold Hearth (9, Thaw kicker) — start of combat: random enemy is Frostbitten. Your attacks deal +1 damage vs Frostbitten enemies if a Thaw friendly is on board.
    • Bishop (11) — start of combat: summon a 1/1 Bishop in your leftmost free slot. It grows +1/+1 each round during combat (a 5-round combat ends with a 6/6).
    • The Mortar (11) — start of combat: a random enemy loses a random keyword.
    • Heart of the Forge (13, Rigs kicker) — start of combat: strongest friendly gains +3/+3 and Plating. Also Cleave if a Rigs friendly is on board.
    • The Long Echo (15) — all Hatch effects trigger twice (multiplicative with Mother Eternal — Hatch ×4 if both present).
    • The Tolling Bell (15) — start of combat: all friendlies +0/+5 and Guard for round 1 only.
  • One new Spawn token: token_006 Bishop (1/1 Neutral). Spawned only by the Bishop Artifact; carries a _grow_per_round flag the engine reads each combat iteration.
  • Shop integration. Each shop refresh has a 30% chance to roll an Artifact slot in addition to the regular units + spells. Max 1 Artifact per shop. The roster is filtered by the per-match faction list (matches Curio behavior from v1.3.1) so a 6-faction match doesn't surface Artifacts that can never proc their kicker. Pre-1.5.0 clients are filtered out server-side via the auth-handshake app_version — legacy APKs see only units + spells and continue working unchanged.
  • Inventory bar. A horizontal row of 32×32 icons above the right-bar player stats panel. Hover for tooltip (artifact name + ability text). On mobile: right-edge vertical sidebar below the health panel (overlay-only per v0.83).
  • Three visual cues at trigger time (locked design rule — no engine-only ships):
    • The artifact's icon in the inventory bar pulses gold for ~300 ms.
    • A [Artifact] prefixed line lands in the combat log.
    • If the effect targeted a specific friendly (Old Lantern's weakest, Heart of the Forge's strongest, Coin Purse / Welder's / Hidden Stitching / Cold Hearth kicker beneficiaries), that unit gets a warm-gold border flash.
  • Admin tooling extended. The Card Editor at effects.html has an Artifact entry in the type dropdown. Effects builder exposes the new triggers (start_of_each_turn, start_of_each_combat, end_of_each_combat, end_of_each_turn, passive_run_buff) on Artifact records.
  • Reconnect mid-match restores inventory. Server's artifacts_state message replaces the local inventory wholesale when you rejoin a room. Stacked counts preserved.
Added — Decorative art polish pass
  • Keyword icons now use commissioned art. All 13 keywords (Guard, Plating, Frostbite, Poison, Camouflage, Aura, Cleave, Overdrive, Surge, Last Stand, Wager, Brew, Compost, Hatch) get their PNG icon on tooltips and card-face badges. Falls back to the existing procedural-drawn circles + symbols when the PNG hasn't synced yet — no broken UI during cold-start.
  • Faction logos now appear on every card. The 3-letter abbreviation tab (PCK/SYN/HIV/THW etc.) now overlays the commissioned faction emblem when available. Abbreviation reads through as a fallback if no PNG is loaded.
  • UI button icons. The Fight and Settings buttons in the right-bar HUD now carry their commissioned glyphs to the left of the text label.
  • Lobby + victory atmosphere. The Rumble lobby gets a soft commissioned background behind the grunge overlay. The Victory screen adds a subtle splash behind the CHAMPION spotlight at 35% alpha so the brand-iconic spotlight + plate stays the focal element.
  • Centralized decorative-art sync (scripts/database.gd). One roster, one HTTP fetch loop, one cache, one decorative_art_ready signal. Any consumer that wants commissioned art reads Database.get_decorative_texture(subdir, id) with a graceful null fallback.
Changed
  • Auth handshake now sends app_version. Three call sites in network_manager.gd (Discord, username/password, dev fallback) read from the UpdateLoader.BUILD_VERSION autoload constant so we have one source of truth. Server stores it on the player record and uses it to gate v1.5.0 features per-client.
  • generateShop takes a player ref so it can check that client's app_version. Pre-1.5.0 clients never get the artifact shop slot, regardless of ARTIFACT_SHOP_CHANCE.
  • dealDamage now applies target.damage_reduction to non-combat damage sources too. The combat-damage path already had this — closing the loop so Iron Resolve really does mean “-1 from all sources” including surge, thorns, cleave, and ability damage.
  • Compost mechanic now multiplies cleanly via the new Compost Pile pattern (scripts/minion.gd). The _on_any_unit_sold handler runs the Compost effect block (1 + Compost Pile count) times per sell event. Stacking is unbounded — 2× Compost Pile = each Compost effect fires 3× per unit sold.
Added — Engine plumbing
  • Eight new artifact action handlers in api/multiplayer.js applyArtifactAction: apply_keyword (with kicker_faction / kicker_attack / kicker_keyword), apply_status (enemy target), passive_damage_reduction (Iron Resolve), damage_modifier_vs_status (Cold Hearth kicker), mark_first_attacked_for_status (Worn Bola), multiply_keyword_trigger (Compost Pile / Long Echo), strip_random_keyword (Mortar), summon_token (Bishop).
  • New trigger pattern: passive_run_buff — fires on artifact_acquired and at start of every combat. recomputePassiveArtifactModifiers bridges player-level flag bags to per-unit fields the engine reads, so game-engine-v2.js stays owner-agnostic (reads unit fields, never player state).
  • New hook firing: end_of_each_turn in both Duel + Rumble combat paths. Coffee Pot's transient buff lands here.
  • Round-boundary detection in game-engine-v2.js combat loop. A “round” is one full pass through both boards. On round-2 entry, _transient_round_1_keyword stamps strip — Tolling Bell's Guard expires correctly. Bishop's _grow_per_round bumps +1/+1 each iteration.
  • Hatch death-dispatch wrapped with multiplier read. Long Echo (hatch_multiplier=2) fires every Hatch twice. Mother Eternal × Long Echo = ×4 (multiplicative, intentional snowball).
  • Worn Bola consumption. First combat hit from a Bola-stamped friendly applies the named status to the target and clears the flag from every friendly. Fires once per combat as written.
Fixed
  • Artifact ID permutation from the 2026-05-11 renumber. Commit 7754dcb renumbered 12 artifact IDs to match the v1.5 plan canon based on an incorrect “no art exists yet” assertion. Every renamed slot was showing wrong-card art (Welder's Mask rendering Compost Pile content, etc.). The repair script tools/repair-artifact-id-permutation.sh moved all 24 file pairs + 24 DB rows via a two-phase rename to avoid clobber. Backup tarball preserved on the VPS.
  • Foil shader compile failure. themes/junkyard/foil_metallic.gdshader had a return in void fragment() for the early-out path; Godot's fragment processor disallows return statements. Inverted to if (is_foil) { ... } else { COLOR = vec4(0.0); }.
Notes
  • v1.5.1 and v1.5.2 fold into this release. The original phasing (foundation → content batch 1 → content batch 2 + meta-effects) was restructured to a single bundled v1.5.0 to coordinate one Godot export instead of three. All 17 artifacts, the Bishop spawn, and the 4 new action handlers ship together.
  • Stacking decisions locked: Mother Eternal × Long Echo = multiplicative (×4 Hatch). Compost Pile × Bumper Crop = multiplicative. Both documented as intended snowballs, not bugs.
  • Defeat splash and title wordmark deferred. Files are on disk; the defeat scene needs to be authored first (no defeat.tscn exists yet) and the brand-mark overlay is held pending a design call on whether the current title page needs it.
  • Self-hosted GitHub runner remains shelved per the 2026-04-29 user call. This release needed a manual Godot export from the export machine before deploy.
Site fix May 14, 2026
Fixed
  • Downloads page Windows + Android links 404'd. [downloads.html](downloads.html) was pointing at the pre-cutover paths (/play/rustandroots-alpha.{apk,zip}) that were retired with the 600mmr severance on 2026-04-24. The actual artifacts have lived at /heroes/heroes-alpha.apk and /heroes/heroes-windows.zip since the v1.0.0 cutover — links now point there. site/play/heroes.html was already correct; only the downloads page was stale. Also corrected the "Drop it at site/play/" instruction in the export guide.
Admin tooling May 13, 2026
Fixed
  • Artifact art is no longer invisible to the manifest. Finalized artifact PNGs were being written into art/artifacts/<id>.png, but /api/art-manifest only reads the top level — so the Godot client could never sync artifact art. Routing now writes artifact full-art top-level alongside cards. A one-time boot-time sweep relocates any pre-existing files. Latent bug that would have hit at v1.5 ship time.
  • Non-card commission entries stop polluting the card-art sync. Categories that aren't actual cards (artifact icons, keyword icons, faction logos, UI buttons, backgrounds, title art, splash art) used to finalize to top-level RNR_ART_DIR/<id>.png, so every Godot client downloaded them as if they were card art — wasted bandwidth + memory, plus collision risk. They now route into per-category subdirs (artifact_icons/, keyword_icons/, faction_logos/, ui_icons/, backgrounds/, title_art/, splash_art/) reachable via /art/<subdir>/<id>.png. The card-art manifest stays card-only. Boot-time migration sweeps any existing top-level pollution into the new subdirs.
  • Stale grok-2-image references in api/xai-image-client.js header and docs/art-commission-tool.md swapped for the live model name (grok-imagine-image-pro / grok-imagine-image). Pricing constant + dropdown were already correct.
Added
  • Attempt retention sweep. Every gen attempt persists forever by default — 220 cards × iterative refinement = multi-GB drift. New daily job prunes rejected, non-finalized, non-anchor-referenced attempts older than ART_ATTEMPT_RETENTION_DAYS (default 30, 0 disables). GET /api/art-commission/retention/preview dry-runs; POST /api/art-commission/retention/sweep executes. Scheduled run kicks off 5 min after boot, then every 24 h.
  • Cheap state-stamp hash on /api/art-commission/cards. Frontend polls every 5 s; now passes ?since=<hash> and the server short-circuits to {cards: null, unchanged: true} when state matches (computed from max attempt_id + finalized_at + counts + anchor stamp + active presence). Idle browsers stop tearing down the 220-tile grid every 5 s.
Notes
  • No Godot client changes. Heroes APKs in users' hands are unaffected. GAME_VERSION remains at 1.4.8 — admin-tool-only change.
  • Hard-refresh required for the art-commission.html page after deploy. The response shape of /cards changed (added hash, plus cards: null on unchanged); a stale tab on the old client would set CARDS = null and break.
  • Migration is idempotent. The legacy art/artifacts/ dir can be removed once boot logs confirm zero skips.
Site infrastructure May 13, 2026
Added
  • Self-hosted visit + login + admin-action analytics. Every page load on rustandroots.io and rustandroots.dev records a session (UUID in localStorage), heartbeat-tracked time on page, and final-duration beacon on unload. Geolocated server-side via geoip-lite (no external API, no rate limit). Four new SQLite tables: analytics_sessions, analytics_pageviews, analytics_logins, analytics_admin_actions.
  • Login events instrumented. Discord OAuth callback, username/password login, and registration each fire an analytics_logins INSERT after issuing the JWT. Failed login attempts (unknown_user, bad_password) are recorded with IP + geolocation for failed-burst detection.
  • Admin actions audit log. The requireAdmin middleware now records every admin-gated endpoint hit (who, what, when, IP, country, truncated params). Full forensic trail if the admin allowlist is ever compromised.
  • Admin dashboard. New page at rustandroots.dev/analytics.html with six sections: Live (5-min map via Leaflet + CARTO dark tiles), 24h summary cards, .dev access log (RED-flagged on non-admin visits), recent logins, admin actions audit, top pages. Auto-refresh every 15s.
  • Discord webhook alerts. Reuses the existing DISCORD_WEBHOOK_URL. Three triggers with per-key cooldowns: non-admin pageview on .dev (5-min cooldown per IP+path), failed-login burst (5+ in 5 min from one IP, 10-min cooldown), admin login from a new IP or country (60-min cooldown, looks back 90 days).
  • Privacy disclosure footer on .io. One-line note injected by nav.js: "This site uses minimal anonymous analytics. No third-party sharing." No banner, no consent prompt. .dev is admin-only and has no public-facing disclosure.
  • Defense in depth on .dev. Three independent gates on every admin page now: nginx serves on .dev only (admin paths return 404 on .io), _dev-gate.js blanks the page until JWT verifies admin, and requireAdmin rejects non-admin API mutations server-side. The beacon fires before the gate hides the page — even a probe that never authenticates leaves a forensic row.
Changed
  • nav.js auto-injects the beacon on every page that loads the shared nav. Skips iframes (parent page already runs it). Same pattern as the existing _dev-gate.js injection on .dev.
  • nav-auth.js admin dropdown adds an "Analytics" entry as the first item under the Admin section.
  • Nginx config on .io and deploy.sh updated to keep analytics.html off the public domain. Already-blocked admin pages (effects / factions-admin / tracks-admin / etc.) remain blocked.
Notes
  • No Godot client changes. Heroes APKs in users' hands are unaffected. GAME_VERSION remains at 1.4.8 — no Heroes version bump for site infrastructure.
  • Mothballed Claude endpoints untouched. The four AI surfaces continue returning HTTP 503 when CLAUDE_ENABLED is false (the default).
v1.4.8 May 11, 2026
Added
  • Reactor Vault atmosphere. New single dark-wood background (assets/textures/bg_wood_dark.jpg) replaces the phase-specific scrapyard / battlefield paintings. Layered on top: parallax mouse tracking (background drifts ±15 px opposite the cursor), GPUParticles2D dust motes (warm amber, fade-in / sustain / fade-out alpha curve, ~80 motes), and a high-amount Reactor Sparks particle field (orange-yellow HDR pinpoints). All wired through a new WorldEnvironment with additive glow at HDR threshold = 1.0 so only the HDR-coloured sparks / dust / damage-flashes bloom.
  • Tactile UI feedback. Right-bar action buttons (Fight, Roll, Freeze, Upgrade) now respond to hover, depress, and release: 1.02× scale + ui_hover click on hover, position.y +4 px and scale.y → 0.95 on button_down, spring-back on button_up with a ui_heavy_click mechanical clack. New ui_heavy_click SFX key in AudioManager.
  • 2.5D card hover + slam. Mouse-over a card now tweens the Visuals child (scale ↑5% from zone-fit, position.y ↑6 px, rotation tilted toward local cursor X). The HBox layout slot stays put — siblings don't shimmy. slam_to_position() helper added on minion + spell cards using TRANS_SPRING + EASE_OUT for placement weight.
  • Combat impact — trauma + hit-stop + flash. MatchManager autoload now owns a 0..1 trauma value with per-frame decay. apply_damage_trauma(damage) normalises against 30 HP and applies a pow(_, 2.5) curve with a 0.1 floor — a 1-damage tap rattles, a 30-damage hit shakes hard. execute_hit_stop(duration, severity) drops Engine.time_scale for real-time milliseconds. flash_card_damage(card) bursts modulate to HDR Color(5, 5, 5, 1) then eases back — reads as a real bloom on glow-enabled builds. game_manager._process samples the trauma noise offset and applies it to self.position (no Camera2D in this scene tree).
  • CRT boot tooltip. Card-hover tooltip now dwells 0.15 s before showing, then animates open with scale.y 0→1 over 0.1 s (TRANS_EXPO + EASE_OUT) like a CRT scan line filling in. Cancels cleanly if the cursor leaves before the dwell completes.
  • Foil shader (T5 / T6). New themes/junkyard/foil_metallic.gdshaderblend_add canvas_item shader with noise_tex uniform + scrolling metallic highlights. Tints pulled from the Colors autoload (T6 brass → copper-hi at intensity 0.40, T5 taupe → bone at 0.25). Attached automatically to a new FoilOverlay ColorRect under Visuals/Overlays/ via _apply_foil_for_tier().
Changed
  • Hard-ceiling card scaling. Cards no longer derive their size from parent.size.y. Both minion.gd and spell_card.gd now use a shared MAX_BOARD_HEIGHT = 210.0 constant; every card on the board renders at exactly 152 × 210 px regardless of how many cards are in the row. Stops the "one card upscales massively" bug at its root. Spell card scene refactored to mirror minion (Control root + Visuals Panel child) so both card types share an identical slot/visual decoupling.
  • Locked zone heights. SalvageYard / OpponentBoard / PlayerBoard HBoxContainers now have custom_minimum_size = Vector2(0, 240). OpponentBoard.size_flags_vertical bumped from 0 → 3 to match PlayerBoard — was the actual root cause of opponent cards rendering at near-native size during combat.
  • Zone panel transparency. The painted plate backgrounds on TopRow / MidRow / BottomRow are gone — replaced with StyleBoxFlat at bg_color = Color(0, 0, 0, 0.35) + 1-px warm metal border + 4-px corner_radius. The new wood background reads through every zone with a subtle dark wash.
  • Combat log / chat collapsed by default. The panel on the left edge starts as just a small Chat button (60 × 32 px, no panel chrome). Click to expand into the full Log / Chat tabbed panel; click to collapse back. Stylebox swap + anchor collapse handle the visual transition.
  • Rumble lobby slots: name only. Removed the per-slot role_label subtitle (AI title for AI slots, "▸ CONNECTED" for the human). Slot height unchanged; name vertically centered in the available row.
  • Combat damage routed through trauma curve. The two combat-engine _screen_shake call sites now call MatchManager.apply_damage_trauma(damage) instead of the older linear tween-based shake. Multi-target combos scale with their aggregate damage.
Fixed
  • Cards bleeding past the zone divider. Added _ZONE_BOTTOM_MARGIN = 20.0 (since rolled into the hard-ceiling math) so card bottoms keep a safe margin off the divider line. v1.4.7's NameLabel min-height made the rendered card slightly taller than NATIVE_HEIGHT × scale; this catches that overflow.
  • Spell / Curio cards rendering at a different visual height than minions. spell_card.gd's _NATIVE_HEIGHT was 210 (didn't match the actual 232 scene native) and _SCALE_MAX was 1.00 (vs minion's 1.80). Plus spell card was a single Panel with no Visuals child, so the HBox slot stayed at full native while the visual scaled smaller. Refactor + unified math = identical slot dimensions for both card types.
  • Mid-combat opponent spawn race condition. Both shop_manager.spawn_card_in_container and online_bridge._spawn_card_from_server_data now await get_tree().process_frame between add_child and _apply_scale_to_zone — the previous call_deferred could still fire before the combat-phase layout had settled.
  • 8 cards' ability_text didn't mention Sick application. Phase 5b shipped the Sick status + shader (v1.4.1) and 8 cards' effects arrays apply it correctly, but the tooltip strings under-claimed what each card did. Rewrote text for Wounded Wildling, Pup Handler, Northbound Scout, Funeral Skald, Sour Mouth, Sister Mercy, Toxicologist, and Plague Doctor. No effect / stat changes.
  • Background texture failed to load. The supplied source PNG was actually JPEG bytes with a .png extension — Godot's PNG importer wrote valid=false in the .import sidecar so load() returned null. Renamed to .jpg and updated the load path to try .jpg first then .png with a legacy fallback.
  • Dust motes invisible. The atmospheric dust GPUParticles2D inherited z_index = -1 from the legacy CPU dust it replaced — pushed it behind the opaque background texture. Removed the override and bumped sustain alpha 0.22 → 0.45 (later HDR-bumped to Color(1.6, 1.3, 0.85) when WorldEnvironment glow landed).
  • art-commission.json artifact IDs didn't match card_database.json. 12 of 17 artifact entries (plus all 12 paired _icon entries) were renumbered to the v1.5 plan canon. The Bench / Old Lantern / Coin Purse now write to the file the in-game client actually loads.
Server-side foundation (gated, dormant)
  • v1.5 Artifact card type — server, REST API, and admin editor staged behind ARTIFACT_SHOP_CHANCE = 0.0. Three starter artifacts (The Bench, Old Lantern, Coin Purse) in data/card_database.json; player.artifacts state + 4 hooks + apply_damage_trauma handlers in api/multiplayer.js; seven new REST endpoints (POST/PATCH/DELETE /api/artifacts/:id) in api/server.js; admin Card Editor extended to create / edit / delete artifacts. No player-facing effect this release — flips on when the Godot v1.5.0 client ships its inventory bar UI.
v1.4.7 May 8, 2026
Changed
  • Card typography → Road Rage. All card labels (NameLabel, AttackLabel, HealthLabel, CostLabel, stat keys, faction tab, type tag, tier roman, ability text) swapped from Oxanium/Teko/Barlow to RoadRage-Regular.ttf (graffiti-style display). Card names and Curio ability descriptions render all-caps via .to_upper() in _set_name_autoshrink + ability_label.text assignment in scripts/minion.gd and scripts/spell_card.gd.
Fixed
  • Card names invisible on shop / battlefield cards. NameLabel's bounding box was being squished by its NameBand PanelContainer parent — the box collapsed regardless of font size, so glyphs had no room to render. Added custom_minimum_size = Vector2(0, 25) + size_flags_vertical = 3 on NameLabel in both scenes/minion_card.tscn and scenes/spell_card.tscn, plus pure-opaque white font_color, pure-opaque black font_outline_color, and outline_size = 8 (was outline 3 with 0.7-alpha black, which bled into light card art).
  • Cards too tall for SalvageYardClip in the shop. _SCALE_MIN = 0.50 in scripts/minion.gd + scripts/spell_card.gd forced cards ≥ 116 px tall (50% of 232 native), but the shop zone's clip mask is shorter — so the bottom 30% of each card (the NameBand strip) was clipped off-screen. Dropped _SCALE_MIN to 0.25, allowing cards to shrink to fit zone height; name band now visible.
v1.4.6 May 8, 2026
Changed
  • Right-bar layout topology. scenes/main_board.tscn rebuilt: TopHUD horizontal scoreboard and BottomHUD horizontal control row are gone. Their content (8-player scoreboard, economy, action buttons, sell zone) consolidated into a 240 px vertical RightBar. The play area gets the full vertical (~744 px) for three full-width rows: TopRow (Shop in shop phase / Opponent in combat phase, content swap by visibility), MidRow (Battlefield), BottomRow (Hand). MidZone wrapper that conflated Shop+Opponent overlap is removed; sibling-visibility swap inside TopRow's ZoneContent handles the phase transition.
  • Vertical scoreboard. 8 player tiles stacked top-of-bar inside RightBar's ScoreboardSection (was a horizontal strip across the top of the play area). Same health_bar_panel.gd tile builder — the existing horizontally-flexible tile shape stacks vertically without rewrite. HPGauge component (scenes/components/hp_gauge.tscn) reused as-is.
  • Drop-to-sell zone. ScrapHeap (the absolutely-positioned sell panel that previously hovered at viewport-right and overlapped the play area) is now SellDropZone at the bottom of RightBar. Same drag-drop logic in scrap_heap.gd, just lives in the bar's flow. Recovers ~28 k pixels of play-area real estate.
  • Card scaling, properly. scripts/minion.gd _NATIVE_HEIGHT 210 → 232 (matches actual .tscn custom_minimum_size.y — the 22 px discrepancy was distorting every scale calculation). Pivot moved from size / 2 (center) to Vector2(size.x / 2, 0) (top-center) so visible cards anchor flush with HBox top instead of shifting downward by (1-scale) * half_height — this was pushing the bottom past the zone's clip line, hiding the NameBand. New _zone_fit_scale member tracks the computed scale; hover, hover-out, breathing, and _stop_breathing tweens now multiply against it instead of resetting to absolute 1.0. shop_manager.gd fan-in tweens to the same zone-fit target instead of Vector2(1.0, 1.0). spell_card.gd hover captures _hover_base_scale on enter for a matching hover-out target. All combined: cards scale to ~73% in the new ~184 px-tall HBox slots and stay at zone-fit through every state change.
  • Lobby fits. scenes/rumble_lobby.tscn: SlotsVBox grid columns = 2 → 4 (8 contestant tiles in 2 rows of 4 instead of 4 rows of 2 — saves 240 px vertical), VBox offset_top = 30 → 48 for breathing room above the "MATCH BRIEFING" eyebrow header. scripts/rumble_lobby.gd: contestant name + role labels gain clip_text = true + OVERRUN_TRIM_ELLIPSIS so long usernames truncate gracefully in the narrower 4-column tiles instead of forcing column expansion.
  • Window aspect locked. project.godot: restored window/stretch/aspect="keep" (the prior session unstaged-deleted it). Canvas now letterboxes when the window aspect doesn't match 1280:760 instead of stretch-distorting.
Fixed
  • Cards no longer cut off at zone bottoms in scrapyard / battlefield / hand. Multiple interacting bugs: shop fan-in animation was tweening newly-spawned cards to absolute Vector2(1.0, 1.0) scale, overriding the per-zone _apply_scale_to_zone calculation. Center pivot pushed visible cards downward past the HBox bottom regardless of scale. _NATIVE_HEIGHT = 210 mismatch with the actual 232-tall card meant even when scaling worked, cards were ~10% larger than the formula intended. Fixed in concert with the layout refactor: cards now anchor top-center, scale to fit each zone, and hover/breathing keep the zone-fit scale instead of resetting to 1.0.
  • Edge buffering across the play area. MainHorizontalLayout has explicit 8 px offsets on all four sides + 8 px separation between PlayArea and RightBar; row stylebox content_margin_top/bottom matches plate_9slice.png's 14 px texture margin so children no longer render on top of the visible metal frame border.
  • "MATCH BRIEFING" no longer crowds the top edge of the lobby. Eyebrow font 44 with letter_spacing = 4 at offset_top = 30 looked clipped at the top of the viewport — bumped to 48.
Removed
  • scenes/combat.tscn and scenes/salvage.tscn — standalone scaffold scenes from the prior FUCKIT/8b4dc1c session that never got wired into the game loop. The TopRow phase-swap obsoletes them.
  • FactionSplash overlay in main_board.tscn + the corresponding @onready vars in game_manager.gd. Was unconditionally hidden + skipped on every match start — pure dead UI, ~50 lines of .tscn noise.
  • Runtime _create_notepad_button() in game_manager.gd. NotesButton now lives directly in main_board.tscn's ActionsPanel with a [connection] entry — same behavior, less indirection.
  • Unused @onready var hand_container declaration in game_manager.gd (declared, never used, pointed at a node that no longer exists).
Notes
  • Mobile layout (phones / mobile-web): the mobile_layout_manager.gd path was simplified to a near-no-op for v1.4.6 because desktop's RightBar already provides the right-column UI consolidation that the prior mobile path created from scratch. Phones get the desktop layout with safe-margin scaling. Full mobile UX polish — tighter card sizing, narrower right bar, optional hand fan — is deferred to a follow-up session.
  • Card NameBand text readability: cards scale to ~73% in zones, so the 16 pt native NameLabel renders ~12 pt visual. Spec §12 names 320×480 ("Ribbon Final") as the hover/Card Detail target where text hits canonical 22/19/16 px. Card Detail modal already exists; auto-trigger on hover-dwell remains disabled per prior playtest feedback.
  • The 8 vertical scoreboard tiles share the top of RightBar with EconomyPanel + ActionsPanel + SellDropZone. RightBar layout is sensitive to viewport height — if a future change adds vertical content, the tile height (~58 px) is the first thing to compress.
v1.4.5 May 3, 2026
Changed
  • Card frame redesign — Ribbon Final. Both minion and Curio (spell) cards rebuilt to the canonical layout from the design system handoff. Full-bleed art with subtle gradient overlays pulling the subject into the bottom name band; top-left split ATK | HP stat pill in faction-tinted Oxanium; top-right faction tag (3-letter abbreviation, faction-color text on dark chip) plus tier mark with grade-colored dot (matte/brass/silver/gold for tier I–III/IV/V/VI) and Roman numeral; bottom name band with faction color2 gradient and Oxanium auto-shrink name (22/19/16 px depending on length). Card slot size grew from 125×165 to 168×252 to accommodate the new layout. Curio variant uses the same shell with a cost pill in place of the stat pill and a CURIO tag instead of a faction tag, plus ability text stacked below the name.
  • Status overlays preserved. The 4 ColorRects (Shader/Aura/Holo/Guard) used by status shaders (frostbite, poison, plating, sick, burning, cursed, marked) continue to apply on top of the new frame — combat behavior unchanged.
Fixed
  • Latent strict-typing parse errors. scripts/player_board.gd:163 (Godot 4's max(Variant, Variant) -> Variant static signature was triggering “variable type inferred from Variant” warning — treated as error in this project) and several Variant-flow lines in scripts/minion.gd's rebuilt apply_faction_color() now carry explicit type annotations or as casts so script load is clean.
v1.4.1 April 29, 2026
Added
  • Status shaders (Phase 5b) — the 4 statuses shipped engine-only in v1.4.0 now have client visuals. shaders/sick_miasma.gdshader (sickly green miasma + slow vapor wisps), shaders/burning_flame.gdshader (orange-red flame licking up from the bottom edges with fast flicker), shaders/cursed_violet.gdshader (slow violet inward gradient + rotating wisp), shaders/marked_target.gdshader (sharp red crosshair reticle with crosshairs + tick marks + edge red wash). All canvas_item shaders rendered on the existing ShaderOverlay ColorRect — never on the PanelContainer.
  • Status priority chainminion.gd now slots Sick / Burning / Cursed / Marked into the status shader picker between Frostbite and Camouflage. Negative statuses always read over positive ones. Frame border colors muted to match each status (sickly-green / ember / violet / bright-red).
  • Replay event handlerscombat_engine.gd handles new server events: sick, burning, cursed, marked, status_strip, sick_tick, burning_tick, sick_spread. Each spawns a floating-text damage-number variant and posts a tagged combat-log line ([Sick], [Burning], [Cursed], [Marked]).
  • Burning / Cursed / Marked card distribution — brought up to Sick parity. Each status now lives on 8 cards across 4 factions (2/faction):
    • Burning: Rigs (Junkyard Juggernaut, Diesel Tank), Parish (Hellfire Sermon, Censer Storm), Apothecaries (Mad Chemist, Chemical Vat), Syndicate (Wharf Heavy, Lockbox).
    • Cursed: Drift (Bag Carrier, The Old Stranger), Grove (The Strangler, Pollen Speaker), Hive (Sister Greed, Sister Envy), Parish (Vespers Hand, Outraged Deacon).
    • Marked: Pack (Blood Tracker, Lone Hunter), Syndicate (Bounty Hunter, Right Hand of the Boss), Rigs (Nitrous Injector, Cannon Walker), Thaw (Far Cousin, Elder Shieldbearer).
  • Keyword definitionsapplied_by arrays added for Burning / Cursed / Marked entries in data/keyword_definitions.json so admin tooling can list which cards apply each.
  • Card ability text rewrites — all 24 status-applier cards now mention the status they inflict in their ability text. Players can read at a glance that Junkyard Juggernaut sets enemies ablaze when its Plating breaks, that Bag Carrier Curses every enemy on Surge, that Bounty Hunter Marks its target before attacking, etc. (See tools/apply-phase5b-ability-text.js for the full rewrite list.)
Changed
  • MinionCard state cache key — the visual state-cache key now includes the 4 new status flags so the panel restyles when they toggle. Spawn / restore reset all four flags (combat-only by design, except Cursed which persists via its restored stat-loss tracking on the server).
  • Static status tints_apply_static_status_visuals() now blends weak per-status tints for Sick / Burning / Cursed / Marked, with the shader doing the dominant visual lifting.
  • Nitrous Injector trigger movedrig_007's Marked applier moved from end_of_turn (shop phase) to surge (start of combat). Marked is combat-only, so applying it during the shop phase was a no-op — the engine cleared it before combat started. The +1/+1 EoT buff to the leftmost Rig is unchanged.
Fixed
  • Card tooltip layering — the hover tooltip was rendering at z_index 0 while card subtrees use z_index 2-3 internally, so card art and keyword icons were drawing through the tooltip body. Tooltip now lives in a dedicated CanvasLayer (layer 60) and the panel itself sets z_index = 100, guaranteeing it draws above all board content.
  • Card tooltip background — the panel was using the Kenney plate StyleBoxTexture 9-slice, whose inner area has alpha. Replaced with an opaque dark StyleBoxFlat (97% alpha, warm-amber border, drop shadow) so card art behind it no longer bleeds through.
  • Card tooltip width — tooltip widened from 220px to 260px and the corresponding centering math updated (130px half, 264px viewport clamp). Long ability text (Made Man's "Deploy: spend all your remaining Scrap. Gain +2/+2 per Scrap spent this way.") now wraps cleanly instead of getting visually clipped.
  • Section labels (BATTLEFIELD / HAND) z-order — the zone labels under MainVerticalLayout/BoardZone and MainVerticalLayout/HandZone had no explicit z_index, leaving them at the same depth as cards rendered inside their zones. Bumped to z_index = 10 so the labels stay readable.
  • Empty board slot placeholders too loud — the metal-panel skeleton outlines for empty board slots were drawing at modulate.a = 0.12, bright enough to read through cards. Dropped to 0.05 (texture style) and 0.04 / 0.10 (flat fallback). Slot container also now sets z_index = -1 so cards always draw above the skeleton.
v1.4.0 April 29, 2026
Added
  • SICK status — spreading degenerative disease. When a Sick unit and another unit exchange damage and both survive, the other becomes Sick too. Each combat iteration the unit takes, atk decays by 1; once atk reaches 0, hp decays — 1/round for 3 rounds, then doubles each subsequent round (2, 4, 8, 16, ...) until the unit dies. Combat-only, clears between fights. Wired into 8 cards across 4 factions (Apothecary / Hive / Pack / Thaw): Funeral Skald, Northbound Scout, Wounded Wildling, Pup Handler, Plague Doctor, Toxicologist, Sour Mouth, Sister Mercy.
  • BURNING status — damage-over-time. -1 Hp at the start of the unit's own attack iteration. Combat-only.
  • CURSED status — persistent stat debuff. -1 Atk / -1 Hp on apply, restored on strip. Survives between combats until cleared.
  • MARKED status — damage amplifier. Takes +1 damage from all sources. Combat-only.
  • Compound 311 (Curio, 2 Scrap, Apothecary) — strips all 4 negative statuses (Sick, Burning, Cursed, Marked) from a friendly unit. Cursed-strip restores the unit's lost +1/+1 stats.
  • Compound 287 (Curio, 8 Scrap, Apothecary) — at start of next combat, deals 4 damage to all Sick enemies and applies Sick to a random enemy. Anti-Sick weapon that scales with how many enemies are already infected.
  • Engine action typesapply_status and strip_status in effect-interpreter.js. Cards now apply / strip statuses through standard effect arrays. Frostbite still uses its own action for backwards compat with the Frostbarrow lock interaction.
Changed
  • Status state on unitscloneBoard() now initializes is_sick / is_burning / is_marked / is_cursed per unit, plus tick counters for Sick's two-phase decay (_sick_atk_ticks + _sick_hp_ticks) and Cursed's restore amounts (_cursed_atk_loss + _cursed_hp_loss). Cursed values carry over from client-submitted card state because Cursed is persistent.
  • Damage calc — Marked units take +1 dmg from all sources, applied in the per-attack damage modifiers block alongside Plating, Camouflage, and the existing Frostbite multipliers.
  • Combat loop — status ticks (Sick atk decay or hp decay; Burning -1 hp) fire at the top of each unit's own attack iteration, before frostbite + camouflage checks. If status ticks kill the unit, it's removed and skipped, with a death cause: status event.
  • data/keyword_definitions.json — entries added for the 4 new statuses, including cleared_by and applied_by arrays for tooling lookups.
v1.3.2 April 29, 2026
Added
  • Lobby faction banner (Phase 3b) — the multiplayer + Rumble lobbies now display the 6 factions chosen by the server for this match (the server side shipped in v1.3.1). Banner sits below the status line and reads "FACTIONS THIS MATCH: A · B · C · D · E · F + Neutral" in warm-copper Heavy Plate styling. Players know what they're playing into before the match starts. NetworkManager.current_active_factions stores the list, populated from room_created / room_joined payloads. Programmatically inserted into the existing lobby VBox — no .tscn churn. Requires a fresh Godot export to land on the live web client.
v1.3.1 April 29, 2026
Added
  • Per-match faction selection (server-side, Phase 3) — the server now picks 6 of 9 non-Neutral factions when a room is created. Only those 6 (plus Neutral) appear in the Salvage Yard for the duration of the match. Faction-locked Curios like Sanctified Voice (Parish-locked) no longer appear in matches without their faction. The chosen factions are broadcast via active_factions in room_created and room_joined messages so the lobby can display the selection (lobby UI follows in Phase 3b).
  • Cards-needing-new-art reference docdocs/heroes-rename-art-needs.md classifies all 152 renamed cards into 4 tiers (no change / existing art works / touch-up / new art required). About 105 cards in Tier 3 (new art needed), driven mostly by the six full faction reskins.
  • Syndicate buff balance reviewdocs/heroes-syndicate-balance-review.md. Pure research, no code changes. Flags 3 imbalance hotspots (Wharf Heavy unbounded scaling, Floor Boss snowball, Right Hand of the Boss canon-violating coin flip) and recommends narrowing the Syndicate from 6 mechanic families down to 2 pillars (Hoarding + Wager).
Changed
  • Spell → Curio cosmetic rebrand (Phase 4) — player-facing strings on the website now read "Curio" / "Curios" wherever the card type appears as a tab, badge, filter, or label (cards browser, compendium, card editor). The internal "spell" type identifier is unchanged — this is a visual rename only. A full code rebrand is deferred to a later phase.
  • AI faction-list scoping narrowed — AI characters in Rumble now have their preferred-faction list filtered to the 6 active factions (was: full 9). Prevents the AI from optimizing toward factions that won't appear in the shop.
Fixed
  • Sanctified Voice / Bumper Crop / Compound 311 etc. shop leaks — faction-locked Curios that require a specific faction unit on board would previously appear in Salvage Yard rolls even when their faction wasn't being played. Now filtered server-side via the per-match active-factions pool.
v1.3.0 April 28, 2026
Changed
  • 151 cards renamed — major rename pass aligning Heroes with Chronicles canon. Ten faction reskins: the Hive (insect swarm → cult-clinic with sin-tagged sisters/brothers), the Drift (electric storms → alien-passing melancholy), the Parish (rock concert → cathedral with bells and grey linen), the Thaw (ice elementals → northern viking refugees), the Pack (animal mob → exiled humans with their hounds and bears), the Grove (plant-only → people-with-plants body horror), plus surgical fixes across Apothecaries, Syndicate, Rigs, and Neutral. T6 finishers are now roles or places — Mother Eternal, The Belltower, The Frostbarrow, The High Altar, The Foundry, The Tower, The Last Apothecary, The Old Master, The Last Hunt, Right Hand of the Boss, The First Bloom. Pre-Event US references (Vegas, NFL, WWE, hockey, Daisy-Cutter, Doomsday Prepper), brand names (Zamboni, Freon), mythological monsters (Chimera, Leviathan, Behemoth, Colossus), and "Wastes/Wasteland" terminology all stripped. Plan and full mapping in docs/heroes-rename-session.md; plain-English summary at docs/heroes-rename-overview.md.
  • Spawn renames — Drone → Initiate, Soldier → Bound, Rescue-Bot → Rescue Bot. Hive Hatch effects now spawn Initiates (1/1) and Bound (2/2). Combat log strings updated.
  • Two Curio renames — "VIP Backstage Pass" → "Sanctified Voice" (Parish-flavored aura grant). "The Penalty Box" → "Sent to the Cold" (Thaw-flavored opponent removal). Other 11 spells kept.
  • Card Editor / admin toolingdata/keyword_definitions.json static name lists for Plating / Frostbite / Guard / Camouflage / Poison applied_by · can_be_granted_by · can_be_stripped_by arrays refreshed to current names. Sandbox starter deck in scripts/setup_automation.gd updated. Doc drift cleaned up across docs/01_factions.md, docs/02_card_roster.md, docs/03_spells.md (and the synced site/data/docs/ mirrors).
  • Rename batch toolingtools/apply-heroes-rename-phase1.js applies the 151-card rename map to the local data/card_database.json in one pass. tools/push-heroes-renames-to-vps.js is the live counterpart: pushes all 151 renames to the live VPS via PATCH /api/cards/:cardId/rename?draft=true in batch, then POST /api/drafts/publish for a single version-bump. Equivalent to opening the Card Editor and applying every rename by hand, but seconds instead of an hour. Idempotent.
Removed
  • Deprecated v1 combat engine retiredapi/game-engine.js deleted (was ~3,000 lines / 231 hardcoded card-id switches). api/test-parity.js deleted (entirely a v1↔v2 comparator). The POST /api/combat-snapshots/:id/compare endpoint and the Compare button on Studies were retired with it. v2 (game-engine-v2.js + effect-interpreter.js) is now the only engine. Removed 231 hardcoded card-id references before the rename pass began — meaningful cleanup for future ID-rename work.
Fixed
  • Faction names match Chronicles canon — the previous Heroes faction set ("The Ferals", "The Blooms", "The Amplifiers", "The Swarm", "The Volts", "The Glaciers", "The Alchemists") never appeared in Chronicles or the manuscript. They’ve been the canonical (Pack / Grove / Parish / Hive / Drift / Thaw / Apothecaries) since Chronicles shipped; Heroes finally agrees.
v1.2.0 April 27, 2026
Added
  • Heavy Plate card decor (chip + tier dots + 4-corner rivets)scenes/minion_card.tscn + scripts/minion.gd got the locked Tin Variations spec applied. Top-left faction chip in faction-color with 3-letter abbreviation (PCK / SYN / RIG / GRV / PAR / THW / HVE / DFT / APO; neutrals are tabless per locked design). Top-right strip of 6 tier dots, brass-tinted on T5+ for high-tier readability. All four corners now carry rivets (was just top two). Subtle warm-amber top edge highlight + dark bottom shadow give the card body proper embossed pressed-tin depth. Drop shadow strengthened (size 14, alpha 0.75, +8 offset) so cards lift cleanly off the board.
  • Phase title overlay actually wired upgame_manager._show_phase_banner() was a literal no-op for as long as anyone can remember; now it instantiates themes/fx/phase_title.tscn for every phase transition. Copper-stenciled 96px Teko title with 8px letter-spacing on a consistent warm-dark wash, atmospheric subtitle pulled from a per-phase table (“Power floods the wires.” / “The yard runs red.” / “The Salvage Yard pays its winner in rust.”). Title tint comes from the calling phase color; bg stays consistent across phases for atmosphere coherence.
  • Lobby redesigned (RUMBLE IN THE RUINS)scenes/rumble_lobby.tscn + scripts/rumble_lobby.gd. Dramatic 56px copper Teko title, “◆ MATCH BRIEFING ◆” eyebrow, atmospheric “Eight walk in. One walks out. The Salvage Yard pays its winner in rust.” subtitle. Contestant slots rebuilt as styled 2-column grid of plate-framed tiles — copper P-badge for the human player with green “CONNECTED” status, dim AI-badge with character title underneath, copper slot index on the right edge. Background gets a subtle plate-grunge texture overlay + soft vignette.
  • Heavy Plate plate texture (solid interior)tools/generate_junkyard_assets.py got a make_plate_9slice() function that produces the 48×48 9-slice plate_9slice.png with a solid warm-dark body, 1px brass perimeter, warm-amber inner highlight at the top, dark inner shadow at the bottom, and a sprinkle of grunge speckle. Replaces an earlier version whose center was transparent — the symptom was tooltip and zone panels letting whatever was underneath bleed through.
  • 3D rivet texturesmake_rivet() generates a 7×7 rivet PNG with a 3-stop radial gradient (highlight at 30%/30% → mid → dark) supersampled 16× and downsampled with Lanczos for smooth shading. Rivets read as actual rounded studs instead of flat dots.
  • Atmospheric phase subtitles — Surge: Power floods the wires. Combat: The yard runs red. Victory: The Salvage Yard pays its winner in rust. Defeat: The yard takes another.
Changed
  • Combat speed +15%battle_speed default and saved-settings multiplier both bumped 1.40 → 1.61. Existing saved settings get the speed-up automatically without flipping a slider.
  • Card stat band layout — The middle slot (formerly faction-name text, redundant with the corner chip) now shows the card name in Teko 12px UPPERCASE with +1 letter-spacing. Card name no longer overlays the bottom of the art window. The stat band reads ATK | NAME | HP across the bottom of every card. Stat numbers pull warmer Heavy Plate colors (gold #f0c060 for ATK, warm red #ff8a78 for HP).
  • Card names: 2-line wrap with smart word break — Long names like “DAISY-CUTTER HOUND” wrap cleanly to two lines on the etched name strip instead of getting trimmed with an ellipsis.
  • Scene transitions use the rust-wipe shaderSceneTransition autoload swapped from the old generic transition_dissolve.gdshader to the spec-correct themes/transitions/rust_wipe.gdshader (diagonal noise mask dissolve with rust splatter, per HANDOFF §6.10). Affects every SceneTransition.change_scene(...) call — menu → lobby, lobby → board, etc.
  • Zone label typography — OPPONENT, SALVAGE YARD, BATTLEFIELD, YOUR HAND, OPPONENT BOARD all picked up +4px letter-spacing for a stenciled industrial feel.
  • Player tile typography — Player names in the top HP-bar tiles now render in Teko UPPERCASE with +1 letter-spacing instead of the body font, matching the rest of the Heavy Plate type system.
  • Zone panel modulate tints — Opponent / Shop / Board / Hand zone backgrounds had heavy-handed pink / gold / green / orange washes; softened ~50% so the board reads as a cohesive industrial scene with subtle zone identity instead of candy colors.
  • Surge phase auto-skips when no Surge cards are on the fieldcombat_engine.trigger_all_surges() now scans both boards for live units with the Surge keyword before showing the banner, log line, or signal. If nothing surges, the round flows straight from setup into the combat phase.
  • Cards: data pre-population pattern — Bulk card spawns (e.g. salvage refresh) pre-populate _name / _faction / _atk / _hp / _tier / _keyword on the instance before add_child instead of relying on a post-add set_card + await ready dance. Avoids a dual-refresh where the first pass renders defaults.
Removed
  • FactionSplash modal — The “THIS GAME’S FACTIONS” intercept screen between the lobby and the first round is gone. Players see the active factions on their cards / shop — the splash was an unnecessary stop. Round now starts immediately on lobby exit. (TODO carryover: showing the faction list inside the lobby itself requires moving MatchManager.initialize_game() to lobby-time so factions are determined before the board scene loads. Flagged in code.)
  • Phase title flanking bars — Two thin copper bars above/below the phase title text were noise; pulled them.
  • Card top “name strip” overlay — Card name moved into the stat band, so the etched-glass overlay across the bottom of the art window is hidden — gives the art more breathing room. Old NameOverlay node is preserved but not rendered.
Fixed
  • Tooltip + zone panel transparency bleed-throughplate_9slice.png had a transparent center, so anything stretched on it (notably the Card Detail tooltip) let the chips / tier dots / frames of cards underneath bleed through. New texture has a solid interior and the bleed is gone.
  • Phase title olive-tint bug — The previous wiring piped the phase color into the background wash, which turned every banner the same washed-out greenish color. Background is now always a fixed warm-dark wash, and the phase color tints the title text only.
  • Card content rendering for instances 2-N (preview-scene only) — In the Junkyard preview scene, only the first card of a 10-card lineup rendered its body content, while rivets rendered for all 10. Surfaced via diagnostic prints (every card has correct data, unique node refs, and post-layout sizes); root cause is a Godot quirk with multiple Panel instances sharing [sub_resource] StyleBoxes via theme inheritance. Workaround in script: pre-populate fields before add_child. Live MinionCard spawn flow is unaffected; themes/junkyard/preview_cards.tscn still reproduces the issue and is filed as a future investigation.
  • Faction tab z-index punch-through — Top-left faction chip and top-right tier dots had z_index = 4 which let them render above the Card Detail tooltip overlay. Removed; tooltip now properly covers them.
  • Faction tab + corner rivet collision — Chip and tier-dot positions were colliding with the top corner rivets. Chip now sits at offset (14, 6); tier dots at (right-42, 14); rivets shrunk from 10×10 to 7×7 with tighter inset. No more overlap.
  • Bottom rivets covering ATK / HP numbers — Bottom-left and bottom-right rivets now render at z_index = -1 so the stat numbers cleanly overlap them when the layout pushes labels toward the corners.
  • Stale font-size override on subtitle (rp_font is null)themes/junkyard/preview_cards.tscn had theme_override_fonts/font_sizes/font_size = 12 — nested under fonts/ rather than the correct theme_override_font_sizes/font_size. Godot interpreted it as a font override with a numeric value and threw Required object "rp_font" is null. Path corrected.
Site UX pass April 24, 2026
Changed
  • Play-page wrappers redesigned — The top title block (“THE CARD GAME / Heroes of Rust & Roots / tagline” and its Chronicles / Runner equivalents) is gone. Back button, Fullscreen button, and native download cards all moved into a right-side sidebar. The game iframe absorbs the freed vertical space, hitting its full 16:9 aspect cap on desktop viewports so nothing scrolls inside the wrapper.
  • Nav unified across every pagenav.js + nav.css rewritten to emit the same cinematic nav used on the landing hub and /play/* wrappers (logo mark + colored-dot game links + Downloads + online count). The old pill-button nav on Downloads, Account, Changelog, admin tooling, Chronicles chapters, etc. is gone; all pages now share the same look.
  • Admin menu folded into the user dropdown — The gold “Admin” nav dropdown is removed. Admin links (Card Editor, Faction Editor, Soundtrack Editor, Continuity Bible, Balance Tools, Dev Console) live inside the profile-picture popup menu now, and on .io they point at the .dev URLs and open in a new tab.
  • Account page rebuilt in the cinematic styleaccount.html now uses the Cinzel / Crimson Pro / Inter font stack, atmospheric city background, ember-glow accents. Existing forms (display name, password, delete account) unchanged.
Added
  • rustandroots.dev access gate — Non-admin visitors to any .dev URL see a full-page login gate (click1.jpg background + Discord sign-in + R&R credentials fallback) instead of the admin console chrome. Admins pass through unchanged. Every admin HTML page loads the gate script synchronously in <head> so there’s no flash-of-admin-content.
  • .dev dev-home polish — Tighter vertical rhythm on the admin console landing, gold status dot matching the online-indicator pattern, ember-glow hover state on admin cards.
Removed
  • Duplicate soundtrack miniplayer — The rounded-oval “Rust & Roots Soundtrack” link in the nav was just a styled <a> to /player/, visually competing with the real floating bar player that has actual prev/play/next controls. The oval is gone everywhere; the bar player stays.
Fixed
  • Stale pre-gzipped CSS served by nginxnginx gzip_static on was preferring a frozen _play.css.gz from April 23 over the fresh _play.css written by the current deploy, so browsers that accept gzip (i.e. all of them) got yesterday’s layout CSS for hours. deploy.sh now purges any .gz whose source .css/.js/.html is newer across both domain roots before the service restart.
Backend cutover April 24, 2026
Changed
  • rnr-comments service flipped off /opt/600mmr/rnr-api/ — Service now runs from /opt/rustandroots/api/ with all paths env-driven (RNR_DATA_DIR, RNR_CONTENT_DIR, RNR_ART_DIR, RNR_SOUNDTRACK_DIR). No more hardcoded /opt/600mmr/* assumptions in api/server.js, api/game-engine-v2.js, or api/multiplayer.js. Shared game content consolidated at /opt/rustandroots/content/.
  • Admin-endpoint middleware normalizedPATCH /api/effects/:cardId, PATCH /api/cards/:cardId, PATCH /api/keywords/:keywordName, and PUT /api/tracks now use the requireAdmin middleware consistently (previously had inline Discord-ID checks mixed with middleware-based ones). Admin allowlist remains ADMIN_DISCORD_IDS env var.
Removed
  • 600mmr.com fully severed from R&R infrastructure — All /rnr/* paths on 600mmr.com now return HTTP 410 Gone (JSON) or redirect to rustandroots.io/downloads.html (browser Accept header). Compatibility symlinks at /opt/600mmr/rnr/play/rustandroots-* deleted. Legacy /opt/600mmr/rnr/ and /opt/600mmr/rnr-api/ trees renamed to *.retired-2026-04-24 suffix. A legacy v0.97 APK still trying to hit 600mmr.com will receive a clear retirement message; user must re-download from rustandroots.io.
  • Claude AI backend features mothballed — All four Anthropic-powered surfaces (/api/chat, /api/tracker/:id/ai-assist, /api/tracker/:id/suggest-actions, fire-and-forget combat log analyzer) gated behind a CLAUDE_ENABLED env var, default off. Calls return HTTP 503 ai_disabled. Code preserved for zero-friction re-enable once API credits are funded again. ANTHROPIC_API_KEY removed from the systemd unit.
Added
  • GitHub Actions export pipeline — New workflow .github/workflows/godot-export.yml triggers on heroes-v*.*.* tag pushes and runs Godot headless export on a self-hosted Windows runner that holds the release keystore. Setup script scripts/setup-gh-runner.ps1 provisions a runner host in one command. Full runbook at docs/17_ci_pipeline.md. No client-side changes.
v1.1.0 April 25, 2026
Added
  • Junkyard Heavy Plate design system — Full visual retool against a designer-authored spec package. Plate-textured panels with riveted corners + grunge overlay + copper trim now span every visible UI surface: minion cards, spell cards, salvage yard / battlefield / hand / opponent zones, combat log panel, tooltip, in-game settings menu, faction splash, game over overlay. themes/junkyard/ ships plate.tres, 4 button 9-slice StyleBoxTexture variants (normal / hover / pressed / primary), HP gauge component, and a full theme.tres registering Button / Label / Panel / HSlider / CheckButton / LineEdit / Separator / PopupMenu defaults so the cascade reaches everywhere not explicitly overridden inline.
  • Heavy Plate minion + spell cardsscenes/minion_card.tscn + scenes/spell_card.tscn rebuilt with plate texture frame, copper faction bar across the top edge, grunge overlay, top-corner rivets (bottom rivets removed because they obstructed stat numbers), brass ATK + danger HP labels in Teko Bold with outlines. Top-right keyword badge slot (Plating / Frostbite / Poison / Camouflage) so the unit’s dominant intrinsic ability reads at a glance.
  • Phase title overlay system — New PhaseOverlay autoload listens to SignalBus and fires the spec-aligned full-screen overlay (Teko 80pt, scale-in + 1.2s hold + scale-out, copper-tinted background) for every phase transition: Surge, Battle (with opponent name as “vs Voltaire” subtitle), Victory, Defeat, Draw, Round N, Eliminated, Champion, Wager. Replaces the old _show_phase_banner + _show_combat_overlay “VS X” system that was duplicating overlays.
  • Combat FX system — Six status shaders punched up (frostbite_frost / poison_drip / plating_sheen / camo_digi / guard_shield / aura_shimmer); frost overlay scene mounts on frostbitten minions on top of the existing shader; buff aura overlay mounts on aura-receivers; plating ring fires when a unit’s plating absorbs damage (yellow radial flash + 100px ring scale 0.6→1.8 per spec §6.7); damage numbers redrawn in Teko Bold 38pt with Junkyard color tokens.
  • Per-theme scene transitionsshaders/transition_dissolve.gdshader rewritten as a Junkyard rust-wipe (copper edges, plate-toned cover instead of pure black, no static-flicker grain). themes/transitions/ additionally includes crt_shutdown.gdshader (Terminal theme variant) and ember_swipe.gdshader (Ruin Glass variant) ready for theme switching when those themes ship. Default transition duration 0.35s → 0.55s for a slower industrial read.
  • ThemeManager autoload — Singleton at themes/theme_manager.gd tracks the active theme (junkyard / terminal / ruin_glass), broadcasts theme_changed on swap, persists choice to user://heroes_ui_theme.cfg. Junkyard is currently the only ready-to-ship theme; d2 Terminal + d3 Ruin Glass slots are placeholders pending design tokens.
  • Procedural asset generatorstools/generate_junkyard_assets.py produces 10 PNGs (button 9-slices, FX overlays, transition mask + ember particle) so any of them can be re-tuned by editing the relevant make_* function and re-running. tools/generate_backgrounds.py regenerates the warm-copper-industrial scrapyard background and the cold-tense combat arena background.
  • Top-right keyword icons on cards — The four icons from the original handoff (camouflage / frostbite / plating / poison) now actually mount on live minions in the top-right corner via _refresh_keyword_icon, sized to 18×18 with KEEP_ASPECT scaling so the source 32×32 PNG fits the badge slot.
  • Session B preview screensthemes/session_b/ ships standalone scenes for Match Results, Run Summary, Settings (with a working theme picker hooked to ThemeManager), Card Detail, and a Junkyard Victory layout (CHAMPION + spotlight beam). Accessible from the new preview hub.
  • DESIGN button + Preview Hub — A small “DESIGN” button top-right of the main menu opens themes/preview_hub.tscn — a navigation surface with buttons for theme components, the Heavy Plate card lineup, phase title test, damage number test, transition test, settings, match results, victory, run summary, card detail, plus “Run Game” back to the main menu.
Changed
  • Combat speed +40% globallybattle_speed default bumped from 1.0 → 1.40 (15% retool baseline + 25% follow-up after live playtest). Saved player settings are also multiplied by 1.40 on load so existing players feel the speed-up immediately without flipping the cycler. All combat tween timings, lunge / impact / return durations, and animation arcs scale through this single knob.
  • UITheme palette repointed at Junkyard tokensRUST_ORANGE #C45A2C → copper #b06a3a, WARM_CHARCOAL → plate #1a1612, WARNING_AMBER → brass #d4a54a, BLOOD_RED → danger #c0302a, TOXIC_GREEN → ok #6fa84a. Cascades through every script that references these constants (tooltips, hover glows, splash titles, faction tints, etc.).
  • UITheme button helpers ship Junkyard texturesstyle_button_primary / secondary / tertiary now load the new btn_*.tres 9-slice resources instead of building flat-color StyleBoxFlats. make_panel_style returns Junkyard plate aesthetic regardless of caller-passed colors. apply_to(root) loads themes/junkyard/theme.tres directly so every scene that calls it picks up the design system.
  • Death effects toned down ~50% — After playtest the explosion was reading too loud. _spawn_impact_burst particle count 12 → 6, particle size 12px → 8px, distance range 30-80 → 15-40. _spawn_flash_impact peak scale 0.8 → 0.45. Death pre-shrink expand 1.25 → 1.10. Faction-specific particle bursts untouched.
  • Camouflage shader dialed back — Was dominating the card art. Alpha formula tightened from 0.30 + edge_bias * 0.45 + break_up * 0.25 (max ~0.78) to 0.10 + edge_bias * 0.30 + break_up * 0.10 (max ~0.55). Edge bias starts later so the center of the card reads through clearly.
  • Zone labels punchier — OPPONENT / SALVAGE YARD / BATTLEFIELD X/7 / HAND X/10 bumped from 13pt neutral white to 22pt copper Teko Bold with 3px black outline. Reads as a visual identifier instead of a utility caption.
  • Top scoreboard health bar tiles — HP number labels switched to Teko Bold 16pt + brass color + 2px outline (was default 14pt white). Background of the bar darkened to plate void so the green fill pops.
  • Settings menu Junkyard passsettings_menu.gd now loads plate.tres for the panel background, delegates buttons to UITheme.style_button_secondary, and clears its own slider / toggle overrides so the theme cascade wins (plate-track + copper fill).
  • Game Over overlay restyled — ColorRect background plate-toned (#0a0706 0.94α), centered GameOverPlate PanelContainer using plate.tres, GAME OVER label in Teko Bold 64pt copper with 5px outline, stats line in taupe.
  • Faction splash skinned — Background plate-toned, “THIS GAME’S FACTIONS” title bumped to 36pt Teko copper with 4px black outline.
  • Combat log panel — Swapped from Kenney metalPanel.png + cool blue-grey modulate to themes/junkyard/plate_9slice.png with neutral modulate so it reads as a Heavy Plate panel instead of generic UI metal.
  • Card frame drop shadow reducedplate.tres shadow_size 20 → 6 and shadow_offset (0,4) → (0,2) so card shadows no longer bleed into the next zone’s plate frame and create a fake section-divider look across the bottom of cards.
  • Backgrounds regeneratedui_scrapyard_background.png rebuilt as warm copper-tinted industrial yard with overhead light bloom, scratch lines, vignette. ui_board_background.png rebuilt as cold tense arena with horizontal centerline rim + dust particles + heavy vignette.
  • Main menu themed — Root Control of main_menu.tscn now sets theme = junkyard.tres; ThemeManager registered as autoload; DESIGN button added top-right.
Fixed
  • Bot-vs-bot players never took damage in offline RumbleMatchManager.resolve_ai_matches() was a deprecated no-op stub left over from the server-cutover (“AI combat is now resolved server-side via game-engine.js”). For offline / single-player Rumble in the Godot editor without a joined room there is no server, so 6 of 7 AI players never lost HP from each other — only when the human personally beat them. Added a local board-strength approximation (sum of attack + health decides winner; damage = sum of winning tiers, min 1) and gated it behind NetworkManager.current_room_code == "" so it can’t double-apply on top of server results in online matches.
  • Doubled phase title overlays — The new PhaseOverlay autoload was firing “BATTLE” on combat_started while game_manager._show_phase_banner("SURGE PHASE", ...) was firing the old in-game banner at the same time. _show_phase_banner is now a return-only no-op and combat_engine drives the BATTLE overlay manually with the opponent name as the subtitle.
  • Duplicate “vs Voltaire” text — The legacy _show_combat_overlay("VS X", ...) overlay rendering below the new BATTLE phase title is gone. Combat opens with one clean “BATTLE / vs Voltaire” overlay (subtitle now 30pt copper with outline) instead of stacked text.
  • Big card flash on attackcombat_engine._spawn_attack_trail was spawning 3 portrait-sized ghost copies of the attacking card (125×165 each) along the lunge path. Now a no-op. The lunge motion + windup + impact still fires; just no more cardboard-cutout trail.
  • Poison overlay misfiring — Was mounting on every unit whose intrinsic Poison keyword makes its attacks lethal (e.g. Scavenger-Medic). Poison is offensive, not a debuff. _refresh_status_decoration now only mounts the frost overlay (the only true debuff state) and skips the others.
  • Giant snowflake icon mid-card — The new keyword icon TextureRect was mis-parented to MinionCard (a PanelContainer), which auto-stretched its 32×32 source to fill the entire card. Re-parented to Decor (a plain Control) and switched stretch_mode to KEEP_ASPECT so the badge renders at the spec’d 18×18 in the top-right.
  • main_menu.tscn corrupt scene — Brief regression where the new DESIGN button node was missing parent="." attribute, which Godot interpreted as a second orphan root and refused to load the file. Fixed.
Did NOT integrate (intentional)
  • d2 Terminal + d3 Ruin Glass theme.tres files — Genuinely blocked on a designer-side §3 (color tokens) + §4 (typography) + §5 (component restyles) spec for those themes. Junkyard is the only fully-specified theme; d2/d3 placeholders point at junkyard.tres until tokens land. Theme picker exists in the preview Settings.
  • combat_engine.gd’s bespoke attack / death animations — The spec’s §6.1 attack arc, §6.2 hit flash, and §6.4 death are simpler position / scale / alpha tweens. The game’s existing animations are richer (camera zoom, screen edge flash, faction-color tint ramps, particle bursts, “DESTROYED” floating text). Replacing them with the spec primitives would be a downgrade. The play_attack_arc / play_hit_flash / play_death methods are still exposed on card.gd + minion.gd for preview scenes and any future generic card use.
  • Live wiring of themes/session_b/match_results.tscn — Live combat outcome flow is tightly integrated with combat_engine’s per-attack loop. Replacing it with the standalone Session B scene would unwind that integration. The Session B scene remains available via the preview hub.
  • Card Detail (§11.4) hover-pin behavior — The live tooltip in main_board.tscn works fine; replacing with a 1.4× pinned card detail panel needs a UX call on hover-vs-pin trigger.
  • Faction flagship art for live cards — Live cards correctly use Database.get_card_art_texture(card_id) per-card. The handoff flagship PNGs were mock placeholders only.
v1.0.0 April 23, 2026
Changed
  • Card game rebranded to “Heroes of Rust & Roots” — The card auto-battler is now Heroes of Rust & Roots, the flagship product under the Rust & Roots umbrella alongside Chronicles (narrative) and Runner (trading). Godot project name, window title, APK package label, web page titles, changelog tab, and main menu title all updated. Umbrella brand “Rust & Roots” stays for the studio / world / hub. Android package ID com.rustandroots.game is unchanged so existing installs still auto-update. Version bumped to 1.0.0 across api/server.js, main_menu.gd, update_loader.gd, export_presets.cfg.
  • Domain migration — 600mmr.com/rnr/ → rustandroots.io + rustandroots.dev — All R&R products now live on their own domains. Public site (hub, heroes, chronicles, runner, player, downloads, profile, account) at rustandroots.io. Admin tooling and dev surfaces (card editor, faction editor, logs, tracker, docs, cards, lore) at rustandroots.dev. Separate Discord-linked JWT cookies per domain. Let’s Encrypt TLS, Hostinger DNS, nginx configs now in tools/nginx/ in the repo.
  • Heroes card-game path is now /heroes/site/play/ → site/heroes/ (git mv preserves history). Every hotfix update URL in main_menu.gd points at /heroes/heroes-*. 600mmr.com/rnr/play/*.pck|.zip|.apk will be symlinked to the new paths in Session 2 so legacy APK installs can self-upgrade to 1.0.0 via the old proxy; the first self-update then flips their baked URL to rustandroots.io.
  • Website redesign live on rustandroots.io — New cinematic hub landing (“Thirty Years After the Event” → Enter the City → three game banners). New full-bleed /play/:game shells for each game with glass title pill, fullscreen toggle (F key), and per-game download panel. Cinzel + Crimson Pro + Inter typography, ember particles, film grain, smoke pulse, parallax drift. User-provided Rust & Roots hero mark now sits behind every page at 28% brightness.
Added
  • v1.0.0 native builds live — Heroes Android APK (heroes-alpha.apk, 335 MB), Heroes Windows full bundle (heroes-windows.zip, 344 MB), and the 311 MB PCK-only hotfix files for each platform. Fresh web export too. Served from rustandroots.io/heroes/heroes-* for new installs. Legacy 600mmr.com/rnr/play/rustandroots-* paths now symlink to the new files, so an existing v0.97 APK self-update will pull the v1.0.0 PCK via the old URL — and once that PCK loads, the game's SERVER_BASE_URL flips to rustandroots.io for every request after. First update walks the user to the new URL, no manual reinstall required.
  • 600mmr.com R&R web UI retired600mmr.com/rnr/, /rnr/chronicles/, /rnr/runner/, etc. now return 404. The only paths under /rnr/ still served are /rnr/api/* (for legacy-APK auth + matchmaking), /rnr/ws (multiplayer WebSocket), and /rnr/play/rustandroots-*.pck|.zip|.apk (symlinked native artifacts for the self-update bootstrap). R&R's public front door is https://rustandroots.io/.
  • New Runner thumbnail — Replaced the earlier title-card art at /assets/brand/logo-runner.png (visible on the hub's Runner banner and the /play/runner shell).
  • Native Discord OAuth in rnr-comments — R&R previously piggybacked off the 600mmr.com backend for Discord sign-in. Now the R&R Express server has its own GET /api/auth/discord and /api/auth/discord/callback handlers with CSRF state, origin validation against ALLOWED_ORIGINS, and cookie-based sessions. New Discord application “Heroes of Rust & Roots” with redirect URIs for both new domains. Existing Discord users on the legacy 600mmr flow continue to work via the kept-alive /rnr/api/* proxy.
  • Hotfix updater integrity check/api/health now returns SHA256 hashes for each native artifact (heroes-windows.pck, heroes-windows.zip, heroes-android.pck, heroes-alpha.apk). deploy.sh writes a heroes-manifest.json at deploy time. main_menu.gd verifies every download against the advertised hash before installing. Corrupt downloads are refused; clients fall back to the next update strategy.
  • Horizontal main menu — The vertical button stack on the right was replaced with a compact horizontal row ([PLAY] [DUEL] [SETTINGS] [QUIT]) at the bottom-center of the screen. Creative Mode is hidden from the main menu (kept as a node for the admin flow that toggles it). New “Heroes of Rust & Roots” title card serves as the main menu background.
Removed
  • Opening video retiredscenes/splash_screen.tscn, scripts/splash_screen.gd, and assets/video/opening.ogv (2.3 MB) all deleted. Game launches straight to the main menu.
  • Old OneDrive clones purgedOneDrive/Desktop/rnr2/ (stale February git clone that was silently confusing cross-machine work) and OneDrive/Desktop/RnR/ both deleted. The canonical repo path is C:\Dev\RustAndRoots\ on every machine.
Fixed
  • Title card PNGs were JPEG content — The rebrand title cards (heroes / chronicles / runner / rust-and-roots / cityscape / hero-bg) were originally saved with .png extensions but had JPEG magic bytes. Browsers rendered them fine but Godot’s PNG importer rejected them silently, leaving logo.png with a stale texture and main_menu.tscn throwing “invalid UID” in the debugger. All offending files re-encoded to real PNG.
v0.97 April 8, 2026
Changed
  • Faction rename to match Chronicles lore — Seven of the ten factions have been renamed so the card game matches the Chronicles manuscript: Ferals → The Pack, Blooms → The Grove, Amplifiers → The Parish, Glaciers → The Thaw, Swarm → The Hive, Volts → The Drift, Alchemists → The Apothecaries. Syndicate, Rigs, and Neutral are unchanged.
  • Card ability text rewritten — 26 cards had prose referencing the old faction names ("friendly Feral", "all Blooms", etc.). All rewritten to use the new faction vocabulary ("friendly Pack unit", "all Grove units", etc.).
  • 3 cards renamedFeral Pack-Leader → Pack-Leader, Glacier-Core Reactor → Thaw-Core Reactor, Volt-Jumper → Drift-Jumper. Also Swarm-Caller → Hive-Caller and The Apex-Swarm → The Apex-Hive.
  • Lore page updated — The Drift (formerly Volts) now occupies slot #8 in the lore numbering. Signal has been dropped from the numbered faction list since it has no cards in the game.
  • Internal IDs unchanged — Card IDs (feral_001, bloom_002, etc.), art filenames, and CSS variable names stay the same. Only display names change. Nothing breaks in the card-linking, notepad, or art sync pipelines.
v0.96 April 2, 2026
Added
  • Soundtrack PWA — Standalone installable music player at rustandroots.io/player/. Background playback with lock screen controls (Media Session API), shuffle, repeat (off/all/one), seek bar, volume control. Like/dislike tracks with localStorage persistence, favorites-only filter, auto-skip disliked tracks. Sleep timer (15/30/60 min). Track feedback sends to Discord. Crossfade transitions between tracks. Deep linking via #track-N. Playlist update detection. Share track links. Dark theme with rust/amber accents, mobile-first design.
  • Track feedback endpoint — New POST /api/track-feedback lets listeners send one-way feedback per track. Rate-limited (1 per track per minute), fires Discord webhook with track title and message. No auth required.
  • Track added_date fieldPATCH /api/tracks/:index now supports added_date (ISO date string). Tracks added within 7 days show a "NEW" badge in the player.
Changed
  • Mobile layout redesign — Replaced the left-side panel with a compact right column containing standings, chat/log, controls (Upgrade, Roll, Freeze), info display, and utility buttons. Card zones now use full screen width with 10% larger cards. FIGHT button centered at bottom, SELL zone moved into the shop area. Generous edge buffer for phone cases. Desktop layout unchanged.
  • Removed opening cinematic — Game now launches directly to the main menu, skipping the intro video.
  • Fixed broken glyph on NEXT opponent indicator — Removed unsupported sword emoji. Now displays "NEXT" in red text.
v0.95 April 2, 2026
Changed
  • Mobile layout redesign (initial) — First pass of the right-column mobile layout. Iterated through v0.95.1–v0.95.3 for edge buffering and sell zone positioning.
v0.94 April 2, 2026
Fixed
  • Card touch no longer opens notepad on Android — Added platform guard to the right-click handler. Godot emulates right-click from touch long-press, which was triggering the notepad and keyboard on every card interaction. Now only fires on desktop.
  • Re-exported all builds with v0.93+ code — Previous builds were exported before Godot reloaded script changes, shipping stale code. All platforms now have correct v0.94 scripts.
Changed
  • Art sync uses hash-based skip — Server now includes a manifest hash in the art-manifest response. Clients compare the hash before checking individual cards. If nothing changed, sync completes instantly with zero downloads.
  • Removed redundant lobby art sync gates — Main menu already blocks entry until art sync finishes. The duplicate gates in Rumble and Duel lobbies were unnecessary and could show confusing "Updating card art..." messages.
v0.93 April 2, 2026
Fixed
  • Hotfix loader validates PCK version — The UpdateLoader now checks whether a downloaded hotfix PCK is older than or equal to the current build. Stale hotfixes are deleted on launch instead of overriding the build with outdated scripts. Fixes the infinite update loop on Windows and Android.
  • Card drag no longer opens notepad on Android — Removed the long-press-to-link feature on mobile devices. The playtest notepad now only opens via the Notes button. Prevents the keyboard from appearing during normal card interactions.
v0.92.2 April 2, 2026
Fixed
  • Design Hub restored — The hub landing page at rustandroots.io/ was incorrectly serving the game instead of the Design Hub. Redeployed the correct index page.
  • Android infinite update loop — Native app prompted for updates endlessly because the server’s version included card-edit patch numbers (e.g., 0.92.1.1) that never matched the baked-in APP_VERSION. Health endpoint now returns the base version for update checks and a separate full_version field for display.
v0.92.1 April 1, 2026
Fixed
  • Sandbox now works in Rumble — Sandbox activation moved entirely server-side. No more fragile iframe URL param chain. Activate sandbox from the Card Editor, open the game normally, and your next Rumble uses sandbox card data. Deactivate when done.
  • Discard reverts changes — Clicking “Discard” in the Pending Changes panel now reverts all edited cards back to their pre-edit stats, clears the draft queue, and deactivates any active sandbox session.
v0.92 April 1, 2026
Added
  • Balance Sandbox — Playtest card changes without affecting the live game. Upload a CSV or edit cards in the Card Editor, click Sandbox, and get a shareable link. Full Rumble works with modified stats — shop, AI opponents, and combat all use sandbox data. Sessions expire after 2 hours.
  • Draft Sandbox — Sandbox button in the Pending Changes panel lets you playtest Card Editor edits before publishing. No CSV needed — just edit cards and click Sandbox.
  • CSV Import Diff Preview — Importing a CSV now shows a detailed diff table (card name, field, old → new) before applying. Choose to import as drafts or publish immediately.
  • Flexible CSV Parsing — Handles case-insensitive columns, aliases (ATK/Attack, HP/Health, Keyword(s)/keywords), repeated header rows, and extra columns. Google Sheets exports work directly.
  • Detailed Balance Changelog — Bulk imports generate per-card changelog entries (e.g., “Daisy-Cutter Hound: attack 2 → 3”) instead of generic summaries.
  • Card Revert Button — Green “Revert” button in the Card Editor restores a card to its pre-edit stats with one click.
  • Sandbox Mode Indicator — Green “SANDBOX TESTING MODE” banner on main menu and in-game when playing in a sandbox session.
  • Balance Tools Guide — Documentation page covering all balance workflows, accessible from Admin nav dropdown.
Fixed
  • Mobile virtual keyboard — Touching or dragging cards on mobile no longer triggers the on-screen keyboard.
  • Dynamic changelog badges — Auto-generated changelog entries now display proper Added/Changed/Fixed/Removed badges instead of always “Changed”.
v0.90.1 April 1, 2026
Fixed
  • Android game freeze resolved — Root cause was card art being excluded from exports, forcing 195 image downloads that killed the WebSocket connection. Card art is now bundled in all builds; delta sync only downloads changed images (typically 0–5).
  • Server heartbeat relaxed — WebSocket heartbeat timeout increased from 30s to 120s, preventing false disconnects on slower mobile connections.
  • Art sync gates restored — Main menu and lobbies now wait for card data sync to finish before allowing game start. With bundled art this is near-instant.
Added
  • Android PCK hotfix system — Android can now receive GDScript and scene updates without a full APK re-download. A lightweight PCK patch is downloaded and applied on next launch, just like the existing Windows auto-updater.
  • Main menu sync indicator — Card data sync progress is now visible on the main menu. Multiplayer buttons are disabled until sync completes.
v0.89.2 April 1, 2026
Fixed
  • Android game start freeze — WebSocket connection was dying during first-time art download. Lobby now detects a dead connection and reconnects before starting the match.
  • Art download status visibility — Progress text in lobby bumped from 12px/faded to 16px/amber so it's actually readable on mobile.
  • Android main menu layout — Buttons were flying off the top of the screen due to broken safe area offset math. Menu is now properly centered on mobile.
v0.89.1 April 1, 2026
Fixed
  • Card art now loads on all platforms — Art sync downloads card images to an in-memory cache on web and file cache on native. Lobby gates wait for art sync to finish before starting a match, preventing blank cards.
  • Android update loop resolved — Fixed version mismatch that caused the app to repeatedly prompt for updates without actually updating.
  • UI textures restored — Board and shop background textures moved out of the excluded card art directory so they bundle correctly in all exports.
  • Combat snapshot error fixed — Resolved useV2 is not defined error that spammed server logs during multiplayer matches.
v0.89 March 31, 2026
Added
  • Faction Editor — New admin tool to manage factions: add, rename, recolor, reorder, and delete. Renames propagate to all cards automatically. Centralized faction data replaces hardcoded lists across the codebase.
  • Soundtrack Editor upgrade — Upload MP3 tracks directly from the admin page. Drag-and-drop batch upload, inline title and duration editing, toast notifications on all actions.
  • Admin nav menu — Gold "Admin" dropdown in the navigation bar, visible only to admins. Links to Card Editor, Faction Editor, and Soundtrack Editor.
  • Card faction reassignment — Faction dropdown added to the Card Editor stat row. Change any card's faction and save as a draft.
Changed
  • Card Editor UX overhaul — Draft mode is now always on. Pending changes panel auto-appears with "Unpublished" badges on affected cards. Toast notifications on every save action. Keyboard shortcuts: Ctrl+S to save, Escape to close modals.
  • Draft pipeline complete — Art upload and art crop now go through the draft pipeline. All card changes are batched and published together.
  • Faction data centralized — Game engine, site pages, and card editor all load faction data from a single API endpoint instead of hardcoded arrays.
Fixed
  • XSS hardening — Card names are now HTML-escaped in all Card Editor views to prevent script injection.
  • Crop modal leak — Event listeners properly cleaned up on cancel and backdrop click, not just on save.
  • Auth timing — Card Editor uses polling instead of fragile nested timeouts for admin detection.
  • Tracks admin nav — Soundtrack Editor page was missing nav-auth.js, now loads the full shared nav with admin menu.

v0.88 March 31, 2026
Added
  • Full card CRUD — Create, rename, archive, and delete cards directly from the Card Editor. Admin toolbar with New Card button, archive filter toggle, and bulk operations.
  • Card art upload + crop tool — Drag-and-drop or click to upload PNG art for any card. Crop/position tool lets you pan and zoom art like a profile pic editor — saved per-card so art displays correctly in-game.
  • Bulk export/import — Export all cards as CSV for spreadsheet editing, then import changes back with full audit trail.
  • Live card preview — Toggle between JSON and visual card preview in the right panel. Shows art, stats, keywords, and ability text styled like the in-game card.
  • The City in nav — Interactive story project now linked in the World dropdown and pulled into version control.
  • Draft / Publish workflow — Toggle draft mode in the Card Editor to batch multiple changes. Review pending edits, then publish all at once as a single version bump with a combined changelog entry.
  • Art sync system — Card art is now synced from the server on app launch. New art, updated art, and crop settings download automatically before gameplay. No Godot export needed for card content changes.
Changed
  • Archive system — Archived cards are filtered from shop generation in both game engine and multiplayer. Soft-delete preserves historical data while hiding cards from active play.
  • Card browser — Shows art thumbnails, archived card indicators, and archived count. Filterable by archive status.
  • Card art pipeline — Art excluded from Godot export bundles. Clients download art from the server and cache locally. First launch downloads the full set (~8MB); subsequent launches only fetch deltas.

v0.87 March 30, 2026
Added
  • Playtest notepad — In-game note-taking panel on all platforms. Right-click a card (or long-press on mobile) to link it with [Card Name] formatting. Notes auto-save and submit to the issue tracker.
  • Transition effects everywhere — Matrix rain into combat, dust blow back to shop, CRT glitch on settings, metal shutters to lobby, amber embers on game start. Every phase change now has its own signature effect.
  • Phase backgrounds — Scrapyard gets its own background art during shop phase. Combat phase has the original battlefield art.
  • New title screen — Updated main menu artwork.
Changed
  • HUD layout — Upgrade moved to right side next to Roll/Freeze. All action buttons match brightness. Notes/Settings/Quit use consistent styling.
  • Combat log — Defaults to minimized on Chat tab. Collapsed bar is now a thin 24px strip.
  • Button visibility — Roll button now matches Freeze brightness. Disabled buttons are clearly dimmed instead of ambiguously grey.
  • Web play page — Removed the sidebar frame. Game is full-width with a compact floating report button.

v0.86 March 30, 2026
Added
  • Combat flash impacts — Kenney flash textures burst on hit for a more visceral combat feel.
  • Attack afterimage trail — Cards leave fading ghost images along their lunge path during combat.
  • Card hover glow — Cards warm up subtly when you mouse over them.
  • Upgrade flash — Golden flash across the shop when your workshop levels up.
  • Victory & defeat effects — Win: gold particle burst + flash. Loss: dark red vignette lingers.
  • Kenney SFX — Coin clinks on scrap gain/spend, metallic slam on card deploy, blade slash layered on combat hits.
  • Windows native build — Download from the Design Hub with PCK-first auto-update (fast hotfixes).
Fixed
  • Damage numbers — Replay combat path now uses proper pop-in damage numbers instead of generic floating text.

v0.85 March 30, 2026
Changed
  • Art-forward card layout — Cards redesigned: art fills the card, name overlays the bottom of the art on a translucent bar. Keywords and ability text moved to hover tooltip.
  • Dark metallic card frames — Subtle faction accent strip on top, dark gunmetal frame. No more bright colored borders.
  • Gold & silver holo — T6 cards shimmer with a prominent gold metallic sweep, T5 with silver.
  • Kenney metal panel textures — Shop zone, board zone, and combat log now use real metallic panel textures.
  • Death effects tuned — All faction death particles are larger, slower, and more numerous.
  • Website card browser — Cards on the website match the new art-forward layout.
Added
  • Opponent indicator — Scoreboard shows “⚔ NEXT” under your upcoming opponent during shop phase.
  • Shop card fan-in — Cards animate into the shop with a staggered slide-in.
  • Freeze frost overlay — Frozen shop cards now show a visible frost shader effect.
  • Player damage vignette — Screen edges pulse red when you take damage.

v0.84 March 30, 2026
Added
  • Visual overhaul — Complete card frame redesign with dark metallic bodies, thin borders, and faction accent strips. Cards now feel premium instead of placeholder.
  • Holographic T6 cards — Tier 6 cards shimmer with a rainbow holographic sweep effect.
  • Aura teal sweep — Units receiving aura buffs glow with a teal/emerald sweep effect.
  • Guard shield overlay — Guard units display a shield-shaped frame, making them instantly recognizable.
  • Rust dissolve transitions — Scene transitions now use a procedural rust dissolve with orange edge glow.
  • Card slam effect — Cards punch and burst particles when deployed to the board.
  • Coin icon — Scrap counter now shows a coin icon.
  • Kenney audio — Card hover now plays a proper rollover sound (fixes ui_hover warning).
  • Smoke death particles — Unit deaths use real smoke textures instead of procedural circles.
Changed
  • Font system — Teko Bold for buttons/HUD, Barlow SemiBold for card names/stats, Inter for body text. All sizes bumped 30-40% for readability.
  • Combat hit feedback — White-gold flash + scale punch + stronger shake on damage.
  • CRT scanlines — Nearly 2x more visible when enabled (intensity 0.08 → 0.15).
  • Status borders — Thin muted status borders (2px) instead of thick bright ones (4-5px). Shaders do the heavy visual lifting now.
  • Health bar panel — Animated color-graded bars, gold accent for player, red pulse for opponent.
Fixed
  • Removed parallax background — Mouse-tracking background shift disabled (felt jittery).

v0.83.2 March 27, 2026
Fixed
  • Rankings now populate on match start — Added deferred refresh timers so rankings appear after player data loads. Fixed round_started signal argument mismatch that silently broke the connection.
  • Safe area margins capped — Notch/cutout safe areas were reporting 100+ pixels, wasting 20% of the screen. Margins now capped at 50px max — enough to clear the notch without huge dead zones.

v0.83.1 March 27, 2026
Fixed
  • Mobile rankings now populate — Connected to server standings signal so player rankings appear as soon as match data arrives, not just after combat.
  • Game zones fill screen — Shop, board, and hand zones now expand to fill available vertical space instead of collapsing to thin strips.
  • Sell zone pulled inward — SELL label now clearly visible, well away from screen edge.
  • Edge margins increased — All UI elements have generous padding from screen edges for better usability on phones with rounded corners.

v0.83 March 27, 2026
Fixed
  • Mobile layout rewrite — Replaced broken node-reparenting approach with overlay-only system. Rankings panel and combat log are now positioned as overlays — no nodes are moved in the scene tree, eliminating silent failures. Rankings visible in left column, combat log below, game area properly shifted right.
  • Bottom HUD compacted — Reduced font sizes and spacing on mobile bottom bar for better fit.

v0.82 March 27, 2026
Changed
  • Mobile layout: left column — Player rankings moved from a cramped horizontal top bar to a vertical list on the left side. Combat log and chat sit below the rankings in the same column. The main game area (shop, board, hand) gets the remaining width. Everything is visible at once — no hidden zones, no tab switching.
Fixed
  • Sell zone margin — Properly respects safe area on Android.

v0.81.1 March 27, 2026
Fixed
  • Sell zone safe margin — “Sell (+1 Scrap)” now properly respects screen safe area on Android (was anchored outside the main layout container).
  • Log button visibility — Floating combat log button is now larger (80x36) with “📋 Log” text and amber styling instead of a tiny grey square.

v0.81 March 27, 2026
Changed
  • Combat log → floating button — On mobile, the combat log and chat are now behind a draggable 📋 button instead of taking up 20% of the screen. Red notification dot appears when chat messages arrive. Tap to toggle the log overlay.
  • Compact top HUD — All 8 player health panels now fit on mobile with smaller fonts and tighter spacing.
  • Collapsible hand zone — When your hand is empty, the Hand zone collapses to a thin bar. Expands automatically when cards are added.
  • Bigger combat cards — During combat, board and opponent cards scale up slightly for better visibility.
  • Find Match moved — The “Find Match” button is now in the Rumble lobby (between Invite and Start), not the main menu.
Fixed
  • Sell zone edge cutoff — “Sell (+1 Scrap)” no longer touches the right screen edge on mobile.
  • Safe area margins — Main menu and game screen both respect Android safe areas (gesture bar, notch, rounded corners).
  • Chat Send button — Larger tap target for the Send button in the chat panel.

v0.80 March 27, 2026
Added
  • Open lobbies: Quick Join — Room browser now sorts by MMR proximity with a one-click “Quick Join” button. MMR badges on each room. Auto-refreshes every 5 seconds.

v0.79 March 27, 2026
Added
  • Mobile UI overhaul — Zone-based layout for phones. Tab bar at the bottom switches between Shop, Board, and Hand views. Only one zone visible at a time. Cards scaled to 70% for readability. Combat auto-switches to Board tab and locks other tabs.
  • Safe area margins — Bottom HUD buttons no longer get cut off at screen edges on phones with rounded corners or gesture bars.
  • Mobile combat log — Collapsed by default on phones with a small toggle button. No longer takes up half the screen.

v0.78 March 27, 2026
Added
  • Friends messaging — Send direct messages to friends from any screen. Messages panel overlay with conversation threads, unread badges, and real-time delivery. Toast notifications during gameplay.
  • Matchmaking queue — “Find Match” button on the main menu. Auto-pairs you with the closest-MMR opponent. Expanding tolerance window (waits longer = wider search). 120-second timeout. Rumble queue fills with AI when enough humans are ready.

v0.77 March 27, 2026
Added
  • MMR / Elo rating system — Every duel and rumble match now adjusts your rating. Default 1000, K=32 for new players, K=16 for established. Leaderboard sorted by MMR.
  • Player profile page — Public shareable profile at profile.html with stats card, W/L/D record, win rate, streaks, MMR rank, match history (last 20), and top-20 leaderboard. Send friend requests directly from profiles.
  • Account settings pageaccount.html — change display name, change password, delete account.
  • Nav identity upgrade — R&R username shown as primary in nav badge with “via Discord” subtitle. Dropdown now includes Profile, Tracker, Account, and Logout.
Fixed
  • Stale “In Game” status — Online users table is now cleared on server restart. Friends no longer show as online after app crash or force-close.
  • Friends panel on Android — Fixed visibility guard that hid the friends panel for R&R-only accounts (was checking only discord_id, now also checks auth_token).
  • Rumble invite button on Android — Invite Friend button now shows for authenticated R&R accounts, not just Discord users.
  • Android keyboard covering login — Login overlay now scrolls when the soft keyboard appears instead of hiding behind it.
  • Chat shows own messages — Your sent messages now display locally in amber (server only broadcasts to other players).
  • Profile avatar display — Fixed avatar URL handling when the stats API returns full URLs instead of Discord hashes.

v0.76 March 27, 2026
Added
  • In-game chat — New Chat tab on the combat log panel. Send messages to other players in your match in real time. Red notification dot when messages arrive while viewing the combat log. Rate limited, sanitized, and broadcast to spectators.
  • Account system — Discord users can claim a username/password on the hub page to log in on Android. Accounts are linked — all stats, friends, and match history carry over.
  • Version check — Android app checks the server version on launch and prompts to update if a newer version is available. One tap to download the latest APK.
  • Android SSL fix — HTTPS connections now work on Android (CA certificate bundle included).
  • Custom app icon — Android app now shows the Rust & Roots logo instead of the Godot default.
Changed
  • Account creation requires Discord — Registration is no longer anonymous. Users must sign in with Discord on the website first, then claim their account with a username and password for the Android app.
  • Android download moved — Download card now appears prominently at the top of the hub page on mobile. Removed from nav bar.

v0.75 March 27, 2026
Added
  • Android alpha build — Native Android APK available for download from the nav bar. Full online multiplayer support — same servers, same matchmaking, same game.
  • Username/password accounts — New account system for native app login. Register with a username and password, sign in from any device. Existing Discord users can claim their account to link both login methods.
  • Native networking layer — All API calls (card database, stats, friends, combat logs, version check) now use native HTTP on Android/Windows instead of JavaScript bridge. WebSocket multiplayer works identically across all platforms.
  • Login screen — Native builds show a Sign In / Register overlay on the main menu. Credentials saved locally so you only log in once.
  • Auto-refresh on updates — Web clients poll the server version every 2 minutes and auto-reload when a new deploy is detected. No more asking users to hard refresh.
Fixed
  • Mobile nav bar on wide phones — Phones in landscape with viewports wider than 900px now correctly hide the nav bar (added max-height breakpoint + CSS specificity fix).
  • Deploy safety — deploy.sh now skips copying WebBuild/ if site/play/ has newer assets from git pull, preventing stale local Godot exports from overwriting good builds.

v0.74.2 March 27, 2026
Fixed
  • Mobile orientation stretching — Game frame now properly resizes after device rotation with debounced timing to handle viewport settling. Added PWA portrait overlay via CSS for instant feedback.
  • Dead links cleaned up — Removed all references to deleted pages (chat.html, replay.html, replays.html) from quick-links, user menu, activity feed, and tracker.
  • Redeploy visual overhaul — Restored vignette, dust particles, hover effects, combat juice, and all v0.74 visuals that were lost from an older build on the VPS.

v0.74.1 March 26, 2026
Added
  • Mobile landscape enforcement — Portrait orientation is now blocked on mobile with an inescapable "Rotate Your Device" overlay. PWA manifest forces landscape for installed app.
  • Mobile install prompt — Every mobile visit shows a prompt to install the PWA for the best experience. iOS shows Add to Home Screen instructions, Android triggers native install.
  • Early orientation lock — Attempts to lock screen to landscape immediately on page load (Android browsers that support it).
Changed
  • Install banners removed — Old bottom install banners replaced by the cleaner modal prompt on mobile.
v0.74 March 26, 2026
Added
  • Screen vignette — Darkened screen edges for atmospheric depth and mood.
  • Ambient dust particles — Slow-floating warm embers drift across the board.
  • CRT scanline overlay — Optional retro aesthetic with scanlines + flicker. Off by default, toggle in Settings.
  • Attack windup — Attacker contracts slightly before lunging, adding anticipation to every hit.
  • Target knockback — Defending unit gets pushed back on impact for visual weight.
  • Floating damage numbers — Damage dealt appears at impact point, scaled by magnitude. Big hits look BIG.
  • Card hover tilt — Cards now scale to 1.08x with a slight random tilt on hover, making interactions feel tactile.
  • Tooltip animation — Card tooltips fade and slide in smoothly instead of popping instantly.
  • Tier-scaled deploy particles — Higher tier cards produce more sparkles when deployed (T1=7, T6=22).
  • Soundtrack manager — Admin page for drag-and-drop track reordering. Soundtrack page + mini-player both fetch from a single tracks.json source.
  • 9 new soundtrack tracks — 32 total tracks including A Conflict of Interests, Overtaking the Old Ways, RU5TANDR00T5, NORUSTNOROOTS, Wrong Part of Town, We Are Not Kin, roots, We'll Get By, Brave New World.
Changed
  • Install button — PWA install prompt moved from bottom banner to a subtle button in the navigation bar.
  • Mini-player resume — Faster audio resume across page navigations (aggressive preload, immediate seek+play).
v0.73 March 26, 2026
Fixed
  • Made it easier for Supe — Reorganized site navigation into a shared component (consistent across all pages), added prominent Play button, streamlined menu structure. Eliminated redundant pages (Chat, Replay Viewer). Fixed play page wrapper losing its chrome on deploys.
v0.72.1 March 26, 2026
Fixed
  • CRITICAL: Combat now uses buffed stats — The server combat engine was looking up base stats from the card database instead of using the client's submitted values. Every buff (brews, auras, end-of-turn effects, spells) was being ignored — a 16/9 Black-Cat fought as a 1/1. Combat now uses the actual attack/health values with database base stats as a floor.
v0.72 March 26, 2026
Added
  • Status effect shader overlays — All 6 keyword shaders re-enabled via a new overlay system that avoids the GL Compatibility white-wash bug. Guard (amber hex shield), Plating (steel shimmer sweep), Frostbite (ice crystal edges), Poison (green toxic drips), Camouflage (scrolling digital camo), and Aura (faction-colored edge shimmer) are now visible on cards.
  • Aura-received glow — Cards buffed by an adjacent Aura unit now show a subtle matching edge glow, visually connecting the aura source to its targets.
  • Guard hex shield pattern — Guard cards display a visible hexagonal energy pattern in their amber glow, making them instantly distinguishable.
  • Impact rings on hit — Expanding faction-colored circle at target on attack, scaling with damage dealt.
  • Deploy slam effect — Placing cards on the board now triggers a satisfying scale punch + faction-colored sparkle burst.
  • Textured particles — Death and impact particles upgraded from colored rectangles to soft circles, star sparks, and smoke puffs generated procedurally at runtime.
  • Card frame redesign — Cards now have drop shadows, styled header bar, dark stat pill background, and tier-based border treatments (T4+ brighter, T6 gold accents).
Changed
  • Shaders use overlay architecture — Status shaders now render on dedicated ColorRect overlays instead of the card's PanelContainer material, fixing GL Compatibility rendering issues on web.
  • Keyword badges removed — Floating icon badges and status particles replaced by shader overlays for cleaner visual feedback.
  • Combat dimming reduced — Non-active cards now dim to 60% instead of 30%, keeping them readable during combat.
  • Death animations tightened — Shake phase reduced from 10 to 5 iterations. Screen shake and impact effects now fire after hit-stop to prevent slow-motion stacking.
Fixed
  • Double-width cards during combat — Spacer placeholder prevents layout thrashing when cards are reparented for attack animation.
  • Long death freeze on fatal hits — Screen shake was running during hit-stop at 0.05x speed, causing 20x slower animations. Now fires after hit-stop completes.
  • Jumper Cables spell error — Added missing _jumper_cables_plating property to MinionCard.
v0.71 March 25, 2026
Fixed
  • Card stat editor now works in multiplayer — Base stat changes (ATK/HP/Tier) from the editor are now instantly live in-game. The multiplayer shop was using a stale card database that never reloaded after saves.
  • Server-authoritative combat stats — The combat engine now looks up authoritative base stats and effects from the server database instead of trusting client-sent values. Editor changes take effect immediately for all games.
  • Data-driven effects now reach combat — JSON effects from the card database are now included in shop data, board submissions, and post-combat boards so the effect interpreter can process them alongside the hardcoded handlers.
  • Cost field no longer shows 0 for units — The stat editor Cost field is now hidden for non-spell cards (only spells have cost). Units no longer get a spurious cost=0 written to the database.
v0.70 March 25, 2026
Fixed
  • Card editor saves now work — PATCH endpoint was writing to the wrong file on VPS. Now correctly writes to the same file the game engine reads.
  • Live card data URL — Fixed fetch URL to correct absolute path /data/cards.json.
  • No more negative HP — Health clamped to 0 minimum.
  • No more float display — Damage numbers forced to int. No more "-3.0".
  • Keyword badges visible — Disabled clip_contents so badges render outside card bounds.
v0.69 March 25, 2026
Changed
  • Live card data — Web builds fetch card stats from the server at startup. Admin card edits take effect immediately without re-exporting.
  • Hit stop — Micro-freeze on big hits (≥5 damage) for impact feel.
  • Attacker knockback — Small bounce-back after landing a hit.
  • Damage on HP label — Shows "-X" in red directly on the card's health stat for 0.4s.
Fixed
  • Badge positioning — Uses layout signal to position correctly. Badges now appear at bottom-right of card, never covering tier.
  • Card Editor labeling — All visible text updated from "Effects" to "Card Editor".
v0.68 March 25, 2026
Changed
  • Combat visuals completely reworked — Damage now flashes directly on the card's HP label ("-3" in red) instead of floating numbers. Cleaner, no overlap, easier to follow.
  • Spotlight dimming during attacks — Uninvolved cards dim to 30% so the attacker and target stand out clearly.
  • Status overlay shaders removed — Guard/Plating/Frostbite/Poison shaders caused white-wash on web export. Cards now use keyword pills, badges, and colored borders instead.
  • Combat pacing rebalanced — Removed redundant effects (duplicate flashes, particle bursts). Each attack is one clean sequence: spotlight → lunge → damage → triggers → return.
  • Effects page renamed to Card Editor — Stat editing (tier/cost/ATK/HP) front and center for admins.
Fixed
  • Float display bug — All stats forced to integers. No more "+1.0 ATK" or "dealt 2.0 damage".
  • Negative HP units — Snapshot restore now clamps health to minimum 1. Fixes units appearing on board with -1 HP after combat timeout.
  • Card editor stat row — Stats form now properly appears when switching between cards.
v0.66 March 25, 2026
Changed
  • Combat pacing ~2× slower at 1x — Every timing doubled: highlight, lunge, impact, return, gaps between attacks, surge delays, trigger gaps, death animations. 2x speed now feels like the old 1x.
  • Guard shader toned way down — Narrow edge-only dark amber glow instead of bright gold wash. Border darkened and narrowed.
  • Plating shader reworked — Cool steel/silver shimmer instead of gold. Visually distinct from Guard.
  • Floating text & phase banners last longer — Text 0.8s→1.2s, banners 0.85s→1.2s.
Added
  • Per-player duplicate cap — T4: max 2 copies, T5: max 2, T6: max 1 per player. Shop won’t offer cards you’ve already maxed.
Known Issues
  • Creative mode — Needs playtesting; may be broken.
  • Duels — Status unknown; needs testing.
v0.65 March 25, 2026
Added
  • Animated status shaders — 6 new shaders: Guard (golden force-field pulse), Plating (metallic sheen sweep), Frostbite (frost creep from edges), Poison (green drip ooze), Camouflage (digital camo overlay), Aura (radiating wave shimmer).
  • Keyword badge icons — Every keyword now has a code-drawn 28x28 badge icon on the card. Consumable badges pop-and-fade when consumed.
  • Attack impact burst — Faction-colored particle burst at impact point. Cleave splash hits get 50% scale bursts.
Changed
  • No more board dimming — Removed 40% alpha dimming during attacks. Board stays fully visible. Attacker/target highlighted with colored glow borders instead.
  • Tighter combat pacing — Keyword gaps 0.18s→0.12s, post-attack gap 0.4s→0.3s. Border glow now fires at attack start, not after.
  • Bolder floating text — Thicker outlines, drop shadows, larger font sizes across all combat text.

v0.64 March 25, 2026
Added
  • Shared card pool — Each card has limited copies per match based on tier (T1: 14, T2: 12, T3: 10, T4: 8, T5: 6, T6: 4). Buying removes from pool, selling returns. Prevents degenerate board states like stacking multiple Main Stages.
  • Admin card stat editor — Effects tool page now includes editable fields for Tier, ATK, HP, and Cost (admin-only) with audit logging.
  • Sandbox combat fixed — Creative Mode sandbox Fight button now works, resolving combat via server API and displaying results with damage and survivor counts.
  • Phase banners — “SURGE PHASE” and “COMBAT PHASE” banners now appear during combat transitions.
  • Action border glows — Cards flash colored glow borders after actions: red for attacks, gold for keyword triggers, purple for debuffs.
  • Attack spotlight — Non-participating cards dim during each attack, spotlighting the attacker and target.
Changed
  • Wider keyword gaps — Increased inter-keyword animation gaps from 0.06s to 0.18s for much clearer visual separation between Cleave, Poison, Frostbite, and reactive triggers.
Fixed
  • Sandbox combat broken — Fight button previously showed a “coming soon” message. Now fully functional.

v0.63 March 24, 2026
Changed
  • Combat presentation clarity overhaul — Refactored the attack loop so every keyword trigger gets its own distinct visual moment instead of all firing in one frame.
  • Plating absorb: “BLOCKED X” — When Plating absorbs a hit, a gold “BLOCKED X” damage number now appears showing the absorbed amount. Previously showed nothing.
  • Poison kill: green death — Units killed by Poison now show “POISONED!” floating text, a green dissolve animation, and toxic bubble particles instead of a normal death.
  • Surge: sequential firing — Surge abilities now fire one at a time with pauses between units. Non-active cards dim during each surge, spotlighting the active unit.
  • Frostbite skip: shiver animation — Frozen units now visually shiver, flash ice-blue, and show “FROZEN!” text when their turn is skipped. Previously completely invisible.
  • Cleave: staggered hits — Cleave damage resolves sequentially (primary, then left, then right) with brief visual gaps instead of all at once.
  • Overdrive: cause indicator — A small “HIT!” or “PLATING LOST!” text appears before “OVERDRIVE”, showing what triggered the ability.
  • Thorns & Quills feedback — Barbed-Wire Wall and Irradiated Porcupine now show floating text when dealing reactive damage.

v0.62 March 24, 2026
Fixed
  • Glacier Frostbite keyword permanently stripped — Post-combat cleanup removed ALL “Frostbite” from keywords, including the base keyword on Glacier units. After one combat, Slush-Slinger, Hailstorm Caster, Freon-Leaker, and The Absolute Zero permanently lost their Frostbite ability. Now checks the card database to preserve base keywords.
  • Dead units respawn at 1 HP — Units that died in combat came back with 1 HP instead of their full pre-combat health. Now restores to pre-combat health plus permanent bonuses.
  • Frostbite visual persists in shop — The frostbite combat debuff flag was never reset when units were restored between rounds, causing frostbite tint to show on units in the scrapyard.
  • Buff message “++6.0 HP” — Combat log showed a double-plus prefix when only HP was buffed. Fixed string formatting.
  • Freon-Leaker Last Stand parity — Godot client targeted 3 positions (left, center, right) while server targeted 2 (adjacent only). Client now matches the server.

v0.61 March 24, 2026
Changed
  • Card visual effects overhaul — Removed "breathing" pulsing effects. Replaced with clean static indicators: subtle tint, solid colored border, no constant animation.
  • Status badges — Icon badges replace text overlays. Shield for Plating, snowflake for Frostbite, skull for Poison, eye for Camouflage.
  • Ambient particles — Active keywords show subtle floating particles: gold sparkles (Plating), ice crystals (Frostbite), toxic bubbles (Poison), purple wisps (Camouflage).
  • One-shot trigger flashes — Keywords flash briefly when triggered instead of constant shimmer.
Fixed
  • Poison visual clearing — Poison tint, border, badge, and particles now clear immediately when consumed in combat.
v0.60 March 24, 2026
Added
  • V3 Effect Interpreter — Data-driven effect resolution engine. Cards declare behavior in JSON; a generic interpreter executes them by calling V2's centralized helpers. Supports 12 action types, 24 conditions, 27 targets, dynamic amounts.
  • Effects data on all 183 cards — Every card in the database now has an effects array. 168 with active effects, 10 keyword-only, 5 tokens.
  • Keyword Definitions — Machine-readable specs for all 14 keywords in keyword_definitions.json. New Keywords page under Dev menu.
  • Interpreter hooks in combat engine — V2 checks the interpreter at 5 trigger points. Data-driven cards handled by interpreter; unimplemented cards fall through to old code.
Changed
  • Effects Builder improvements — Pre-fills from database. Context-aware form fields per action type. Status badges show "Defined" vs "Edited".
v0.59 March 24, 2026
Added
  • Effect System Specification (Doc 16) — Complete V3 blueprint for data-driven card effects. Defines JSON schema for triggers, targets, actions, conditions, and amounts. All 183 cards mapped to the new format (78% data-driven, 22% custom handlers). Includes keyword registry, trigger priority ordering, and interpreter architecture.
  • Effect Builder tool — New page under Dev menu. Form-based visual builder for card effect JSON — pick triggers, targets, and actions from dropdowns. Live JSON preview with copy-to-clipboard. Drafts saved to localStorage.
Changed
  • Combat Spec (Doc 13) — 7 ambiguities resolved — Overdrive unlimited (confirmed), Cleave blocked by Plating (change), Cleave uses modified damage (confirmed), Queen checked before Hatch (change), Apex-Swarm uses board-loaded state, single engine (combat_engine.gd is dead code), Plating blocks all damage (confirmed).
v0.58 March 23, 2026
Fixed
  • Removed fabricated triple/merge mechanic — AI was combining 3 copies of the same card into an upgraded unit. This mechanic does not exist in Roots & Rust. AIs no longer waste resources buying duplicates for a nonexistent upgrade.
  • Black-Market Dealer wrong ability — AI was replacing shop slots with off-faction cards. Real ability: deploy gives a free unit from the shop. Now picks best shop unit for free during buy phase.
  • Jumper Cables permanent Plating — AI treated Plating from Jumper Cables as a permanent keyword. Real: Plating is combat-only. Now uses temporary flag.
  • Flask-Tender/Recipe-Thief auto-applying brews — AI was immediately applying brew stats to units on deploy. Real: these cards add a brew to your hand. Now correctly pushes brew spell to hand for later use.
v0.57 March 23, 2026
Fixed
  • Board overflow from combat spawns — Matriarch, Apex-Swarm, and Scourge-Beast Chimera spawned real card clones during combat that incorrectly persisted between rounds, causing boards to grow to 14+ units. Only pre-combat units now persist. Hard 7-unit cap enforced everywhere.
  • Repeated consecutive matchups — Anti-repeat pairing data was stored on ephemeral objects that were recreated each round. Opponent history now persists correctly. Players should no longer face the same AI 4+ rounds in a row.
  • AI never selling T1 junk — Keyword bonuses and minor buffs inflated power scores, making worthless 1/1 units appear “strong.” Added raw stat floor: low-tier units with pathetic stats are now sellable regardless of keywords.
Improved
  • AI shop logging — Each AI’s log line now includes personality attribution: phase profile, archetype, preferred factions, and recent W/L record.
v0.56 March 23, 2026
Added
  • Personality-driven AI shopping — Full port of ai_controller.gd to both server engines. All 20 AI characters now use their personality parameters (aggression, upgrade priority, dream cards, archetypes, phase profiles) for every decision. AIs are no longer identical.
  • 12-phase AI shop pipeline — AI shopping runs through 12 phases: loss adaptation, upgrade, sell weak, generate shop, buy, deploy, sell-and-upgrade board, roll-and-buy, optimize, end-of-turn effects, spell application, positioning, and freeze.
  • AI spell buying — AIs purchase and apply spells with dream spell prioritization and diminishing returns.
  • AI board positioning — Guards front, aura buffers interleaved between carries, dream cards prioritized.
  • AI triple detection — AIs detect and auto-merge sets of 3 into upgraded +2/+2 versions.
  • AI shop freeze — AIs freeze the shop when a dream card or spell appears they can't afford.
  • AI end-of-turn effects — 11 card-specific EOT triggers simulated (Black-Cat, Tesla-Coil, Volume Knob, Brew generation, etc.).
  • AI smoke test — test-ai-shop.js verifies all 20 characters across 15 rounds with personality differentiation checks.
Fixed
  • Missing Alchemists faction — ALL_FACTIONS was missing "Alchemists". Alchemist cards were invisible to AI.
  • AI never upgrading workshop — Now uses personality-driven upgrade_priority with phase-profile awareness and round-pressure scaling.
  • AI buying duplicates — Now picks from top-5 with dupe penalty, plus triple completion priority.
  • AIs all building identical boards — Character personalities from ai_characters.json now drive all decisions.
  • AI never selling weak units — Sell-and-upgrade logic breaks the full-board deadlock.
  • AI character factions ignored — initRumble() now uses each character's preferred factions.
  • AI loss-streak not adapting — W/L tracked after combat; personality adjusts based on adaptability.
  • V1 upgrade cost bug — Set next upgrade cost to current tier's cost instead of next tier's.
v0.55 March 23, 2026
Added
  • Engine Comparison tool — Studies page has a new “Engine Comparison” tab. Every combat round is saved as a snapshot. Click “Compare” to replay the same matchup through the other engine and see differences side-by-side.
  • Server-driven version display — Title screen, browser tab, and nav bar now pull version + engine name live from the server. No Godot export needed for version bumps.
Fixed
  • Overdrive double-fire — Units with Overdrive were getting their bonus twice per Plating pop. Now fires exactly once per attack exchange.
  • AI never upgrading workshop — Upgrade threshold was too low for any upgrade to ever happen. AIs were stuck at Tier 1. Now uses round-aware scaling.
  • AI buying 5 copies of the same card — AI always picked the highest-power card deterministically. Now picks from top 5 with randomness and a heavy duplicate penalty.
  • AI never selling weak units — Added sell logic when board is full and a much better card is available.
  • Repeated opponents — Pairing system now tracks last opponent and avoids consecutive rematches when 4+ players remain.

v0.54 March 23, 2026
Added
  • Combat Specification — Canonical reference document for all combat mechanics: phase order, keyword dictionary, trigger taxonomy, buff lifecycle, state cleanup rules, and server authority contract. Available in Docs tab.
  • Card Audit — Every card in the game audited against its code implementation. 12 mismatches, 3 missing implementations, and 11 unclear texts identified and resolved.
  • Rebuilt Combat Engine (v2) — New server-side engine with centralized damage handling. All damage now flows through a single dealDamage() function that checks Plating and Immunity in one place, eliminating the source of most recurring bugs.
Fixed
  • Camouflage reworked — Now stripped when the unit attacks, not when targeted. A Camouflaged unit cannot be attacked unless its Camo is removed by an ability or it attacks first.
  • Plating blocks all damage — Plating now absorbs the next hit from ANY source: main attacks, Cleave, thorns, pre-attack triggers, Surge damage, and Plague Doctor.
  • Living Generator — The attacking Volt now receives the stolen ATK, not the Living Generator itself.
  • Junk-Armored Rhino — Now only triggers adjacent Ferals’ Last Stand, not Hatch.
  • Wasteland Grizzly — Spawns a Cub when damaged even if the Grizzly dies.
  • Snap-Trap Vine — Absorbs target’s base stats, not buffed current stats.
  • Apex-Flytrap — Absorbs target’s actual base stats and heals to full, not a flat +20 HP.
  • 7 card texts corrected — Toxic-Pollen, Shadow-Stalker, Scourge-Beast, Matriarch, Plasma-Cutter, Arc-Welder, High-Voltage Phantom all updated to accurately describe their behavior.

v0.53 March 22, 2026
Added
  • Keyword Specification — Established authoritative rules: keywords array is the cross-round persistence layer (never mutated during combat); boolean flags handle within-combat consumption; cloneBoard() re-initializes all flags each round.
  • has_guard boolean flag — Guard now has a proper boolean flag like Plating, Poison, and Camouflage. Targeting logic uses the flag instead of checking the keywords array directly.
Fixed
  • Keywords permanently destroyed mid-combat — EMP-Grenadier and Peacekeeper used kw.splice() to remove Guard/Plating/Camouflage from the keywords array during combat, making v0.52’s post-combat fix useless. Now all stripping sets boolean flags only.
  • Acoustic Panel aura accumulated duplicate Guard — Aura pushed “Guard” into keywords on every recalculation. Now sets has_guard flag instead.
  • Blood-Scent Tracker & Swarm-Caller — Both pushed Guard into keywords permanently. Now set the flag instead.
  • Surge abilities bypassed buffUnit() — Casino Leviathan, Ultimate Survivor, Heavyweight Draft-Pick, Cryo-Tube Sleeper, Blood-Scent Tracker, and Ammo Scavenger all used raw stat mutations. Converted for consistent event logging.

v0.52 March 22, 2026
Added
  • buffUnit() helper — Centralized buff function that handles both combat and permanent bonuses in one call, preventing the “permanent buff is actually temporary” bug class.
  • Slot-Machine Sentry scrap drop — Last Stand now awards 1 scrap via combat results.
  • Bounty Hunter ability — Kill-for-scrap implemented (limit once per combat).
Fixed
  • Consumable keywords permanently lost — v0.50 regression: Plating, Poison, and Camouflage were stripped from keywords when consumed, breaking cross-round refresh. Now only Frostbite is stripped.
  • 10 “permanent” buffs were temporary — Scrap-Iron Bruiser, Coal-Fur Prowler, Tread-Light Scout, Heavy-Duty Hauler, Frost-Harden Shield, Surge-Protector, Shadow-Stalker, Carrion Vulture, Fertilizer Pod, and Toxic-Pollen Flower all failed to track permanent_*_bonus.
  • Junk-Yard Juggernaut — Was self-buffing +2 ATK; now deals 2 damage to a random enemy.
  • Overclocked Engine — Was buffing itself; now buffs the unit that lost Plating, permanently.
  • Static-Spark targeting — Was hitting random; now targets directly opposite enemy.
  • Pack-Leader stats — Was hardcoded +2/+2; now gives the dead Feral’s actual base stats.
  • Apex-Flytrap heal — Was adding flat +20 HP; now permanently absorbs stats and heals to full.
  • Snap-Trap Vine & Apex Predator — Absorbed/summon stats now persist permanently.
  • EMP-Grenadier vs Overdrive — Surge strip no longer triggers Overdrive. EMP is a hard counter to Plating.
  • Defender-only triggers — Frost-Harden Shield, Surge-Protector, and Junk-Armored Rhino now fire on counter-damage too.
  • Jumper Cables server sync — Plating now visible to server via temp_plating flag.

v0.51 March 20, 2026
Fixed
  • Permanent buffs now display correctly — Board restoration was loading base stats from card database, ignoring server’s baked values. Now overrides with server-authoritative attack/health/keywords.

v0.50 March 20, 2026
Fixed
  • Combat state leaking — Poison, Plating, Camouflage now correctly stripped from keywords when consumed. Only Frostbite was being cleaned before.
  • Negative HP — Units can no longer display negative health between rounds.
  • Server-authoritative board merge — Server merges client board submissions with stored post-combat stats. Permanent buffs no longer reset.
  • Permanent buffs pipeline — Full data flow now works: engine bakes bonuses → server stores → client submits positions → server merges → combat uses correct values.

v0.49 March 20, 2026
Fixed
  • Permanent buffs lost between rounds — Server now returns authoritative post-combat boards with permanent bonuses baked into base stats. AI and human board storage are written back so buffs persist across rounds.
  • Board wipe after draw — Client now rebuilds the player board from the server’s authoritative board data instead of relying on local snapshots that fail when all units die.
  • Double elimination messages — Elimination processing now deduplicates: if a player is already marked as eliminated, the duplicate notification is skipped.
  • 0th place on game over — Duel mode game over messages now include placement. Client-side fallback derives placement from alive state if the field is missing.
  • Server authoritative board — Combat results now include the authoritative post-combat board so the client uses the server as source of truth for board state restoration.
  • Spell HP costs now server-authoritative — Black Market Deal and other HP-modifying spells now report their effects to the server. Server applies the change and sends back authoritative health updates.

v0.48 March 20, 2026
Added
  • Replays listing page — Browse recent match replays at replays.html (removed) with placement badges, round counts, and dates. Top-level nav link added.
  • View Replays button — After an online match ends, a “View Replays” button appears on the game over screen.

v0.47 March 20, 2026
Changed
  • Single authoritative engine — game-engine.js is now the ONLY combat engine. All games run through the server. No divergent gameplay paths. Deleted headless_combat.gd.
  • Permanent buffs persist cross-round — 12 cards now correctly retain combat buffs between rounds (Grid-Runner, Worker-Ant Bot, Carrion-Fly, Shadow-Stalker, and more).
Fixed
  • Arc-Welder — Cleave now deals 1 damage to adjacents (was full ATK).
  • Living Generator — Triggers on ANY friendly Volt attack (was self-only).
  • Glacier-Core Reactor — Buffs ALL Glaciers +2/+2 on Frostbite (was self +1/+1).
  • Pack-Leader — Buffs random Feral (combat-only), not self permanently.
  • Corpse-Lily — +2/+2 is combat-only (was permanent).
  • Diesel Behemoth — Plating refresh limited to once per combat.
  • Swarm-Caller — Drone now spawns with Guard.
  • Freon-Leaker — Frostbites 2 adjacent enemies (was 3).
  • Carrion-Fly — Only triggers on Hatch deaths, not all spawns.
  • Poison vs Immunity — Immune units now block Poison.
  • Locust-Plague — Spawned tokens now attack immediately on server.
  • Sound-Wave Surfer — Adjacent allies now attack during surge on server.
  • Plague Doctor, Penalty Box, Oil Spill — Spell effects ported to server engine.

v0.46 March 20, 2026
Added
  • Spectator Mode — Watch live Rumble games in progress. Eliminated players auto-convert to spectators. Spectators see standings, eliminations, and combat summaries. Spectator count displayed to all players.
  • Shareable Replays — Every Rumble game is automatically recorded. Web replay viewer at replay.html (removed) with round-by-round navigation, color-coded combat log, and shareable URL.

v0.45 March 20, 2026
Added
  • 25 sound effects — CC0 audio from Kenney.nl: combat hits, death, round results, keyword triggers (plating clang, poison sizzle, frostbite, surge, hatch, cleave, guard, overdrive, brew), shop actions (buy/sell/roll/freeze), and UI (round bell, workshop upgrade, timer warning).
  • Shop timer warning — Audio cue when 5 seconds remain in shop phase.
Fixed
  • Token spawn reactive hooks — Worker-Ant Bot, Carrion-Fly, Pack-Hunter Coyote, Apex Predator, and Locust-Plague now correctly trigger when tokens spawn during combat.

v0.44 March 20, 2026
Added
  • Damage type colors — Color-coded floating numbers: red (normal), toxic green (poison), orange (cleave), ice blue (frostbite), green (heal).
  • Attack direction indicator — Target tints red when being attacked, paired with attacker’s yellow highlight.
  • Keyword trigger VFX — Floating text for OVERDRIVE, CLEAVE, and FROSTBITE effects.
  • Combat pacing — Longer pause after surge phase for readability.

v0.43 March 20, 2026
Fixed
  • Mid-combat aura recalculation — Auras now update when units die or tokens spawn during combat. Main Stage immunity, damage reduction, and all stat auras stay accurate.
  • Glacier-Core Reactor (headless/server) — +1/+1 self-buff on Frostbite now works in AI and online matches.
  • Main Stage immunity (headless/server) — Adjacent immunity now works in all combat modes.
  • Distortion Pedal parity — Splash damage now correctly uses half Attack in headless combat.

v0.42 March 20, 2026
Changed
  • “Deathrattle” renamed to “Last Stand” — Global keyword rename across all code, card data, site, and docs. “Hatch” remains separate for Swarm token deaths.
  • Overdrive reworked — Now fires every time a unit survives an attack or loses Plating (was once per combat on Plating loss only). All 8 Overdrive cards affected.
  • Poison + Plating interaction — When Poison hits Plating, both are consumed. Plating blocks the kill, Poison is used up.
Fixed
  • Glacier-Core Reactor — Fixed from “all Glaciers +2/+2” to “self +1/+1” per card text.
  • The Main Stage — Adjacent allies now truly immune (was +5 Health aura).
  • Grid-Runner — +2 Attack per strike now stacks permanently.
  • Corpse-Lily — Death trigger buff now permanent across rounds.
  • Pack-Leader — Self-absorbs dead Feral stats (was random Feral).
  • Living Generator — Self-only steal on attack (was all Volts).
  • Sound-Wave Surfer, Cleave, Locust-Plague — Now implemented in headless/server combat for full online parity.

v0.41 March 12, 2026
Fixed
  • Card HP not updating during combat — Health labels on cards now update in real-time as units take damage during combat replay. HP numbers decrease visually, turn red when damaged, and trigger a punch animation on stat changes. Buff stats also display correctly

v0.40 March 12, 2026
Added
  • Shader glow status effects — Status effects now render with a CanvasItem glow shader instead of pulsing borders. Frostbite glows ice-blue, Poison toxic green, Plating bright gold, Camouflage purple. Includes a diagonal shimmer sweep across the card surface
  • Status word tags — Active status effects display a color-coded word tag on the card portrait ("FROZEN", "POISONED", "PLATED", "CAMO"). Multiple statuses combine with a dot separator. Tags and glow disappear immediately when statuses clear
  • Rot-Feeder targeting UI — Deploying Rot-Feeder highlights valid friendly targets with a green glow and a "Select a unit to devour" prompt. Auto-picks weakest after 6 seconds
  • Recipe-Thief Discover UI — Deploying Recipe-Thief presents 3 brew options from distinct tiers in a dark overlay. Player picks one; auto-selects first option after 8 seconds
Fixed
  • Brew generation broken online — All Alchemist Brew-keyword units (Sludge-Mixer, Chemical-Vat, Mad-Botanist, Grand Synthesizer, Golden Cauldron) now correctly generate brews in multiplayer
  • Round-start effects skipped online — Catalyst-Junkie +4/+4, Loan Shark debt, and Bookie payouts now fire in multiplayer mode
  • Permanent combat buffs lost between rounds — Overdrive and reactive trigger buffs now persist across rounds online. Replay buff handler syncs base stats so snapshot restoration preserves combat buffs
  • 20+ server abilities invisible — Added missing replay events for all Overdrive triggers (7), Surge buffs (6), post-attack reactives (9+), plating-lost reactions, and deathrattle buffs. Client replay now shows every server-side stat change
  • Amp-Rack Brute one-sided trigger — Now triggers +2 ATK when adjacent ally takes counter-damage as attacker, not just when being attacked

v0.39 March 11, 2026
Changed
  • Dramatic animated status borders — Status effects now feature highly visible pulsing borders during combat. Frostbite pulses bright ice-blue (4→8px), Poison toxic green (4→7px), Plating bright gold (5→9px), and Camouflage purple (4→6px). Border color oscillates between faction and status colors. Card tints are also stronger and faster for maximum visibility

v0.38 March 11, 2026
Fixed
  • Ghost kills in online play — Added 14+ missing event emissions so ALL combat damage is now visible during replay. Lightning-Rod zaps, Fused-Wire chains, Distortion Pedal splash, Barbed-Wire thorns, Porcupine quills, and surge damage all now show floating damage numbers and HP updates
  • Frostbite invisible in online play — On-hit Frostbite, counter-freeze, and surge Frostbite now show "FROZEN!" floating text with icy blue visual tint on affected units
  • Distortion Pedal splash damage wrong — Server engine now deals half-attack splash damage instead of flat 1 damage, matching the visual engine
  • Cleave missing from server engine — Arc-Welder and Scourge-Beast Chimera Cleave now implemented server-side
  • End-of-turn cards broken online — Black-Cat, Chassis Welder, Nitrous Injector, and all end-of-turn cards now work in online mode. Board submission now sends post-buff stats
  • Hailstorm Caster duplicate targeting — Visual engine now picks 2 distinct targets (matching server fix from v0.36)
  • Replay damage from abilities invisible — Attack animation now processes ALL damage sources during replay, not just direct combat hits
Added
  • Glacier-Core Reactor parity — All Glaciers now get +2/+2 in the server engine whenever an ally applies Frostbite
  • Visual status effect indicators — Cards pulse with animated color tints during combat: icy blue for Frostbitten, green for Poison, gold for Plating, semi-transparent for Camouflage. Multiple effects stack visually

v0.37 March 11, 2026
Fixed
  • Game over firing during combat — Game-over screen now waits for the final round's combat animation to finish before appearing. Previously the last round's combat was skipped and the combat log was missing the final fight
  • Carrion-Fly buff invisible online — Carrion-Fly's +1/+1 on friendly Hatch death now shows with floating text and stat updates during online replay
  • 3 more death reactions invisible online — Carrion Vulture, Shadow-Stalker, and Corpse-Lily buffs now emit replay events so clients can display them
  • Peacekeeper strip invisible online — Peacekeeper's keyword removal (Guard, Plating, Camouflage) now shows "STRIPPED!" floating text and removes unit icons during replay
  • Apex-Swarm spawning random units — Server and AI engines now correctly spawn 2 copies of the first friendly unit to die, matching the card text. Previously spawned random low-tier Swarm units
  • Online attack log missing stats — Attack messages now include ATK/HP values (e.g., "Static-Spark (3/2) attacks Slush-Slinger (2/4)") and buff events are logged

v0.36 March 11, 2026
Fixed
  • Server/client combat desync — Visual combat now plays back the server's authoritative events instead of re-simulating with independent RNG. What you see is what actually happened
  • B-side attack index bug — Side B's attack order was incorrectly tied to Side A's index, causing some B units to never attack. Both sides now use independent counters
  • Tire-Iron Thug Plating strip — Stripping Plating now properly triggers Overdrive and plating-lost reactions (Sprocket Spinner, Overclocked Engine)
  • Surge firing on dead units — Units killed during the Surge phase can no longer fire their own Surge ability
  • Hailstorm Caster double-hit — Hailstorm Caster's Surge now picks 2 distinct targets instead of potentially hitting the same enemy twice
  • Pyrotechnic Rig overkill — Split damage now only targets living enemies per pip and stops if all enemies are dead
  • Camouflage mass-reveal — Targeting no longer reveals every camouflaged unit at once — only the single targeted unit loses Camouflage
  • Snap-Trap Vine absorption — Now absorbs the target's buffed attack (not base stats) and properly exits combat on kill
  • Pack-Leader absorbing 0 HP — Pack-Leader now absorbs the dead Feral's base health instead of their current HP (which was always 0)
  • Matriarch copy keeping buffs — Matriarch copies now reset to base attack, clear Overdrive, and restore Camouflage
  • Volt-Jumper, Reactive, Glacier deathrattle — Multiple death reactions and triggers now correctly filter dead units before targeting
Added
  • Server-authoritative combat replay — Full event-driven replay system with attack animations, screen shake, knockback, floating damage numbers, and glow effects. The server records every combat event and the client animates them in sequence

v0.35 March 11, 2026
Fixed
  • Enemy board always empty in combat log — Combat log now captures both boards AFTER they are populated, fixing the issue where enemy units always showed "(empty)" in online matches
  • HP & elimination spoilers during countdown — Health updates, standings, and eliminations are now buffered during combat animation and applied after it finishes, preventing leaderboard spoilers
  • Shop timer desync (timer jumps to 0) — Replaced room-wide server timeout with per-player ACK-based timers. Players now get their full shop time regardless of how long combat animation takes, fixing auto-submits and missing rounds
Added
  • Match timestamps in combat logs — All combat log entries now include [MM:SS] match-relative timestamps. Server logs include millisecond precision for forensic analysis

v0.34 March 11, 2026
Fixed
  • Matriarch copies lose all keywords — Matriarch of the Wastes copies now only strip Last Stand and Hatch (per card text "no Last Stand"), keeping Guard, Plating, and other keywords intact
  • Flask-Tender gives overpowered brews — Flask-Tender (Tier 1) now correctly gives only Vial of Gunk instead of any random brew including Golden Elixir (+5/+5). Added brew tier system
  • Recipe-Thief ignores Workshop Level — Recipe-Thief now gives a brew matching your current Workshop Level (Gunk at 1, Mutagen at 2, Thickener at 3, Serum at 4, Elixir at 5+)
  • Hostile Takeover hidden discount removed — Removed undocumented mechanic where the spell cost decreased per friendly unit on board. Now always costs 3 Scrap
  • AI Hostile Takeover tier pool — AI opponents now use exact-tier matching for Hostile Takeover, matching player behavior
Changed
  • Database cleanup — Removed orphaned token entry. Added "Reactive" keyword to Scrap-Yard Raccoon, Irradiated Porcupine, and Wasteland Grizzly

v0.33 March 11, 2026
Fixed
  • Acoustic Panel permanent Guard — Aura Guard no longer permanently sticks to units. Guard aura is now checked dynamically during targeting, so it correctly disappears when the Panel dies or the unit moves away
  • Penalty Box not working — Fixed stale units from previous combat persisting in the opponent board, causing the Penalty Box to target already-dead units instead of the real highest-attack enemy
  • Brew generation invisible — Sludge-Mixer, Mutagen-Brewer, and other Brew units now generate brews before combat starts so players can see what was brewed. Added combat log messages for each brew
  • Hive-Mother spawning nothing on death — Hive-Mother's deathrattle now correctly counts only living units when checking the 7-unit board limit, so her Soldiers actually spawn
  • Slot-Machine Sentry scrap lost — Scrap earned during combat (from Sentry deathrattle, etc.) now persists into the next shop phase instead of being overwritten by the income reset
  • Poison not consumed — Poison is now consumed after triggering an instant-kill, matching Plating behavior. Poison refreshes each round when units rebuild from snapshots
  • Overdrive not triggering consistently — EMP-Grenadier, Scrap-Cannon Walker, and Peacekeeper now properly trigger Overdrive and plating-lost reactive effects (Sprocket Spinner, Overclocked Engine) when they strip Plating
  • Salvage Rights refreshing to empty shop — Now uses exact-tier matching per card text ("one Tier higher") with fallback pools so the shop always has units to offer
  • Hostile Takeover wrong tier pool — Now pulls from exact current Workshop Level instead of all tiers up to current level

v0.32 March 10, 2026
Added
  • Server-side game log — The server now accumulates a complete game log (all AI shopping, combat pairings + boards, eliminations, standings) and auto-submits it on game end. Works even if you disconnect
  • Background catch-up logging — Returning from a backgrounded tab now records what was missed: skipped combat results, elimination events, and a [Catch-up] marker
Fixed
  • Background tab catch-up — Returning from a backgrounded tab now instantly jumps to the current server state instead of replaying frozen animations. Stale combat loops are properly cancelled
  • Combat loop cleanup — Attack animation chains bail out immediately when a background skip has already resolved the combat
  • Upgrade cost not decrementing (online) — In server-hosted games, upgrade cost now properly decreases by 1 each round, matching offline behavior
  • Elimination toasts appearing early — Elimination notifications are now buffered during combat and shown after combat finishes, instead of spoiling results
  • Combat log not saving (online) — The game over handler now emits the correct signal so the combat log is properly submitted to the API
  • Server AI stuck at tier 1 — AI opponents' upgrade cost now decrements each round on the server, so they actually upgrade over the course of the game
  • Eliminated player stuck on "Waiting..." — When eliminated in Rumble, the game now shows your final combat and the game over screen instead of freezing
  • Double elimination toast — Eliminated players no longer see their own elimination notification twice
  • Console errors (freeze_tween) — Fixed harmless but noisy errors in the browser console when clearing shop freeze visuals
  • Games play to completion — When you disconnect or close the tab, the server now plays out the remaining game to its natural end. The complete log is submitted with final standings and a winner

v0.31 March 10, 2026
Changed
  • Server-hosted single player — Solo games now run on the server, identical to multiplayer. The VPS manages all AI opponents, round timing, combat resolution, and eliminations. Browser tab throttling is no longer an issue — the game continues at real speed regardless of tab state
Fixed
  • Offline fallback — If the server is unreachable, the game seamlessly falls back to local offline mode
  • Desktop recursion bug — Fixed infinite recursion in timer helper that would crash desktop builds

v0.30 March 10, 2026
Fixed
  • Browser tab throttling — Shop timer and combat countdown now use wall-clock time instead of delta accumulation. Switching browser tabs no longer freezes or spikes the timer
Added
  • Server-side round timeout — Multiplayer server now enforces a round deadline. If a player fails to submit their board (e.g. due to disconnect), the server auto-submits their last known board
  • Post-elimination spectating — When eliminated in single-player, the game now simulates remaining bot rounds with a live standings display. Watch or skip to final results showing all 8 players’ placements

v0.29.1 March 10, 2026
Added
  • Battle Studies — Every combat log is now automatically analyzed by Claude AI upon submission. The new Studies page shows individual game breakdowns (narrative analysis, metrics, balance flags) and an aggregate dashboard across all games
  • Player name tracking — Combat logs now record the player’s Discord username, shown in log listings, study cards, and the aggregate “Top Players” leaderboard
  • Live online indicator — Nav bar now shows how many players are online in real time, with a clickable dropdown listing who’s playing. Authenticated users also see which friends are online

v0.29 March 9, 2026
Added
  • Dynamic faction adaptation — AIs detect when preferred factions aren’t in the game pool and pivot using archetype affinity. They also recognize emergent board factions and adapt their strategy to what they’re actually building.
  • Board keyword synergy scoring — AIs evaluate cards based on keyword interactions with current board (Plating↔Overdrive chains, Frostbite stacking, Brew+targets, death trigger chains, Aura scaling) instead of flat bonuses.
  • Spell economy phase — After board is full, AIs spend remaining scrap on spells with a carry bonus: spells score higher when the board has high-stat units to buff.
Improved
  • Scaling faction commitment — Off-faction penalty scales with round number (1.4× at R10, 1.8× at R15), so AIs commit harder as the game progresses.
  • Greedy minimum board — Greedy AIs can no longer upgrade past Workshop 3 with fewer than 3 units or past Workshop 4 with fewer than 5 units.
  • Tempo upgrade floor — Tempo AIs are forced to Workshop 3 by round 7 and Workshop 4 by round 10 minimum.

v0.28 March 9, 2026
Improved
  • AI early-game faction seeding — AIs now strongly prefer their preferred factions when buying their first 1-3 units, establishing correct faction identity early
  • AI aggression floor — Low-aggression AIs now have a minimum aggression for card scoring, preventing boards with 2 avg attack that can’t win fights
  • AI tier-appropriate buying — AIs now penalize buying units far below their workshop level, preventing late-game downgrades like selling T4 to buy T1

v0.27 March 9, 2026
Improved
  • AI won't buy spells with empty board — AIs no longer waste scrap buying spells when they have zero units to fight with
  • AI sell-to-upgrade on full board — When board is full at 7 units, AIs now sell their weakest unit to buy a significantly better one from the shop
  • AI upgrade speed boost — All AIs upgrade workshop faster with shifted cost thresholds and round-based pressure after R6
  • AI faction commitment — Increased off-faction penalties and added board-ratio bonus, reducing faction scatter
  • AI spell diminishing returns — Repeat spell purchases now score lower, preventing spam like buying Penalty Box 8× in one game

v0.26 March 9, 2026
Added
  • AI dream cards — Each of the 20 AI characters now has up to 4 "dream cards" they actively hunt for, giving them unique strategic identities (Prof Vex → Syringe-Dart, Queenie → Queen of the Wastes, etc.)
  • AI archetype system — 8 engine archetypes (brew_engine, death_trigger, swarm_flood, glacier_control, volt_aggro, rig_armor, aura_position, economy) provide context-aware scoring bonuses
  • AI spell purchasing — AI characters now buy and use spells from the shop, with character-specific dream spell lists
  • AI shop freeze — AI can freeze the shop when a dream card appears they can't yet afford
  • AI loss-streak adaptation — High-adaptability characters dynamically adjust strategy when losing
Improved
  • AI shop parity — AI shop now mirrors the human experience: units + guaranteed spells, Black-Market Dealer support, full shop regen on rolls
  • AI phase awareness — Three game phases (early/mid/late) with greedy, tempo, and balanced profiles per character
  • AI sell logic — Buffed survivors and dream cards are now protected from being sold
  • AI positioning — Adjacency-aware placement: Volume Knob and Tesla-Coil placed between carry units for maximum buff coverage

v0.25 March 8, 2026
Fixed
  • Online multiplayer combat flow — Matches now play identically whether against bots or humans: VS overlay, VICTORY/DEFEAT/DRAW result screen, round banners, animated phase transitions, and shop timer scaling all work in online mode
  • Online scoreboard — TopHUD health bar panels now display correctly in both Duel and Rumble online modes, with live health updates
  • Combat race condition — Server round_start messages arriving during combat animations are now buffered and processed after combat ends, preventing the shop from opening mid-fight
  • Shop visibility during combat — Scrapyard and shop zones are now properly hidden when online combat begins
Improved
  • Online/offline parity — Freeze pulsing animation, opponent HP in VS overlay, and smooth fade transitions between phases now match the offline experience exactly

v0.24.2 March 8, 2026
Added
  • AI end-of-turn effects — AI boards now trigger all end-of-turn stat buffs: Scrappy Black-Cat, Chassis Welder, Nitrous Injector, Blizzard Generator, Tesla-Coil, Volume Knob, Hoarder Drone, Doomsday Prepper, Dahlia-Seed Cultivator, and Catalyst-Junkie
  • AI Brew system — Alchemist Brew cards now generate and auto-apply brew spells each turn. Syringe-Dart receives double brew effects. Scavenger-Medic gains +1 HP per brew. Bio-Hacker triggers +1/+1 per brew
  • AI deployment effects — Flask-Tender and Recipe-Thief generate brew spells on deploy. Toxicologist grants Poison to a friendly unit
Improved
  • AI card valuation — Scaling cards (Brew engines, end-of-turn buffers like Volume Knob, Blizzard Generator) are now prioritized during shopping

v0.24.1 March 8, 2026
Fixed
  • AI units vanishing after combat — Critical bug: AI units that died in headless combat were permanently removed from the board instead of being restored like the human player’s snapshot system. This caused AI boards to shrink every round until opponents had 0–2 cards
  • AI sell function index bug — The sell-weak-cards logic used incorrect index arithmetic after removals, potentially selling the wrong cards or crashing
Improved
  • AI upgrade timing — AI no longer upgrades workshop tier when board has fewer than 3 units and scrap is tight — prioritizes buying units first
  • AI desperate buying — When board is critically small (<4 units), AI rolls more aggressively and buys any available card to rebuild

v0.24 March 8, 2026
Fixed
  • AI stat persistence — AI cards now accumulate combat buffs between rounds, just like the human player. Previously, all AI units reset to base stats every round
Improved
  • AI board positioning — Guard units are placed at the front of the board to absorb damage; Surge units positioned for early impact
  • AI selling strategy — AI now sells weak off-faction, low-tier cards in mid-to-late game to make room for stronger options
  • AI triple detection — AI detects when buying a card completes a set of 3 and prioritizes the purchase. Triples merge into an upgraded +2/+2 version
  • AI contextual scoring — Card buying considers existing board composition for deeper faction synergy scaling, and skips weak cards when the board is strong

v0.23.1 March 8, 2026
Added
  • Version in browser tab — Browser tab now shows “Rust & Roots v0.23.1” instead of the generic Godot title
  • Changelog notification badge — A red dot appears on the Changelog nav link when a new version has been released since your last visit
Changed
  • Version label styling — Version number on the main menu is now brighter and bolder for better visibility

v0.23 March 8, 2026
Changed
  • VRAM texture compression — Enabled S3TC compression on all 194 card art images and the logo. Textures were previously stored as uncompressed pixel data in the game package
  • Excluded unused assets — Removed 27 unused sprite sheet source files from the web export, saving ~36 MB
Fixed
  • Scene parse error — Fixed a missing alpha component in a Color value that prevented the main menu from loading
  • Property shadowing bug — Renamed an internal network property that conflicted with a Godot built-in method, causing editor errors

v0.22 March 8, 2026
Added
  • Main menu online indicator — Shows “● Online as <name>” in the top-right corner when connected to the multiplayer server. Updates in real time as the WebSocket connects and authenticates
  • Main menu friends list — “Friends” button toggles a panel showing your friends with online/offline status. Auto-refreshes every 10 seconds while open
  • Main menu invite popup — Incoming friend invites now display an Accept/Decline overlay on the main menu, not just in lobbies
Fixed
  • “Friend not online” bug — Players showed as offline even when they were in the game. The WebSocket now auto-connects on startup for authenticated web users so friends can see each other immediately
  • Persistent WebSocket connection — The connection is no longer dropped when navigating between screens. Players stay visible as online across all menus
  • Lobby fast-path — Duel, Rumble, and Invite buttons now detect an existing connection and skip redundant auth, eliminating hangs

v0.21 March 7, 2026
Added
  • Public matchmaking — New “Browse Open Games” button in the 1v1 lobby lets players find and join public rooms without needing a room code or friend invite
  • Public lobby toggle — Room creators can toggle their lobby between public and private visibility. Public rooms appear in the Browse Open Games list for all players
  • Match list panel — Right-side panel in the lobby shows available public games with room code, creator name, and player count. Includes refresh button and auto-styling matching the friends panel
Changed
  • 7-card hand limit — Hand size reduced from 10 to 7. Cards generated beyond the limit (brews, tow-truck, Hostile Takeover discovers) are now discarded. All hardcoded limits updated to use MAX_HAND_SIZE constant
  • Friend invite always available — Invite button now shows for all friends when you’re in a room, regardless of their online status. Previously required the friend to be actively connected to Online Mode
  • Online status clarity — Friends list now shows “In Game” label next to the green dot for WebSocket-connected friends, making it clear the indicator means they’re in Online Mode specifically
Fixed
  • Card browser broken images — Card art on the website (cards page, compendium, card links) now loads correctly. Deploy script copies card art from assets/art/cards/ into site/art/
  • Compendium auth for Discord users — Discord-authenticated users can now edit card statuses and notes on the compendium page. Auth was reading from localStorage (never set) instead of the cookie token and window.rnrNavUser set by nav-auth

v0.20 March 6, 2026
Changed
  • God Object refactor — Split game_manager.gd (2,985 lines) into four focused modules using the Facade pattern. All public-facing methods remain on game_manager as thin proxies so external scripts are unchanged
  • game_manager.gd — Orchestrator + UI (1,099 lines)
  • combat_engine.gd — All combat logic, attack sequencing, deathrattles, token spawning (1,259 lines)
  • shop_manager.gd — Shop generation, rolling, freezing, selling, upgrade, round-start economy (305 lines)
  • online_bridge.gd — Multiplayer sync, lobby, networked combat (332 lines)
  • No gameplay changes — Internal architecture refactor only. All card abilities, combat, shop, and multiplayer behavior identical to v0.19

v0.19 March 6, 2026
Changed
  • Compact single-row HUD — Bottom HUD flattened from three vertically-stacked panels into one horizontal bar, freeing ~85px of vertical space for card zones. No more overlap or card clipping at 100% scale
  • Stable board layout — Card containers wrapped in plain Control nodes that break minimum-size propagation. Zones dynamically share available space and clip gracefully at higher UI scales
  • Expand stretch aspect — Uniform scaling on all screen sizes. Cards and UI remain proportional on ultrawide, 4K, and mobile displays
  • UI scale slider — New setting (60%–100%) lets players scale down the game UI for high-DPI or large screens. Capped at 100% to prevent card clipping
  • Compact HUD labels — Shorter labels (HP, R1, 3/3 Scrap) to fit the horizontal bottom bar
Added
  • In-game settings — Settings button on the bottom-left opens the full settings menu as an overlay without leaving the game
  • Floating report button — On small viewports where the sidebar is hidden, a floating action button appears for submitting playtest reports
Fixed
  • Board stretch ratio removed — All zones now equally sized for consistent card presentation

v0.18 March 6, 2026
Changed
  • Board commitment is permanent — Once a unit is deployed from hand to the board, it cannot be returned to hand. Deployment is a one-way strategic decision
  • Sell restrictions tightened — Only deployed units on the board can be sold. Cards in hand and spells cannot be sold
  • Board-wide spell casting — Non-targeted spells can now be cast by dragging from hand to anywhere on the board. Targeted spells still require dropping onto a specific unit
  • Progressive shop timer — Shop phase time scales with the game: 35s for rounds 1–2, 45s for 3–4, 55s for 5–6, etc.
  • Ready-up system — Clicking FIGHT locks you in as “READY ✓”. Once all players are ready, a 3…2…1 countdown begins before combat
Added
  • Mini music player — Compact soundtrack player in the site nav bar on all pages except Play and Music. Persistent playback across page navigations
Fixed
  • Web loading splash screen — Loading image now displays correctly during download
  • Evolution Serum brew — Now correctly transforms units into the next tier instead of random tiers
  • Permanent buffs lost on death — Mid-combat permanent buffs now persist through death
  • Freeze scrapyard pulsing — Blue pulsing animation now clears when entering combat

v0.17.2 March 5, 2026
Changed
  • Live ranked scoreboard — The top health bar now sorts dynamically by rank: 1st place (highest HP) on the far left, last place on the far right. Each panel shows its rank number (e.g. “#1 Rusty”)
  • Rank tiebreakers — Same HP? Player with more total round victories ranks higher. Still tied? Longest current win streak wins. Still tied? Same numerical rank displayed, positions arbitrary
  • Eliminated players hold rank — Once eliminated, a player’s scoreboard position is locked. Alive players continue to re-sort each round
  • Win tracking — Players now track total round victories and current win streak for scoreboard tiebreaking
  • Enhanced tooltips — Hovering a scoreboard panel shows ordinal rank, total wins, current streak, last 3 results, and elimination status
Fixed
  • Surge-killed units permanently lost — Units killed by enemy Surge abilities at the start of combat were permanently destroyed instead of being restored next round. The board snapshot was being taken after surge deaths were removed. Now snapshots before surges, preserving all units

v0.17.1 March 5, 2026
Changed
  • Sell zone repositioned — Moved the sell zone out of the bottom HUD and anchored it to the right side of the screen, vertically centered. Much easier to spot and reach when selling cards
  • EconomyPanel reordered — Health and Round labels now sit at the bottom of the right-side HUD, directly above Scrap count and Roll/Freeze buttons

v0.17 March 5, 2026
Added
  • 20 AI characters — Named opponents with unique titles and personalities: Rusty, Magnolia, Fernwood, Tinkerbelle, Voltaire, Professor Vex, Shiverfang, Queenie, Bassline, Cinder, Willowshade, Gravelmouth, Lucky Seven, Permafrost, Bonesaw, Harmonica, Rotgut, Monocle, Edison, Bramblewood
  • AI personality system — Each character has aggression, upgrade priority, roll willingness, synergy weight, and preferred factions that shape their shop and combat decisions
  • Rumble Lobby — New pre-game lobby showing 8 player slots (human + 7 randomly assigned AI characters with names and titles)
  • Invite Friend button — Connects to the server, creates a room, and opens a friends panel where you can invite online friends to your game
  • Friends panel in lobby — Right-side panel with add friend input, online status indicators, invite buttons, and incoming friend request handling
  • Online/solo dual mode — Lobby supports both solo play (click Start immediately) and online multiplayer (Invite Friend → friends join → Start when ready). AI fills remaining slots in both modes
  • Dynamic slot updates — When friends join online, they replace AI slots in real-time with a [P] tag; when they leave, AI refills the empty slot
  • Falling ember particles — 80 bright warm-orange falling ember particles on the main menu, replacing the old parallax drift
  • Discord auth required — No more guest players. Discord login is required to play; main menu shows a login prompt if not authenticated
  • Discord name everywhere — Player’s Discord display name replaces “You” throughout the game (standings, toasts, game-over screens)
  • Scalable multiplayer — Server now supports 1–8 human players per Rumble room, with AI filling remaining slots to 8
  • Party leader system — Room creator (party leader) controls when to start the game via a new start_game message
  • Public/private lobbies — Rooms can be set to public (visible in lobby browser) or private (invite/code only). Creator toggles visibility
  • Ghost matches — When odd players remain, lowest-HP alive player fights the highest-ranked dead player’s last deployed board instead of getting a free bye
Changed
  • Main menu buttons — Reordered to Rumble, Duel, Creative Mode, Settings, Quit. “Start Run” renamed to “Rumble”, “Online” replaced by “Duel” (inline WS connect)
  • AI names synced — Server and client now share the same 20-character name pool (no more hyphenated names)
  • AI decision logic — Upgrade thresholds, reroll triggers, and card scoring now factor in each AI’s personality parameters
  • Lobby button layout — Three buttons: Back, Invite Friend, Start. Invite Friend is hidden in local/unauthenticated builds
Fixed
  • Empty board round 1 glitch — Fixed a bug where having zero cards on the board when the timer expired would prevent combat from ever starting. Empty boards now correctly auto-lose
  • Workshop buttons hidden by battle log — Upgrade and Menu buttons on the left side of the scrapyard were too high up, overlapping with the combat log. Aligned them to the bottom of the HUD to match the Reroll/Freeze buttons on the right side

v0.15.1 March 4, 2026
Changed
  • Sell zone relocated — Moved ScrapHeap above ScrapCount in the EconomyPanel, tripled height (32→96px), bumped font to 13pt with “SELL (+1 Scrap)” label
  • Attacker highlight — Brief warm-yellow glow (0.12s) on the attacking unit before lunge, so players can see who is about to attack
Fixed
  • Triple damage numbers — Removed duplicate _spawn_floating_text calls that overlapped with damage_number.tscn system. Hits now show one damage number instead of three
  • Upper-left combat artifacts — Fixed 1-frame flicker when reparenting cards for attack/death animations by setting position before add_child()
  • Combat overlay centering — VS and Victory/Defeat overlays now use explicit positioning instead of unreliable anchor presets. Text reliably centers on screen
  • Main menu button overlap — Button entrance animation changed from position tween (conflicted with VBoxContainer) to scale+alpha tween

v0.15 March 4, 2026
Added — Visual Polish Pass
  • Fade-to-black scene transitions — New SceneTransition autoload. Every scene change fades through black (0.3s each way) with input blocking
  • Hit impact effects — White flash on attacker & target, screen shake, and micro-knockback on every attack
  • Card damage flash — Cards flash red with micro-shake when taking damage
  • VS Opponent Intro — “VS OpponentName” overlay with HP comparison before each combat round
  • Combat Result Overlay — VICTORY (gold) / DEFEAT (red) / DRAW (gray) with damage summary after combat
  • Round Number Banner — Round number slides down at start of each shop phase
  • Surge visual — Units glow and show “SURGE” floating text before executing surge abilities
Added — Faction-Themed Death Animations
  • All factions — Units shake, flash faction color, shrink, and fade instead of vanishing. Each faction has unique particle effects:
  • Ferals — Red-orange rapid particle burst with upward bias
  • Rigs — Gray elongated spark rectangles
  • Blooms — Green spore particles floating slowly upward
  • Syndicate — Gold coin particles falling with bounce
  • Amplifiers — Blue ring expansion + scattered particles
  • Glaciers — Cyan ice shards tumbling with rotation
  • Swarm — Purple splatter particles that shrink
  • Volts — Fast yellow burst particles + central flash
  • Alchemists — Magenta smoke puffs expanding upward
  • Neutral — Gentle taupe fade particles
Added — Transitions & Economy
  • Phase transition fades — Shop/combat zone swaps now fade smoothly (0.2s out, 0.3s in) instead of hard-cutting
  • Scrap feedback — Label punch + floating red/green text on spend/gain
  • Health low-HP pulse — Health label pulses red when HP ≤ 10
  • Sell animation — Sold cards shrink + fade out instead of vanishing
  • Workshop upgrade — Golden flash, “Level Up!” floating text, tier label punch
  • Shop refresh stagger — New shop cards fade in with staggered 50ms delay
  • Token spawn animation — Tokens scale from 0 → 1.1 → 1.0 with faction-colored flash
Added — Card & UI Polish
  • Rich drag preview — Dragged cards show a full card duplicate at 85% opacity instead of a blank rectangle
  • Drop zone highlights — Board and hand glow green when a valid card hovers over them
  • Card placement bounce — Dropped cards bounce into place (80% → 105% → 100%)
  • 4-state stat coloring — Cyan (aura), green (permanent buff), red (debuff), gold/base colors on attack/health labels
  • Stat label punch — Attack/health labels bounce on value change
  • Floating buff text — “+N/+N” green text above cards when buffed
  • Keyword tooltip descriptions — 16 gameplay keywords now show full explanations in tooltips
Added — Menu & Audio
  • Game Over animation — Overlay fades in with title scale-bounce. Victory = gold, Defeat = red
  • Main menu entrance — Logo fade-in, staggered button cascade, dark-amber button styling, subtle background drift
  • Music crossfadefade_to() and fade_out() for smooth music transitions
Fixed — Bug Fixes
  • Freeze tween memory leak — Shop freeze tweens were never killed on unfreeze, causing growing memory usage. Now properly tracked and cleaned up
  • Spell tooltip hardcoded cost — Always showed “3 Scrap” regardless of actual cost. Now reads card cost dynamically
  • unit_purchased signal — Was defined but never emitted. Now fires after successful purchase

v0.14.2 March 4, 2026
Changed — Shop Timer on Fight Button
  • Timer moved to Fight button — Shop countdown now displays directly on the green FIGHT button instead of a floating label. Shows FIGHT! 0:40 with live countdown
  • Urgent pulse at ≤5 seconds — Button background pulses bright red, text flashes with «⚠» markers, and button physically scales up/down to demand attention
  • Warning state at ≤10 seconds — Button transitions to orange warning styling before the urgent pulse kicks in
  • Default timer increased — Shop timer default changed from 30s → 40s for all game modes (single-player and online). Configurable in Settings
  • Version label — Main menu updated from v0.14.1 to v0.14.2

v0.14.1 March 4, 2026
Added — Settings Page
  • Settings menu — New main menu screen with Master/Music/SFX volume sliders, Screen Shake toggle, Fullscreen toggle, Shop Timer duration (15–60s), and Battle Speed (0.5×–3.0×)
  • Shop timer (single-player) — 30-second countdown now runs in offline mode too (was online-only). Duration configurable in Settings. Auto-fights when timer expires
  • Battle Speed setting — Scales all combat animation timings from 0.5× (slow) to 3.0× (fast). Affects attack tweens, post-surge delays, status pauses, and between-attack waits
Fixed — Bug Fixes
  • Free spell exploit — Spells could be purchased for free by dragging directly from the shop onto a deployed unit, bypassing the hand/purchase step. Now only accepts spells already in the hand
  • Damage popup overlap — Floating damage numbers stacked on top of each other when multiple hits landed. Added random offset scatter for readability
  • Headless return type_do_attack() in headless_combat.gd returned bare null on Parasite-Wasp pre-kill path. Now returns proper Dictionary to match function signature
Changed — Combat & UI Polish
  • Smooth attack animations — Replaced jittery single-step tween with 4-phase sequence: lunge → impact pause → damage dealt → return. Creates “felt impact” feel
  • Combat log sizing — Panel width reduced from 248px → 200px, font sizes from 15px/14px → 12px
  • Hatch card text — Removed “(When summoned)” parenthetical from all 5 Hatch cards. Now reads simply “Hatch:”
  • Version label — Main menu updated from v0.14 to v0.14.1
Fixed — Play Page
  • Notepad sidebar restored — Play page wrapper was accidentally overwritten by raw Godot export HTML during v0.14 deploy. Restored custom wrapper with auth gate, game canvas, notepad sidebar, auto-save, and tracker submit

v0.14 March 4, 2026
Fixed — Combat Trigger Bugs + Engine Parity
  • Reactive trigger fixes (2 high-severity)
  • Wasteland Grizzly feral_010 — Only triggered as defender. Now also triggers when Grizzly attacks and takes counter-damage. Also fixed false trigger on 0 damage (e.g., 0-attack unit). Logs board-full warning if no space for Cub
  • Scrap-Yard Raccoon feral_002 — Only triggered as defender. Now also triggers when Raccoon attacks and takes counter-damage. Removed incorrect survival check (Raccoon can buff allies even if it dies). Added 0-damage guard
  • Headless combat v0.12 desyncs (4 cards)
  • Carrion Vulture feral_006 — Headless/JS engines still used pre-v0.12 trigger (Feral death OR Last Stand). Fixed to Last Stand only
  • Ammo Scavenger neutral_008 — Headless/JS engines still used pre-v0.12 logic (+2/+2 when kills attacker). Fixed to +1 Atk (this combat) when any friendly kills
  • Fused-Wire volt_002 — Headless/JS engines still chained full attack damage. Fixed to 1 damage
  • Barbed-Wire Wall neutral_010 — Headless/JS engines still dealt 1 thorn damage. Fixed to 2
  • Spell system fixes
  • Spell cost display — All spells showed “3 Scrap” regardless of actual cost. Now displays real DB cost (e.g., Black Market Deal shows “Free”)
  • Hostile Takeover spell_009 — Discount mechanic was never implemented. Now costs 1 less Scrap for each friendly unit on your board
  • Snapshot safety
  • Deep copyget_combat_snapshot() now uses .duplicate(true) (deep copy) to prevent shared reference corruption between rounds. Adds diagnostic logging for save/restore unit counts
Changed — Combat Log Overhaul
  • Verbosity improvements
  • All reactive buff messages now indicate duration: “permanently!” for base-stat buffs, “(this combat)” for temp buffs
  • Board state logged at start of each shop phase
  • Board state logged at start of each combat round (both sides)
  • Silent failures logged (e.g., “Wasteland Grizzly roars! Board full — no space for Cub”)
  • Snapshot save/restore counts logged for debugging card disappearances
  • Panel sizing
  • Combat log panel width reduced from 310px → 248px
  • Font size reduced from 16px → 15px
  • Added [Board] color tag (dim blue) to colorizer
  • Version
  • Main menu updated from v0.13 to v0.14
Changed — Card Text Standardization (20 cards)
  • Duration text — Standardized “for the remainder of combat” → “for this combat” (2 cards): Corpse-Lily, Feral Pack-Leader
  • Last Stand — Renamed keyword from Deathrattle to Last Stand on all Last Stand cards (5 cards): Rabid Brood-Mother, Scourge-Beast Chimera, Fertilizer Pod, Freon-Leaker, Slot-Machine Sentry
  • Compost (When you sell a unit) — Added trigger explanation to all Compost cards (4 cards): Spore-Caster, Sun-Drenched Petal, Overgrown Oak, The World-Tree Sprout
  • Hatch (When summoned) — Added trigger explanation to all Hatch cards (5 cards): Roach-Scuttler, Larva-Launcher, Brood-Tender, Hive-Mind Beetle, Apex-Swarm
  • Deployment — Removed “(Battlecry)” from 3 cards to match the other 18 Deployment cards
  • Penalty Box spell_010 — Simplified text to “The highest-Attack enemy sits out the next combat.”
Technical — Damage Tracking Refactor
  • game_manager.gd: Added last_atk_dmg / last_def_dmg instance variables, set during damage resolution for use in post-attack triggers
  • headless_combat.gd: _do_attack() now returns {atk_dmg, def_dmg} dictionary; _trigger_post_attack() accepts damage parameters
  • api/game-engine.js: Same refactor — doAttack() returns damage values, triggerPostAttack() receives them
  • All three engines now handle Plating absorption correctly (actual damage = 0 prevents false reactive triggers)

v0.13 March 4, 2026
Added — Online Playtest Fixes
  • 30-second shop timer (online) — Countdown at top-center during shop phase. Auto-submits board when timer expires. Color shifts from amber → orange (10s) → pulsing red (5s)
  • 3...2...1 combat countdown — After all players submit and server resolves, a 3-second countdown plays before combat visuals begin. Creates definitive round transitions
  • “Waiting for opponents...” state — After clicking FIGHT in online mode, opponent zone displays a waiting message until the server responds
Changed
  • Sell zone relocated — Scrap Heap moved from above the Salvage Yard to below the Battlefield. Creates a natural top-to-bottom flow: buy → deploy → sell
  • Sell zone label updated — Now reads “SCRAP HEAP — Drag here to sell (+1 Scrap)” for clarity
  • Standings panel height reduced — Rumble standings panel no longer overlaps the BottomHUD buttons
Fixed
  • Opponent cards invisible during online combat — Shop UI now properly hides and opponent zone shows during the waiting state. Cards no longer attack unseen enemies in the top-left corner
  • No spells in online shops — Server-side generateShop() now includes guaranteed spell slots (1–2 per shop), matching offline shop generation
  • Spell cards not rendering from server data_spawn_card_from_server_data() now detects spell card IDs and spawns them correctly using spell_scene

v0.12 March 3, 2026
Fixed — Comprehensive Card Audit (35 bugs)

Every card’s database text compared to its code implementation. All 184 units, 13 spells, and 6 tokens verified and corrected.

  • v0.11.1 Reversions (3 cards)
  • Shadow-Stalker Feline feral_007 — v0.11.1 moved to summon hook with +2/+2. Card says “Whenever a friendly Feral dies, gain +1 Attack.” Moved back to death reactions with permanent +1 Attack
  • Feral Pack-Leader feral_012 — v0.11.1 changed to permanent buff. Card says “for the remainder of combat.” Reverted to combat-only buff, now gives stats to a random friendly Feral (not self)
  • Apex Predator feral_013 — v0.11.1 changed to combat-only. Card says “permanently.” Restored to permanent +2/+2 in token spawn hook
  • Wrong Damage / Buff Values (4 cards)
  • Fused-Wire volt_002 — Chain damage was using attacker’s full attack value. Card says “deal 1 damage.” Fixed to 1
  • Subwoofer Goliath amp_013 — Shockwave was giving +1/+1 to all Amplifiers. Card says “+3/+1.” Fixed to +3/+1
  • Distortion Pedal amp_011 — Splash was dealing fixed 1 damage. Card says “half its Attack damage.” Now deals max(1, attack/2)
  • Barbed-Wire Wall neutral_010 — Was dealing 1 thorn damage via direct health subtraction. Card says “takes 2 damage.” Fixed to 2 damage via take_damage()
  • Wrong Trigger Conditions / Scope (4 cards)
  • Living Generator volt_015 — Was only triggering on its own attacks. Card says “Whenever a friendly Volt attacks.” Now triggers for any friendly Volt attack when this unit is on board
  • Ammo Scavenger neutral_008 — Was only triggering when it killed the attacker, giving +2/+2. Card says “When a friendly unit destroys an enemy, +1 Attack for this combat.” Completely rewritten
  • Carrion Vulture feral_006 — Was triggering on any Feral death OR Last Stand death. Card says “friendly unit with Last Stand dies.” Narrowed to Last Stand only
  • Bounty Hunter syndicate_007 — Could trigger unlimited times per combat. Card says “Limit once per combat.” Added per-unit tracking
  • Permanent Stat Reduction (1 card)
  • Toxic-Pollen Flower bloom_012 — Attack sap only reduced current attack (lost on restore). Card says “permanently loses 1 Attack.” Now reduces base_attack too
  • take_damage() Consistency (1 card)
  • Irradiated Porcupine feral_009 — Was using direct health subtraction. Now uses take_damage(1) so Plating, damage reduction, and death triggers fire correctly
  • Surge / Deploy Effects Not Working (5 cards)
  • Static-Spark volt_001 — Was targeting a random enemy. Card says “deal 1 damage to the enemy directly opposite.” Now targets by board index
  • Arc-Welder volt_006 — Surge set no flag; cleave never happened. Card says “gain Cleave for this combat.” Now sets cleave flag; attacks deal full damage to enemies adjacent to target
  • Scourge-Beast Chimera feral_015 — Same issue as Arc-Welder. Surge now sets cleave flag for adjacency damage
  • Sound-Wave Surfer amp_010 — Surge only printed a log message. Card says “adjacent friendly units attack a random enemy.” Now actually triggers those attacks
  • Junk-Yard Juggernaut rig_008 — Overdrive only printed a log message. Card says “deal 2 damage to a random enemy.” Now actually deals 2 damage
  • Deployment / Wager Fixes (2 cards)
  • Rigged-Dice Roller syndicate_008 — Wager coin-flip never deducted Scrap. Card says “Wager 2 Scrap.” Now deducts 2 Scrap before the flip
  • Toxicologist alch_005 — Was applying Poison to itself. Card says “give a random friendly unit Poison.” Now targets a random ally
  • Alchemist System Fixes (3 cards)
  • Grand Synthesizer alch_015 — Mega-Brew combine produced a brew with no stats. Now sums attack/health from all brews into a single Mega-Brew with combined stats
  • Plague-Doctor alch_014 — Plague damage counter accumulated but never fired. Card says “deal 2 damage per brew to random enemies at combat start.” Now deals queued plague damage
  • Chief Mechanic Marlin neutral_017 — Upgrade reward only gave 1 free roll. Card says “gain 3 free rolls.” Now grants 3
  • Combat Stat Absorption (1 card)
  • Apex-Flytrap bloom_016 — Was only absorbing attack from killed targets. Card says “absorb its Attack and Health.” Now absorbs both
  • Last Stand / Hatch Fixes (3 cards)
  • Freon-Leaker glacier_007 — Frostbite Last Stand was targeting up to 3 random enemies. Card says “adjacent enemies.” Now targets adjacent by index
  • Apex-Swarm swarm_015 — Was spawning random Swarm units. Card says “summon 2 copies of the first friendly unit that died.” Now tracks and copies first death
  • Carrion-Fly swarm_009 — Was not in token spawn hooks. Card says “+1/+1 permanently when a friendly unit Hatches.” Added to spawn hook
  • Spell Fixes (2 spells)
  • VIP Backstage Pass spell_008 — Was giving a flat +1/+1 buff. Card says “give an Amplifier Aura: adjacent units gain +1/+1.” Now grants actual Aura keyword with adjacency buff
  • Oil Spill spell_003 — 50% miss chance only applied to the first enemy that attacked. Card says “all enemies.” Each enemy now independently has a 50% miss chance on first attack

v0.11.1 March 3, 2026
Fixed
  • Permanent buffs now actually persist — Fixed snapshot timing bug: board was saved before effects fired. Affected ~25 cards across every faction
  • Snapshot now uses base stats — Prevents aura bonuses from baking into saved state
  • In-combat permanent buffs persist for survivors — Surviving units’ snapshots updated after combat
  • Surge effects corrected — Blood-Scent Tracker, Ultimate Survivor, Casino Leviathan, Cryo-Tube Sleeper, Heavyweight Draft-Pick now combat-only
v0.11.0 March 3, 2026
Added
  • Progressive Web App (PWA) — Play page now includes a web app manifest and service worker. Mobile users can install the game to their home screen for a fullscreen, no-browser-chrome experience. Manifest enforces landscape orientation and fullscreen display mode
  • Service worker caching — Game shell (HTML, JS, WASM, PCK, audio worklets, icons) is cached on first load. Network-first for game assets, API/auth/WebSocket requests bypass the cache entirely
  • Mobile play support — Play page no longer shows “Desktop Required” on small screens. Mobile devices get the game at full viewport with nav bar and sidebar hidden automatically
  • PWA install banner (Android) — Custom install banner on mobile: “It’s the only way to play on mobile”
  • iOS install instructions — iOS Safari users see a banner with “Tap Share → Add to Home Screen” instructions
  • Portrait rotation overlay — Mobile users in portrait orientation see a fullscreen overlay prompting them to rotate to landscape
  • Fullscreen button (mobile) — Fullscreen toggle on mobile screens, locks orientation to landscape via the Fullscreen API
  • Bare card name linking in combat logsscanBareNames() matches all 165+ card names by word boundary without needing [bracket] syntax. Logs page calls processCardNamesRaw() to linkify every card name in combat log detail views
Changed
  • Play page mobile layout — Below 900px: nav bar hidden, sidebar hidden, game area fills full viewport. Replaces the old “Desktop Required” notice with actual mobile gameplay
  • Tracker description rendering — Issue descriptions now show a readonly preview div with card-links + an “Edit” toggle for the textarea. Previously, the <textarea> was skipped by the card-link TreeWalker
  • card-links.js expanded — Added scanBareNames() and public processCardNamesRaw() API for bare card name matching

v0.10.0 March 3, 2026
Added
  • Full gameplay parity for online mode — Online Duel and Rumble now run through the real game manager with an is_online flag. All offline features (drag-and-drop, hand zone, freeze, roll, upgrade, combat animations, tooltips, auras) work identically online
  • Visual combat replay — Server sends opponent board data with combat results. Client plays full visual combat (surges, attacks, damage numbers, death effects). Server result is authoritative for health
  • Server shop roll & upgrade tracking — Server generates tier-filtered shops on roll request and tracks workshop level via upgrade messages
  • Rumble standings panel — Shows all 8 players with rank number, name (humans + AI), health bar or elimination status, and “YOU” indicator matched by Discord ID
  • Admin bulk close (Tracker) — Bulk edit mode with checkboxes to close multiple tracker items at once
  • Admin bulk complete (Action Items) — Same pattern for action items — select and complete in one click
  • Card-link formatting in modals — Tracker and Logs detail modals now render [Card Name] as interactive hover-popup links
Changed
  • Discord auth reworked — Replaced JWT decode with direct /api/auth/me fetch for reliable username resolution
  • Discord ID-based identification — All standings and isYou comparisons now use discord_id instead of display names
  • Rumble placement sort fixed — Eliminated players sort ascending (8th at bottom)
  • Bye rotation in Rumble — Fair bye rotation via lastByeId tracking
  • Scene routing — Online lobby navigates to main_board.tscn instead of deprecated online_game.tscn
Fixed
  • Discord username showed “Discord User” — Now fetches /api/auth/me directly for guaranteed correct display name
  • No combat visualization online — Full animated combat with opponent boards now plays every round
  • Freeze/Roll didn’t work online — Online mode uses same shop UI as offline
  • Upgrading never brought T2+ cards — Server tracks workshop level for tier-appropriate shop generation
  • Rumble placement ordering wrong — Fixed sort direction for eliminated players
  • 3-player pairing bug — Bye now rotates fairly instead of always hitting the same player
  • No card tooltips online — Online mode now uses real game scene with full tooltip support

v0.9.1 March 2, 2026
Added
  • Right-click card → Notepad — Right-clicking any card in the web build injects [Card Name] into the play page's Testing Notepad. The linked name renders as a hover-popup when submitted to the tracker
Fixed
  • Discord username showed "Discord User" — Online menu now reads the resolved username from the parent play page instead of decoding the JWT directly

v0.9.0 March 2, 2026
Added
  • Rumble In The Ruins (Online) — Full 8-player online mode: 2 humans + 6 server-controlled AI in a standard elimination lobby. Accessible from the Online menu alongside 1v1 Duel
  • Server-side AI shop logic — Complete port of AI controller to JavaScript. Server runs all 6 AI shop turns each round with faction synergy, keyword evaluation, and upgrade timing
  • Live standings panel — Sidebar showing all 8 players with rank, name, health (color-coded), and elimination placement. Updates after every round
  • Elimination toasts & game over — Notification banners on player eliminations. Final screen shows ordinal placement (1st–8th) with full standings
  • Discord friend system — Add friends by Discord username, see online/offline status, send in-game Rumble or Duel invites via WebSocket
  • Friend list in lobby — Multiplayer lobby shows friends with online status and one-click invite buttons
Changed
  • "Turf War" renamed to "Rumble In The Ruins" — Updated throughout the entire codebase: main menu, match manager, game manager, health bar, and all references
  • Multiplayer lobby supports both modes — Lobby UI dynamically adapts based on Duel vs Rumble mode selection
  • Online game manager dual-mode — Handles both 1v1 Duel and Rumble with mode-specific HUD, combat results, and game over screens
  • Server disconnect handling — Rumble keeps disconnected players in standings for proper placement tracking
Fixed
  • Rumble button showed "Coming Soon" — Online menu had hardcoded disabled state; now shows "Play Rumble" and enables on connection

v0.8.0 March 2, 2026
Added
  • Online Multiplayer (1v1 Duel) — New "Online" button on the main menu. Create or join a room with a RUST-XXXX code and play head-to-head against another player in real-time
  • Server-authoritative combat engine — Full-parity port of HeadlessCombat to JavaScript (1,100+ lines). All card abilities, keywords, surges, deathrattles, and triggers work identically on the server
  • WebSocket relay server — Room management, real-time state sync, round progression, and combat resolution handled server-side via multiplayer.js
  • Player stats tracking — Wins, losses, draws, win streaks, total rounds played, and match history stored server-side. Stats displayed on the Online menu for Discord-authenticated players
  • Stats APIGET /api/stats/:id for player stats, GET /api/stats for leaderboard, GET /api/match-history/:id for recent matches
Changed
  • Server architecture — Express API now uses http.createServer() to share the HTTP server with WebSocket connections on port 3847

v0.7.1 March 2, 2026
Added
  • Card autocomplete — Type [ in any text input on the site to get a dropdown of matching card names. Filter as you type, select with arrow keys/Enter/Tab, or click. Inserts [Card Name] which renders as a hover-popup link
  • Discord login in nav bar — Shared nav-auth.js adds a Discord login button (or user badge when logged in) to the navigation on every page. Logged-in users see avatar, name, and a dropdown with logout
  • Consistent nav bar — Activity link and badge now appear on all pages (was missing from Changelog, Logs, and Play)
Fixed
  • Compendium redesigned as checklist — Converted from card grid to checklist layout grouped by faction. Click checkbox to quick-toggle QA status. Click row to expand inline detail panel

v0.7.0 March 2, 2026
Added
  • Creative Mode — New main menu option with two sub-modes: Sandbox Board Builder and Custom Run
  • Sandbox Board Builder — Place any card from the full catalog onto player or opponent boards. Search and filter by name, faction, tier, and type. Toggle target board, press "Fight" to resolve combat instantly. Right-click cards to remove
  • Custom Run — Start a Rumble In The Ruins game with custom settings: starting health (1-100), workshop level (1-6), scrap (1-99), AI opponents (1-7), and active faction selection (3-9 factions)
Changed
  • MatchManager config supportinitialize_game() now accepts a config dictionary for custom starting values
  • MinionCard sandbox safety — Card hover/drag logic now safely handles non-game scenes
v0.6.0 March 2, 2026
Added
  • Card Compendium page — New website page for tracking QA status of every card. Status badges (Untested/Testing/Working/Broken), free-form notes per card, progress bar, filter by status/type/faction/name
  • WoW-style card linking[Card Name] text renders as styled hover-popup links across the entire site. Hover shows card art, stats, and QA status. Click navigates to the Compendium entry
  • Compendium API — Three new endpoints for card QA data. New card_status database table
v0.5.5 March 2, 2026
Added
  • Opening video splash screen — Game now boots into a splash screen that plays a video before the main menu. Click or press any key to skip
  • Title screen music — "Rust & Lanterns" plays on the main menu screen and loops continuously
  • Gameplay music rotation — 4 gameplay tracks play in shuffled order during matches, auto-advancing when each track finishes. Music stops on game over, resumes title music when returning to menu
Changed
  • Combat log readability — Log text font size increased from 14 to 16pt, panel widened from 280px to 310px for better readability at 720p
  • AI faction synergy overhaul — AI now values tier scaling, penalizes off-faction cards, considers hand units for dominant faction, and weights all 11 keyword types. AI opponents now build focused faction boards
  • Freon-Leaker targeting — glacier_007 deathrattle now targets 3 random enemies instead of always the first 3 (leftmost). Fixed in both visual and headless combat
Fixed
  • Scrap-Pit Bookie payout broken — Wager win set loan_shark_debt negative, but round-start only processed positive debt. Added elif branch to pay out bonus Scrap
  • Grasping Kudzu not removing shop unit — bloom_014 now removes the absorbed unit from the Salvage Yard after stealing its stats
  • Rescue Bot persists permanently — spell_006 Rescue Bot now tagged as temporary. Combat snapshot skips temporary units, so the bot fights once then vanishes
  • Combat log missing enemy board — Added enemy board state log message after opponent board is populated at combat start
  • Roadie-Bot missing repositioning — amp_006 now moves the buffed target adjacent to self on deploy, in addition to giving +1/+1

v0.5.4 March 2, 2026
Added
  • Drag-and-drop overhaul (BG-style) — All card interactions are now drag-and-drop only. Drag from Salvage Yard to Hand to buy, Hand to Battlefield to deploy, Battlefield to Hand to un-deploy, and Hand/Battlefield to Scrap Heap to sell
  • Scrap Heap sell zone — New dedicated sell strip above the Salvage Yard. Highlights with an orange glow when dragging a valid card over it. Shows "SELL +1 Scrap" text on hover
  • Tire Iron Thug combat damage — neutral_003 now deals 1 damage to a random enemy at combat start (both visual and headless combat)
  • Enhanced freeze visual — Frozen shop cards now pulse and display a "FROZEN" label overlay in icy blue
  • Card tooltip — Hovering a card during the shop phase shows a floating tooltip with name, stats, keywords, and full ability text at readable size
Changed
  • All click-based interactions removed — Cards no longer respond to left-click or right-click for buying, selling, or deploying. All interactions are drag-only
  • PlayerBoard deployment triggers — Dropping a card onto the Battlefield now properly calls execute_deployment() and emits unit_deployed signal
  • HandArea accepts spells — Hand zone now accepts SpellCard drops from the Salvage Yard in addition to MinionCard drops
Fixed
  • Diesel Powered Behemoth infinite plating loop — Overdrive now tracks overdrive_used flag per combat, preventing infinite Plating refresh loop
  • Units disappearing during combat — Attack tween reparents attacker to root node before animating, preventing clip_contents from hiding cards
  • Ghost cards after combat — Dead attackers no longer get orphaned. Added safety sweep in end_combat_phase
  • Card text overflow — AbilityText now has clip_text and text overrun behavior to prevent layout overflow
  • "Permanently" buffs now actually permanent — 13 cards using temp_buff() changed to buff() so stat gains survive between rounds

v0.5.3 March 1, 2026
Changed
  • Card proportions — Cards changed from 145px expand-fill to 125×165px shrink-center with tighter margins, 1px VBox spacing, 18pt stat font, and 9pt faction font

v0.5.2 February 28, 2026
Added
  • Animated status effects — Frostbite, Poison, Plating, and Camouflage now display as continuously pulsing color tints instead of static colors, making active effects immediately visible during combat
  • Shop freeze visual — Freezing the Salvage Yard tints all shop cards with a blue overlay to clearly indicate they're locked in for next turn
  • Styled buttons — All game buttons (Roll, Freeze, Upgrade, Menu, Fight, BEGIN, Return) now use dark-themed StyleBoxFlat with amber borders, hover/press states, and disabled styling. Fight button has a distinct green accent
Changed
  • Card stat bar redesigned — Faction label moved into the bottom stats bar (Attack | Faction | Health) for a clear at-a-glance layout
  • Viewport resolution reduced — Changed from 1920×1080 to 1280×720 to reduce downscaling blur in the web iframe embed
  • Fixed layout: buttons stay on screen — BottomHUD no longer uses expand-fill, so buying cards can't push buttons off-screen. All four game zones use clip_contents to stay within their allocated space
  • Cards flex to fit zones — Cards use expand-fill to stretch to their zone's height. Portrait art absorbs remaining space. Card width minimum set to 145px
  • OpponentZone hidden during shop — Opponent board is empty during shopping, so hiding it gives the remaining 3 zones ~33% more vertical space each. Shown during combat when shop/hand are hidden
  • Zone spacing tightened — VBox separation reduced from 6px to 4px, card HBox separation from 8px to 6px, zone label font to 11pt — maximizing card display area at 720p

v0.5.1 February 28, 2026
Changed
  • Spells now bought like units — Spells in the Salvage Yard are purchased via left-click for 3 Scrap (same as units), moved to hand, then dragged onto friendly units to apply. Right-click a spell in hand to sell for 1 Scrap
  • Spell drag restricted to hand — Spells can only be dragged from the hand (not from the shop). Shop interaction is click-to-buy only, matching unit behavior
  • Spell cost display — Spell cards now display "3 Scrap" as their buy cost, matching the universal card buy price
Fixed
  • Slush-Slinger Frostbite visual — glacier_001 Surge now calls update_stats_ui() after applying Frostbite, showing the icy blue tint immediately
  • All Surge status visual updates — Added update_stats_ui() calls after every Surge ability that modifies status flags: Hailstorm Caster, Ice-Age Mammoth, Scrap-Cannon Walker, EMP-Grenadier, Peacekeeper, Casino Leviathan, Jumper Cables, Golden Elixir
  • Cryo-Tube Sleeper logging — glacier_006 now logs a message when it stays dormant (no other Glacier allies on board)
  • Black Market Deal health bar — spell_001 now explicitly updates the health bar HUD after dealing self-damage
  • Blurry game screen — Play page iframe now sets exact pixel dimensions via HTML attributes, rounds to even numbers to prevent sub-pixel rendering
  • Play page nav links — Added missing Changelog and Logs links to the Play page navigation bar

v0.5.0 February 28, 2026
Added
  • Reactive combat triggers — ~50 passive card abilities now fire during combat: pre-attack, post-attack, in-attack modifiers, death reactions, Plating-lost, Frostbite-applied
  • Pre-attack triggers — Lightning-Rod (3 pre-damage), Parasite-Wasp (1 pre-damage + hatch on kill)
  • Post-attack triggers — Kinetic-Dynamo, Venus Fly-Trap, Apex-Flytrap, Fused-Wire, Subwoofer Goliath, Distortion Pedal, Living Generator, plus defender-side Raccoon/Shield/Protector/Scavenger
  • Death reactive triggers — Carrion Vulture, Shadow-Stalker, Pack-Leader, Corpse-Lily, Volt-Jumper
  • Damage modifiers — Shatter-Fist (2x vs frozen), Snow-Plow (-1 from frozen), Hive-Guard Beetle (-1 all), aura damage_reduction
  • Plating-lost triggers — Sprocket Spinner (+2 Atk), Overclocked Engine (+3/+3), Iron Colossus (all Rigs get Plating)
  • Shop-phase reactive triggers — 9 cards react to shop refresh, brew, deploy, wager, upgrade, and sell events
  • Absolute Zero — glacier_015 prevents Frostbite from clearing while alive
  • Glacier-Core Reactor — All Glaciers +2/+2 when Frostbite is applied
  • Missing abilities — glacier_006, swarm_006, syndicate_010 Surge; rig_015 Overdrive; alch_015 End-of-Turn
Changed
  • Combat timing doubled — All animation delays increased 100% for more readable battles
  • Headless combat full parity — AI-vs-AI now resolves ALL reactive triggers, damage modifiers, Absolute Zero, and Plating-lost reactions
  • Combat log fully verbose — Every trigger, modifier, and reaction emits detailed log messages
Fixed
  • Aura damage_reduction — Feedback Looper's damage reduction was set but never applied during combat; now works
  • unit_deployed signal — Now properly emitted when units move from hand to board

v0.4.1 February 28, 2026
Changed
  • Combat log overhaul — Persistent across rounds, board state snapshot at combat start showing all units with stats/tier/faction/keywords, side labels [YOUR]/[ENEMY] on attacks, damage detail, copy-to-clipboard button
  • Combat log colors — New color rules for Deploy (teal), End-of-Turn (soft green), Aura (electric blue), Wager (gold), Poison (toxic green), YOUR/ENEMY attack coloring
Fixed
  • Server crash — Fixed illegal continue statement in server.js (outside loop context)
  • Mouse click offset — Changed viewport stretch aspect from expand to keep
  • Scrap-Iron Bruiser — Added missing Overdrive keyword and case: adjacent Rigs +1 Attack on Plating break
  • Coal-Fur Prowler — Added missing Overdrive keyword and case: +1/+1 on Plating break
  • Neon-Sign Tower — Aura system referenced wrong card ID amp_008; corrected to amp_007
  • Headless Overdrive parity — Added rig_001 and feral_003 to headless combat Overdrive
  • Activity feed attribution — Backfilled empty author names in chat messages

v0.4.0 February 28, 2026
Added
  • Faction rotation system — Each game randomly selects 6 of 9 non-Neutral factions. Neutrals always included. Shop pool exclusive to active factions
  • Faction splash screen — Overlay before round 1 showing chosen factions with color-coded labels and BEGIN button
  • Deployment system — 20+ cards trigger on-place effects: stat buffs, Scrap generation, Wager coin-flips, Brew creation, unit absorption
  • Aura system — 9 Amplifier/faction aura cards with strip-recalculate-apply pattern. Sonic-Boom Titan makes all auras board-wide
  • End-of-turn triggers — 10 cards trigger effects at end of shop phase (scaling buffs, conditional bonuses, token spawning)
  • Wager mechanic — Syndicate coin-flip system with Scrap risk/reward and board-wide buff on wins
  • Poison keyword — Poison units instantly kill any target they damage (visual + headless combat)
  • Oil Spill spell — 50% chance for opponent's first attack to miss
  • Hostile Takeover spell — Auto-discovers strongest unit from top 3 in filtered pool
  • Penalty Box spell — Removes highest-attack enemy unit at combat start
  • Salvage Rights spell — Clears shop and regenerates with workshop_level + 1 tier units
  • Changelog page — Version history page added to the design hub
Changed
  • AI faction synergy — AI tracks dominant faction and weights purchases toward synergies (+3 bonus). Keyword bonuses for Guard, Surge, Plating
  • Headless combat parity — AI-vs-AI matches now resolve Overdrive, Camouflage, Poison, and 15+ card-specific Surge abilities
  • Compost buffsbloom_008, bloom_011, bloom_015 now actually apply stat buffs to other Blooms (previously only logged)
  • Overgrown Oak — Corrected ability from "Heal all friendly Blooms to full Health" to "Give all friendly Blooms +1 Attack"
Fixed
  • Rescue Bot board limit — Emergency Flare spell checks board < 7 before spawning
  • Freon-Leaker targeting — Last Stand frostbite targets first 3 enemies instead of cross-board index mismatch
  • Spell Scrap deduction — Spells now properly deduct cost from player's Scrap
  • Workshop upgrade costs — Fixed to match design doc (5/7/9/11/13)
  • Upgrade button text — Max workshop shows "MAX" instead of invalid tier
  • Combat damage cap — Damage capped at board-size * max-tier
  • Freeze + roll interaction — Frozen shop persists through rolls
  • AI upgrade cost sync — AI uses same cost table as player
  • SQL injection — Column name allowlists on all dynamic SET clauses
  • XSS — Inline onclick handlers converted to data-attribute event delegation
  • CORS — Restricted from wildcard to specific origin
  • PIN rate limiting — Auth endpoint limited to 5 attempts per minute

v0.3.0 February 27, 2026
Added
  • 8-player Rumble In The Ruins — MatchManager autoload with AI opponents, round pairings, and elimination tracking
  • Combat log — Collapsible panel with bbcode support, auto-scroll, anchored left side
  • Health bar HUD — TopHUD displays all 8 players' health with color-coded bars
  • Game-over overlay — Final stats and Return to Menu button on elimination
  • Zone wrapper UI — OpponentZone, ShopZone, BoardZone, HandZone with labeled sections
  • Web deployment — Game playable at rustandroots.io/heroes/ via iframe embed
  • Playtest notes sidebar — Notepad with auto-save, submit to tracker, sendBeacon on exit
  • AI controller — AI shopping and decision logic for computer opponents
  • Headless combat — Off-screen AI vs AI combat resolution
  • Brew system — Alchemist brew mechanic with all brew type definitions
Changed
  • Upgraded project from Godot 4.3 to Godot 4.6
  • SignalBus expanded from 14 to 19 signals
  • Autoloads expanded from 4 to 5 (added MatchManager)
  • Updated all documentation to match deployed state
Fixed
  • Combat log anchoring (stuck at top → properly positioned)
  • Salvage Yard background opacity adjusted for readability

v0.2.0 February 26, 2026
Added
  • Core game loop — Shop phase, combat phase, round progression
  • Shop system — Salvage Yard generates tier-appropriate units with 20% spell chance
  • Workshop upgrades — Leveling costs (5/7/9/11/13) and tier unlocks
  • Combat system — Board snapshot, surge phase, left-to-right attack loop, death resolution
  • Keywords — Plating, Guard, Camouflage, Frostbite, Poison, Surge, Last Stand
  • Spells — 10 of 13 spells implemented
  • Design hub website — Hub, Card Browser, Docs, Tracker, Chat (5 pages)
  • API backend — Express + SQLite with auth, rate limiting, Discord webhooks
  • Junkman Jones — AI chat assistant with tool use and conversation management

v0.1.0 February 25, 2026
Added
  • Project scaffold — Godot project with scenes, scripts, autoloads
  • Card database — 165 units, 13 spells, 6 tokens across 10 factions (JSON)
  • Card art — 189 PNGs covering all units, spells, tokens, and UI assets
  • Design documentation — 12 docs covering all game systems
Tooling pass June 9, 2026
Changed — the commission tool can finally match existing art
  • Grok reference-image generation is wired. The xAI client now uses the /images/edits endpoint, feeding the locked anchor (parent / shipped / character-portrait art) to Grok as a source image. New art is conditioned on what already exists instead of guessed from text — "another Doyle that matches the shipped Doyle" actually works now. Generations with no reference still use the text-to-image path.
  • The engine is no longer invisible. The header badge reads "xAI Grok ✓ reference-capable (edits)" when xAI is live, and every Generate sends references by default. Previously the reference data was loaded and then thrown away by the text-only generations endpoint.
  • Lock a face to a character. A 🔒 button on any attempt assigns that image as the character's locked face; Grok is then shown it as the primary reference everywhere that character appears, so the right person lands in new art. A new "🔗 Grok will be shown" panel lists the exact reference images (★ = primary) before you generate, and the result toast reports how many references were sent.
  • Stale UI copy corrected — the field hints no longer claim the API "does not accept reference images."
Notes
  • Admin tooling only — no change to any shipped Chronicles chapter. Grok supports up to 3 source images; we send the primary anchor for now (the multi-image array shape is a fast follow once verified).
Narrative pass June 5, 2026
Changed — Arc One cosmology tightened
  • The city is the world. Arc One now reads from fully inside its own cosmology — for the people who remain, there is no “before” and no “outside.” Threads that pointed past the walls have been pulled back so the edge of the world stays the edge of the story until the arc is ready to cross it.
  • The northern visitors have been held for a later arc. The two travelers who used to turn up at Doyle’s — and every reference that leaned on them across Chapters I–XI — have been lifted out of Arc One. They were arriving too early. When something steps in from outside the walls, it should land as a rupture, not a regular at the bar. That entrance is being saved.
  • What moved where. The Signal’s late-period analysis now turns inward on its own blank sectors instead of on outside arrivals; Avra’s sample rack is the patient catalogue of ordinary people, with a single vial still labeled anomalous; and the Parish’s hardest doctrine now points at the sin of believing there was ever anything to remember. Same mysteries, cleaner spine.
Notes
  • Nothing was lost, only relocated. The held material is reserved, not deleted — its voice and color stay registered in the engine, dormant, waiting for a real entrance.
Tooling pass May 29, 2026
Added — Chronicles Art Commission tool
  • Admin-only workflow surface for finalizing Chronicles art. Lives at rustandroots.dev/chronicles-art-commission.html, behind the same Omega + Supe gate as the Heroes art commission tool. Same xAI Grok Imagine integration (grok-imagine-image-pro at $0.07/img), same voting + auto-finalize pipeline, same solo-mode env flag — sibling tool, parallel API surface (/api/chronicles-art-commission/*).
  • Schema v2 registry at data/chronicles-art-commission.json — the hand-curated source of truth. Adds three concepts the Heroes registry doesn't have: characters{} (canonical descriptions for every named character that appears in art, with optional anchor attempts), scene_groups{} (a location rendered from a fixed camera, shared by multiple variants), and per-asset parent_id + mood_state + characters_present. Mood variants of the same scene/portrait inherit the parent's subject_block and the scene_group's framing, so the same room stays the same room across variants.
  • Comprehensive coverage — 77 assets across all 13 chapters (prologue + ch01–ch12). 13 mandatory (HTML-referenced but not yet shipped: ch03 doyle/kit/wren portraits, ch11 lab variants and portraits), 57 backfill (shipped on disk pre-tool — ch01–ch09 mostly), 6 planned (ch10 signal states, ch12 gin variants), 1 optional. The tool now sees the full Chronicles art state, not a slice.
  • SHIPPED-art surface — for every asset, the server checks whether final_path_relative exists on disk (io / dev / repo-site, with .jpg fallback for the ch06/ch07 mixed-extension assets) and surfaces shipped + shipped_url on the response. Tiles render the canonical image directly via nginx with a gold SHIPPED pill (no center overlay — you should SEE the art so you don't drift). The detail-view canvas does the same with a SHIPPED · filename marker.
  • “Already shipped in this chapter” reference strip in the per-asset workspace. Gold-bordered panel below the context strip showing 84-px thumbnails of every other asset in the chapter that has shipped art. Click to jump. Built so that when generating a new variant of (e.g.) Avra's lab, you see lab-default + lab-trial-administered alongside — lock palette / framing / faces before clicking Generate.
  • Server-side prompt composer stitches chapter anchor → scene_group canonical + framing → characters present descriptions → parent subject (for variants) → this asset's subject → mood callout → output spec. Per-asset Generate button uses the composed prompt by default; the textarea is editable for one-shot tweaks; ↻ Rebuild from schema discards your edits and re-pulls the composer output.
  • Confirm-before-overwriting safety — opening a shipped asset turns the Generate button gold and labels it “Generate (replaces shipped art if approved)”, with a confirm() dialog explaining the shipped path and the 2-of-2 approval step that overwrites it. Once you've finalized a tool replacement, the asset moves to DONE state and the warning goes away.
  • Dual-site finalize — every approved attempt writes to BOTH /opt/rustandroots/io/{final_path_relative} AND /opt/rustandroots/dev/{final_path_relative} so chapter HTML's relative art/chXX/*.png references resolve on both subdomains with no deploy step in between.
  • Per-chapter anchors — the first finalized asset in a chapter auto-anchors; click Set as Chapter Anchor on any other finalized asset to replace. The grid shows the anchor's 48×48 thumbnail in each chapter header (gold border).
  • Operator guide at docs/chronicles-art-commission-tool.md — setup, schema editing, SHIPPED-state semantics, FAQ.
Fixed
  • xAI generate endpoint was calling a non-existent xaiImage.generate() with the wrong arg shape — would have thrown on every gen call. Corrected to generateImage(prompt, {model}) with a transcoding pass through ensurePngBuffer() so JPEG bytes returned by Grok land on disk as real PNG.
  • deploy.sh now ships data/chronicles-art-commission.json to /opt/rustandroots/content/ alongside the Heroes equivalent. Previously the server would silently fall back to a path that didn't exist on the VPS.
Notes
  • No narrative content change. Infrastructure pass — no Chronicles semver bump. The next semver entry will be Ch12 (The Frames) when the wedding-photo-frames thread payoff lands.
  • Bulk generate intentionally omitted. Chronicles assets carry parent-continuity dependencies (a portrait-variant must match the parent's face); a loop generator would ignore that. Per-asset generation only.
v1.9.0 Latest June 3, 2026
Added
  • Chapter XII rebuilt — Under the Ground — The old Frames chapter (Gin as philosophical center, 6/6–frames capstone, “mechanism’s wallpaper” thesis) is torn out and replaced with a quieter, structurally larger chapter that ends Arc One on a cliffhanger. Four scenes: a 5–paragraph cinematic walk to the townhouse on the western edge, a long conversation with Gin in her living room (drift-cognition voice; offers tea she doesn’t have, water she does, then nothing), a descent into Eli’s basement, and Solomon Cross’s arrival. The chapter ends on Sol’s line: “Hello, Eli. Tell me about the trains.”
  • Eli enters Arc One — mid-40s, wire-rimmed glasses pushed up onto his forehead, brown cardigan, pencil behind one ear and another in his hand. Has logged underground trains for nine years (his mother doesn’t hear them). Thirty-seven notebooks of theories in the basement, eleven more buried eighteen inches under a flat stone in the yard with a potted plant his mother waters every morning. A locked 30-year-old PC he has been trying passwords on for twenty-five years. When the Chronicler offers to share the passwords, Eli says don’t faster than any of his rehearsed sentences: “The trying is part of it. The trying is most of it. If somebody walks in and hands me the answer, I won’t know who I am after.”
  • Frame 87 easter egg — if the Chronicler has examined all six seeded frames across Ch01/03/04/06/09/11, Gin offers a wooden frame off the wall (oak, hand-carved leaf motifs, hairline crack across one corner of the glass). “This one’s my favorite. I don’t know why. Here. Hold it.” From the front it is identical to the other 113. The Chronicler does not turn it over. Neither does she.
  • Ch10 signal-gives-coordinates node — the Signal’s “then disclose one thing” branch off secrets-1. Signal frames its disclosure as protective-curator (not the old “quietly amused” posture), shares the address, and notes that “most people will tell you the address is abandoned. Most people will be wrong.” This is the new Ch12 unlock gate.
  • Ch04 western-edge node — if the Chronicler has the coordinates from Signal, a new dialogue choice opens on Solomon’s return visit: “Signal gave me coordinates. An address on the western edge. Do you know it?” Sol’s clipped controlled reply (“Western edge. Pack squatters, last I heard. Why do you ask?”) branches to either a casual deflection or, if pushed, the “Has it.” one-beat internal-reaction line.
  • VOICE_STYLES: gin + eli — Gin in soft sepia Crimson Pro (#b89868); Eli in muted bone Crimson Pro with subtle letter-spacing: 0.2px for the slightly cramped feel (#9a9088). Solomon’s existing Teko gold (#c8a84a) preserved for his Ch12 lines.
  • Hub Ch12 unlock condition refactored — was “every chapter complete”; now chapter-complete: ch10 + node-visited: ch10/signal-gives-coordinates. The discovery path runs through the Signal, not through the frames thread. The 6/6 frames thread now feeds the Frame 87 examine inside Ch12; it no longer gates the chapter itself.
  • ARC_ONE_NARRATIVE.md — a ~9,500–word prose retelling of the full Arc One Chronicler-walk, written in fidelity to every deployed line. Lives at site/chronicles/ARC_ONE_NARRATIVE.md.
  • CH12_REBUILD.md + SHIP_LIST.md — design doc for the new Ch12 and a comprehensive Arc One ship list (sections A–N, items 1–66).
Changed
  • Six frame gatedDescriptions rewritten in quiet Chronicler voice — the post-Ch12 deeper text on the frame examines in Ch01 (Maren’s shelf), Ch03 (Doyle’s crooked frame), Ch04 (Solomon’s desk), Ch06 (the Cathedral vestry), Ch09 (Breck’s bent-frame straightedge), and Ch11 (Avra’s control sample) had been written in a thesis voice that invented canon — “the mechanism placed it on Day Zero,” “the image was issued, not selected,” “Frame 87’s degradation is the mechanism wearing through,” “a performance written for him by something he has never named.” All replaced with observational language that notes the pattern without naming the cause. The recognition is preserved; the speculation is removed.
  • Canon corrections in data/chronicles-art-commission.json — Solomon Cross: mid-60s → 53; Thomas Alder: 40s → 60s (with silver-grey hair and close-cropped silver-grey beard); Gin: mid-60s → 59; Eli: 33 → mid-40s.
  • physical_anchor filled on 23 characters — 5-trait comma-separated visual cues (Maren through Eli, plus the Ch05–Ch11 supporting cast). The schema v2.1 field is no longer empty; the prompt builder appends these to every generation that names the character, lifting cross-asset character likeness consistency.
  • Ch12 hub titleThe FramesUnder the Ground.
  • Solomon’s Ch04 stock-photo wall comment depoliticized — the comment block above the frame examine had a hidden thesis about “performing the part the mechanism wrote for him.” Rewritten to match the new gatedDescriptions voice.
  • Ch11 lab control-sample post-Ch12 text — reframed: the control was the thing she was studying. Eleven years inside the lock, holding the key.
Fixed
  • Commission tool auth gate no longer hangs on “Checking authentication…”site/chronicles-art-commission.html bound an addEventListener on #char-editor-overlay at script parse time, before the overlay <div> existed in the DOM. The null.addEventListener threw a TypeError, aborted the script, and bootstrap() never ran — so the page sat on its initial “Checking…” text whether the API returned 401 or 200. Listener wiring now defers to DOMContentLoaded with defensive null checks.
  • Ch02 continuity bug“Thomas has lived in four buildings in thirty years” contradicted the under-the-floor notebook (which is from his pre-Event home and would have to be the first building). Now reads: “Thomas has lived in two buildings in thirty years — the one where the notebook was found, and the one he moved into when that one wouldn’t hold weight anymore.”
  • Eli is no longer called “Dex” — the legacy Dex character in the deployed Ch12 and his stale references in design docs have been retired. Eli’s canonical_description rewritten to drop pre-Event hints and lean into the Mel-Gibson-in-Conspiracy Theory voice the chapter actually performs.
  • Thomas Alder spelling normalized — was inconsistently “Aldren” in CONTINUITY_BIBLE-driven entries; everything now matches the manuscript’s “Alder.”
v1.8.0 May 13, 2026
Added
  • Chapter XI — What She Found (Avra / The Apothecaries) — A full reimagining. The Chronicler arrives at the fourth-floor research wing, talks with Avra Lien about her eleven-year research into the memory barrier (where did the memories go, not what erased them), then watches her perform compound 311 on a consenting subject named Colm. As Colm describes a recovered sense-memory in real time — bread baking, humming in another room, blue towel, morning light, I was happy and I didn't know it was going to end — the Chronicler's notebook fills with timestamped entries on the right side of the screen.
  • The Hadestown moment — one quiet, complete beat. Colm's brow furrows. He says I… and stops. The notebook letters scramble and fade per-character, the page replaces itself with two earlier corridor notes that have nothing to do with Avra, and when the camera returns to the lab, Avra is gone. Her notebooks are gone. Her vials are gone. The frame on the workbench — the stock-couple control sample — remains. Colm sits in the chair. He doesn't remember why he is in the room. No character in the city remembers Avra. The mechanism that erased a hundred thousand minds on Day Zero is still active, still working, still reachable into the present.
  • The Chronicler is the only consciousness the mechanism cannot reach. The chapter answers what the Chronicler is in this world — not just a documentarian but an anomaly. The player is the only mind that carries Avra Lien out of the lab.
  • Unique presentation, same game — like Ch10's terminal chapter, Ch11 has a per-chapter inline UI (the trial notebook + scramble keyframes + state-purge body classes) layered on top of the shared Chronicles chrome. Three body-class phases: dialogue-phase (default, talking with Avra), trial-phase (notebook fills as Colm speaks), post-erasure (Avra and her creations purge from the scene via [data-avra="true"] hiding + lab-empty.png art swap).
  • Four examines — the notebooks (vanish in post-erasure), the sample rack (remains; Avra handled but didn't create), the refrigeration unit (borderline; vanishes with Avra's other creations), the stock-couple frame on the workbench (remains; the mechanism passes over mass-produced objects).
  • VOICE_STYLES additions — Colm joins the cast with warm parchment Crimson Pro (#b0a090). Avra's existing rose tone (#c07a8a) preserved.
  • Cross-chapter retroactive unlocks — finishing Avra's research-3 beat (the molecular-lock explanation) now retroactively unlocks the previously-orphan gates in Ch06 Dara (What if the Event is still happening?), Ch07 Nessa (An Apothecary has made a compound that thins the memory barrier), and Ch08 Issa (Avra has proof. The Event was done to us.). The gates existed; they referenced a Ch11 node that didn't exist. Now they do.
Changed
  • Manuscript canon supersession (deliberate) — The manuscript's Ch11 has Colm survive with the recovered sense-memories intact, because 311 altered his neurochemistry beyond the mechanism's reach. The new chapter supersedes that: the mechanism reaches even Colm. Protection from the mechanism is not chemical alteration — it's being the Chronicler. The Chronicler is the one mind the mechanism does not see. This is canon law going forward. The hedge (Or could not yet. Or had chosen not to. Or had not realized it needed to.) now belongs to the player, not to Colm.
  • Callis → Reade — Avra's dead mentor renamed to match the manuscript. Global rename in the chapter; design docs will follow.
Fixed
  • Three previously-broken gates in Ch06/Ch07/Ch08 now actually fire. They were gated on ch11/avra-barrier, a node that did not exist in any version of Ch11. They are now gated on ch11/research-3, which is the new chapter's framework-reveal node and exists in the dialogue tree.
Wrapper pass April 24, 2026
Changed
  • Chronicles play page no longer scrollsrustandroots.io/play/chronicles.html dropped its top title block (“THE INTERACTIVE NOVEL / Rust & Roots Chronicles / tagline”). Back and Fullscreen now live in a narrow right-side sidebar; the iframe grows to its full 16:9 aspect. The hub + chapter content fit above the fold on desktop viewports.
  • Nav parity with the rest of the site — Chronicles chapter pages now share the same cinematic nav as the landing hub and /play/* wrappers (logo mark + colored-dot game links + miniplayer + online count). The old pill-button nav is retired site-wide. Chapter layout offset updated from 56px to 72px to match the new nav height.
v1.7.1 April 22, 2026
Added
  • Chapter X (Signal) cross-chapter gating — Six new dialogue nodes wired into the Signal’s terminal, four of them as gated query options that only appear once the player has unlocked the relevant beat in another chapter. QUERY: DRIFT_NODE_INTERACTION (gated on Ch05 sevi-task-2 — Sevi reveals the tones / home is key) reveals the Signal’s DRIFT-1 through DRIFT-7 surveillance log, including DRIFT-7’s 11:43-minute listening window matching the Day 0 silence. QUERY: GOSS (gated on Ch09 breck-wrench) reveals the only flagged death in 30 years and 4,147 deaths catalogued, plus the unidentified frequency captured four seconds before the killing blow. QUERY: GROVE_ANOMALY (gated on Ch08 issa-grove-1) reveals the Grove’s 340m mycelial mat extending under the Syndicate’s commercial district and the Signal’s read of the Grove as a parallel networked intelligence. QUERY: HIVE_FREQUENCY (gated on Ch07 nessa-dissolution) reveals the 0.4 Hz harmonically rich waveform on the eastern margin matching the Signal’s own multi-node coordinated processing.
  • Two previously-broken cross-chapter gates now actually fire — Ch07’s walls deeper-examine text and Ch09’s “The Signal flagged his death. The first one it flagged.” choice were both gated on Ch10 nodes (drift-construction and signal-first-flag) that did not exist anywhere in the codebase. Both gates referenced phantom IDs and could never trigger. The new Ch10 nodes use those exact IDs, so the long-standing dead links now resolve.
  • Hub retroactive-discovery notifications for Ch10chronicles-progress.js GATED_DISCOVERIES registry gains a 'ch10' block listing the four new gated queries, so the hub flags Ch10 with a “new content available” pulse and adjusts its discovery percentage when the player completes Ch05/07/08/09 source nodes.
Changed
  • Ch10 discoverable node count rises from 39 to 45 — six new nodes (drift-construction, signal-first-flag, signal-first-flag-2, grove-anomaly, grove-anomaly-2, hive-frequency) added to discoveries.dialogueNodes. Discovery % recalculates downward on first revisit until the player works through the new branches.
v1.7.0 April 22, 2026
Added
  • Chapter IX — Iron and Teeth (Breck / The Rigs) — Full enhancement to reference quality. 52 dialogue nodes across three scenes (Rigs body shop pre-tournament, arena plaza + broken wall mid-tournament, Rigs shop post-tournament) plus cinematic intro, narrator-driven fight sequences for Breck vs Quick (Syndicate, round one) and Breck vs Ash (Pack, round two), the canonical “Good hand.” — “Good throw.” post-fight exchange, and the Tuesday-nod walk-home past Thomas’s bench.
  • Four new characters — Breck (31, Rigs first-chair, six years fighting, three as first chair), Tam (19, first tournament, bent-hook rebar), Cole (Pack scout on the broken wall), Ash (Pack first-chair warrior). Plus Quick (Syndicate first-chair) established for the round-one fight. All added to VOICE_STYLES in chronicles-effects.js.
  • Seven new art assets — Four portraits (breck, tam, cole, ash), three scenes (shop with a shop-cooling variant, plaza, broken-wall). Two faction visual languages locked in this ship: Rigs = oily charcoal drawing (Käthe Kollwitz register) — established on Hadley (Ch08) and extended to Breck, Tam, and all Rigs-primary scenes; pure greyscale with a single muted rust-ochre accent per image. Pack = weathered / distressed woodcut print (russet + black on off-white paper, heavy ink-splatter and torn-edge weathering) — iterated through multiple failure modes (too civilized refined woodcut, tribal-shaman antler stereotypes, punk-rock styling) before landing on the “feels like a survived artifact, not a crafted image” register. Reference painters: Kollwitz + Daumier (Rigs); Kirchner + Heckel + Masereel (Pack).
  • Four new cross-chapter receiver gates — Ch09 receives content from Ch01 (Maren’s Apothecary past → Breck admits Maren treated her orbital break, made her the same coffee Goss made), Ch04 (Solomon’s tournament ledger → Breck’s “the ledger is 20% of the city” reflection), Ch05 (Sevi named by Goss → Breck pauses at learning Goss named a Drift without realizing), Ch10 (Signal flagged Goss’s death → Breck: “Say it again”). Forward contributes breck-wrench to already-shipped Ch08 Hadley receiver gates on Goss and the tournament, plus a walk-home / tuesday-nod forward to Ch02 Thomas and a tool-wall examine forward to Ch12 (wedding-frame seed on the leftmost tool-rack post).
  • Two-medium scene composition rule made explicit — when factions meet in the same image, each retains its faction’s visual medium; the visible seam IS the chapter’s visual argument about boundaries. Locked in water-station.png (Ch08, Grove oil + Rigs charcoal) and extended across Ch09 in broken-wall.png (Rigs charcoal + Pack woodcut meeting at the wall itself) and plaza.png (primarily Rigs charcoal with Parish stained-glass halation accents in the crowd, Pack woodcut at the right-edge treeline).
  • CH09 development documents (site/chronicles/CH09_DIALOGUE_SCRIPT.md and site/chronicles/CH09_ART_GEN.md) — the pre-port screenplay with full dialogue/mood effects/cross-chapter gating, and the canonical art-generation reference recording faction visual canon decisions for future chapters to inherit.
Fixed
  • Pack faction visual canon corrected mid-iteration — Initial generations produced the stereotyped “tribal warrior with antler headdress and ritual bone totems” read, which we explicitly avoided. Pack now renders as weathered print-medium artifacts with restrained cultural markers (bone beads in braids, leather-and-tooth neck cords, symmetrical pigment face markings for warriors only). Explicit forbidden-list added to CONTINUITY_BIBLE.md: no antler / horn / skull-mask / totem iconography.
  • Rigs faction medium correctly identified as charcoal, not chromatic offset — a mid-session misattribution initially placed Rigs in the red-cyan chromatic-offset register. Drift owns that register via .fx-drift CSS animation. Rigs is specifically oily-charcoal / Käthe Kollwitz industrial-worker register. Canon now explicit.
Changed
  • Hub baseDiscoveries for Ch09 — Set to 56 (52 dialogue nodes + 4 examine items).
  • Breck mood arc is ready → cooling → reflective — Pre-tournament steady-functional, post-tournament body-registering-cost, late-night the-wrench-is-heavier-tonight reflective. Scene-swap engine triggers the shop-cooling.png variant when mood reaches open. The Grove’s tidal mood pattern (Ch08) becomes the Rigs’ linear arc here — Breck moves forward through her moods, she does not return to baseline.
  • Fight sequences are narrator-driven, not dialogue-tree-driven — the two tournament rounds (Breck vs Quick, Breck vs Ash) and the walk-home-past-Thomas moment are prose scenes the player reads through, not choice-interactive branches. The interaction is the conversation AROUND the fights (shop pre + broken wall mid + shop post), not the combat itself. The chapter is about the city’s most honest conversation, and that conversation is in the moments before and after the ring, not inside it.
v1.6.0 April 22, 2026
Added
  • Chapter VIII — Good Soil (Issa / The Grove) — Full enhancement to reference quality matching Ch01–07. 69 dialogue nodes across three characters (Issa, Hadley, Bramble), cinematic intro, three-scene structure (the tending section, the water station boundary, the deep-interior weekly-meal clearing) plus a terminal boundary encounter with Marsh carrying into three possible closings.
  • Three new characters — Issa (34, seventeen years in the garden, the woman the garden is still making), Hadley (Rigs mechanic, seven years of Tuesday trade, the decent-man flinch), and Bramble (the oldest Grove body still walking, twenty-five years in, speaks rarely; Bram to some of the Grove). Bramble and Hadley added to VOICE_STYLES in chronicles-effects.js; Issa was already registered from Ch07 prep.
  • Nine new art assets — Three Issa mood variants (garden-rooted/attentive/expressive tracking her opening toward the Chronicler), three scene swaps (water-station, clearing, boundary), and three portraits (issa, hadley, bramble). Visual identity: chiaroscuro botanical + expressionist distortion — Caravaggio tenebrism on the canopy, Soutine-esque flesh rendering on the darkening and root-patterning. Deliberately distinct from Ch06 Parish stained glass and Ch07 Hive Byzantine mosaic. Three sacred art languages now: Parish = light through colored glass, Hive = body tessellated into pattern, Grove = body absorbed into dark soil and emerging with green light. Fourth faction aesthetic also locked-in for future chapters: Rigs = oily charcoal drawing (Käthe Kollwitz register) with mining-headlamp iconography, established on Hadley’s portrait and the Rigs-side of the water-station scene.
  • Six new cross-chapter receiver gates — Ch08 receives content from Ch04 (Solomon’s asset-class framing → Issa on why the Grove cannot be purchased), Ch06 (Mourne’s southern-sector plan → Issa on bread-for-the-fed), Ch07 (Nessa’s dissolution → Issa’s Hive-vs-Grove distinction: mind-with-many-bodies vs body-with-many-minds), Ch09 (Breck’s wrench → Hadley on Goss and the tournament, two separate branches), and Ch11 (Avra’s compound 311 → Issa’s reflection on whether the Grove’s soil ever had the barrier). Forward contributes issa-grove-1 and issa-soil to already-shipped Ch06 and Ch07 receiver gates.
  • Scene transition engine pattern — Per-node art swaps via Chronicles.Core.on(’dialogue’) handle the three scene changes (garden ↔ water station ↔ clearing ↔ boundary). Returning to the garden re-applies Issa’s current mood variant via Chronicles.Core.getMood(’issa’), so the art always reflects the emotional state the player has earned.
  • Ch08 dialogue script (site/chronicles/CH08_DIALOGUE_SCRIPT.md) — The pre-port screenplay: full line-by-line dialogue, mood effects, gating, canonical corrections against the manuscript. Lists the baseline’s canon errors that this ship corrects.
  • Ch08 art generation prompts (site/chronicles/CH08_ART_GEN.md) — Per-asset prompts for the nine images in the baroque-expressionist mode, plus a coherence-check table ensuring the three religious-chapter art languages (Parish / Hive / Grove) stay visually distinct.
Fixed
  • Ch08 canon corrected against the manuscript — The baseline Ch08 had three material canon errors that this ship fixes: (1) Issa’s arrival was described as “poisoning from bad water and air” — the manuscript is specific that it was an infection from a cut on a piece of debris the Apothecaries couldn’t reach. (2) Issa was described as growing thorns from her forearms — the manuscript has no thorns; the darkening is on knees/shins/tops of feet and the patterning is beneath the skin of the forearms, like branched veins. (3) The baseline claimed the first Grove members were “still alive, distributed through the root network, speaking through the soil” — the manuscript does not support this immortality-as-distributed-consciousness reading. The ship rewrites those sections: the dead become soil, become fruit, become the living. That is the cycle. Nothing preserves a distributed self past death.
  • Ch08 layout pattern fixed at authoring time — Grid is 70% 30% with .narrative-panel { display: none } (the corrected pattern from the 2026-04-21 Ch06/07 hotfix), not the baseline’s 1fr 400px two-column which left no room for the art panel. .char-portrait, .msg-portrait-img, and .found-area CSS are present from the start — no need for a follow-up fix commit.
Changed
  • Mood arc is tidal, not escalating — Issa’s moods map to rooted (default, the calm that is attunement), attentive (a guest has been noted), expressive (the rare permission to speak the private things — Pell’s trace, the barrier). The chapter opens rooted, rises to attentive around the water station, returns to rooted in the clearing, and ends attentive or expressive at the boundary depending on the player’s choices. The Grove does not escalate; the garden does not permit the grievance escalation would require.
  • Hub baseDiscoveries for Ch08 — Set to 73 (69 dialogue nodes + 4 examine items). Ch05’s missing baseDiscoveries remains a separate tension; not touched in this ship.
  • Grove elder renamed Root → Bramble (Bram to some) — Post-release cleanup: a named character called “Root” inside a franchise called Rust & Roots read as a naming collision, especially since his role (the oldest Grove body who greets new arrivals at the gate with the first fruit) is load-bearing and audiences would meet him early. Renamed to Bramble — earthier, canonical to the manuscript’s “the name grew over the old one the way moss grows over stone” logic, and distinct from the franchise title. Short form Bram is used by close Grove members once the clearing has held them long enough. Cross-cutting rename applied across chronicles-effects.js VOICE_STYLES (with a manual NAME_PATTERNS regex for the “Bram” diminutive), all bramble-* dialogue nodes, scene-swap handlers, discovery arrays, portrait filename, continuity bible, and this changelog.
v1.5.0 April 21, 2026
Added
  • Chapter VII — The Hum (Nessa / The Hive) — Full enhancement. 60 dialogue nodes across two characters (Nessa, Calla), cinematic intro, nested early-Nessa flashback structure (player meets late Nessa, asking the right questions unlocks memory-layer nodes), 4 examine items, per-node art swaps via Chronicles.Core.on(\u2019dialogue\u2019) for the four scene states.
  • Byzantine mosaic visual identity — Ch07\u2019s aesthetic is deliberately distinct from every other chapter. Deep violet and amber palette, visible tesserae throughout, hexagonal negative-halo signature for Nessa (Hive-as-sacred-art-subverted), traditional gold-disc halo for Calla as the old-anchor saint, tessellated architecture and chorus staging. Chronicles now has a Parish stained-glass tradition and a Hive Byzantine-mosaic tradition — two sacred art languages for two opposite answers to the Event\u2019s wound.
  • Six new art assets — Exterior flat (October night, pavement), interior open (first weeks inside), interior full (six months in, boy in her lap), exterior spring (April morning coda), Nessa portrait, Calla portrait.
  • Calla VOICE_STYLE — Added to chronicles-effects.js with lavender-grey color tuned to sit beside Nessa\u2019s deeper violet without competing.
  • Temporal markers spread across the chapter — Explicit date-stamping (\u201Cit was the seventh night,\u201D \u201Ctwo months after the seventh night,\u201D \u201Csix months after the wind carried the hum to her\u201D) so the reader viscerally feels the six-month arc compressed into a single conversation.
  • Five new cross-chapter receiver gates — Ch07 receives content from Ch03 (Wren\u2019s attention), Ch06 (Mourne\u2019s southern-sector plan \u2014 already shipped), Ch08 (Grove mycelia context on the insects examine), Ch10 (Signal EM interference on the walls examine), Ch11 (Avra\u2019s barrier compound). Forward contributes nessa-dissolution to Ch06 and Ch10.
Changed
  • Mood semantics for Nessa invert the typical pattern — In Ch07, Nessa at \u201Cguarded\u201D means pulled back toward the hum and less present in the conversation; at \u201Copen\u201D she is permeable to the question, willing to speak about what she lost. Scene art literally draws her closer into the collective pattern as she opens up — thematically, her vulnerability tessellates her into the Hive more, not less.
v1.4.0 April 21, 2026
Added
  • Chapter VI — The Good Shepherd (Dara / The Parish) — Full enhancement matching the Ch01–05 reference quality. 65 dialogue nodes across three characters (Dara, Shepherd Mourne, Marsh), cinematic intro, mood system tracking Dara’s guardedness toward the Chronicler, stained-glass visual aesthetic, and the chapter’s emotional terminus gated behind mood progression.
  • Three new characters — Dara (27, four years in grey), Shepherd Mourne (the outreach shepherd, tall, kind-and-immovable), and Marsh (twelve, four months in, rings the bells). All three added to VOICE_STYLES in chronicles-effects.js with distinct amber-palette colors.
  • Seven new art assets — Four cathedral scenes (three Dara mood variants + bell tower for the closing beat), three character portraits. Stained-glass jewel-tone palette across all scene art; Parish-light signature carried into the portrait backgrounds to unify the chapter visually.
  • Wedding-frames thread seeded — Hidden vestry examine unlocks after Mourne appears, seeding the Ch12 frame-recognition payoff. Behind the hymnals: the first of the 114 stock-couple frames the player will encounter.
  • Cross-chapter gating web expanded — Seven forward contributions from Ch06 (unlocks in Ch05, Ch07, Ch08, Ch10, Ch11, Ch12) and six retroactive receivers into Ch06 from other chapters. Adds seven new GATED_DISCOVERIES entries.
  • Four authoritative Chronicles development documents (committed over the previous weekend) — DEVELOPMENT_PLAN.md, ENHANCEMENT_PLAYBOOK.md, CH06-12_BUILD_MAP.md, and MASTER_SUMMARY.md. Plus two decision docs: FRAME_CANON_REVIEW.md and CH11_BRIEFING.md.
Changed
  • Ch06 canon corrected against the manuscript — Shepherd Mourne is a woman (not male), Dara is four years in the Parish (not eleven), Dara is 27 (not “30s”). The baseline Ch06 had the wrong canon throughout; full prose rewrite against manuscript/chapters/The_Good_Shepherd.md.
  • Parish doctrine aligned to manuscript — The four factions “beyond saving” are Drift, Grove, Hive, and Pack. The Thaw are classified as recoverable because they carry memory fragments. The baseline had the Thaw as the Parish’s object of terror, which the manuscript contradicts.
  • Hub baseDiscoveries for Ch06 — Set to 69 (64 dialogue nodes + 5 examine items), enabling the adjusted-discovery-percentage math for retroactive unlocks to fire correctly once the chapter is complete.
v1.3.0 April 6, 2026
Added
  • Chapter V (Sevi / Drift) — Full enhancement with cinematic intro, mood system, “home is key” deep-trust branch, 9 scene art images with dialogue-triggered swaps
  • Chapter X (Signal) password system — Dual-key terminal authentication. CRT aesthetic. Custodian dialogue chain with Theory 3
  • The City Bible — Interactive admin tool (7 tabs) with 223 workshop questions for chapter development
Changed
  • Signal reclassified — Entity, not faction. Ch10 available from hub immediately
  • Goss death — Killer changed to Parish. Not malicious — the system kills, not participants
Fixed
  • Removed Unseen — All references purged from Ch04, Ch06, prologue
v1.2.0 April 5, 2026
Added
  • Chapter III — Last Call (Doyle’s Bar) — Full enhancement: 67 dialogue nodes across three characters (Doyle, Kit, Wren), mood system tracking Doyle’s trust, cinematic intro, oil painting scene art with Rembrandt chiaroscuro lighting
  • Multi-faction art rendering — Ch3 scene art renders each faction patron in their own visual style (Syndicate in noir, Drift glitching, Rigs in charcoal) coexisting in one warm candlelit room
  • Character-based scene swapping — Clicking a character switches the entire scene to their perspective (Kit’s ledger view, Wren’s moving-through-the-room view)
  • Retroactive unlock system — Completing Ch3 unlocks new dialogue in Ch1 and Ch2. Completed chapters drop from 100% and glow on the hub
  • State persistence — Visited dialogue nodes, examined items, and journal entries now restore across sessions
  • Return visit greetings — Characters remember you. Previously explored branches stay hidden; only new content appears
  • Voice styles for Kit and Wren — Auto-colored names in all text via city-effects.js
  • Hub glow indicator — Completed chapters with newly unlocked content pulse with amber border
Fixed
  • Prologue navigation arrows — Were invisible due to CSS collision with site navbar. Renamed to .prologue-nav-arrow
  • hideOnRevisit not persisting — Explored choices reappeared on page reload because visitedNodes Set was never restored from progress
v1.1.0 April 3, 2026
Added
  • Cinematic chapter intro — Entering a chapter presents dramatic paragraph-by-paragraph text over blurred scene art
  • Art-forward 2-column layout — All chapters now use 70/30 split (scene art | action panel)
  • Drift context in Ch1 intro — Four paragraphs establish Maren’s backstory and why treating a Drift is controversial
  • Hub navigation — “← Hub” button in every chapter header
  • Prologue and Ch1 music — Background tracks for prologue and Maren’s clinic
  • Prologue progress sync — Completion now saves to server via shared progress module
Changed
  • Prologue redesigned — Full-screen cinematic with city map background, speaker region highlighting, faction voice styling
  • Ch1 layout — Narrative panel removed. Scene description delivered via cinematic intro
  • Auto-convert layout — city-core.js dynamically restructures chapters to art-forward layout
v1.0.0 March 31, 2026
Added
  • Shared module architecture — 5 JS modules (city-core, city-progress, city-audio, city-effects, city-theme) replace duplicated inline code
  • Discovery-based chapter unlocking — Chapters unlock through narrative discoveries instead of linear sequence
  • Examine item gating — Items are locked until relevant dialogue reveals them
  • Discovery completion meter — Per-chapter percentage tracking displayed on hub
  • Per-chapter audio system — Background music with crossfade, moment-triggered track changes, SFX hooks
  • Speaker-specific typography — Character voices styled with distinct fonts and colors
  • Server-side progress sync — Auto-saves discoveries to server when logged in, accumulative merge across devices
  • Multi-character dialogue support — Ch03 supports three separate conversations in one chapter
Changed
  • Hub redesigned — Discovery progress bars, contextual unlock hints, v2 progress format
  • Progress data migrated — v1 (boolean) to v2 (granular discovery tracking)
Landscape pass Latest April 24, 2026
Changed
  • Title screen is now landscape — New cinematic RUNNER hero art (1260×840, baked-in “RUST & ROOTS / RUNNER” wordmark) fills the left column; mode buttons, meta shop, inbox, stats, and version all stack compactly on the right. No more vertical scrolling to reach Normal Run / Endless Run on desktop.
  • Compact right column on desktop — Above 900px viewport, the stats block collapses from a 5-row table into a single inline footer row (Runs / Best / Stash), standings hide, mode button padding tightens. All action controls sit above the fold inside the wrapper iframe.
  • Full stacked layout preserved on mobile — Below 900px viewport, the title screen falls back to the original single-column layout with the complete stats table and standings leaderboard visible.
  • Runner play page wrapper redesignedrustandroots.io/play/runner.html dropped its top title block. Back and Fullscreen moved into a narrow right-side sidebar alongside a short “Web only” PWA hint. The iframe now claims the full 16:9 aspect within the wrapper.
v0.12.1 April 16, 2026
Fixed
  • Market row layout — Tags (HOT, VICE, HOME, SCARCE/GLUT) no longer overlap the price column on high-contraband or vice commodities. Commodity names no longer wrap word-by-word when tags stack alongside them. Tags now flow to a second line inside their own column when they don't fit on one row.
  • Noise on "Not sourced" rows — The HOT and VICE badges are suppressed on commodities you can't buy at the current district and aren't carrying in cargo. A vice you can't touch doesn't warn you about heat you can't gain.
  • Heat Sink meta upgrade now actually works — The Heat Sink meta upgrade (6,000₡) claimed "all heat gains are 10% cheaper" but was never wired up. All 17 heat-gain sites (travel, contraband carry, checkpoints, vice events, quest failures, hunters, pit fights, fleeing, debt escalation, etc.) now route through a central helper and the 10% discount is properly applied. Players who bought Heat Sink are finally getting what they paid for.
Changed
  • Dead code cleanup — Removed the orphaned activity-ticker system that v0.12.0 replaced with the Intel feed. The parallel ticker array was still being populated on every significant event but never rendered — 33 call sites plus associated state, CSS, and helper code have been removed. Smaller payload, less confusion on save load.
  • Legacy stamina references removed — The stamina meter was cut in v0.11.0 but staminaRestorePerRest benefits on all 8 safehouses and "Stamina −N" text on pit-fight choices were still in the data. Cleaned up to match the current HP-only model.

v0.12.0 April 14, 2026
Changed
  • Intel feed replaces the log panel — The right panel is now a live situation feed. Entries are color-coded by type: TRADE (buys and sells), HEAT (heat events with full context), EVENT (world events that rotate each day), and untagged for ambient log entries. Newest entries at top, up to 40 entries retained.
  • Compact market rows — Commodity descriptions removed from the main market list. The market is no longer a full page of scrolling text. Hover a commodity name (desktop) or tap it (mobile) to see the description as a tooltip.
  • HUD decluttered — The scrolling headline ticker has been removed from the top bar. World events now appear in the Intel feed when a new day begins. The activity ticker strip above the market is also gone — that info flows into the feed.
  • Mobile: travel list collapses — On narrow screens the district flavor text is hidden and the travel destination list collapses behind a toggle. The market is immediately reachable without scrolling past district content.
  • Changelog consolidated — The standalone /runner/changelog.html has been removed. RUNNER version history lives in the RUNNER tab of the main changelog.
  • Version link updated — The in-game version number now links directly to the RUNNER tab of the main changelog.

v0.11.0 April 13, 2026
Added
  • Syndicate Settlement — At any Syndicate-territory district when heat exceeds 40, a new button lets you pay the Syndicate their cut. Cost scales with current heat and cash on hand (minimum 150₵). Reduces heat by 35. The proactive relief valve the heat system was always missing.
  • Clickable heat bar — Tap the Heat meter at any time to open a breakdown explaining what heat is, what raises it, and how to reduce it.
  • Downloads page — New page at downloads.html with Android APK, Windows ZIP, and PWA install guides for RUNNER, Chronicles, and Soundtrack Player. Linked from the nav bar.
Changed
  • Heat redesign — Heat no longer fires on standard profitable trades. It now comes exclusively from contraband items, dirty events, and location-based triggers. Carrying contraband into Cathedral district has a 40% chance of drawing Parish warden attention (+heat). Carrying unregistered contraband into Syndicate territory automatically draws scrutiny (+heat). Normal green-to-red arbitrage generates zero heat.
  • Stamina / Legs removed — The stamina meter has been cut entirely. It added friction without meaningful decisions. Travel, food costs, and events no longer reference it. Upgrades that mentioned stamina have been updated.
  • End screen — plain English cause trail — All cause trail entries are now written in player-facing language ("Drew Parish attention arriving with contraband. +15 heat." instead of debug strings). The log excerpt on the end screen now filters out bare buy/sell/travel lines and shows only the 4 most meaningful events.
  • Nav bar auth links fixed on all RUNNER pages — Profile, Account, and Admin dropdown links now resolve correctly when visiting any runner page. Previously they 404'd due to a missing path prefix.

v0.10.0 April 13, 2026
Added
  • Failure transparency — Heat warnings fire at 80% and 90% capacity. HP critical warning fires once when HP drops to 25 or below. Hunter pre-telegraph fires the moment a faction's standing hits −5 in Endless mode, naming the faction before they dispatch anyone.
  • Cause trail on end screen — The bust/death screen now shows a "What got you" block listing the specific events that led to the run's end: heat spikes, HP damage sources, bust trigger, hunter dispatch.
  • Run History — New "Run History" button on the main menu. Shows the last 5 completed runs as compact cards: mode, days survived, final cash, end reason, and cause trail.
  • Opening Move event — On the very first travel of any run, a three-way event fires: take a delivery job for 280₵ (no loan needed), enter a pit fight for 250₵ (HP risk), or walk on. Sets up a distinct early game before the Syndicate loan feels mandatory.
  • 8 new mid-game events — Frostline Courier (smuggling chain), Hive Whisperer (market intelligence), Injured Courier (pickup/patch), Cathedral Forgiveness (heat relief via The Parish), Pack Debt Collection (faction tension), Market Panic (cargo risk), Stranger's Offer (Endless standing reset), Greenstrip Medicine Run (healer path).
  • Brawler's Wrap upgrade (The Yards, 175₵) — Reduces fighter death risk and boosts pit fight payouts, making the fighter path competitive with early arbitrage.
  • Mercy Route upgrade (The Parish, 220₵) — One-shot bust intercept: if heat would cause a bust, heat drops to 60 and all cargo is lost instead. Run continues.

v0.9.0 April 12, 2026
Added
  • Full Locker UI — All three lockers now have deposit/withdraw modals accessible directly from the district panel (button appears only when the locker is owned). The Syndicate Vault (Gilded Row) shows stored/capacity and accepts any amount up to available cash. The Root Cellar (Greenstrip) and Cold Rooms (Frostline) move herbs/preserved between cargo and storage with cargo-space checks on withdraw.
  • Vault is now the only way to carry cash between runs — The 10% auto-carryover at run end has been removed entirely. Cash deposited into the Syndicate Vault is transferred to your stash when the run ends, regardless of how it ends (retire, timeout, bust, death). If you don't deposit, you don't keep it. The Stash Vault meta upgrade now doubles vault capacity from 3,000₡ to 6,000₡ instead of the old carryover bonus.
  • Quick Eye price trend arrows — With the Quick Eye meta upgrade purchased, each commodity row now shows a trend arrow next to the price: cheap (good buy), dear (good sell), mid-range. Based on comparing current price to the commodity's base range midpoint.
  • Five new quest chains — Triggered from fence shops or existing district interactions:
    • 🔩 The Haul (Rigs) — Sprawl fence, carrying ≥ 3 scrap iron and Rigs standing ≥ +1. Carry scrap to the Hollow, return to Sprawl. Reward: +2 Rigs, 160₡, +5 carry capacity.
    • ❄ The Cold Chain (Thaw) — Frostline fence, carrying ≥ 2 preserved and Thaw standing ≥ +1. Deliver cold rations to Cathedral, return to Frostline. Reward: +2 Thaw, 140₡, −6 heat.
    • 📣 The Amplifiers' Request (Parish) — Confessional at Cathedral, Parish standing ≥ +2. Carry a message to Hive Market, return. Reward: +2 Parish, 180₡, −10 heat.
    • 🐝 The Swarm's Three Districts (Hive) — Hivemarket fence, Hive standing ≥ +1. Three-stop route: Yards → Hollow → back to Hive Market. Reward: +2 Hive, 200₡, 2 Drift Crystal.
    • ⚗ The Formula (Alchemists) — Sprawl fence, carrying ≥ 3 antiseptics and Alchemists standing ≥ +2. Source herbs from Greenstrip (need ≥ 2 herbs on arrival), return to Sprawl. Reward: +2 Alchemists, 170₡, +3 antiseptics.
  • Four new travel events — World-building events for underserved factions: Rigs Loader Down (help shift cargo or walk past), Thaw Temperature Test (loan your box for a study, earn coin), Hive Toll (pay kids' tribute or push through), Chemical Runoff (go around or cut through Alchemist runoff).
  • Runner stats on the Profile page — Players with at least one completed run now have a Runner — City Stats panel on their public profile page. Shows lifetime stats (runs, biggest haul, deepest day, busts) and leaderboard ranks across all three modes.

v0.8.0 April 11, 2026
Added
  • Leaderboard page — New leaderboard page with three tabs: 14-Day Blitz, Endless, and Daily Challenge. Shows best run per player, sorted by score (Cash + Days × 50). Linked from the main menu footer.
  • Score submission for all modes — Every completed run (normal, endless, daily) now submits to the server. Score formula: final cash + (days survived × 50) rewards both wealth and longevity. Previously only Daily Challenge scores were recorded.
Fixed
  • PWA re-login every session — The OAuth session cookie was session-scoped (no Max-Age), forcing re-authentication every time the PWA was closed. Auth token is now also persisted to localStorage and validated by JWT expiry on return visits — no re-login required for up to 30 days.

v0.7.0 April 11, 2026
Added
  • Vice Contraband Tier (Section O) — Four new high-heat, high-margin commodities with a vice: true flag: Frostline Brew (Thaw, heat 5), Apothecary Pills (Alchemists, heat 6), Grove Smokes (Grove, heat 4), and Drift-Touched Wire (Drift, heat 8). Vice commodities are source-locked — each can only be purchased at 2 specific faction districts (e.g., Smokes only at Greenstrip & Yards). At all other districts the Buy button shows "Not sourced" and is disabled; you can only sell. Vice rows get a deep-purple VICE badge. Checkpoint events scale heat by +5 per vice unit carried (up to +30), even when bypassed with False Papers (though Papers reduce it). Arriving at the Cathedral District while carrying vice triggers an automatic +10 heat & −1 Parish standing with a slide-down warning toast.
  • Meta Shop (Section P) — A new persistent upgrade shop accessible from the main menu via a gold 🏪 Meta Shop button showing your current stash balance. Funded by stash cash — the 10% carryover from successful runs. 10 permanent upgrades that carry into every future run:
    • Passive: Extra Carry (+5 capacity, 3,500₡), Runner's Rep (+1 home faction, 4,500₡), Stash Vault (carryover 10%→20%, 8,000₡), Heat Sink (heat costs 10% less, 6,000₡), Quick Eye (price trend arrows, 2,500₡)
    • Starting Kits: Medic (2 antiseptics, 2,000₡), Runner (4 scrap iron, 1,500₡), Smoker (3 Grove Smokes, 3,000₡)
    • Stash Expansion: Cargo Stash I (10 units, 5,000₡), Cargo Stash II (25 units, 12,000₡ — requires Tier I)
    Tier-locked upgrades show a Locked status until prerequisites are met. Purchases are immediate and saved persistently.
  • Stash Cargo Expansion (Section Q) — After buying Cargo Stash I/II, successfully retiring or timing out triggers a stash deposit modal before the end screen. Player selects how many units of each carried commodity to stash (capped at tier capacity: 10 or 25). Stashed cargo appears in your next run's starting inventory. Cargo stash is consumed on use — deliberate choice each run. Daily challenge runs and failed runs (busts, deaths) bypass the modal.
  • Faction Signets (Section R) — Collectible tokens earned by completing quest chains. Stored permanently in state.stats.signets. One can be equipped per run for a passive bonus. Earned via:
    • 🐺 Pack Signet (Enforcer Trial) — Pack standing +2 at run start; pit fight payouts +50%
    • 🔑 Syndicate Signet (The Collection) — Banker grace period +2 days; start with +50₡
    • 🌿 Grove Signet (Medicine Run) — Herbs sell at +25%; herbalist prices −20%
    • Drift Signet (The Parcel, sealed ending only) — Strange events 30% chance to yield coin instead of heat
    Equip via the new 🔰 Signets button on the main menu (appears once at least one is earned). Active signet shows as a green pill in the in-run HUD top bar.
v0.6.0 April 11, 2026
Added
  • Scarcity Sweeps (Section K) — Mid-run commodity shortages and gluts that spike or crash prices in 2–4 specific districts for 2–4 days. Eight sweep types added to a new SWEEP_POOL in data.js: Fuel Drought, Harvest Glut, Coin Crackdown, Silk Drought, Crystal Freeze, Ration Surplus, Med Shortage, Scrap Glut. Every new run seeds one sweep on day 1. Each day there is a 35% chance a new sweep fires (max 2 active at once); expired sweeps are pruned at day advance. A ⚑ SCARCE (red) or ⚑ GLUT (green) badge appears on affected commodity rows. District travel buttons show a small ⚑ icon when any sweep is active there. Slide-down toast fires on each new sweep: “⚑ Fuel Drought sweeping 2 districts”.
  • Rotating District Moods (Section L) — Each district can carry a temporary mood that modifies its heat, prices, and event character. Four moods: 🔒 Crackdown (+4 heat, −10% prices), 🎉 Festival (−3 heat, +10% prices, +2 goodwill on any trade), ⚠ Tense (+2 heat), 🤝 Open (−2 heat, +5% prices). Two random districts get moods at run start (seeded for Daily Challenge so all players share the same opening). Thereafter, when moods expire a new one rolls with a 40% daily chance (max 3 active); the mood pool is weighted by the player’s current standing with that district’s faction — good standing brings festival/open moods, bad standing brings crackdown. Mood icon appears next to the district name in the travel list; a .mood-badge pill shows in the district panel when you are there. Unvisited districts hide their mood unless Whisper Network is owned.
  • Upgrade Expansion — 20 total upgrades, 16 new (Section M) — Every district now has at least 2 exclusive upgrade reasons. New upgrades by district:
    • Yards (Pack): Smuggler’s Vest (+8 cargo, heat-per-sale −1) · Combat Stims (stackable ×4: +30 stamina +20 HP on use)
    • Gilded Row (Syndicate): Scrap Car (one-use fast-travel to any district, no heat/stamina) · Burner Phone (5 tips + reveals active sweep on arrival)
    • Sprawl (Rigs): Scrap Armor (+35 max HP, +35 HP now) · Rig Contacts (Rigs price discount spreads to 2 extra districts)
    • Hive Market (Swarm): Whisper Network (all district moods always visible) · Stolen IDs (stackable ×3: absorbs 1 standing-loss per charge)
    • Greenstrip (Grove): Grove Remedy (stackable ×3: +40 HP +25 stamina on use) · Herb Pouch (herbs sell at +15% everywhere)
    • Frostline (Thaw): Thaw Coat (water −2 ₡/day, +10 HP regen/day) · Preserved Stack (stackable ×3: gain 5 preserved goods each morning)
    • Cathedral (Parish): Absolution Token (stackable ×5: clears 15 heat per use) · Blessed Canteen (food/water −3 ₡/day, +8 HP regen/day)
    • Purple Hollow (Drift): Strange Compass (next travel: zero events) · Drift Shard (stackable ×4: random boon — 50% +60–100 ₡, 50% +1 random standing)
    Consumable upgrades show a charge counter (charges/max) in the fence and can be re-bought up to their maximum. A new 🎒 Use Item button appears in the district panel whenever you have charges. Scrap Car adds a 🚗 Drive button (disabled after use).
  • Faction Quest Chains (Section N) — Four multi-step jobs that trigger from existing district interactions and reward standing + coin on completion:
    • Pack: The Enforcer Trial — Win a heavy Pit bout at Yards with Pack standing ≥ +2. An accept/decline modal fires. Accept: carry a message to Hive Market, then return to Yards. Reward: +2 Pack, +120 ₡.
    • Syndicate: The Collection — Take any Banker loan with Syndicate standing ≥ +1. A “Take a collection job” button appears in the Banker modal. Visit the Cathedral, return to Gilded Row. Reward: +2 Syndicate, +200 ₡, −8 heat; bonus at standing ≥ +4: the Banker waives a day’s interest.
    • Grove: The Medicine Run — Visit the Herbalist at Greenstrip with herbs ≥ 4 and Grove standing ≥ +2. The courier job choice appears. Deliver locked herbs to Frostline, return to Greenstrip. Reward: +2 Grove, +150 ₡, +30 HP, herb compensation.
    • Drift: The Parcel — Visit the Drift Shrine at Purple Hollow with Drift standing ≥ +1. Accept the parcel (+8 heat). Carry it to Frostline for a two-ending delivery: Deliver sealed (+3 Drift, +180 ₡) or Inspect first (−2 Drift, +15 heat, random goods).
    A 📋 N pill appears in the HUD whenever jobs are active. Clicking it opens a quest log modal with per-job step descriptions. Step advances flash a “→ QUEST” toast. Completions open a gold QUEST COMPLETE modal.
v0.5.1 April 10, 2026
Added
  • Randomized starting faction standings (Section H) — Every new run (Normal, Endless, and Daily Challenge) now opens with a small randomized opening derived from your starting district instead of the same flat zero-line. The home faction always opens at +1 to +3, two or three adjacent districts get a ±1 nudge based on a coin flip, and one to three historical rivals start at −1 to −2. A new DISTRICT_RELATIONS table in data.js drives the adjacency/rival graph: the Pack are tight with the Sprawl and the Hollow but loathe Gilded Row and the Cathedral; the Drift are at war with the Cathedral, Gilded Row, and Frostline; the Hive sits comfortably between Gilded Row and the Sprawl. Daily challenge runs roll their starting standings under the seeded RNG so every player gets the exact same opening on the same calendar day. The same-shaped opening was the #1 staleness complaint — runs should feel different from minute one now.
  • Faction standings never persist across runs anymore — Previously only Endless mode wiped lifetime standings on death; Normal and Daily Challenge runs inherited standings from the player's account-level state.stats.factionStanding, which meant a single bad run could poison the next ten openings. freshRun() now calls a new rollStartingStandings() helper for every mode that wipes the standings table to zero, then immediately re-rolls the randomized opening from above. Carryforward invariant locked in code, not just docs.
  • The Syndicate Banker (Section I) — A new district-action behind the Quiet Assayer at Gilded Row. The Banker offers three predatory loan tiers: 100 ‰ (small purse, easier to repay), 250 ‰ (working stake), and 500 ‰ (serious loan, they will not forget your face). Loans accrue interest at 25% per day, compounding, after a 2-day grace window. The full owed amount is computed on demand by a new computeDebtOwed() helper so the principal stays clean in state. A new state.run.debt field tracks { principal, takenOnDay, dueDay, faction, escalated }. Normal-mode loans are due on day 14; Endless-mode loans get a day 30 ceiling. Past due, the Banker takes a one-time +25 heat shock on the first overdue day (with a slide-down toast: "Your loan is past due. The Banker will not forget.") and then a quiet +5 heat tax every day after that, on top of the still-compounding principal. Repaying in full clears the debt and grants +5 Syndicate goodwill for paying clean.
  • Loan forgiveness for trusted runners — Reach Syndicate standing ≥ +5 and a new Loan forgiveness · available choice unlocks inside the Banker modal. Click it and the Banker tears up the ledger — the principal is wiped, no coin changes hands, but it costs you 2 Syndicate standing (he owns a piece of you now). Below +5, the same choice is visible but disabled with the prompt "need Syndicate ≥ +5" so the player can see what the path forward looks like.
  • Live debt indicator on the top HUD — A new .debt-badge chip joins the lookout badge on the right side of the top bar whenever state.run.debt is non-null. Shows the live owed amount (recomputed every render off the compounding helper) and the due day (e.g. 💰 142 ‰ owed · day 14). When the loan goes overdue the badge swaps to a red OVERDUE variant with a soft pulsing red box-shadow so the player can't miss it. Tooltip nudges the player to "visit Gilded Row to repay."
  • Daily debt tick wired into applyDayAdvance() — A new applyDebtDay() hook fires alongside applyLivingCosts() and applySafehouseDay() at every day flip. Handles the first-time overdue heat shock, the per-day heat tax thereafter, and the log/ticker/toast bookkeeping. Past-due interest still compounds because computeDebtOwed() reads the elapsed-days math directly from state.run.day instead of accruing into a stored field.
  • Every district has at least one unique reason to visit (Section J) — New actions[] field on DISTRICTS entries in data.js, rendered as new buttons under the existing fence button on the district panel using the existing .fence-btn class (no new CSS patterns). A new runDistrictAction() dispatcher in runner.js looks up the handler name and calls the matching modal. Districts that already had fences (Sprawl · Geargrinder's Yard, Hive Market · Whisper Stall) still satisfy the audit through their fence; districts that had nothing now have a destination of their own:
    • The Yards · The Pit — A bareknuckle pit fight ring run by the Pack. Choose a light bout (80 ‰ purse, 70% win, −15 stamina, 10–25 HP) or a heavy bout (200 ‰ purse, 55% win, −25 stamina, 20–50 HP). Wins grant +1 or +2 Pack standing and goodwill. Gated on stamina ≥ 15 like all fight choices.
    • Gilded Row · The Syndicate Banker — The loan modal described above.
    • Greenstrip · The Herbalist — A Grove tincture for 60 ‰: heals +30 HP, +20 stamina, +1 Grove standing, +5 Grove goodwill. The bitter green works.
    • Frostline · The Memorial Wall — A wall of frosted names. Standing in silence costs nothing but gives +2 Thaw standing and +8 goodwill, once per run (tracked by a new state.run.usedActions map). The cold counted you.
    • The Cathedral · The Confessional — Two penance tiers. Confess and pay penance for 60 ‰ drops 12 heat, +1 Parish, +4 goodwill. Light a candle for 10 ‰ drops 3 heat. Walk on if you've nothing you'd trust them with.
    • Purple Hollow · The Drift Shrine — A wire-and-bone altar in the angle of two streets that should not meet. Touch the wire for a random Drift effect — 30% gift (80–200 ‰), 25% cut (15–35 HP loss), 20% recognition (+2 Drift), 15% mark (+8 heat), 10% mercy (full stamina + 30 HP). Leave an offering for 40 ‰ is the safer path: +1 Drift standing and a 30% chance of a free informant tip.
Changed
  • Carryforward invariant: faction standings are always per-run — Standings used to feed back into the next Normal-mode run's stash bonus loop. With H/I/J locked in, every run is a clean start with the city. The 10% stash carryover (Normal mode only) still rewards good runs through coin, not relationships.
  • The Quiet Assayer at Gilded Row now has two doors — The existing fence button and the new Banker action button stack vertically on the district panel. Both reuse .fence-btn styling so the layout doesn't shift on either width.
Fixed
  • Service worker cache key bumpedCACHE_NAME in site/sw.js bumped to rnr-202604101100 so returning players get the new modals, action buttons, and HUD badge without a force-refresh.
v0.5.0 April 9, 2026
Added
  • Stamina & HP system — Two new vital meters added to the HUD next to Heat. Legs (stamina, 0–100) and Body (HP, 0–100). Travel costs 8 stamina (4 with a bicycle). Natural regen is +15 stamina / +5 HP per day advance. Exhaustion matters: below 30 stamina, vendors charge a +10% markup citywide; below 15 stamina, any event choice that reads as fight, flee, run, bolt, break, sprint, or race is greyed out with a "Too exhausted — your legs refuse" blurb. If HP hits 0 the run ends with a new YOU FELL death screen (endReason: 'starved'). Both bars are clickable — tap for a full breakdown of what drains them and how to recover.
  • Daily living costs — Every day-advance automatically pays for food (15 ‰) and water (8 ‰). Grove standing ≥ 5 drops food to 70% (10 ‰); Apothecary standing ≥ 5 drops it to 85% (13 ‰). If you can't cover the food bill you eat −20 stamina, −5 HP and a slide-down toast ("Missed a meal. Your legs know."); missed water is −10 stamina / −2 HP. Runners with too much in their satchel and not enough in their pocket now have to choose between capacity and survival.
  • Safehouses (eight, one per district) — Visit the fence in any district that has one and a new Safehouse section offers a district-flavored stash house for sale. Each has a baseCost, daily rent, a private cargo stash, a per-rest stamina/HP restore, a heat reduction on rest, and a destructibleBy faction flag for a future burn-it-down mechanic. The Yards shack is cheap (450 ‰, 18 ‰/day, 20 cargo) and Pack-destructible; the Gilded tenant room is expensive (2500 ‰, 60 ‰/day) with a daily Syndicate goodwill drip. Greenstrip's greenhouse has the best stamina regen, Frostline's boarded unit has preservedNoSpoil, the Cathedral cell has the best HP restore plus Parish goodwill drip, the Hive market room gives a 5% global vendor discount, and the Hollow room has a daily drift blessing. Owning one unlocks a Rest at … button on the district panel that advances a day without travel.
  • Lockers (three) — Long-term specialty storage attached to specific fences. The Syndicate bank deposit box in Gilded Row holds up to 3000 ‰ cash for 20 ‰/day. The Grove seed cache in Greenstrip holds 200 bundles of herbs for 8 ‰/day and requires Grove standing ≥ 3 to buy. The Thaw cold rooms slot in Frostline holds 150 tins of preserved rations for 12 ‰/day.
  • Safehouse and locker rent · grace days · foreclosure — Rent and locker fees are deducted automatically at every day-advance. Safehouses have 3 grace days before foreclosure (lock changes, cargo stash is gone, +20 heat, and if you were penniless in endless mode that's a FORECLOSED death screen with endReason: 'foreclosed'). Lockers have 2 grace days before the keeper takes what you left inside.
  • Event density overhaul — rollEventChance() — The flat 55% travel roll is gone. Early-game (day 1–7) rolls a 75% event base, mid-game (8–20) 60%, late-game (21+) 55%. Add +3% per faction at standing ≤ −5 (hostile amplifies), add +1% per heat-mid point of the destination, and hard-cap the result at 95%. Soft-force cap: if you've travelled 5 times in a row with no event, the next travel is guaranteed to fire one. state.run.travelsSinceEvent tracks the streak.
  • Recent-activity ticker — A new feed at the top of the game HUD (above the faction standings row) surfaces the 3 most recent significant events as italic chips with day tags and green/red/amber color coding. Survives renders (stored in state.run.ticker, max 6 buffered, 3 visible). The bottom log panel still exists untouched — the ticker adds, doesn't replace. Fixes the long-standing feedback that the bottom log is "too out of the way."
  • Slide-down toast — A new bigger, slower, higher-priority notification (4.2s) drops from the top of the screen for significant events. Separate from the existing flash toast, which continues to handle minor/routine UI feedback.
  • Teaching layer — first-trigger tutorials — Persistent across runs via state.stats.seenTutorials. The very first time profit→enmity drops a player's standing, a gold-trimmed "They Keep A Ledger" tutorial modal pauses the game and explains the system (what just happened, why, how to recover, and a pointer at the clickable pills). It never fires again. Subsequent drops use the ticker + slide-down toast path.
  • Clickable faction pills — breakdown modal — Every HUD faction pill is now a button. Click one to see the faction's current standing, the hidden goodwill buffer (previously undocumented to the player), any accumulated profit pressure, and a tailored list of recovery actions for that faction (buy at their home, sell native goods fair, favorable event choices). Answers the user's complaint that hidden mechanics felt opaque.
  • Clickable stamina and HP bars — Both vital bars are clickable and open a breakdown modal listing every drain (travel, fight events, starvation, dehydration, drift anomalies) and every recovery path (natural regen, safehouse rest, apothecary heal, inn bed) with exact numbers from STAMINA_CONFIG and HP_CONFIG.
  • 12 new modal events — Pasted before empty_road. Four bad, three good, three neutral, two weird.
    • Frost Delivery — A Thaw matron asks you to walk preserved rations up the canopy road. Gated on preserved ≥ 3 in Frostline. Stamina-draining.
    • Back Alley Healer — An Apothecary offers to patch you up for coin or a favor. Rare. Fires at HP ≤ 40.
    • Grave Market — Illegal Grove root-market under a bridge. Buy herbs cheap (and take a Grove standing hit) or tip off a warden (and take a small Apothecary hit).
    • Pack Initiation — A Pack lieutenant lays a blade crosswise. Run her gate for a scar and Ferals +2, or buy respect with 200 ‰. Requires Ferals standing ≥ 3 and stamina ≥ 25 for the run branch.
    • The Mirror Man — Drift cosmic-horror: a figure at the end of the alley with your face, buttoned wrong. Speak first for coin (and heat), walk through him (coin flip), or run (stamina burn).
    • Syndicate Tax — A tax collector assesses a 12% walking tariff in Gilded Row. Pay for +1 Syndicate, argue (60% it doubles), or bolt (heat spike + Syndicate −2). Fires at cash ≥ 400.
    • Parish Confession — A priest offers to halve your heat in exchange for Parish standing. Fires in Cathedral at heat ≥ 50.
    • Alley Medic — A drunk field medic offers a needle. Fires at stamina ≤ 40.
    • Runner Race — A street race, four blocks for a 150 ‰ pot. 70% win chance. Fires at stamina ≥ 70. (Throw the race for a 50 ‰ side-bet at a Ferals cost.)
    • Hive Commission — A Hive silk vendor commissions 2 spools. Payout doubles during the Moth Die-off pulse. Requires Hive standing ≥ 2.
    • Coin Trap — A Syndicate gate-trap for raw coin carriers, gated on the Coin Crackdown pulse. Stash an ingot in a gutter, pay off the "beggars," or run the gate.
    • Broken Wire Ghost — Drift visitation that asks for a drift crystal shard. Feed her for HP and heat clear, refuse with a secret for a next-district discount, or run and crack half your shards.
  • Daily Challenge — A new shared-seed mode added to the menu screen. Every UTC day has a deterministic seed (runner-YYYY-MM-DD) derived from the date; everyone starts in the same district, with the same market pulse, the same per-district price jitter, and the same initial prices. After that, player choices branch the run. Finished daily runs submit to a new server leaderboard. Click the Daily Challenge button on the menu to see today's top 10 with a Start today's challenge button. The game HUD shows a DAILY gold badge during an active daily run. Daily runs skip stash carryover so everyone starts equal.
  • Mulberry32 seeded RNG — A deterministic 32-bit PRNG is injected (via Math.random monkey-patch) for the entire lifetime of a daily challenge run. Seeded from a string hash so the same runner-2026-04-09 seed produces the same sequence on every machine. Restored to native on run end. Regular runs are unaffected.
  • Server endpoints for the daily leaderboard — New runner_daily_runs SQLite table with a unique index on (user_id, seed_id). Three new routes: GET /api/runner/daily-seed returns today's UTC seed string, POST /api/runner/daily-runs submits a finished run (auth required, keeps best score per user per day), and GET /api/runner/daily-leaderboard?limit=N&seedId=... returns the top N rows sorted by final cash then days survived.
  • New death screensYOU FELL (starved to death, empty stomach and empty lungs) and FORECLOSED (lost your safehouse with nothing else left) join the existing BUSTED / YOU DIED / HUNTED DOWN set.
Changed
  • Travel events fire much more often early game — Day 1–7 base event rate went from 55% to 75%. The bottom log used to feel dead on empty runs; it's now full on day one so you learn the rhythm of the city fast.
  • Vendors charge an exhaustion markup — Buying while stamina < 30 adds 10% to every market price. The ledger reads tired runners differently.
  • Buy and sell checks now track effective price, not base price — Refactored buy() so the stamina markup flows through the max-affordable and actual-cash-deduction math in one pass (no double-dip, no rounding bugs).
  • Faction HUD pills converted from <span> to <button> — Same visual language, hover lift, and now they open the standing breakdown modal when clicked. No regressions to the existing layout.
  • Event modal outcomes surface in the ticker — The first sentence of any modal event's outcome gets a short-form chip in the activity ticker, color-coded by the event's tone.
  • Trackprofit standing drops now also push a slide-down toast — In addition to the existing flash toast, log entry, and (new in v0.5.0) ticker chip, the diegetic "You charged X too much…" message rides in from the top of the screen as a slide-down toast.
  • Lookout intercept messaging switched from flash to ticker + toast-down — Lookout ("A whistle from the rooftops — your lookout spotted …") now surfaces in the new ticker and slide-down instead of just the small flash.
  • Stash carryover is normal-only — Daily challenge runs never carry over, so everyone starts from the exact same cash. Endless mode death still loses everything (unchanged).
  • Tutorial gating is persistent across runsstate.stats.seenTutorials is on the account-level stats object so a player only ever sees each tutorial once, not once per run.
Fixed
  • Per-run event streaks of 5+ empty travels in a row — Old flat 55% roll could hit miss-streaks of 7 or more. The new soft-force cap guarantees an event after 5 misses in a row regardless of the computed chance.
  • Hidden mechanics had no diegetic explanation on first trigger — The first-ever standing drop now pauses the game with a full tutorial modal instead of a 2-second flash toast nobody saw. Same for the first click on a faction pill or vital bar — click-to-learn is now a documented path, not a hidden discovery.
v0.4.2 April 9, 2026
Fixed
  • Pause menu was a one-way trap — The in-game Menu button opened a pause overlay that only offered Resume Run or Abandon & Start New. There was no way back to the main menu screen without dying or restarting. Added a third Back to Main Menu option that cleanly exits to the mode-select screen without losing your run progress lookup (stats persist).
  • Menu button's confirm prompt removed — Clicking Menu no longer shows a "Back to menu? Your run is saved" confirm dialog; the overlay itself provides all three clearly-labeled options.
  • "Abandon & Start New" now respects the current mode — Abandoning an Endless run and starting a new one now starts another Endless run, not a Normal one. (Previously defaulted to Normal.)
v0.4.1 April 9, 2026
Fixed
  • 401 Unauthorized errors on mail and stats endpoints — Discord-authenticated users were getting 401s on /api/runner/stats and /api/runner/mail because the Runner's fetch calls only sent Authorization: Bearer, not the X-User-Info header the main-site auth middleware requires for Discord tokens. Added an authedFetch() wrapper that fetches the current user from /api/auth/me once on boot and attaches both headers on every authenticated call.
Changed
  • Starting cash 500 ‰ → 50 ‰ — Early runs were too forgiving. With 500 ‰ you could skip the cheaper commodities entirely. 50 ‰ makes you engage with scrap iron, herbs, and the low end of the market before you can touch drift crystal.
Added
  • Version number on the menu screen — Small v0.4.1 tag at the bottom of the menu card so you always know what build you're on.
v0.4.0 April 9, 2026
Changed
  • Profit→enmity v2 — The endless-mode hostility system was redesigned around who would actually notice. Only the Syndicate tracks your citywide profits (they're literally the mint). Every other faction only reacts when you sell at gouging prices in their own district. Pressure scales with percentage markup over "fair" base price (1.2× is free, 2× hurts, 3× hurts a lot), is reduced by existing positive standing (+10 = 80% forgiveness), and is absorbed by a new hidden goodwill buffer that you build by favoring a faction (buying at their home district, favorable event choices). Selling a commodity in its own home district is now free, not enmity-inducing.
  • Standings visible, heat hidden — Travel buttons now show your current standing with each faction as a color-coded pill instead of a numeric heat cost. Heat is now rolled from a per-district heatRange and only revealed after travel, not before. Each district's mood (Quiet · Calm · Tense · Hostile · Volatile) is shown as a soft signal derived from the heat range midpoint.
  • Syndicate friendship perk — At +5 Syndicate standing or higher, the Syndicate's global profit pressure on you is halved. The accountants protect their own.
  • Standings row in the game HUD — Current non-zero standings show as compact colored pills above the game grid. You always know who's watching.
  • Diegetic enmity logs — When pressure crosses a threshold, the log entry names the specific district: "You charged The Yards too much. The Pack are starting to notice."
Added
  • Runner PWA — Runner is now a standalone Progressive Web App. Install button on the menu screen (Chrome/Edge) and iOS "Add to Home Screen" instructions. Separate manifest from the R&R play PWA — you can install Runner by itself, with its own crimson-R icon, opening straight to /runner/ in standalone mode. Web-only distribution gets a real install path.
  • Cash mail — New "Mail" button in the game HUD opens a friend picker. Pick a friend, pick an amount (50–5000 ‰), add an optional note, send it. Recipient gets an inbox item they can claim from the menu screen. Works between any two R&R-account friends.
  • Bequest on death — When you die in endless mode, the death screen now has a "Bequeath" button that lets you leave 15% of your peak cash to a friend. Your run is over, but the coin finds its way home.
  • Contracts — Endless-only "Contract" button lets you pay 100 ‰ to put heat on a friend's next travel (+15 heat, their name next to yours in the log). Default opt-in; friends can toggle off in Settings. Contracts expire in 7 days if unclaimed.
  • Runner settings — New Settings button on the menu screen with a "Accept contracts from friends" toggle. Saved to your R&R account and synced across devices.
  • Mail inbox — Menu-screen inbox button shows unclaimed mail count. Click to view all mail from friends with claim buttons.
  • Goodwill system (hidden) — Buying a commodity at its home district grants goodwill with that faction (3 per buy). Selling it fair in its home district grants 1 per unit. Favorable event choices (name-drop a Pack contact, bandage a dying Grove runner, submit to Parish inspection) grant 8–10 goodwill. Goodwill absorbs incoming profit→enmity pressure before it hits your standing. Decays 5%/day — half the rate of enmity decay.
Fixed
  • Cell-phone lore bug cleanup — The v0.3.1 Burner→Lookout rename carries through — no cell-phone references anywhere in the social mail system. Contract delivery is described as paying someone to hunt your target, not dialing anyone.
v0.3.2 April 9, 2026
Added
  • Hero art by Grok — A proper film-poster image now lives on the title screen, on the main hub (new "A Side Hustle" section), at the top of this changelog tab, as the blurred background behind the crimson YOU DIED death screen, and as the OpenGraph image when the runner URL gets shared on Discord / Twitter. Replaces the text-only Rubik Glitch title on the menu.
  • OpenGraph + Twitter social preview — Sharing /runner/ in any social app now previews with the hero image, a proper title, and a description.
Fixed
  • GitHub Actions deploy workflow no longer spams failure emails — The auto-deploy workflow was failing on every push because the DEPLOY_SSH_KEY secret was never set. Now it skips cleanly with a notice-level log instead of a hard failure. If the secret is added later, auto-deploy just starts working with no further changes.
v0.3.1 April 9, 2026
Fixed
  • Lore fix: Burner Phone → Lookout — Cell phones don't exist in the Rust & Roots universe, so the "Burner Phone" upgrade was jarringly out of place. Renamed to Lookout"A kid on a rooftop, paid to whistle if trouble's coming." Same mechanic (intercepts the next bad event), grounded in the R&R street-level vibe. Old saves migrate automatically on load.
v0.3.0 April 9, 2026
Added
  • Endless Mode — New hardcore survival mode alongside the 14-day Normal Run. No day cap, no retire button. Heat ≥ 100 means you're dead, not busted: lose everything, no stash carryover. Mode select card on the menu screen.
  • Profit → enmity — Every profitable sell in endless mode ticks up a hidden per-faction pressure meter. Cross a threshold (200‑3800 ‰) and the faction's standing drops. Pressure decays 10% per day so you can't park on one lane forever. Log entries warn you diegetically: "Word is getting around. The Pack is starting to notice your profits."
  • Hunter events — Once a faction's standing drops to −5 they start actively hunting you. Travel rolls check each hostile faction; the chance grows with run length and number of enemies. Six new hunter modals (Pack Hunters, Assayer Squad, Scrapmen, Briar Witches, Parish Enforcers, Drift Ghosts) each with three choices: Pay tribute / Fight / Flee. Fight can kill you.
  • Positive standing ceiling decay — In endless mode your best days are early. The cap on how high you can push any faction drops over time: +10 through day 14, +7 through day 28, +4 through day 42, +2 after that. You can still climb, but not as high.
  • Death screens — New crimson "YOU DIED" / "HUNTED DOWN" end screens for endless deaths, with Rubik Glitch title font, randomized flavor epitaphs, peak-cash tracking, and days-survived stats.
Changed
  • Title / nav font swap — Rock Salt → Rubik Glitch on the title screen and nav button. Dropped the gray→rust-red gradient, now solid crimson (#c0302a) for better readability at small sizes.
  • Endless mode resets faction standings — Every endless run starts with clean standings so the profit→enmity system has somewhere to fall from. Normal mode still keeps lifetime standings.
  • Weighted-average buy price trackingbuy() now tracks a running average per commodity, used by sell() to compute net gain for profit→enmity. Not visible to the player; feeds the new system.
v0.2.0 April 9, 2026
Added
  • Event choice modals — Significant travel events are now must-dismiss modal cards with 2–3 choice buttons (Slay-the-Spire style), faction-tinted border-tops, and real consequences. Six events upgraded: Pack Shakedown, Syndicate Audit, Drift Anomaly, Dying Runner, Shady Merchant, Parish Checkpoint. Minor flavor events still fire as flash toasts.
  • Diegetic fences — Three districts now have a Visit the Fence shop button: Sprawl (Geargrinder's Yard — gear), Gilded Row (The Quiet Assayer — information), Hive Market (The Whisper Stall — quick fixes). Each fence has its own themed inventory.
  • In-run upgrades (4 types): Runner's Satchel (+5 cargo, 150₡, Sprawl), Bicycle (2 travels per day, 500₡, Sprawl/Hive), Informant Network (3 price tips per run, 75% accurate, 250₡, Gilded/Hive), Lookout (a kid on a rooftop paid to whistle at trouble, 120₡, Gilded/Hive). Informant and Lookout are stackable.
  • Market pulse — Each run picks one of 6 hidden market pulses that shifts specific commodity prices the entire run (Oil Scarcity, Greenstrip Bloom, Coin Crackdown, Moth Die-off, Drift Hush, Thaw Storehouse). The pulse is never announced directly — you infer it from the daily headline.
  • Daily headlines ticker — New line in the top HUD rotates every day. Weighted 50/50 between generic city flavor and pulse-specific hints, so the headline is a diegetic clue at the hidden market mood.
  • Per-run price jitter — Every district's price modifiers are re-rolled at run start with a ±20% jitter on each entry. Greenstrip herbs are still cheap, but how cheap varies by run. The map has to be re-read every time.
Changed
  • Travel is now async — travel() pauses on modal events until the player picks. No game time advances while a modal is open.
  • Pack Shakedown and Syndicate Audit reworked — Old flash-toast versions replaced with their new modal equivalents (3 choices each).
v0.1.1 April 9, 2026
Added
  • Runner nav button — New Runner entry in the site nav bar (Dokdo font with the gray→rust-red gradient) so the game is reachable from any page.
  • Recent purchases pill bar — Top-of-market strip showing the last 1–3 buys so you're not stuck reading the trade log at the bottom to remember what you paid. Clears when you travel.
  • Sell All button — One-click sell-everything button next to the existing Sell button on each commodity row.
  • Boot overlay on the Play page — Runner now overlays the Godot iframe on /play/ while the engine loads. Auto-dismisses on a godot-ready postMessage (reserved for a future Godot bridge), 10 seconds after iframe load, or via a manual Minimize × button.
Fixed
  • Nav links from inside /runner/nav.js was not treating the runner directory as a subdirectory, so Chronicles / Play / etc. resolved relative to /runner/ and 404'd. Fixed the isSubdir detection.
v0.1.0 April 8, 2026
Added
  • Runner prototype — Drug-Wars-style side game in the Rust & Roots universe. Standalone page at rustandroots.io/runner/. 14-day trading loop across 8 faction-themed districts, 8 commodities, 12 travel events, heat/bust system, persistent stash and faction standings.
  • Dokdo title screen — Title uses the Dokdo handwritten font with a gray→rust-red gradient, matching the brand look.
  • Server-synced lifetime stats — New runner_stats table on the API. GET/POST /api/runner/stats endpoints merge progress across devices (monotonic counters, Discord-auth'd).