Status history
Status history (moved from CLAUDE.md)
Section titled “Status history (moved from CLAUDE.md)”The dated “Current status” section of CLAUDE.md, moved verbatim on 2026-09-27 so ~40KB of build-by-build narrative stops loading into every session. Entries are as-written, so the newest status here may be stale: check memory bullet-heaven-v01-goal-run and bullet-heaven-roadmap for current state. Append new dated status entries to memory or here, not to CLAUDE.md.
Current status — v0.1 “Dark Cosmos” launch prep (BUILD 183 deployed to Apple TV + iPhone, 2026-07-23: fixed a real “crashes on launch, zero crash log” iOS deploy bug — see below — plus a 9-cycle overnight perf/code-quality loop that landed 16 small fixes)
Section titled “Current status — v0.1 “Dark Cosmos” launch prep (BUILD 183 deployed to Apple TV + iPhone, 2026-07-23: fixed a real “crashes on launch, zero crash log” iOS deploy bug — see below — plus a 9-cycle overnight perf/code-quality loop that landed 16 small fixes)”-
App Store 1.0 SUBMITTED, 2026-09-24: iOS (universal iPhone + iPad, there is no separate iPad build) and tvOS 1.0, build 22,
WAITING_FOR_REVIEW. Screenshots are locked while in review, and as of 2026-09-25 every set (iPhone, iPad, Apple TV) holds just 1 shot, by Chris’s choice (it got past the “uploads in progress” error); the full sets go in with the next release. Screenshots, status, submit and the “screenshot uploads in progress” trap: shared skillappstore-connect-release. Status: memorybullet-heaven-v01-goal-run. -
Liquid-glass UI, Plan 1 (core), 2026-09-24 — v0.1 freeze exception 4, built on branch
liquid-glass-ui(commits listed indocs/RELEASE-0.1.mdexception 4), NOT on any device yet.GlassPanel(ui/theme/, frosted = screen-read blur for paused screens only, clear = no screen read) now skins the level-up (bottom card strip + Y/Tab ship-stats sheet), theStatsSheet, and the pause menu (read-only stats). Dud crystal cards are re-rolled; no determinism re-pin. Switch:VisualLook.glass_ui/ Debug Settings “Liquid-glass UI” (pause swaps next pause, level-up swaps on the next run, sincemain._new_run()rebuilds it;LegacyLevelUpPanelis the old panel). ⚠️ Owed: the on-device ATV frame check and Chris’s before/after pick; Plan 2 (other screens, HUD docks) not started. Detail:docs/architecture/rendering-and-performance.md,docs/RELEASE-0.1.mdexception 4. -
Tutorial rebuilt as a 10-lesson track, 2026-09-24 — merged to
mainand pushed (96d8f14..ca73403), deployed to Apple TV as BUILD 191. Replaces the beat-gated Tutorial the two entries below describe: ten lessons (WAKE UP → BLASTER → LEVEL UP → SHIP STATS → RIFT BOLT → WARP → DECOY → CRYSTALS → NOVA → THE WARDEN, table insim/tutorial_lessons.gd), each unlocking exactly one thing, gated on its intro beat being read, not merely queued (closes the 2026-08-19 audit’s “gates open on queue” hole) — architecture:docs/architecture/meta-and-story.md§ “Tutorial lesson track”. Headline mechanics: a clear-glass objective panel (top-centre, LESSON N OF 10, glyph for the last-used input device); drawn speaker emblems + role + side (allies left, enemies right — Ash/The Null now introduce themselves reaching the Warden); the tutorial flies the starter loadout on the untouched save (no loadout writes); the Pulse gift and its encounter heals are REMOVED from the tutorial (Chris’s call — makes the Warden meaningfully harder, see Open items); lesson 4 blocks a level-up pick until the stats sheet has been opened once, with a visible nudge on a refused attempt. Also found + fixed along the way: the warp could tunnel a sealed gate in story mode (now slides along the wall instead) and a dialogue-panel-rendered-off-screen render bug.tools/story_auto/story_trace.gd --mode=tutorialnow drives every real objective (not just beats) and checks unlock order:lessons: ok, all 10 in order, 153.0s sim time (13 level-ups, 107 kills, level 14; excludes the read-freeze, not wall clock). Both determinism baselines unchanged, no re-pin (test_determinism_survival/test_determinism_coop— the lesson track is gated onsim.tutorial != null, tutorial-only). GUT 273/273 scripts green, 0 failing; soak clean;ui-sweepclean (all 11 baselines, including the two previously-flaky ones). ⚠️ Owed: a human playtest — Apple TV + controller, Mac keyboard AND controller (prompts must switch), iPhone touch; script indocs/RELEASE-0.1.md. The Warden is now measurably harder without the removed heals (a mortal bot dies ~4s afterwarden_intro) — that balance call is Chris’s, not a bug. -
Adversarial audit session, 2026-08-12 (2 Workflow runs, code-only — no BUILD bump) — merged to
mainand pushed. Fixed: a Master-busAudioEffectLimiter(audio/bus_layout.tres) stops concurrent-SFX clipping (verified viaffmpeg amix normalize=0that a routine combat overlap — weapon fire + hit + death + pulse — clipped flat at 0.0dB;audio_manager.gd’s round-robin pool is the same pattern~/Claude/gothtime’s SoundManager copied from, gain-staging gotcha now indocs/godot-gotchas.md); the mandatory fresh-save Tutorial’secho_giftdialogue (data/story.json) taught a “BURST”/Plasma elemental-combo mechanic archived 2026-07-09 — every player who completed the tutorial learned a fake mechanic, rewritten to match real Nova behavior; an O(W²) per-tick allocation in Wyrm chain AI (sim/enemy_behaviors.gd, commit3d40092); several stale reactions-mode-era doc/comment claims presented as current architecture (docs/architecture/content-and-elemental.md+enemies-bosses-survival.mdmarked historical,sim/elemental_system.gd/sim/elemental.gdheader comments corrected,main.gd’s twoV01_LOCK_COOPcomments corrected from a stale “P2 is P1-only” claim to the REAL remaining co-op gap — see below). Found but NOT fixed (flagged for Chris, see “Open items” below): a real balance bug —apply_element()never resetsstacks/aura_remaining, so Fire’s burn DoT and Lightning’s shock-vulnerability have dealt ZERO actual damage in live gameplay this whole time despite visibly tinting enemies (existing test coverage hand-sets state instead of exercising the real call path, masking it). Full findings + everything tracked but not yet actioned:NEXT_TASKS.md. GUT suite stayed 246/246 scripts green throughout (2329/2333 passing, same 4 pre-existing risky/pending); determinism baseline untouched (the balance bug fix above would need a deliberate re-pin once actioned). -
Tutorial stage-gating redesign shipped, 2026-08-10 — merged to
mainAND pushed toorigin/main(commits1ace99e..5a627a4), NOT yet deployed to any device (no BUILD bump this session). Makes the 2026-07-21 Tutorial onboarding below genuinely progressive: every taught system is now inert until its own dialogue beat fires, not just narrated in passing while already usable — no movement HUD beforemove_intro; Blaster granted (not pre-armed) atember_intro; manual (Rift Bolt) weapon locked untilaim_intro; dash/warp locked untilpulse_learn; HP bar + threat radar narration fire reactively the first time each would have something to show; level-up panel stays shut untillevelup_intro; decoy meter frozen at 0 untilecho_decoy;ember_e1’s arena spawns one enemy at a time; local co-op join blocked for the run; the post-Warden Dimension Choice popup is suppressed in story runs. Gate primitive:StoryState.tutorial_locked(beat_id). 12 implementation tasks, every one task-reviewed clean (fix rounds only on Tasks 8/9/12, all closed) — PLUS a final whole-branch review (dispatched on Opus) that found and fixed 2 more real cross-task issues no single task’s review could see:move_introwas missing its"tutorial": trueflag (would have leaked into ordinary Story mode), and thelevelup_introteaching line opened under the level-up modal and auto-dismissed itself unread. Full verification: GUT suite 246/246 scripts green (2333 tests, 2329 passing, 4 pre-existing unrelated risky/pending, 0 failures), test-count guard OK, both determinism baselines unchanged, headless boot smoke clean. Design/plan:docs/superpowers/specs|plans/2026-08-10-tutorial-stage-gating*; punch-list entry:docs/RELEASE-0.1.md. ⚠️ Owed: the manual Mac playtest (not automatable) — seedocs/RELEASE-0.1.md’s entry for the 8-point script. The Story Board capture bullet below is now stale re: what to capture — BUILD N+1 (whatever the next real device deploy of THIS feature becomes) is what Eve should record + capture next, per Chris’s 2026-08-10 decision; her in-flight BUILD 185 capture targeted the pre-redesign Tutorial and is superseded, not merged with it. -
Story Board tool BUILT + on main (2026-07-23) — BugSmash-style storyline/tutorial PACING review; docs
docs/architecture/dev-tools.md, full status in memorybullet-heaven-roadmap. Record a tutorial replay → windowed capture harness screenshots each dialogue beat + logssim.story.events→ pureBeatLog→tools/story_board/web tool (pin comments) →annotations.json→ Claude batch-applies. ⚠️ In-flight capture is SUPERSEDED (2026-08-10): the BUILD 185 recording build (RECORD_REPLAY on, deployed to the ATV for Eve to play) targeted the pre-stage-gating Tutorial — don’t pull/use that replay. Re-record on the next real device deploy of the tutorial-stage-gating redesign above instead.mainstays clean (RECORD_REPLAY=false). Two gotchas found + fixed getting there:DirAccess.make_dir_recursive_absolute("user://<subdir>")silently fails on tvOS (save to user:// ROOT —docs/godot-gotchas.md), and RECORD_REPLAY lost the tutorial at the survival hand-off (fixed). Pull the replay off the ATV / resettutorial_done/ confirm the running BUILD via telemetry: memorybullet-heaven-tvos-device-file-access. -
iPhone deploy crash fixed (BUILD 183, 2026-07-23) — root cause + fix now baked into
bh-deploy, read that skill’s iOS section before the next Godot version upgrade. First iPhone deploy since the 2026-07-19 stock Godot 4.6.3→4.7.1 upgrade:platform/tvos/build-ios/BulletHeaven.xcframework’s compiled engine was still the pre-upgrade version, so packing game data with the newgodotbinary via--export-packwrote a pack format the stale engine couldn’t read (Pack version unsupported: 4). Symptom was brutal to diagnose remotely: Godot’s own boot splash shows, then the app exits cleanly (exit code 0, no signal) with zero crash report anywhere and zero console output overdevicectl --consoleeven on USB — worked perfectly on a fresh-save Mac export the whole time, which is what made it look like a code bug rather than a build one. Real cause only surfaced viaidevicesyslog(neededbrew install libimobiledevice—devicectl/Xcode’s own tooling never found it); full diagnostic trail + the exact fix (--export-release, not--export-pack, to regenerate the engine) in memorybullet-heaven-ios-pack-version-crash. -
Overnight perf/code-quality loop (2026-07-22/23, 9 cycles, 16 commits) — read
docs/research/2026-07-22-overnight-perf-code-quality-audit.mdfor the full per-cycle trail before re-running a similar sweep. A session-local cron-driven Workflow loop (adversarial find→verify→fix, hard-gated to risk=low only) found and fixed 16 small perf/code-quality issues with zero bad commits, catching itself twice (reverted a fix that broke a test; later cycles found+fixed 2 real gaps in its own earlier fix). Cycle 1 exposed a genuine concurrency bug — parallel Fix-phase subagents editing the same non-isolated working tree — documented as the 8th instance in memorybullet-heaven-multiagent-deploy(same root-cause class as the earlier cross-session collisions, new trigger: a single Workflow’s own parallel subagents, not separate Claude sessions). A separate one-off adversarial audit the same session found the live Codex was telling players to use “elemental reactions” to bypass armor — a mechanic archived with reactions-mode on 2026-07-09 that no longer fires; fixed (1c00fa9). Still open: a recurring redundantSpatialHash.rebuild()pattern across several weapon files, flagged repeatedly across cycles but never fixed (correctly hard-gated at risk=medium each time) — worth a deliberate pass. -
Neon glow rendering technique reworked, BUILD 180-182 (2026-07-22), all on Apple TV. Chris flagged the glow as reading flat/pastel vs. a lightsaber-style white-hot core + colour halo. Root cause: the core mesh was a flat hard-edged quad (no internal gradient) and the halo was capped at alpha ≤1.0 (never triggered Godot’s real HDR bloom). 3 rounds, each corrected by Chris looking at a real render, not by reasoning from code: (1) shrink the core + add a soft round
GlowTexture“hotcore” layer — Chris caught that a round halo doesn’t follow an angular shape’s silhouette (a circle blurs a star’s points into a ball); (2) switched procedural shapes to a “shell” technique (6 scaled copies of the enemy’s own shape mesh, alpha descending outward — ref: a Unity lightsaber-aura-shader thread) — this looked right; (3) baked the (static, no per-frame variation) shell stack into 1 texture per shape for perf (7 draw layers → 2) via newtools/glow_bake/bake_shape_glows.gd— Chris: “that sort of hasn’t worked very well” on real hardware, reads visibly weaker than live even after fixing a real sizing bug found along the way (BAKE_OVERSAMPLEmismatch, glow rendering at 1/3 size). Both techniques now live side by side behindArchetypeRenderer.USE_BAKED_GLOW(defaultfalse= live shell, currently shipped) — flipping it is a one-line change, not archaeology, for whenever baking gets revisited. Ghost (SHAPE_WISP) has NO glow at all (Chris’s call). Full before/after evidence (isolated dots, full 25-type enemy gallery, real in-game screenshots, live-vs-baked A/B) is on a private Claude Artifact page (URL not persisted here — ask Chris if it’s still needed) rather than committed to the repo. Also discovered while auditing enemy colours for that same page:bible.json’s per-enemycolorfield is dead for 24 of 25 enemy types — every type except Skirmisher renders by its innate ELEMENT, not its own declared colour (the element check runs first inmain.gd._base_color_for_type()); worth deciding whether to remove the field or wire it back in. ⚠️ Owed: a real on-device FPS comparison of the shell technique’s added draw-layer cost — not yet measured, only reasoned about in code. -
Tutorial Onboarding (Ember Reach) shipped, 2026-07-21/22 — merged to
mainand pushed (858c09d..890dbd4), but NOT yet deployed to any device (no BUILD bump this session). Fresh saves now launch straight into a Tutorial run (skips the menu entirely); it’s capped to Ember Reach only (not the full 4-domain campaign) and auto-hands off into a Survival run the moment the Ember Warden falls and the new “tutorial_complete” dialogue is read. Teaches movement (implicitly, by requiring it to reach Echo), the auto/manual weapon split, the decoy (both already-existing dialogue), and dash/warp (genuinely new content — the one previously-untaught mechanic).ControlHint(the movement-reminder overlay Chris removed from Survival on 2026-07-05, commitc7ef9d9) is now re-instantiated for Tutorial-mode runs only — Survival’s removal is untouched — and its dismiss-trigger wiring bug (not _auto, true from frame 1 of any human session) was fixed to key off realsim.player.velocity. Built via full brainstorm→spec→plan→8-task subagent-driven-development→clean whole-branch review cycle; every task individually reviewed clean, zero Critical/Important findings anywhere. Design/plan:docs/superpowers/specs|plans/2026-07-21-tutorial-onboarding*; full task-by-task history: memorybullet-heaven-roadmap. ⚠️ Owed: a real human Mac/on-device playtest (nothing here was feel-verified) — script indocs/RELEASE-0.1.md. Design-sanctioned quirk worth confirming on-device: a player who bails to Survival before finishing Ember Reach gets force-routed back into the Tutorial on every subsequent cold boot (not just the first-ever launch), sincetutorial_doneonly flips once Ember is actually cleared — intentional per brainstorming, but the thing most likely to feel surprising in the playtest. -
Sound Map tool built, 2026-07-19 (dev tooling, no game/build changes) —
tools/sound_map/lets Chris browse every SFX-tied event next to its real in-game graphic, play its current sound, manage a candidate pool, and assign a winner (writes straight intoaudio/*.wavor, for previously-silent events, intoaudio/audio_manager.gd).audio/SOUND_MAP.mdis retired in favour ofaudio/sound_map.json. Newdark-cosmos/audio-direction/role owns using it. ⚠️ Genuinely unverified in-engine as of this writing — a system memory-pressure issue (seedocs/godot-gotchas.md’s SIGKILL/exit-137 entry) blocked every Godot-dependent check (fresh bake, full GUT suite,check-test-count.sh) for the tool’s entire build; re-run those once memory is free, before fully trusting theaudio_manager.gd/weapon_panel.gd/weapon_icon.gdedits. Full build history + the 2 real bugs a real browser click-through caught and fixed (thumbnail-path mismatch, live-play 404): memorybullet-heaven-sound-map-tool. -
Threat radar reworked AGAIN 2026-07-18, deployed BUILD 175 (2026-07-22) — the per-enemy MultiMesh+SubViewport mist from BUILD 173 is GONE, replaced with a top-K (24) sharp-dot layer + an analytic per-sector angular-Gaussian glow shader (
KERNEL_WIDTH=0.6, extendsfx/screen_feedback.gd’s edge-falloff technique). Fixed the SCALING problem it targeted (draws now flat ~400-430 regardless of enemy count, confirmed via telemetry) but shipped with a real regression of its own, found + fixed same-day via a device photo + live telemetry:ui/threat_radar.gdforcedvisible=trueunconditionally every frame, so the full-screen per-pixel glow shader paid its full fragment cost even at ZERO enemies — BUILD 175 idle (avg_enemies=1.5) measured 34.1fps/29.75ms render, WORSE than BUILD 173’s old per-enemy system at the same low-enemy bucket (34.3fps/28.78ms), the opposite of the “fixed-cost, zero per-enemy cost” design intent (draw-call count was genuinely fixed; fragment-shader cost scales with screen pixels, not draw count — different thing). Fix (BUILD 176, 2026-07-22):visible=falsewhenever there’s nothing to show, matchingfx/screen_feedback.gd’s ownvisible = enabled # kill the full-screen shader passpattern andui/boss_edge_indicator.gd’s real content-gated visibility — both patterns this file claimed to extend but hadn’t actually followed. ⚠️ Still needs a real on-device FPS re-check — root cause is fixed but not yet re-measured live; full history + telemetry trail:docs/research/2026-07-18-threat-radar-cost-redesign-research.md, spec/plandocs/superpowers/specs|plans/2026-07-18-cheap-threat-radar*,docs/RELEASE-0.1.md’s BUILD 176 entry. -
Live telemetry is now genuinely queryable for real analysis, not just the gated dashboard — use the
bh-telemetryskill (covers both querying the existingsamples/runs/encounterstables directly viawrangler d1 execute --remote, and the full pattern for adding new capture: table+route+client-tracker+deploy). This is how the FPS regression above and a human-vs-AI charger death-rate comparison were found this session — see memorybullet-heaven-telemetry-analysisbefore assuming a question needs new instrumentation; it may already be answerable by just querying what exists. -
Charger/spider dodge-orbit AI (
ai/skilled_auto_player.gd, 2026-07-17) shipped but did NOT measurably help — a real soak A/B (60 runs each side) showed the charger death SHARE went UP (60%→70%) and mean survival went slightly DOWN after adding orbit/dodge behavior, not the intended improvement. Code is correct/tested (30 unit tests, real geometry verification) — it’s a tuning/effect-size problem, not a bug. Not yet re-tuned or re-investigated. See memorybullet-heaven-roadmapfor the full soak numbers before assuming this is fixed. Full build-by-build history and every deploy narrative lives in memorybullet-heaven-roadmapand thedocs(claude.md): BUILD Ngit commits. Keep this a condensed CURRENT-state snapshot — update it in place, never append a new dated bullet. That append-per-build habit is exactly what re-bloated this file (see memorybullet-heaven-claude-md-maintenance). -
Polish batch (BUILD 167/168, deployed 2026-07-16): Chris’s own “look out for these classes of issue” pass — low-HP screen border now ramps continuously from half HP (was a hard on/off snap at 30%, ease-in intensity + colour desaturation); manual (Aim) weapon got a tail-to-nose gradient shader tied to a new
WeaponAim.visual_tier()plus a real evolution, “Railspike” (void≥30 crystals: ×1.5 damage/+2 pierce/+30% velocity — was the only weapon with no evolve() at all); Dimension Choice popup + the death Results screen’s 3 actions converted from button lists to the established single-card carousel (scoped to genuine “pick 1 of N” pickers only, not config/browse screens — Chris’s own call). New skillbh-polish-auditcaptures the 4 issue-classes found (asset-fiction mismatch, snap-vs-ramp effects, UI pattern inconsistency, invisible progression) as a reusable audit method for future polish passes. Also fixed same night: the real Wyrm per-segment DoT bug, Boss2 hidden from play (sidesteps its OVERSEER/Sentinel dual-name dispute rather than picking one), and the mouse-aim redesign (permanent motion-latch + controller/platform device gating, replacing a 200ms window that itself caused “acting weird since mouse was enabled”). Full detail:docs/RELEASE-0.1.md, memorybullet-heaven-roadmap. -
Polish-batch follow-ups (same night, 2026-07-16; BUILD 169, deployed to Apple TV + iPhone —
71452ec/6e775a6/c35c2fa/855ff57): app icon ✅ WIRED IN (platform/tvos/icon.png) — Gemini web generated it from atools/ship_previewhero3d-mode reference render of the ACTUAL starter hull, SynthID watermark removed via thegemini-image-genskill’s flat-top-mask blur-inpaint technique; replaces the old generic holographic emblem. Player ship’s orbiting accent-orb upgrade indicator REMOVED entirely (Chris: “we need a different way to show upgrade”) — tier progression still reads via halo size/hue + thruster recolor + the ascension flash; a replacement is wanted but not yet designed, Chris hasn’t picked a direction. Thruster plume now starts small and only reaches its old “big” look at full upgrade (PlayerRenderer.THRUSTER_TIER_MULT, a 3.2× tier range replacing a flat 1.6× one). New universal enemy arena leash (Sim._recall_stray_enemies, survival-only, no rng draw so determinism-safe by construction): any enemy stranded beyondARENA_HALF + STRAY_MARGIN(250px) forSTRAY_RECALL_TIME(8s) gets clamped back inside — enemies never had aclamp_arenaequivalent before, so knockback/a boss field/a no-pull-back behavior could strand one unreachably forever. HP bar HUD subtlety pass: number hidden, the always-visible-regardless-of-time cutoff moved from literal full health toHud.HP_LOW_HP_FRAC=0.5(a previously dead const from a superseded design, now actually wired up), more transparent backing + less glow. Full history: memorybullet-heaven-roadmap. -
Skilled AutoPlayer + balance-signal soak tooling (merged to main via overnight swarm, 2026-07-16 — QA tooling, no gameplay/build change, no deploy needed): a genuinely competent AI player (
ai/skilled_auto_player.gd,SkilledAutoPlayer extends AutoPlayer— the original dumbAutoPlayeris untouched, still used for attract-mode/coverage soaks) plus extendedsoak_runner.gd/SoakRunreporting (--player=skilled, per-upgrade impact scoring, cross-runfun_signals: death-tick distribution, build diversity, the pre-boss/boss anticlimax ratio, upgrade dud/overpowered rates) — a numeric proxy for “is this fun” where Chris and Claude agreed Claude structurally can’t judge feel directly. Real finding awaiting Chris: 0 of 80 skilled-AI runs (40 seeds × 2 ships, mortal) ever reached a boss — every run died in the wave phase, 45s-3.3min in. Is that intended difficulty or is early-wave lethality too high? Not a single-lever fix. No auto-tune was applied — everything that looked like a 90%+ dud/overpowered upgrade turned out to be 1-2-occurrence sample noise once checked directly. Spec/plan/runbook/report:docs/superpowers/specs|plans/2026-07-16-skilled-autoplayer-balance-signal*,docs/overnight-swarm-{runbook,report}-2026-07-16.md. Full history: memorybullet-heaven-roadmap. -
Centurion enemy (BUILD 165, deployed to Apple TV; merged to main, 2026-07-06): a new ranged enemy demonstrating a Nova Drift-style multiply-tint technique —
SHAPE_ROSETTE(ArchetypeRenderer) is the first genuinely colourless procedural shape in the renderer (reuses the existing_star_pts()builder), so it renders in whichever colour its current Elemental Dimension assigns, automatically, with zero new tinting code. Real discovery: spawn ELIGIBILITY is gated separately from colour, by THREE independent systems (sim/area_defs.gd’s per-dimension roster — evenhomeis gated — plus the primarySpawnTableand the secondarySpawnDirector), now documented indocs/architecture/enemies-bosses-survival.mdas the pattern for the next enemy addition. 7-task subagent-driven-development cycle + a clean Opus final review (zero Critical/Important findings). Spec/plan:docs/superpowers/specs|plans/2026-07-06-centurion-enemy*; full history: memorybullet-heaven-roadmap. -
Player Ship Tilt / banking (BUILD 165, deployed to Apple TV, 2026-07-06): the ship banks into turns via
render/ship_tilt.gd. Two selectable mechanisms live behind a dev-only Debug Settings row (Off/Shader Warp/Baked Flipbook, flipbook iscobalthull only). ⚠️ Still owed: Chris play both and pick a winner. Full history: memorybullet-heaven-roadmap. -
Start menu = clear-glass vertical list (2026-09-24, replaced the BUILD 164 carousel): title + one
GlassPanelwith big TUTORIAL/SURVIVAL rows, a divider, then SHIP/SHOP/ENEMIES (+REMOTE in dev builds); up/down wraps, A/tap activates, glyph hint for the last-used device. Row gating is the pureStartMenu.build_items(crystals_only, progressed, dev). ⚠️ Owed: confirm Siri Remote swipes arrive as up/down on the Apple TV. -
Real sprite art for Orbiter + Warden (BUILD 163, deployed to Apple TV): both now use dedicated
ArchetypeRenderershape buckets (SHAPE_ORBITER_SPRITE/SHAPE_WARDEN_SPRITE, Recraft-sourced art with native alpha) instead of procedural silhouettes — each isolated from the shape bucket it used to share (SHAPE_RINGw/ Graviton,SHAPE_CIRCLEw/ Boss2/FunZo/Eye), regression-tested. Warden’s body reads its natural sprite colour while calm, crimson (BOSS_COLOR) oncesim.boss.enragedlatches — same pattern every other boss renderer already reacts to. Glow-baking a sprite’s own texture (Nova-Drift-style layered glow, seetools/glow_bake/) was tried and shelved for swarm-scale sprites (imperceptible next to the existing runtime halo) but confirmed worthwhile at boss scale — keep in mind for any future boss/large-entity art. -
Platform: the tvOS/iOS build target is folded into
platform/tvos/(2026-07-04, BUILD 147) with gameplay dirs symlinked back to the repo root — one source of truth, no sync step (see the top-of-file pointer for the rules). The old~/Claude/bullet-heaven-tvosrepo is archived at~/Claude/_archive/bullet-heaven-tvos-old/. Runs live on Apple TV / iPhone / iPad (directdevicectl), plus a local macOS export and the R2 web demo. Deploy via thebh-deploy/bh-appstore-releaseskills. ⚠️ The iOS build shell’sInfo.pliststill lacksNSLocalNetworkUsageDescription— fine now (networked MP gated), but the M-B/M-C merge needs it re-added or iOS silently blocks LAN sockets. -
Determinism baseline:
snapshot_string().hash()=4217109746,state_checksum()=3312602286(last re-pinned 2026-07-07; the old separate reactions-mode baseline was archived 2026-07-09 along with reactions mode itself — see_archive/reactions-mode/). Read the literal pinned assertion intests/test_determinism_survival.gd, never a prose number — this line has gone stale before. Re-verify after any spawn/rng-touching change; re-pinning is normal, not a break. A SECOND, separate 2-pilot baseline now lives intests/test_determinism_coop.gd(seed 1234, 600 ticks, P2 owns a deployed Sentinel; re-pinned 2026-09-23 for the element-status fix — read the file, not this note). Thedronespool is now included instate_checksum()/snapshot_string()(afor d in drones:loop — baseline-safe because the single-pilot run deploys none); the accruing per-pilotdrone_chargescalar stays EXCLUDED (its only sim effect is deploy timing, caught via the pool). Both baselines are the source of truth in their own test file, not this prose. -
⚠️
ADAPTIVE_QUALITY := false(main.gd) since 2026-06-28 — the adaptive quality ladder is NOT running. Deliberate (so graphics changes can be evaluated without the ladder fighting mid-test), confirmed via direct telemetry query: the Apple TV’s tier has been stuck at 0 across every build since, even at 100% of frames under 40fps. Re-enable at the v0.1 release (Chris’s call, 2026-07-04). Until then, any new full-screen/decorative render effect gets ZERO automatic shedding under load — cut its raw cost at the source instead of assuming the ladder will catch it (default pattern +NebulaBg’s SubViewport-downres reference implementation:docs/architecture/rendering-and-performance.md). Full detail: memorybullet-heaven-measurement-open-loop. -
Player ship: baked-sprite hull,
BAKED_CLASS='cobalt'(PlayerRenderer.USE_BAKED_HULL). -
Input — Siri Remote ignored entirely (BUILD 154, deployed BUILD 155): on tvOS the Apple TV Siri Remote reports as a joypad but can’t play the game, so
InputRouterfilters it out of every all-joypad scan AND the co-op device mapping via oneplayable_joypads()source of truth (keyed on the pure, testedis_ignored_joypad()name-match —"remote"/"siri"). Single-playerpoll()and co-oppoll_device(playable[i])/join all exclude it. Verified on-device — the remote no longer moves the ship. The dev-only joypad debug readout used to confirm this is now REMOVED entirely (BUILD 161/162, Chris asked for it gone even from tvOS — no remaining use case). -
FX-events pipeline + thruster-trail flicker — 6 bugs found across BUILD 156→162 (now BUILD 165, deployed to Apple TV + Mac): 3 separate fx-events bugs (a pause-overlay early-return gap, cross-tick event clearing, and drain running after an early-return) and 2 thruster-flicker attempts before the real cause — a render-frame speed derived from cross-frame position-diffing reads as zero whenever physics/render cadence isn’t a perfect 1:1 (routine, not an edge case). Fixed at the source with a new
PlayerState.velocityfield set every tick. Full story + the two general anti-patterns to watch for in future render-timing bugs: memorybullet-heaven-roadmap. -
Ship classes (EVE-style, deployed BUILD 151+): 6
frigate-class hulls (ShipBonuses.TABLE, 3 weapon/1 drone slots) plus a gold-unlocked Obsidian cruiser (klass:"cruiser", 5 weapon/2 drone, 170HP/210spd/24px, +10 armor) in the “Ships” shop tab. ⚠️ Cruiser is still on an Aurum-copy PLACEHOLDER sprite — realtools/ship_previewbake + on-device shop/picker check owed. Spec:docs/superpowers/specs|plans/2026-07-04-ship-classes*. -
Starter + signature manual weapon (BUILD 165, deployed to Apple TV): starter is the Blaster auto-shooter (
sim/weapon_blaster.gd); melee blade is now acquirable, not the starter. The always-on right-stick manual weapon issim/weapon_aim.gd(WeaponAim) with baseline pierce(1)/impact-burst(48px)/knockback + 6 upgradeable attributes, progressed viaWeaponThresholds.TABLE["aim"](crystal-grant thresholds, the primary path) and also offered asaim:level-up cards. Fixed 2026-07-14 (merged+pushed,f8e2c5e): the mouse-aim fallback (input/input_router.gd, desktop only) was firing it nonstop whenever no other aim input was held, on every platform — fixed to require actual recent cursor motion, not just cursor presence; technique note indocs/godot-gotchas.md. ⚠️ Owed: on-device playtest (does the manual weapon feel worth learning?) + balance-tune the ladder numbers. In-run reconfiguration (piece 3) deferred tosovereign. Why the threshold ladder mattered: memorybullet-heaven-crystals-is-primary-mode; architecture:docs/architecture/weapons-and-buildcraft.md. -
Reset Shop / respec (merged to main
bf66ed2, 2026-07-05; BUILD 165, deployed to Apple TV): a “RESET SHOP” tile on the meta shop’s root carousel opens a confirm dialog; confirming refunds every gold coin ever spent (stats AND unlocks) viaMetaState.reset_shop(defs), clearslevels, and reverts ship/decoy/drone-loadout to starter defaults. Leavesseen_enemies/tutorial_doneuntouched — a respec, not a save wipe. ⚠️ Owed: on-device playtest (dialog legibility + the real save/refresh path is deliberately untested in CI). Spec/plan:docs/superpowers/specs|plans/2026-07-05-reset-shop*; full history: memorybullet-heaven-roadmap. -
Modal input gating (2026-07-14,
8a95e7b/1d8474a):mainis the scene root, so its_input()sees hotkeys before the childCanvasLayerpanels. It suppresses all decorative hotkeys (HUD toggle Y/V, debug overlay X/F2, codex C, quality F4, remote F6) whenever any modal is open, via a polled_any_content_modal_open()helper (dialogue/level-up/dimension/codex/ship-config/boss-teaser/debug-settings) +_paused_for_menu— same pattern as the pre-existing_shop_open()/_bay_open()guards._input()is three stages: pause keys (Start/Back/ESC →_toggle_pause, kept reachable so it can CLOSE the pause menu) → modal-suppress gate → decorative hotkeys._toggle_pause()self-guards so ESC won’t stack a pause menu over a content modal. When adding a new global hotkey OR a new modal panel, wire it into these two places. -
HUD/FX: player HP bar has no numeric label (2026-07-16) and stays fully visible at/below half HP; above half HP it only flashes in on taking damage, then fades back out (see
Hud.HP_LOW_HP_FRAC); build number lives on the pause screen, not the live HUD; attract-mode shows “AUTOPILOT ACTIVE” with a slow breathing fade; low-HP screen border is an animatedblend_addshader glow. -
v0.1 launch gates (verified in code; flip to restore the gated feature):
StartMenu.V01_CRYSTALS_ONLY=true— menu shows Tutorial + Survival (changed 2026-07-22; was Survival-only before the Tutorial Onboarding work below). The full 4-domain Story campaign stays hidden. The const name is a pre-2026-07-09-rename holdover; renaming it is optional cleanup, not required — see_archive/reactions-mode/README.mdfor the history.main.V01_LOCK_AREAS=false— Elemental Dimensions is LIVE (BUILD 141; since 2026-07-10 reached via a boss-kill dimension-choice popup —Sim._roll_dimension_choiceoffers 3 of the 7 non-Home dimensions after a boss dies, not the old 3 simultaneous portals). v2 (2026-07-05, MERGED to main2cb686d; BUILD 165, deployed to Apple TV): replaced the original Pyre/Null/Drift mapping. All 7 non-Home dimensions are now defined + eligible insim/area_defs.gd(fire/ice/void_dim/blood/electricity/light/poison), plus a themed Generic/homedimension (its own Warden/FunZo/Graviton/Eye boss rotation). Bosses reuse existing archetypes — native:void_dim→Graviton,poison→FunZo,light→Eye (as “Sentinel”). Warden stands in forfire/ice/blood/electricity(their bespoke bosses — Nautilus/The Queen/The Last Computer etc. — are not built yet, but the dimensions themselves ARE live and offered; confirmed visited in soak). Design:docs/superpowers/specs/2026-07-05-elemental-dimensions-v2-design.md. FlipV01_LOCK_AREASback totrueto re-lock. Details:docs/architecture/enemies-bosses-survival.md+ memorybullet-heaven-explorable-areas.main.V01_LOCK_COOP=false— local co-op is ON and deployed (BUILD 135). Join = explicitJOY_BUTTON_Aon device 1. P2 progression is now DONE (kill-XP 2026-07-09, upgrade pipeline 2026-07-10, drone/decoy 2026-07-11 — all merged, see thepilotsarchitecture note below); ⚠️ a real 2-controller playtest is still owed to confirm on-device behaviour.- Networked LAN MP (M-B + M-C) is built + real-device tested but UNMERGED, in worktree
.claude/worktrees/networked-multiplayer-mb-mc. Its gate flagmain.V01_LOCK_NETWORKED_MPexists only in that worktree — the const is NOT onmain, so don’t hunt for it in a flag audit. Needs re-reconciling against main before merge; inherits the P2-can’t-level-up gap (same root cause as co-op). main.SHIP3D_MEASURE=false,main.MEASURE_FULL_QUALITY=false— measurement-only flags, both closed.
-
Content batch (2026-07-09): 6 new weapons (Momentum Core, Chronowell, Scar Tissue, Railgun, Wildfire, Thunder Wake) and 6 new enemies (Beacon, Glass Wisp, Halo Chain, Leech, Coil, Fleet Kite;
TYPE_*24-29) merged and verified (full suite + determinism, no re-pin needed). ⚠️ Not yet playtested for feel/balance. -
Multiplayer (Phase 3): M-A (sim foundation —
Sim.pilotsarray, per-pilotPilotArsenal,tick(inputs)) DONE + merged; architecture in## Architecturebelow. M-B+M-C unmerged (above). M-D (online / dedicated server) is post-launch. -
Sound: all 5 phases done + merged (2026-07-02). Living per-event audit:
audio/sound_map.json(viatools/sound_map/browse tool); remaining SILENT/GENERIC entries are deferred, not gaps. Full history: memorybullet-heaven-sound-effects. -
Balance direction — EVE-style: power grows across runs (meta-progression), not within one run; don’t rubber-band enemies to the player. Rationale: memory
bullet-heaven-balance-philosophy. -
Open items flagged for Chris: a human playtest of the 10-lesson Tutorial (2026-09-24 rebuild) — automated tracing (
story_trace.gd --mode=tutorial) verified lesson order, gating, and objective completion for real, but nothing automated can judge feel: the Warden is measurably harder now that the Pulse gift and its encounter heals are gone (a mortal bot dies ~4s afterwarden_intro, no heal rewards left) and whether that’s the right difficulty is Chris’s balance call, not a bug; the 45° wall-slide warp distance (found fixing the wall-tunnel bug this plan also caught) wants a feel check; and lesson pacing overall — the read-freeze means real wall-clock cadence only shows up by playing it. The balance numbers this rebuild introduced (TUTORIAL_XP_TO_NEXT, the story-boss XP scaling) are unchanged, first-pass, and still want your eye;apply_element zero-damage bugFIXED 2026-09-23 (1 stack per foreign hit, 4s window; accumulation still off); 0 of 80 skilled-AI soak runs ever reached a boss (2026-07-16 finding, see the tooling bullet above) — is early-wave lethality too high, or is this the intended mortal-run lifespan at this seed range?; playtest-tune the balance consts (FIRE_RATE_CAP,BOSS_HP_TIME_FRAC,XP_LEVEL_GROWTH,ELITE_HP_MULT/ELITE_CONTACT_MULT); a real 2-controller (+ mouse) co-op playtest of the now-per-pilot upgrade pipeline AND drone/decoy system (P1 can’t hijack P2’s level-up panel, panels chain correctly, P2’s own drone deploys/recharges independently); confirm whether the MTU/reliable-channel fix resolved the client “no enemies” bug; a hands-on 2-device MP playtest; the ~12 promotable enemy types still get only the generic elite buff, not a bespoke power; play both Ship Tilt mechanisms and pick a winner; a real-time normal-mapped 2D lighting pass for the player hull (render/hero_lights.gdalready runs a plain-glowPointLight2Dbut explicitly deferred the normal-map/shadow-occluder path —~/Claude/godot-graphics-showcase’sdynamic_lighting_2d.gdtechnique already solved the Godot 4.6.3Sprite2D-has-no-normal_mapworkaround; surfaced 2026-07-06 but not yet specced, shelved when the conversation pivoted to Ship Tilt instead).