Restructure balancing docs into docs/balancing/

Split the cluttered progression_design.md and content_design.md into
separated documents by role:

- docs/balancing/rules.md    - design rules and principles (moved from
                               progression_design.md, which is removed)
- docs/balancing/targets.md  - the chosen base numbers: run shape,
                               factory curve, threat ladder (achieved
                               values adopted), combat anchors, pacing
                               anchors
- docs/balancing/derived.md  - current tuned state of all derived
                               numbers, mirroring the configs
- docs/balancing/process.md  - pass order, tuning discipline learned in
                               arena rounds 1-5, tools, next-round
                               checklist
- docs/balancing/history.md  - chronological record: decisions, numbers
                               pass, calculator bugs, arena rounds,
                               pacing pass
- docs/balancing/README.md   - index, status, open action items (moved
                               from progression_design.md)

content_design.md slims back down to actual content: footprint gating,
hull grids, gating matrix (module names updated to railguns), and the
production tree structure with its fiction - numbers, anchors, arena
logs, and pacing all moved to docs/balancing/. Stale references in the
config comments updated to the new locations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
This commit is contained in:
2026-07-06 17:12:25 +02:00
parent dcc6af123f
commit b4fa3e6dff
10 changed files with 604 additions and 543 deletions

164
docs/balancing/derived.md Normal file
View File

