Experimental Build — Complete Change Review¶
Covers: everything on branch
bza-dev-gameplay-pivotsince6d92290("Pivot docs", 22 Jul 2026) — 69 commits, ~1 370 lines of gameplay code, ~240 lines of new tunables.
0. What you are looking at¶
Two design programmes landed back to back on the same build:
- The action pivot (probes 0.1–0.13,
6d92290..5a90b5d) — the publisher test said the moment-to-moment was the problem: no verbs in the hands, passive overlong fights, invisible rewards, raids as long as a whole session. This programme rebuilt input, combat feel, perception and encounter rules. - The Dive (
7e2cb9d..914ac04) — the answer to "a different extraction game from the same assets, not an iteration." This programme rebuilt the session and progression shape: one run is now a continuous descent, and you only keep what you carry out.
Both are fully A/B-able from the in-game tuning panel. Nothing here is a one-way door:
| Programme | Master flag | Off = |
|---|---|---|
| The Dive | dive.enabled |
the pre-dive game exactly (descend banks + ends the run) |
| Action input | action.enabled |
classic tap-to-move / double-tap sprint / swipe-dodge |
| Stealth-lite perception | combat.aggroOnly |
the full detection-fill / suspect pipeline |
| Rival neutrality | rival.neutral |
legacy always-reactive rivals |
| Peace/War | combat.peaceWar |
legacy always-fire |
| Closing exits | extraction.closingStart ≤ 0 |
no closures |
| Storm death | extraction.stormFinale |
(currently off) — restores the HP-drain finale |
How to read each entry: Problem → What ships → Why it should help → Status → Your call. "Status" is honest: ▣ verified in play, ▢ built, unplayed, ⚠ known risk.
1. The headline rule changes (read this if you read nothing else)¶
| # | Old rule | New rule | Flag |
|---|---|---|---|
| 1 | The raid clock kills you (storm finale, HP drain) | No timer death. The clock only decides which safe exits close | extraction.stormFinale: false, dive.enabled |
| 2 | A raid is 10 minutes | A floor is 3 minutes (roundTime: 180) |
map.roundTime |
| 3 | Extract = bank + end the run | Two doors. Safe exit = bank + advance checkpoint + end. Descend portal = bank nothing, end nothing, continue deeper | dive.enabled |
| 4 | Death resets the floor ladder | Death costs only the carried haul — never gear, never floors; retry drops at the checkpoint | shipped |
| 5 | Nothing survives death | Safe Pocket: your best found item is auto-protected and survives death | loot.safeSlots: 1 |
| 6 | Floors are just harder | Each descent offers 1 of 3 upgrade cards (Body / Edge / Greed), run-scoped | dive.cardCount |
| 7 | Loot value is flat | Depth bonus: currency banks at ×(1 + descents × 0.12), capped ×1.6 | dive.depthBonusPerFloor |
| 8 | Meeting a rival = a fight | Rivals are neutral by default. You choose war by marking one and landing the first hit | rival.neutral |
| 9 | Stealth is a meter you manage | Detection is instant and binary — the drawn cone is the truth | combat.aggroOnly |
| 10 | Tap to move | Floating joystick steers directly; dash is an on-screen button on a cooldown | action.enabled |
| 11 | You always auto-fire on sight | At peace your weapon is down while moving; planting takes aim; being seen/hit = war | combat.peaceWar |
| 12 | FTUE = 7 stages | FTUE = 3 stages (loot → fight → descent) | shipped (legacy table parked, not deleted) |
2. Input & controls¶
2.1 Floating virtual joystick — action.enabled: true¶
- Problem. Tap-to-move gives the player nothing to do moment to moment; the telemetry's D1 22.5% and one-raid-per-session read as "not fun to hold", not "too hard".
- What ships. Drag anywhere → a floating stick appears under the thumb and steers the raider
directly.
stickRadius: 56, dead-zonestickDead: 0.12(UnityJoystickInputparity). Keyboard: WASD/arrows steer, Space dashes. Tap-to-move, double-tap sprint and swipe-dodge are all off while this is on. - Why it helps. Strafing exists. Kiting exists. Every other pivot mechanic (flank crit, dodging telegraphs, outrunning a charge's aim) is only expressible with continuous steering.
- Status. ▣ Verified — this is the foundation everything else was tuned against.
- Your call. Keep/drop is effectively a decision about the whole pivot; the rest of §2–§3 is meaningless without it.
2.2 The Action Button (dash) — action.dashCd: 0.9, action.dashFree: true¶
- Problem. The dodge was a swipe — undiscoverable, and it competed with steering.
- What ships. A big on-screen button with a cooldown sweep. No stamina cost — the pivot's
cooldown-verb model. Dodge duration widened
0.25 → 0.35s(≈87px of travel, i-frames =dodgeTime + 0.05). - Why it helps. One reliable panic button ⇒ deaths become readable mistakes instead of resource-management failures. Stamina as a dodge tax punished exactly the players already losing.
- Status. ▣ Verified.
- Your call.
dashCdis the pacing knob — 0.9s currently reads generous. Worth an explicit decision at 0.9 vs 1.4.
2.3 Potions are a swig, not a channel — player.potionChannelTime: 0, player.potionSwig: 0.35¶
- Problem. A 1.2s rooted channel that cancelled on movement is disengage-and-hide design. Under strafe combat it is unusable — it fights the thumbs.
- What ships. Drinking takes 0.35s, is not rooted, and is interrupted only by taking a hit (the potion is kept, not consumed) — never by movement. Drink mid-strafe, but not mid-beating.
- Status. ▣ Verified.
2.4 Extraction boards on stance, not a tap — (no flag; Unity Portal.cs parity)¶
- Problem. The fast 3s force-board was tap-triggered — orphaned by stick input, leaving only the slow 9s passive board.
- What ships. Standing still on the pad, not hunting, not in a fight → the fast rooted channel. Moving across the pad or fighting on it → passive boarding (you keep shooting while you leave). Taking a hit stalls both; being in a fight downgrades rooted → passive, so rooting can never skip a fight.
- Why it helps. The stance is the intent — the active/passive extraction choice survives without a button. Also makes the FTUE's board lesson tap-free.
- Status. ▣ Verified.
2.5 Camera — camera.fitMin: 0.75, leadSteer: 225, leadFight: 150, leadSmooth: 0.02¶
- Problem. With direct steering you outrun your own sight; phones saw too little.
- What ships. Phones zoom out meaningfully further (
0.9 → 0.75). The camera leads along the stick while free, and switches to lead toward the foe while fighting. Easing softened so the bigger leads glide rather than swing. - Note. The G0 pass reverted an earlier
fog.radius 300 → 330bump — the wider camera does the "see further" job better than a bigger fog circle. - Status. ▣ Verified.
3. Combat feel¶
3.1 The sponge is retired — combat.mobHpMult: 2 → 1, mobDmgMult: 0.5 → 1¶
- Problem. The old "prolonged but survivable" model (double HP, half damage) made every fight a long, safe chip-fest. Fights were passive: no decisions inside them.
- What ships. Neutral multipliers. Trash dies in seconds; hits hurt.
- Why it helps. Deaths become readable ("I ate that telegraph") instead of attritional. Kill speed is now paced by the player's positioning, not by an HP tax.
- Status. ▣ Verified. ⚠ This is the single biggest balance lever on the build — the boss-wall problem in §8 lives downstream of it.
3.2 Always-on flank crit — combat.flankCrit: true¶
- What ships. Any player hit — melee or ranged — from the target's blind spot crits, every time. No stealth arming, no silent-opener fire-lock.
- Why it helps. It converts positioning into damage continuously, which is what makes a twin-stick fight readable and skill-expressive without adding buttons.
- Status. ▣ Verified.
3.3 Flank-crit windows — who you're allowed to out-turn¶
The crit is an in-fight punish earned against committed enemies, not a free orbit:
| Knob | Value | Meaning |
|---|---|---|
turnMelee |
6 rad/s | trash turns snappily — cannot be orbited (frontal DPS check) |
turnRanged |
5 | |
turnHeavy |
3 | heavies at mid range — approach on the flank is possible |
turnClose / turnCloseRange |
4.5 / 70px | point-blank whip: inside 70px everything turns fast — a ranged heavy is not a free melee execution |
mobMeleeArc |
1.75 rad (~100°) | a mob's melee swat requires a frontal arc — no hitting what it can't face |
melee.recover |
0.15 → 0.35s | a dodged lunge reliably grants one flank strike on its exposed rear |
bodyBlock |
true | enemy bodies are solid to steering, homing and the dash — flanking means going around, i-frames are for attacks, not bodies |
| - Status. ▣ Verified. This is the densest cluster of feel-tuning in the build and the one most | ||
| worth a dedicated playtest. |
3.4 Charged shots — the settled model (no mode flag)¶
- Problem. Charge attacks previously froze the mob into a statue and then snapped to perfect aim at fire time — the wind-up taught nothing, because dodging it didn't work.
- What ships. While charging, the mob braces (slow weave, not frozen) and its look
direction is the aim — cone, dashed telegraph line and the eventual shot all agree.
The aim fine-tracks at
chargeTurn: 1.8rad/s (well below combat turn — strafing outruns it, and that lag is your window), freezes for the finalchargeLockLead: 0.25s(line snaps solid = dodge now), and the shot fires along the look direction, never at your live position. A charge can only begin once you're in front of it — no winding up a shot at someone behind its back. Hands busy: no melee while charging. - Why it helps. Same track → lock → release grammar as the melee lunge, so one lesson covers
every enemy. Boss and Gatekeeper wind-ups were lengthened (
chargeDur0.5→1.0 / 0.55→0.7) so they read at a glance. - ⚠ The aim was broken until 2026-07-29 — found by playtest, confirmed by measurement. Charged shots missed a player standing perfectly still, by 43–157px at ~260px range. Two faults:
chargeTurnwas written as "rad/s" but implemented as a per-frame fractional lerp, i.e. exponential smoothing — which asymptotes and never arrives. The aim kept a standing lag proportional to how fast the bearing moved, and the mob's own bracing weave supplied enough bearing rate to make it miss a stationary target. It is now a true rate cap.- The flat
chargeArc(40°) let a mob commit to a shot it could not finish aiming. A Warden only tracks for 0.2s — 0.36 rad of authority — yet started charges 40° off and fired ~30° wide. The entry gate is now derived per mob from its own wind-up (chargeAimMargin: 0.6), so the effective arc runs 9° (Emberling) to 40° (Boss).chargeArcsurvives as the ceiling. - Measured after the fix (pinned player, first shot, ~260px): every charging mob now lands — aim error 0–4°, 0–15px lateral. And the counterplay is intact: stand still → hit; strafe at walking pace → miss; dash on the lock → miss. Before the fix the wind-up was decoration; it now enforces "keep moving," which is the pivot's whole thesis.
- Status. ▣ Verified — ⚠ but note this is a real difficulty increase: charged shots that used to always miss now punish standing still. Worth watching on the B1 boss.
3.5 No out-of-combat regen — player.hpRegen: 0.005 → 0¶
- Why. HP attrition across a run is a core greed lever ("at 30%: push the vault, or leave?").
A trickle regen quietly deletes it. The fix for doomed walks is more potion drops
(
consumableChance 0.45 → 0.6), not regen. - Status. ▣ Verified. ⚠ Now load-bearing under the dive, where HP carries between floors.
3.6 Smaller combat items¶
| Change | From → To | Why |
|---|---|---|
weapons.sniper.mag |
2 → 3 | "one fight per mag" — 3×34 kills a trash mob with margin; 2 couldn't without a crit |
noise.waveSpeed |
(instant) → 560 px/s | sound travels: creatures react when the drawn ring actually reaches them, and head for where the sound happened — fire and reposition and they converge on a stale spot |
combat.patrolHold |
(none) → 1.2× | patrollers dwell at every leg end, cone parked — kills the surprise 180° sweep onto a stalker |
combat.fightLinger |
2s | you count as "in a fight" for 2s after the last hit — blocks chest/gate channels (Unity parity) |
Startle beat (mobReact) |
removed | lead call — a reaction-by-sense flourish nobody read |
4. Perception — "stealth-lite"¶
4.1 Instant binary detection — combat.aggroOnly: true¶
- Problem. The old stealth pipeline (detection fill, suspect state, gradual meters) asked mobile players to read a simulation. Telemetry says they didn't.
- What ships — three rules, no meters:
- CONE-GATED. The drawn cone is the detection zone. Outside the facing arc = the earned opener (hits crit via flank crit; damage aggros).
- BUSH. Binary concealment — un-aggroed enemies detect a bushed target only inside
bushDetectMult × radius; locked-on enemies ignore foliage. Two bodies in the same bush cluster always see each other (you can't lose, or be ambushed by, someone standing in your own shrub). - SOUND. Noise recruits; echo blips warn.
UI is
❗ locked / ? searching / nothing. Dropped forever: gradual fill, suspect state. - Status. ▣ Verified. The tutorial keeps legacy perception.
4.2 See it → fight it — combat.mutualSightFire: false + fog.sightFairness: true¶
- What ships. The symmetric "you may only fire once spotted" gate is off. To stop that becoming unfair, a new invariant: nothing may shoot — or even acquire — the player from beyond the player's own sight radius. Six enemy types out-see the fog; this clamps them. Chase memory after aggro is unaffected.
- Status. ▣ Verified.
4.3 Engage range — combat.engageRange: 200 (+ ui.engageRing)¶
- Problem. With the fire gate gone, auto-fire started fights the player hadn't chosen.
- What ships. Your auto-fire only opens on un-aggroed enemies inside 200px (< sight radius). Outside it you can see, read and position without your own bow committing you. Return fire at anything already fighting you has no range gate. A faint dashed ground ring shows the boundary when a visible un-engaged enemy is near it.
- Why it helps. Restores choice of engagement to a game with no fire button.
- Status. ▣ Verified.
4.4 Peace / War — combat.peaceWar: true, plantTime: 0.25, aimTime: 0.9¶
- Problem. The engage ring alone still made walking around a declaration of war. Successive fixes ("stalk-hold", "moving = quiet") turned into an if-ladder nobody could read.
- What ships — one visible state:
- PEACE (nothing is hunting you): weapon down while moving — walking anywhere is silent, with no per-target conditions.
- PLANTING: 0.25s of genuine stillness (finger off the stick — a dead-zone transit while
reversing never counts) → the bow draws for
aimTime: 0.9swith a building gold telegraph line, then releases. Any movement cancels the draw. - WAR: the walk-in stab, or being seen/hit, flips you — fire is then unrestricted (full strafe/kite combat).
- The engage ring displays the state: blue = peace, gold-filling = taking aim, red = war.
- Why it helps. Enemies telegraph with a wind-up; now so do you. One state, one colour, and the deliberate opening shot becomes a choice with a cost instead of an accident.
- Status. ▣ Verified. ⚠ The most novel single idea in the build — highest risk of reading as "my gun doesn't work" to a new player. Explicit verdict wanted.
4.5 Echo-sense tightened — fog.senseRadius: 660 → 420¶
Sonar blips are a near-warning ring just past sight, not a map-wide radar. Kept as the counter to bush ambushes.
5. Rival raiders (Tier 0 — encounters as a choice)¶
5.1 Neutral by default — rival.neutral: true¶
- Problem. Every rival meeting collapsed into combat, so all the social behaviour the bots already have (looting, fleeing, key-racing, extracting with a real haul) was invisible. The pivot made this acute: under aggro-only perception with the fire gate removed, encounters would have become instant automatic fights.
- What ships. Every rival carries one state toward you: NEUTRAL (excluded from auto-fire both ways — you pass, loot and fight mobs side by side) or HOSTILE (normal symmetric fight).
- Status. ▣ Verified. This is a hard dependency of "rivals from floor 1", not flavour.
5.2 Tap-to-MARK — rival.declareRange: 260¶
- Problem. The first version was tap-to-declare: your tap instantly told the rival it was at war. That is the one thing an ambush must not do.
- What ships. The tap marks a rival silently — your intent, its ignorance. Targeting, aim and backstab open up on it while it keeps looting. War truly starts when your first hit lands. Mark → stalk → the charged shot or the rear-arc knife. Tap again to lift the mark.
- Status. ▣ Verified.
5.3 Safe crossfire — rival.safeCrossfire: true¶
Stray fire between neutral parties is harmless — shots pass through, no damage, no war. So fighting the same mob pack side by side can't accidentally flip a truce. War starts on purpose (mark, or contested prize). ⚠ This is a deliberate deviation from the GDD-literal "any damage flips hostile" — flagged for your ruling.
5.4 Escalation and cooling¶
| Knob | Value | Behaviour |
|---|---|---|
warnRadius / warnTime |
140px / 1.5s | both of you crowding the same prize (vault gate, a pad it's boarding) → amber warning → hostile. Backing off de-escalates. |
resetTime |
6 → 30s | a hostile rival cools back to neutral after 30s of lost contact — a fight should be remembered for a while |
rememberAttacker |
false | set true = a war you declared is forever |
⚠ Contested-objective escalation is the one Tier-0 path not confirmed in play.
5.5 Fair looting — lootSight: 480, crackMult: 1.35, lootPause: 2.5¶
- Problem. Rivals looted omnisciently — beelining chest-to-chest off the global list while the player explored through fog, leaving only spent chests behind.
- What ships. A rival only targets chests it could plausibly have seen (480px); otherwise it wanders and searches like you do. It pries 35% slower than you, and rummages 2.5s after each chest — so you can win footraces and contest chests.
- Status. ▣ Verified (playtest fix).
5.6 The Opportunist (Tier-1 slice pulled forward) — oppChance: 0.45, oppFromBiome: 1¶
- Problem. Fully neutral rivals are scenery. Late-raid greed had no teeth.
- What ships. Some rivals are rolled predators: neutral until you're worth it — wounded
(
oppHpFrac: 0.45) or hauling fat next to an open pad (oppHaul: 5items within 300px of a pad). Then the amber warning beat (it is sizing you up — your window to disengage), then it jumps you. Biome 1 rivals stay fully placid. - Dive interaction.
oppHaulPerDescent: 3— the fat-haul threshold grows per floor descended, because the bag never resets under the dive; a flat count would leave every Opportunist permanently triggered from ~floor 2 and turn the back half of a run into a gauntlet. - Status. ▢ Built, lightly played.
5.7 Rivals from floor 1 — prog.botsFromBiome: 1 → 0, botSpawnClear: 380¶
The extraction fantasy is on screen from the first minute (safe now that neutrality is the default). Rivals spawn at least 380px clear of any creature, so they arrive as looters with breathing room, not mid-fight.
6. Raid structure & extraction pressure¶
6.1 No timer death — extraction.stormFinale: false¶
- Problem. The storm finale (near-end banners, final-30s HP drain, cataclysm flash) is a hard-fail that punishes exactly the players who are already struggling — and it cannot coexist with an accumulating haul.
- What ships. The storm is off. Under the dive the clock never ends the raid.
- Status. ▣ Verified.
6.2 Closing extractions — the spatial endgame — closingStart: 0.5, closingInterval: 60, closingFromStep: 1¶
- What ships. Halfway through the floor's schedule, safe exits shut one by one, nearest-to-spawn first, with a broadcast banner and a per-pad countdown. The reserve (farthest) safe pad never closes under the dive — removing the last way to bank would turn the central choice into coercion, and a player denied a cash-out on a big haul reads it as the game cheating. The funnel intent is carried by the depth bonus instead: pull down with reward, don't push down with denial.
closingFromStep: 1— floor B1F1 has no clock at all (the designed win); the closing pressure debuts on B1F2, as do the off-screen threat arrows (arrowsFromStep: 1).- ⚠ Fix worth knowing:
tilesPerExit 30 → 20. B1's small floors rounded to a single safe exit, which the scheduler then reserved — so nothing ever closed before floor 4 and the closing lesson literally could not exist. At 20, floor 2+ has two exits and one closes as designed. - Status. ▣ Verified after the fix. This was flagged in the plan as the pivot's designated tension-carrier and its go/no-go probe — it deserves a direct verdict.
6.3 Guarded descend portal — guardsFromStep: 1¶
Floors below step 1 spawn no Gatekeeper at the descend portal (B1F1 is a free walk-in, part of the designed win). Everywhere else the descent is a finale fight: clear the guard, then hold the pad. The boss floor is never exempt.
6.4 Round length — map.roundTime: 600 → 330 → 180¶
Now a per-floor closure schedule, not a raid length. First pad closes at 90s, then every 60s.
Also gateGiveUp 330 → 240 so the rival keybearer can still dramatically extract with its haul
instead of dying on-mission to the sweep.
7. THE DIVE — the progression restructure¶
The pitch: a session is one continuous descent, and you only keep what you carry out. Everything else in §7 exists to make that one sentence true.
7.1 The two doors — dive.enabled: true¶
- Problem. Extracting was the only verb that ended a run, so every run was "go in, get some, leave". There was no escalating tension inside a session and no reason to ever feel greedy.
- What ships.
- Safe exit (green) → banks the haul, advances the checkpoint, ends the run. A floor is unlocked by cashing out from it.
- Descend portal (👑) → banks nothing, ends nothing. The next floor generates and your haul, wounds, consumables, field-equipped gear and upgrade cards all carry.
- Death → costs the haul only. Gear and ladder are never lost; retry drops you at the checkpoint, not at the floor you died on.
- Why it helps. It creates the one decision the game never had: bank now, or take it deeper? The haul compounds, your HP does not recover, and the answer changes every floor.
- Status. ▣ Verified end to end (carry, banking, checkpointing, death, A/B off).
7.2 Depth bonus — depthBonusPerFloor: 0.12, depthBonusMax: 1.6¶
- What ships. Currency and valuables bank at ×(1 + descents × 0.12), capped at ×1.6. It counts descents, not floor number — which kills the "start deep, bank immediately" exploit.
- ⚠ The rule that sizes it. The depth bonus prices risk, and it must sit below break-even.
Break-even for a per-floor death chance
pisp/(1-p). The original 0.25 was asserting "you die on one floor in five"; at a realistic ~10% that made descending strictly correct and deleted the choice. It must stay below break-even because descending also earns you a whole extra floor of loot, which already pays for part of the risk. - Status. ▣ Re-sloped after playtest (first test: exactly one safe exit taken all session, and only to dodge the boss). Not yet re-measured at 0.12.
7.3 Upgrade cards — 1 of 3 per descent¶
- Problem. Descending needed a pull, not just a payout — and going deeper on a fixed character makes the back half of a run strictly worse.
- What ships. Each descent offers one card per category (
cardCount: 3), run-scoped:
| Body (survive) | Edge (kill faster) | Greed (carry more out) |
|---|---|---|
| ❤ Patch Up — restore health now ✅ | 🗡 Sharpened — +25% flank-crit damage ✅ | 🔒 Deep Pockets — +1 Safe Pocket slot ✅ |
| 🛡 Thick Hide — +20% max health ✅ | 💨 Quickstep — −20% dash cooldown ⚠ | 💰 Scavenger — +10% depth bonus ✅ |
| 🩸 Bloodletting — flank crits heal you ⚠ | 🎯 Steady Hands — +20% attack speed ⚠ | 🧲 Wide Magnet — +40% pickup radius ⚠ |
✅ = fully wired · ⚠ = the card writes a field no system reads yet (deliberate — see §9).
- Anti-death-spiral rail. Below healCardHpFrac: 0.40 HP, the Body slot is forced to be
the heal — the run can't dead-end because the RNG offered you three things you can't use.
- ⚠ Bug found only by playing it. applyCards() re-applied every pick on every floor, so
Patch Up healed forever — making it strictly dominant and deleting attrition (the dive's second
compounding resource). Instant cards now carry once: true and never re-fire.
- Status. ▣ Verified. ⚠ The GDD marks the whole card system as cuttable — it is the most
"roguelite" thing in a game that is not otherwise one.
7.4 The Safe Pocket, made real — loot.safeSlots: 1¶
- Problem discovered mid-review. The Safe Pocket was dead content. The manual "🔒 Protect"
chip lives in the Loot Station, which is parked behind
loot.inRunInventory: false— so it was unreachable, nothing was ever protected, and the Deep Pockets card was buffing nothing. - What ships. The Safe Pocket is now automatic: the N most valuable found items in your bag are protected, chosen continuously (derived, not stored — it re-picks the moment you find something better). Shown as 🔒 chips in the HUD during the run, and they lead the death screen as "kept". Your own equipped gear is excluded (it was never at risk).
- Why it helps. Death needed to leave something. One protected find turns "I lost everything" into "I got the good one out" — and it makes the risk legible before the risk is taken.
- Status. ▣ Verified (junk knife lost, legendary Plate banked; with Deep Pockets, two survived).
7.5 Salve carry cap — player.potionsMax: 3¶
- Problem. Potions auto-grab on contact and now carry between floors, so uncapped they piled up until chugging trivialised every fight. This was the exact G0 "watch item".
- What ships. Cap of 3. At the cap the salve is left on the ground — still there when you come back hurt. (The alternative, lowering the drop rate, would have made potions scarce on the shallow floors where they aren't the problem.)
- Status. ▣ Verified.
7.6 The HUD tells you what's at stake¶
The two numbers that are the decision now sit in the corner: at-risk value (haul × the current
depth multiplier) and ⬇ depth · ×multiplier, plus the 🔒 Safe Pocket chips. Result screens read
Dive: N floors · depth bonus ×M · banked V value, and death leads with "⚔ Dive Again".
7.7 Two G0-frozen rules were deliberately retired¶
Flagged explicitly so they can be re-tested as such: the timer death, and the last safe pad closing. Reasons are in the dive GDD.
8. Economy & loot¶
8.1 Depth must not pay twice — CUR_MULT split from RAR_MULT¶
- Problem (found by playtest). Currency amounts scaled by the gear rarity multiplier
RAR_MULT(1 → 5) and rarity is itself depth-driven. So depth paid currency once through the loot table and again through the depth bonus. Reported result: one bank took gear power from ~1500 to ~4500. - What ships. A separate
CUR_MULT(1 → 2) for currency only; gear keeps its full 1→5 spread, which is depth's proper reward. Legendary blueprint drops fall from 3–6 to 1–2. Combined with the depth re-slope, income at depth is down roughly 4×. - Status. ▣ Shipped, ▢ not yet re-measured.
8.2 Loot feels abundant (probe 0.9)¶
| Knob | From → To |
|---|---|
fieldChestDiv |
720 → 520 (more chests) |
groundLootDiv |
520 → 380 (more ground items) |
t1MaterialChance |
0.50 → 0.65 (more kills visibly pay) |
consumableChance |
0.45 → 0.60 (potions are the only heal now) |
chestTime |
4.0 → 3.0s (the crack survives as the loud-exposure beat, tuned shorter) |
firstFloorGearBoost |
2.5× gear odds on the very first floor — first sessions reliably produce a felt upgrade |
8.3 Telemetry-driven enemy intro re-slope¶
The Jul 16–19 test showed fail spikes exactly where new mobs enter. Each floor now introduces at most one new enemy:
| Mob | Was | Now | Reason |
|---|---|---|---|
| Hound (pack) | B1F2 | B1F3 | drove the 1-2 fail spike (13.8) — the first real melee pressure |
| Emberball | B1F3 | B1F4 | knock-on |
| Skeleton | B1F4 | B1F5 | knock-on |
| Warden (first out-sighting mob) | B2F1 | B2F2 | stacked onto 2-1's rivals + map jump (fail 18.9, churn 35%) — now 2-1 introduces only the new biome |
B1F2's only new pressure is the closing clock.
8.4 ⚠ Not fixed — handed to you deliberately¶
- The sink is flat. Upgrade cost is
it.level * 2blueprints, independent of rarity and depth (game.js:6505). Every extra blueprint converts 1:1 into progression speed. Changing income and sink in the same pass would make the next playtest unreadable — so only income moved. - The B1 boss is a power wall at ~1500 power and trivial after one bank. These are the same bug: the economy is destroying the difficulty curve, so the game reads as impossible, then trivial. Both belong to a dedicated TTK/economy pass, not to a guessed knob.
9. FTUE — 7 stages → 3¶
- Problem (measured). Tutorial completion 75.5%. No individual step is broken — per-step completion is 93–98%. The 24.5% loss is simply the price of seven sequential gates. Three gates at the same per-step rate ≈ 88%+.
- What ships — three stages, in the order the game actually plays:
- First Steps — steer + loot. A chest yields the full starter kit (a fresh save is gearless, so fighting can't be stage 1); one off-path chest teaches "exploring pays"; board the pad.
- The Fight — crack a chest, the pop pulls a listener, hold your ground (the ⭕ circle fights automatically), then walk up behind a second goblin that's facing away and crit it. Grants the Whisper Dagger. Every lesson is placed on verified noise/sight geometry — the listener sits in the pop band but out of engage range; the stalk target sits beyond every fight-noise radius so it can't be spoiled.
- The Descent — a Gatekeeper bars the 👑 descend portal. Dash through its wind-up, circle behind, kill it with the dagger you just earned. Teaches the two-door rule in one screen.
- Design notes. The dash lesson moved to the Gatekeeper (lead call): trash dies too fast to ever demonstrate a wind-up, so teaching dodge against it was a lesson about nothing. The stealth stages (Unseen, Heard) and the vault stage retire — the vault teaches itself later via the existing key/gate nudges.
- The 7-stage table is parked, not deleted (
TUTORIAL_LEGACY) — swap back by renaming. - Status. ▣ Verified.
10. UI & readability¶
| Change | Flag | Note |
|---|---|---|
| Minimap shows objectives only — chests, exits, closing status; no enemies | ui.minimapEnemies: false |
the big tactical map keeps its blips |
| Engage ring — the peace/war state circle | ui.engageRing: true |
blue peace / gold aiming / red war |
| Alerted cones read hot — brighter red, higher alpha, edge stroke | — | "this one has me" at a glance |
| At-risk + Safe Pocket HUD chips | — | §7.6 |
| Threat arrows debut on floor 2 | prog.arrowsFromStep: 1 |
B1F1 is pure loot-and-fight, no HUD pressure |
| Frozen-cone highlight | — | removed entirely after playtest — the aim line was doing the job |
| "Raid/Dive Again" leads the death screen | — | lobby demoted to secondary |
| Detection UI | — | binary only: ❗ locked / ? searching / nothing |
11. Everything that was turned OFF or removed¶
| Thing | State | How to restore |
|---|---|---|
| Storm finale (HP drain, cataclysm) | off | extraction.stormFinale: true |
| Timer death | off under the dive | dive.enabled: false |
| Gradual detection fill / suspect state | dropped forever | combat.aggroOnly: false (whole pipeline) |
| Mutual-sight fire gate | off | combat.mutualSightFire: true |
| Out-of-combat HP regen | zeroed | player.hpRegen |
| Rooted potion channel | off | player.potionChannelTime > 0 |
| Stamina cost on dodge | off | action.dashFree: false |
| Tap-to-move / double-tap sprint / swipe-dodge | off | action.enabled: false |
Startle beat (mobReact) |
removed | — |
| Frozen-cone highlight | removed | — |
| Enemies on the minimap | off | ui.minimapEnemies: true |
| Ladder reset on death | already gone (pre-pivot) | — |
| 7-stage FTUE | parked as TUTORIAL_LEGACY |
rename the table |
| In-run Loot Station (manual Safe Pocket, dump/inspect) | still parked | loot.inRunInventory: true |
12. Known risks and open questions¶
- ⚠ Five card effects are inert.
Bloodletting,Quickstep,Steady Hands,Wide Magnetwrite player fields no system reads yet. Each category still has at least one fully live card, so the pick is never empty — but a player choosing Steady Hands gets nothing. Deliberate: the plan says wire them only if the card system survives your verdict. - ⚠ The economy re-slope is unmeasured. Income at depth dropped ~4× in one pass. It could now be too slow.
- ⚠ Contested-objective rival escalation (§5.4) is the one Tier-0 path never confirmed in play.
- ⚠ HUD declutter never happened — the pivot plan calls for removing the stamina ring and detection vignette; the new at-risk/Safe-Pocket chips were added on top.
- ⚠ The boss wall + blueprint flood (§8.4) is unresolved and is the biggest single threat to the pivot reading well in a fresh test.
- Depth-bonus / bank-early balance is the open tuning question. The one ratio to watch: banked value from a bank-on-floor-1 run vs a full dive to floor 5. If a full dive is worth more than ~3× a shallow bank, the shallow bank is dead content. And the behavioural version of the same question: do you ever actually take a safe exit early? In the first playtest, the answer was once, and only to dodge the boss — which is what triggered the re-slope.
13. Your decision sheet¶
Tick one per row. Anything marked cuttable was built to be removable without touching the rest.
| # | Feature | Cuttable? | Keep | Tune | Drop |
|---|---|---|---|---|---|
| 1 | Floating joystick + Action Button dash | no (foundation) | ☐ | ☐ | ☐ |
| 2 | Sponge retired (fast TTK) | flag | ☐ | ☐ | ☐ |
| 3 | Always-on flank crit + turn-rate windows | flag | ☐ | ☐ | ☐ |
| 4 | Charged-shot track→lock→release grammar | no | ☐ | ☐ | ☐ |
| 5 | Body-block (solid enemies) | flag | ☐ | ☐ | ☐ |
| 6 | Stealth-lite perception | flag | ☐ | ☐ | ☐ |
| 7 | Engage range + ring | flag | ☐ | ☐ | ☐ |
| 8 | Peace / War | flag | ☐ | ☐ | ☐ |
| 9 | Rival neutrality + tap-to-MARK | flag | ☐ | ☐ | ☐ |
| 10 | Safe crossfire (GDD deviation) | flag | ☐ | ☐ | ☐ |
| 11 | Opportunist rivals | flag | ☐ | ☐ | ☐ |
| 12 | Closing extractions (no timer death) | flag | ☐ | ☐ | ☐ |
| 13 | Guarded descend portal | flag | ☐ | ☐ | ☐ |
| 14 | 3-minute floors | knob | ☐ | ☐ | ☐ |
| 15 | THE DIVE — two doors, haul compounds | master flag | ☐ | ☐ | ☐ |
| 16 | Depth bonus | knob | ☐ | ☐ | ☐ |
| 17 | Upgrade cards (1 of 3) | yes — GDD marks it cuttable | ☐ | ☐ | ☐ |
| 18 | Automatic Safe Pocket | knob (safeSlots: 0 = off) |
☐ | ☐ | ☐ |
| 19 | Salve cap (leave on ground) | knob | ☐ | ☐ | ☐ |
| 20 | Loot abundance + first-floor generosity | knobs | ☐ | ☐ | ☐ |
| 21 | Enemy intro re-slope | knobs | ☐ | ☐ | ☐ |
| 22 | 3-stage FTUE | swap back | ☐ | ☐ | ☐ |
| 23 | Objectives-only minimap | flag | ☐ | ☐ | ☐ |
Every value above is editable live in Developer → 🎛 Tuning and persists to localStorage.
"Re-roll run" re-applies spawn/density/layout values; map size needs a page reload.