@@ -0,0 +1,164 @@
# Derived Values (current tuned state)
Everything here is derived from `targets.md` under the rules in
`rules.md`, and mirrors the config files. Item threats, ship threats,
ratios, and belt checks are verified by `tools/threat_report.py` — re-run
it after any recipe or material change and update this file when values
move. Combat stats were tuned empirically against the arena suite in
`bin/balancing/data/balancing.toml` (round-by-round record in
`history.md`).
## Economy constants
- `scrap_per_threat = 0.25` — 1 scrap per 4 threat destroyed (a cruiser
kill drops ~59 scrap); threat(scrap) = 4.
- Scrap smelting: 1 scrap → 1 iron_ingot, 1 s — deliberately
value-losing; reprocessing is the value-preserving path.
- Reprocessing: 4 scrap per cycle, 4 s; full-pool weights iron_ingot 30 /
copper_ingot 30 / silicon 20 / voidsteel 20 → threat(voidsteel)
= (4·4 + 4)/0.2 = 100.
- `scrap_despawn_seconds = 120` (a capital kill drops hundreds of scrap,
collected one per salvage cycle).
## Recipes and item threats
(dur in seconds; threat is per output unit)
| item | recipe | dur | out | threat |
|---|---|---|---|---|
| iron_ore / copper_ore | miner | 1 | 1 | 1 |
| quartz | miner (deposit) | 2 | 1 | 2 |
| iron_ingot | 1 iron_ore | 1 | 1 | 2 |
| copper_ingot | 1 copper_ore | 1 | 1 | 2 |
| silicon | 1 quartz | 2 | 1 | 4 |
| steel_plate | 2 iron_ingot | 3 | 1 | 7 |
| copper_wire | 1 copper_ingot | 1 | 2 | 1.5 |
| copper_coil | 2 copper_wire | 1.5 | 1 | 4.5 |
| building_block | 2 steel_plate | 2 | 4 | 4 |
| control_chip | 1 silicon + 2 copper_wire | 5 | 1 | 12 |
| capacitor_bank | 2 copper_coil + 1 silicon | 5 | 1 | 18 |
| hardened_steel | 3 steel_plate | 12 | 1 | 33 |
| ceramic_plate | 2 quartz | 4 | 1 | 8 |
| drive_unit | 2 steel_plate + 2 copper_coil + 1 control_chip | 8 | 1 | 43 |
| voidsteel_plate | 1 voidsteel + 1 hardened_steel | 8 | 1 | 141 |
| capital_core | 2 voidsteel + 1 capacitor_bank + 1 control_chip | 10 | 1 | 240 |
Shortcut recipes (drop-only; item threat stays defined by the base path
via the max rule): `shortcut_steel_plate` 3 iron_ore → 1 plate (2 s,
level 1), `shortcut_control_chip` 2 quartz → 1 chip (4 s, level 2),
`shortcut_hardened_steel` 4 iron_ingot → 1 hardened (8 s, level 2).
Ratio curve realized: t1 all 1:1 (miner:smelter); t2 clean 2:3
(ingot→plate, wire→coil); t3 strange — 2:5 (silicon→chip), 3:5
(coil→capacitor), 3:4 (plate→hardened, plate→drive); t4 inverted 3:2
(hardened→voidsteel_plate). Belt check: worst input demand 1.33 items/s,
under the ~2/s single-belt cap everywhere.
## Module prefabs
(contribution = item threat + module production time)
| module | recipe | dur | mod. time | contribution |
|---|---|---|---|---|
| railgun_s | 1 copper_coil | 1 | 1 | 6.5 |
| salvager | 1 steel_plate + 2 copper_wire | 2 | 1 | 13 |
| repair_tool | 1 steel_plate + 2 copper_wire | 2 | 1 | 13 |
| armor_plates | 4 steel_plate | 3 | 1 | 32 |
| maneuvering_thrusters | 1 steel_plate + 1 copper_coil | 2 | 1 | 14.5 |
| sensor_booster | 2 copper_wire + 1 copper_coil | 2 | 1 | 10.5 |
| afterburner | 2 copper_coil + 1 steel_plate | 3 | 1 | 20 |
| weapon_stabilizer | 1 steel_plate + 1 copper_coil | 2 | 1 | 14.5 |
| weapon_primer | 1 capacitor_bank + 1 copper_coil | 4 | 2 | 28.5 |
| weapon_upgrade | 1 control_chip + 1 copper_coil | 4 | 2 | 22.5 |
| railgun_m | 1 capacitor_bank + 2 steel_plate + 1 copper_coil | 4 | 3 | 43.5 |
| drone_bay | 1 control_chip + 2 steel_plate + 1 copper_coil | 4 | 3 | 37.5 |
| railgun_l | 1 capacitor_bank + 2 hardened_steel + 1 ceramic_plate | 6 | 4 | 102 |
| drone_hangar | 1 voidsteel_plate + 2 control_chip + 1 drive_unit | 10 | 6 | 224 |
## Ships
(fitted = hull item + ship base time + default loadout; the default
loadouts are the `default_modules` used by enemy waves and are
geometry-validated against the hull grids)
| ship | hull recipe | dur | base | default loadout | fitted |
|---|---|---|---|---|---|
| drone | 1 iron_ingot | 1 | 1 | railgun_s | 10.5 |
| frigate | 2 steel_plate + 1 copper_wire | 2 | 2 | 2× railgun_s, maneuvering_thrusters | 47 |
| destroyer | 3 steel_plate + 2 copper_coil | 4 | 3 | 3× railgun_s, armor_plates, sensor_booster | 99 |
| cruiser | 2 hardened_steel + 2 control_chip | 6 | 4 | 2× railgun_m, armor_plates, maneuvering_thrusters | 233.5 |
| battlecruiser | 3 hardened_steel + 2 control_chip + 1 drive_unit | 8 | 5 | 3× railgun_m, armor_plates, 2× railgun_s | 354.5 |
| battleship | 3 voidsteel_plate + 1 drive_unit + 2 control_chip | 10 | 6 | railgun_l, 2× railgun_m, weapon_stabilizer, 2× railgun_s | 722.5 |
| dreadnought | 5 voidsteel_plate + 1 capital_core + 2 drive_unit | 12 | 8 | 3× railgun_l, 4× armor_plates, railgun_s | 1491.5 |
| carrier | 5 voidsteel_plate + 1 capital_core + 2 drive_unit | 12 | 8 | drone_hangar, 2× railgun_m, 2× armor_plates, sensor_booster | 1436.5 |
## Combat stats
(arena-converged, 2026-07; see `history.md` rounds 15)
**Weapons:** railgun_s 2 dmg × 2.0 Hz (4.0 DPS), range 50 m;
railgun_m 14 × 1.5 (21), range 70; railgun_l 52 × 0.8 (41.6), range 100.
**Hull HP** (15/threat prior + empirical trims): drone 60, frigate 300,
destroyer 550, cruiser 1500, battlecruiser 2400, battleship 6300,
dreadnought/carrier 24000.
**Mobility ladder** (speed m/s | main accel | maneuvering | angular |
max rot): drone 45|60|30|12|6, frigate 35|45|22|8|4,
destroyer 30|35|18|6|3, cruiser 24|25|12|4|2, battlecruiser 20|20|10|3|1.5,
battleship 15|14|7|2|1, dreadnought/carrier 10|8|4|1|0.5.
Sensors: 150/200/220/250/260/280/300/350 m.
**Other modules:** armor_plates +1200 HP; repair_tool 9 HP × 1 Hz,
range 80; salvager range 60, cargo 20, 0.5 collections/s; afterburner
×1.6 speed +60 accel; maneuvering_thrusters ×1.2 speed +10 maneuvering;
sensor_booster +50 m; weapon_upgrade ×1.2 damage; weapon_primer ×1.2
rate; weapon_stabilizer ×1.3 range ×0.8 rate.
**Stations:** HQ 5000 HP. Player station 3000 HP, 25 dmg × 1 Hz,
range 120, scrap 40. Enemy station: 3000+1500x HP, 25+12x dmg,
1.0+0.1x Hz, range 120, scrap 40+30x (x = push level).
## Pacing
**Unlock ladder** (level → unlocks; ← marks `unlock_requires`; starting
set at 1: drone, frigate, railgun_s, salvager, building_block recipe):
| level | ships | modules | recipes |
|---|---|---|---|
| 0 | destroyer | repair_tool, armor_plates | |
| 1 | | maneuvering_thrusters, sensor_booster | shortcut_steel_plate |
| 2 | cruiser | railgun_m, afterburner | shortcut_control_chip, shortcut_hardened_steel |
| 3 | | weapon_stabilizer | |
| 4 | battlecruiser ← cruiser | weapon_primer, weapon_upgrade | |
| 5 | | drone_bay | |
| 6 | battleship ← battlecruiser | railgun_l ← railgun_m | |
| 8 | dreadnought ← battleship | | |
| 9 | carrier ← battleship | drone_hangar | |
Level 0's pool has exactly three entries (a full first dialog). Level 2
is the quartz gate: cruiser and railgun_m are the first schematics whose
chains reach quartz; the shortcut outputs only become implicitly
unlocked alongside them, so shortcuts cannot drop early.
**Threat rate** `2*x + 0.15*x*x` (x = boss cycle counter), against the
factory-size curve with ~half the player's output assumed military:
| cycle x | rate (threat/s) | player military (≈ curve/2) |
|---|---|---|
| 2 | 4.6 | ~12 |
| 6 | 17.4 | ~30 |
| 15 | 63.8 | ~60 |
| 20 | 100 | ~75 |
| 24 | 134 | — |
**Economy:** `starting_building_blocks = 200`; expansion cost formula
`300 + 50*x + 10*x*x` (x = expansions already purchased: ~1 affordable
per cycle mid-game at ~1/3 of block income, stretching to 23 cycles
late — quadratic so costs outrun the roughly linear block income
gradually, never with a hard wall); `artifact_win_count = 5` with
`artifact_chance_formula = 0.05*x`. Building costs: belt 2, splitter 3,
tunnels 5, miner 15, smelter 20, assembler 35, reprocessing plant 40,
salvage bay 25, shipyard 60 — averaging ≈18 blocks per placed building
(belts included), which meets the 4-minute doubling target at block
threat 4.