Updated 2026-09-03.
The system as it stands. FASA-style power model: one pool per ship per
turn; movement, beams, missile arming and special systems spend from it;
shields absorb damage out of the residue, capped per facing per round. Ships
move forward along their facing, turn at a class rate, and fire only mounts
whose arcs bear. Turns are three rounds and each weapon fires at most once per
turn. Fleets deploy in one or more line-of-battle ranks. Ships can share a hex
but cannot fire at one another there. Destroyed ships may detonate. The live
engagement area is a bounded 72×40 rectangle; mapRadiusHexes remains only as
a compatibility fallback for old replays. Scenarios may add planets, moons,
large asteroids, asteroid fields and nebulae. The editor, replay viewer and
one-side-vs-AI playfield all use the same headless engine.
Hulls and points. Corvette 1 (ZAN only) / FF 2 / DD 4 / Krelath Strike
Cruiser 8 / CL 10 / CA 16 / BB 32, with special hulls EAR Dreadnought 16,
VRA Monitor 20 and Krelath Carrier 16. Dreadnought, Monitor and Carrier are
limited to one and require a 52-point fleet; the Strike Cruiser requires 32.
The Earth Command Ship is retired from the roster and remains in
hullClasses only so old replays load. data/tactical-tuning.json rosters
and hullClasses.*.points are authoritative.
Factions. EAR: best shields, long accurate lasers, nose-heavy arcs and the Yamato’s photonic cannon. VRA: thickest hulls, weakest shield efficiency, heavy blasters and fire on every bearing; their Monitor is a slow siege hull. ZAN: poor shields, tough and fast hulls, mixed weapons, emergency manoeuvre and corvette swarms. KRE: short brutal guns, plasma, the rear-insertion warp jump, fast Strike Cruiser and standoff Carrier with persistent strike craft. No cloak currently exists in play; cloak/detection scaffolding is dormant.
Balance method. node test/fleet-trial.js sweeps the six current harness
budgets, 4 / 18 / 32 / 52 / 68 / 132, and a 52-point equal-shape matrix.
test/buy.js, test/probe.js, test/scan.js and test/xp.js provide focused
buy-value, strike-system and tuning diagnostics. Sections below are a dated
decision log: old ladders and measurements remain historical evidence, not
current rules. Re-run a sufficiently large seeded sweep before treating a
balance cell as settled.
Living document. Captures decisions settled in design conversation; supersedes the rev. 1 brief where they conflict. Original design — no licensed material. Lineage is acknowledged (FASA STCS, Star Fleet Battles) but nothing is copied.
| Power | Code | Colour | Beams | Missiles | Cloak | Shields | Hulls |
|---|---|---|---|---|---|---|---|
| Earth Federation | EAR | Blue | Laser cannons | Neutronic | No | Excellent | Average |
| Vraygon Star Realm | VRA | Gold | Heavy blasters | Neutronic | Light hulls only | — | Sturdiest |
| Zandrax Horde | ZAN | Red | Laser cannons | Neutronic + Plasma | No | Poor | Strong |
| Krelath Empire | KRE | Green | Blaster beams | Plasma* | Yes | Average | Average |
*Krelath heavy cruiser is the exception: neutronic missiles instead of plasma.
Note the pattern — blasters go to both cloaking powers, lasers to both uncloaked ones. Blasters and plasma are short-range weapons; a cloaked ship closes and strikes on decloak. Doctrine and armoury agree.
Earth: disciplined line fighter, standoff weapons, arcs cover the rear (frigate mounts a single 360-degree beam). Krelath: pure ambusher, nothing that reaches. Arcs 90-180 degrees forward. Vraygon: close-quarters bruisers with a standoff opener. They begin the engagement at range with neutronic missiles, cross under fire on the sturdiest hulls in the game, and finish with the heaviest short-range gun anyone fields — the heavy blaster, brutal inside 4 hexes and useless past 6. Their cloak covers only the light hulls, so the battle line walks in openly while its screen is hidden.
Vraygon’s heavy cruiser is a missile boat: its beam and missile counts are inverted against the class envelope (3 beams / 5 missiles) with an enlarged magazine. This is faction flavour, not a change to the heavy cruiser class — the other three powers keep the standard 5 beams / 3 missiles. Loadouts may override the class envelope for exactly this kind of character. Zandrax: mixes all three weapon types. No signature weapon, cannot be countered by preparing for one threat. Grinds.
Models live in assets/models/, five hulls per power.
Beams — no ammunition, variable power investment up to a maximum, damage modified across four range bands.
Missiles — finite magazine, fixed power cost to arm, interceptable.
Points double per class. The class sets a maximum envelope; each design fills it differently, which is what makes “destroyers may mount one missile” work.
| Class | Pts | Cores | Beams | Missiles | Magazine | Screen | Point defence | Assault |
|---|---|---|---|---|---|---|---|---|
| Frigate | 1 | 1 | 1 | 0 (hard) | — | 1 | light | no |
| Destroyer | 2 | 1 | 2 | 0-1 | small | 2 | light | no |
| Light Cruiser | 4 | 2 | 3 | 1-2 | medium | 3 | medium | no |
| Heavy Cruiser | 8 | 2 | 5 | 2-3 | large | no | no | yes |
| Battleship | 16 | 4 | 8 | 4-5 | large | no | no | yes |
Mounts grow ~1.6x while points double. A swarm out-shoots a capital ship on raw mounts but dies faster and cannot take a world. Planetary assault is inherent to CA and BB. Screening and point defence live on FF/DD/CL — the light hulls are how a fleet survives a missile alpha strike.
Reference fleet at 24 points: 1 CA + 2 CL + 2 DD + 4 FF. Nine ships, eight screening hulls, and exactly one assault-capable ship — kill it and the fleet wins every exchange in space and still takes nothing.
A frigate does not mount the battleship’s gun. Each class carries a smaller
mark of the same weapon, with weaponReach scaling both maximum range and the
range-band boundaries: frigate 0.50, destroyer 0.62, light cruiser 0.75, heavy
cruiser 0.88, battleship 1.00. An Earth laser reaches 9 hexes on a frigate and
18 on a battleship.
This follows the FASA pattern, where a beam type appears in successive marks of growing reach, and it is the answer to light hulls out-fighting capitals on equal-reach fire: a capital can now hold a range its lighter opponents cannot answer. It also gives the standoff AI something to work with — out-reaching an enemy is now a real advantage that a ship will manoeuvre to keep.
Six shields, one per hex side. Side facing — a distinct forward shield. Numbered clockwise from front-left: #1 front-left, #2 forward, #3 front-right, #4 rear-right, #5 rear, #6 rear-left.
Each shield is allocated power per turn, up to a maximum. Power converts to shield points at the ship’s shield point ratio — this is where faction character lives. Earth’s excellent shields are a favourable ratio, not bigger raw numbers. Same power in, different protection out.
Engine cores generate power. Cores are a rules abstraction; the visible engine pods on the 3D models are cosmetic and carry no power meaning. Every ship also has an impulse engine. Core capacity scales with class, so a battleship’s four cores are individually larger than a frigate’s one.
Each turn every ship allocates its available power across four categories: movement, shields, weapons, cloak.
Power converts to movement at the ship’s movement point ratio.
Engine damage reduces available power directly, which gives big ships graceful degradation and small ships brittleness: a battleship losing one of four cores fights on at three-quarters budget; a frigate losing its single core is finished. Sixteen frigates have sixteen single points of failure. This is the efficiency advantage that concentration of force ought to have.
Three separate pools:
Individual weapon mounts can be damaged, repaired, or knocked out.
Shields regenerating while superstructure does not is what makes Earth and Zandrax feel different rather than being the same ship with numbers moved around. Earth shrugs off sustained fire from a direction it prepared for and rebuilds between turns. Zandrax lets damage through to a deep structure it can never recover. Earth wins engagements it controls the geometry of; Zandrax wins ugly ones.
Power to cloak scales with hull size, calibrated so that cloak and weapons are an either/or choice at every class. In effect the cloak occupies the weapons slot in the power budget: a cloaked ship of any size has given up its guns, and on decloak that exact budget returns as weapons fire.
Movement and shields are unaffected. A cloaked ship is not weakened generally — it is specifically disarmed. It manoeuvres and shields normally while invisible, which makes cloak a pure positioning instrument: all that power buys is where you are when you appear.
Because the cost scales, Vraygon’s restriction to light hulls is a categorical capability limit, not an economic one. Their capitals do not carry the device at all; it is not that they cannot afford to run it.
A cloaked ship cannot fire. This is a hard prohibition, not merely an economic pressure — firing would reveal position, and the cloak already taxes the power systems. It holds even if a ship somehow has weapon power to spare.
Two consequences follow without needing separate rules. A cloaked ship cannot run point defence, because interception is firing. And it cannot screen, because screening means presenting yourself as a target and a cloaked ship is not visible to be targeted. Cloak therefore removes a ship from the defensive economy entirely.
For Vraygon this is the central per-turn decision: cloak the escorts and they contribute nothing to fleet defence, or decloak them and they screen and intercept but are visible. Hidden or protective, not both.
Decloaking occupies a combat turn, but the power reallocation from cloak to weapons happens on that same turn — so the guns charge while the ship is uncloaking rather than costing a second turn afterwards.
Sequence: turn N cloaked and manoeuvring into position; turn N+1 decloaks, shifting the cloak budget into weapons, exposed and unable to fire; turn N+2 opens fire with a full weapons budget.
The defender therefore gets exactly one turn of warning. That single turn is the entire counterplay against ambush.
Detection costs no power but consumes a combat turn, and it is directional: the scanning ship picks one of its six numbered shield faces and sweeps the arc originating there. Guess the wrong arc and the turn is spent for nothing.
You can always look; you cannot look and shoot. Both sides pay: the cloaked ship gives up its guns, the hunting ship gives up its turn. Hunting a cloaked fleet is expensive, which is what keeps cloak worth its cost.
Range is limited to 10 hexes. Beyond that the cloak simply holds — a cloaked ship crossing open space at distance is undetectable by any means. Ten hexes is the contested approach: the band an ambusher must cross while vulnerable to being found.
A successful detection informs all friendly forces. One scanner protects the whole fleet, so the scanning tax is a few dedicated hulls rather than every ship looking for itself.
A successful scan pays twice over — it finds the enemy and tells you which shield facing to pour power into before the strike lands.
Detection persists, but is breakable. Once found, a cloaked ship stays found until it escapes. Each turn a detected cloaked ship may roll to evade, and a success loses it to the scanner again.
The evade roll resolves before movement, which makes a successful break clean: the hunter loses contact and only then does the cloaked ship move, so its new position is unobserved. Fail the roll and it moves under observation, handing the defender both its bearing and the shield facing to reinforce.
That gives a detected ambusher a real decision each turn — press the approach while visible, or spend the turn trying to disappear and start the approach over.
The two cloaking powers differ by distribution, not by rule — same mechanic, fitted to different hulls.
This also splits the two powers’ intel texture on the campaign map: a Krelath fleet is simply absent from foreign sensors, while a Vraygon fleet reports as capitals only, with unknown escort strength.
Assembled from rules settled so far; ordering beyond the evade/move relationship is inferred and needs confirmation.
Captain’s skill rating, crew efficiency rating, weapon damage factor. Casualties degrade the ship progressively, with a threshold beyond which it cannot fire at all.
data/factions.json predates all of this. It carries flat beam/torpedo
scalars, costs of 4-25 rather than the 1/2/4/8/16 ladder, blasters wrongly on
Zandrax, and no cloak on Vraygon. Rewrite it once the numbers above land.
node test/fleet-trial.js runs point-buy fleets against each other and reports
win rates. --watch EAR KRE narrates a single battle. Seeded throughout, so
any result reproduces.
| Power | Win rate |
|---|---|
| Earth Federation | 95% |
| Zandrax Horde | 69% |
| Krelath Empire | 33% |
| Vraygon Star Realm | 2% |
The structural finding: short-range weapons without full cloak are unplayable. Earth’s laser cannons reach 15 hexes and Zandrax’s the same, so both can fight at a distance the blaster powers cannot answer. Krelath survives it by cloaking every hull and choosing the engagement. Vraygon cannot — their capitals must cross open ground under fire carrying an 8-hex weapon — and they sit at 2%.
Vraygon holds the worst structural position in the game: the short-range armoury without the cloak that justifies it. This is a design question rather than a tuning one. Options include giving them laser cannons, extending blaster reach, widening their capitals’ missile armament, or granting the capitals some other compensation entirely.
Equal points, different shapes, Earth on both sides:
| 1 BB | 2 CA | 4 CL | 8 DD | 16 FF | |
|---|---|---|---|---|---|
| 1 BB | – | 54% | 100% | 100% | 100% |
| 2 CA | 0% | – | 100% | 100% | 100% |
| 4 CL | 0% | 43% | – | 100% | 100% |
| 8 DD | 0% | 24% | 100% | – | 100% |
| 16 FF | 0% | 0% | 42% | 99% | – |
Strictly transitive, big beats small, and overshot in the opposite direction from the first draft. Before the rebalance eight destroyers beat everything; now sixteen frigates lose to one battleship 100-0, because a frigate beam does 4 damage against a 44-point shield facing that fully regenerates each turn. Small ships literally cannot scratch a capital.
The sweet spot is between the two runs. The dial is the ratio of capital shield capacity to light-hull damage output — currently far too wide.
Six research agents read the public record on the FASA factions. The findings were largely a critique of what we had built, and several reversed our choices.
Two of our four Vraygon pillars matched and two did not. Sturdiest hulls: yes, best-evidenced fact about them. Close-quarters bruiser: half — FASA Gorn want the close brawl for an arc reason, not because they own a short-range gun; their beams reach about as far as a Federation phaser of the same era. Standoff missile opener: no, and inverted — FASA’s Gorn were the faction that got out-ranged, and FASA has no ammunition-limited weapon anywhere. Heaviest short-range gun: no — in FASA that is unambiguously the Romulan plasma launcher, which is our Krelath. We had given the same signature to two powers.
The FASA Gorn distinctive is arcs, not range. Every other power concentrates firepower in the nose. The Gorn spread their guns into four wide quarter-arcs with no straight-ahead position at all. Vraygon are now the power with no blind side: quarter-arc beams, missile tubes fore and aft, no privileged bearing. You can flank a Vraygon; it will not help you.
The research is blunt that FASA did not solve our problem either. Its Federation dominated for exactly our reasons — best shields, longest reach, most power, no cloak tax — and contemporary players describe the game collapsing into “park at optimum range and trade dice.” Its Romulans were the weakest major by a wide margin, and the cloak cost 55-73% of the power pool: never cloaking meant playing an undercosted ship, always cloaking meant playing one with half its stats switched off. Our Krelath sat at 33% for the same reason.
So we should not expect to inherit a solution. The per-facing damage tables are the one mechanism FASA had that genuinely rewards crossing open ground, and we have now taken it.
Two settings, each good at one objective and bad at the other:
Faction balance and fleet-shape balance are currently pulling against each other through the same lever. That is the open problem.
Ships previously moved with complete freedom: each picked the nearest enemy and closed at its own speed. Since movement costs differ by a factor of six across the classes, a mixed fleet arrived piecemeal every battle — frigates were in contact on turn one while the heavy cruiser was still four hexes back, and the fleet was beaten in detail. Screening, which needs ships within two hexes of what they protect, was only ever half-covering and collapsed to nothing by the midpoint.
Both human and AI commanders would at least try to hold formation, so the AI now does. Escorts hold station on the capital they screen, and no ship advances more than a cohesion radius ahead of the fleet’s centre of mass. Measured effect: screen coverage of the capital rose from 2 (decaying to 0) to a steady 3, and fleet spread tightened from 8 hexes to 2.
That change cost turns. A formation-keeping fleet closes at the pace of its slower elements, and a 24-hex approach on a 12-turn clock began timing battles out before contact — Earth against Krelath drew 94% of the time. The approach is now 16 hexes on a 16-turn clock.
Scenarios run from about 2 points to 64 or more, so the harness now sweeps six sizes rather than testing one. Compositions scale from two frigates up to a 64-point fleet of 2 BB, 2 CA, 2 CL, 2 DD and 4 FF.
This immediately falsified the idea that one balance number describes the game. Win rates by scenario size:
| points | EAR | VRA | ZAN | KRE |
|---|---|---|---|---|
| 2 | 55% | 2% | 40% | 23% |
| 8 | 17% | 26% | 47% | 92% |
| 16 | 68% | 33% | 71% | 5% |
| 24 | 73% | 40% | 58% | 23% |
| 32 | 78% | 52% | 57% | 4% |
| 64 | 86% | 76% | 38% | 1% |
Krelath are dominant in small actions and worthless in large ones — 92% at eight points, 1% at sixty-four. The mechanism is clear once stated. A cloaked ship cannot fire, so cloaking a whole force switches off all of its firepower during the approach. In a small action that is two or three ships hiding for a couple of turns, and the ambush pays. In a large action it is a dozen ships contributing nothing while a dozen enemies shoot, and the bigger enemy fleet also fields more sensors to hunt with. The cost of the cloak grows with fleet size while its payoff does not.
This is a structural property of the cloak rules as ruled, not a tuning error, and no adjustment to the evade chance or power fraction will remove it. If Krelath are to work at every scenario size, the cloak probably needs to be partial — a force that hides part of itself while the rest fights — rather than all-or-nothing across the fleet.
Vraygon show the inverse and milder version: weakest at 2 points, strongest at
Each power now has one unique sixth hull, carrying its doctrine as a capability
rather than a stat modifier. Models for all four are in assets/models/.
| Power | Hull | Pts | Character |
|---|---|---|---|
| Zandrax | Corvette | 0.5 | Soviet-tank doctrine: cheap, numerous, one short heavy gun, almost no shields, and a x3 explosion yield |
| Krelath | Dimension Submarine | 4 | The only cloaking hull in the game |
| Vraygon | Monitor | 16 | Silicoid siege hull: 221 structure, guns on every bearing, 14.5 power per hex |
| Earth | Command Ship | 8 | +1 to hit and extended detection for friendlies within 6 hexes |
Two new mechanics came with them. Ships detonate when destroyed, damaging neighbours in proportion to the power left in their engines over distance — a healthy ship is a bomb, a gutted one fizzles. And command ships coordinate, which makes the counter to the submarine a purchase rather than a free trait.
Restricting cloak to the submarine does what it was meant to: a fleet no longer switches off all its firepower during the approach, so the cost of cloaking scales with the points committed to it rather than with fleet size.
It also removed Krelath’s entire identity, and nothing of comparable value replaced it. Faster engines and slightly better shields do not compensate for losing the ability to choose every engagement. Krelath now sit at 4% overall.
Worse, their own sixth hull makes them weaker. Measured at 24 points:
| opponent | Krelath with submarine | Krelath without |
|---|---|---|
| Earth | 0% | 1% |
| Vraygon | 1% | 26% |
| Zandrax | 0% | 5% |
Trading a fighting light cruiser for a hull that hides and never fires is a straight downgrade. A cloaked ship contributes nothing while hidden, so it only pays if the ambush it eventually delivers is worth more than four points of guns for the whole battle. As costed, it is not close.
Krelath need a replacement fleet-wide identity. One hull cannot carry a faction. The options, none of which the build should choose unilaterally:
Krelath’s replacement fleet-wide identity, standing in for the cloak that moved onto the submarine.
Once per turn a Krelath ship may spend 30% of its power pool to reposition up to 9 hexes, arriving by preference in the target’s rear arc. The jump takes the ship’s action for that round, so the guns come to bear the following round of the same turn.
It answers precisely the two things that were killing them:
The old cloak identity was choosing whether to engage. This is choosing where you appear in an engagement, paid for in guns rather than in silence. It is louder, more aggressive, and more Krelath.
Measured effect at 24 points: 4% → 13% on the warp alone, then 23% once the submarine was re-costed. At 32 points all four powers now fall between 33% and 54%, a 22-point spread and the tightest yet recorded.
Dropped from 4 points to 2, with stats trimmed to match. The measurement was unambiguous: at 4 points, swapping a light cruiser for the submarine cost Krelath 25 percentage points against Vraygon. With the warp carrying the faction identity, the submarine is the scout and flanker you buy on top of it, not the doctrine itself — and it was priced as though it were the latter.
Vraygon at 80-84% in the larger actions: their monitor and all-round arcs look too strong at scale. Earth at 87% in the 2-point skirmish. Krelath at 8% at 64 points, so the warp has not fully solved their large-action problem.
Two of five search agents completed before a session limit stopped the rest. Between them they found five genuine bugs — four in the AI, one in the sim — and their combined result is adopted.
The AI always turned a ship’s nose toward its nearest enemy. So any mount whose arc excluded dead-ahead never fired. Instrumented: the destroyer’s stern beam, the light cruiser’s quarter beam, the heavy cruiser’s aft mount, both battleship stern chasers, most of Vraygon’s broadside — 0.00–0.03 firings per battle. A Vraygon frigate, whose single gun sits in a port arc, could not shoot at all: mirror matches were 100% draws.
Every arc decision made since the FASA research was running on top of this.
Vraygon’s “no blind side” identity, Earth’s soft tail, the monitor’s all-round
battery — none of it was actually being exercised. Ships now turn toward the
heading that brings the most weight of fire to bear (bestHeading), which
makes the arc system real for the first time.
minGain hexes, with a fleet-fraction cap per turn.preferredRange had a floor of 4 hexes, silently stationing short-gun
hulls (Krelath light hulls, the corvette) outside their own best band.Also from measurement: Vraygon’s dominance tracked one hull almost exactly (the six-tube heavy cruiser: 64–78% with it, 27–35% without), and the command ship’s +1 aura scaled from a 4% buy at 24 points to a 93% buy at 64. Both re-statted. The submarine measured 13–43% against a same-cost destroyer at every scale — still a bad buy; its capability has no target since nothing enemy ever cloaks. Open design question.
Mirror matches are fair, the concentration matrix is non-transitive with no degenerate shape, and per-size spreads dropped from 51–86pp to roughly 28–53pp at most sizes. Two clear outliers remain: Zandrax collapse at 32 points (~5%) and Krelath excess at 24–32 (~70–90%). A warp re-price barely moved either, so the levers are elsewhere. Three of the five search agents never ran; the next search session starts from a much sounder foundation.
The Dimension Submarine is removed by ruling. Its epitaph is the measurement:
a hull that hides and never fires is a bad buy at any price in a game where
nothing enemy cloaks to hunt — and its apparent value in earlier trials was a
scoring artifact (a cloaked survivor banking its points at the tiebreak while
contributing nothing). No hull in the game now carries a cloak. The cloak
and detection rules remain written and dormant; the model is repurposed:
Krelath Dimension Submarine.stl is renamed Krelath Strike Cruiser.stl and
serves as the strike cruiser’s model.
Krelath’s sixth hull is now the strike cruiser: a missile-dominant light cruiser with real legs — 4 points, 1 beam / 4 tubes, 16-round magazine, movement at 1.2 power per hex against the light cruiser’s 2. With the warp it repositions, launches, and runs.
First measurements: it is a mild negative buy (−4 to −13pp against the light cruiser it displaces), through two loadout variants (pure plasma; 50/50 mix). Handed to a focused diagnose-and-verify workflow rather than more blind iteration; constraints hold it to the ruled spec (4 pts, missile-dominant, fast).
A diagnose-and-verify workflow instrumented the failing hull rather than guessing. Three measured causes, none of them “numbers too low”:
screen: 2 classed the fastest hull in the game as a picket, bolting it
to within 2 hexes of the heavy cruiser and making it unscreenable itself.Rebuild (data only): 3 tubes + 2 beams (still missile-dominant), movement 1.5 (still fastest cruiser), screen 0 (a light capital the fleet screens), structure 22, paid for with impulse and a point of PD. Like-for-like in the same deployment slot the buy went from −8.6 to +5.5, reproduced by an adversarial verifier on independent seeds.
The verifier also caught a harness artifact worth more than the hull: the sixth hull was APPENDED to compositions and deployment ran in list order, so it always deployed on the extreme flank — a slot measured at ~27pp of win rate against any 4-point hull placed there. Deployment now forms a proper line of battle, heaviest hulls in the centre, wings light. Mirror matches stay fair (30/28/2).
Where it lands: the flank artifact is gone (buy −25 → ≈−9 in fleet context) but the strike cruiser still runs slightly negative against a plain light cruiser at 24 points. The hull is sound like-for-like; the residue is a fleet-composition effect, left for the next balance pass. Sweep after adoption: spreads 27–60pp, worst cells EAR 78% at 32 and KRE 23% at 64.
A three-agent workflow (large-action tuner, small-action tuner, merger with
independent verification) closed the remaining scenario-size outliers.
Every faction now sits inside 35–65% at all six sizes, held on five
independent seed sets at up to 800 battles per pairing. The change set is
data-only — 21 values in tactical-tuning.json, 16 in loadouts.json, the
resolver untouched — so any single change reverts independently.
The diagnoses matter more than the numbers:
Caveat recorded by the merger: the sweep at default --battles gives only
±7pp per cell. Use --battles 450 (150/pairing) as the honest minimum and
--battles 2400 for a definitive table. Thinnest margins: Zandrax 37–39%
at 32 points, Krelath ~60–63% ceiling there.
Hulls below 8 points take a to-hit malus firing at hulls of 8 points and up,
and heavies take the same firing down — small guns cannot hurt capitals,
capital guns cannot track small ships. Config: toHit.classInteraction.
Units are d10 pips; fractional pips resolve probabilistically through the
seeded PRNG, so −0.5 is a true −5%. Beams only — missiles carry no
accuracy roll in this sim, an asymmetry with consequences (below).
Measured at −5% and −10% (both ways, 150 battles/pairing, against the §18 baseline):
Default adopted: −0.5 (−5%) both ways — the gentler setting; the shape matrix keeps its non-transitive texture with no cell below 26%. At −10% the swarm-versus-capital game starts collapsing. If the “capital guns cannot track small ships” half should bite equally, the missile analogue would be a small interception/accuracy penalty for heavy-launched missiles against light hulls — an open option, not built.
toHit.missileClassInteraction: a missile launched by a heavy hull at a light
hull is evaded outright with the configured probability, rolled before
interception — a nimble ship dodging a capital-grade warhead needs no point
defence nearby. One-directional by design; light-launched missiles at big slow
targets need no help. Missiles carry their shooter’s class with them in flight.
Measured at 5% and 10% against the beam-only baseline (150 battles/pairing):
Both dials (classInteraction, missileClassInteraction) are independent
single-value edits if balance needs shading later.
Chris: ships were “sliding around like hockey pucks” — movement had no relationship to heading, because the engine had none. Ruled and built:
A ship moves only straight along its facing, and may turn at most
turnRatePerRound hexsides per round (corvette 3; frigate, destroyer,
strike and light cruisers 2; every heavy hull 1). Turning costs no power —
the cost is tempo, as in FASA. Config: tuning.movement.
Consequences that fall out with no further rules: pursuit becomes banked arcs; capitals wallow through their turns while light hulls dance; a ship that wants to open the range must first turn away, pointing its forward guns off-target — retreat now has a price in fire. The warp jump is exempt (it is dimensional travel, not flight) and Zandrax’s emergency burst spends its free hexes along the facing like any other flight. Momentum (forced carry-over of speed between rounds) is deliberately not in v1; noted as a future dial.
Balance broke along doctrine lines, as it should. At 100 battles/pairing:
Earth collapsed to 17% at 24 points (its kiting doctrine requires facing away,
silencing six of its eight forward guns; its soft tail cannot fight
retreating) while no-blind-side Vraygon rose to 76% (it does not care which
way it flies). Krelath (warp-exempt) and Zandrax held. The full sweep spread
widened to 57–63pp at mid/large sizes. This is the new rules being real, not
a defect — a re-balance pass under the flight regime is the next step, and
the old balanced state remains reachable by movement.coupledToFacing: false.
Viewer: replays re-recorded; all radial-gradient effects hardened against
non-finite coordinates (safeRadial), and arena.js now carries a
cache-busting version query — a stale cached script cost a full debugging
loop chasing a ghost error.
Three-agent workflow; all 24 faction/size cells now inside 35–65%, held on eight independent seed runs and re-verified after adoption (spreads 8–26pp). The change set: ~20 changes across the tuning data plus two faction-neutral resolver changes.
movement.withdrawFireFraction 0.7: opening the range is a decision, not a
reflex — a ship only withdraws if it keeps at least 70% of its weight of
fire while doing so; otherwise it stands and fights. Watching the arena, Chris
saw Earth “retreat to maintain maximum range and get chased down rather than
stick it out in the knife fight” — this rule is that observation, faction-
neutral. The merger rates it one of the two most load-bearing changes
(reverting it breaks five cells).
Two code-intent bugs recorded, deliberately unfixed: poolScaling’s sign
contradicts its comment (but the comment’s intent measures as the worse
game), and the command ship’s sensor/detection ratings buy nothing while no
cloak exists in-game.
Chris: “the Earth needs the Yamato more than ever,” and “a Krelath carrier as a first go.” Both adopted from referee-verified prototype trees.
Earth Dreadnought (8 pts, sixth hull, replacing the command ship): three cores driving a 63-power pool into the photonic cannon — a spinal keel mount that draws the pool off the top for ~4 turns (visibly soft while charging, by the residual-shield model’s own arithmetic), fires one 26-damage shield-bypassing bolt, then vents dark for 2 turns. Aimed by pointing the ship; worst band inside 6 hexes (a keel gun cannot track a knife fight). No stern battery — it cannot withdraw fighting, and per measurement it should not. Killed mid-charge, the capacitor bank goes up with the ship. The referee proved it the only candidate that repairs the balance hole the command ship’s retirement opens (the old hull was secretly Earth’s handicap holding Krelath in band).
Krelath Carrier (8 pts, bought from the heavy cruiser): the strike-craft system adopted engine-wide — squadrons as persistent sub-units (2×6 interceptors, 2×4 bombers), permanent attrition, PD interaction, and a carrier exempt from the withdrawal-fire test because its battery is its wing, which bears on every heading. Krelath keeps the strike cruiser too; fielding policy per scenario size is a harness matter. First measurements: fixes Krelath’s chronic large-action weakness and overshoots (94% at 16, 77-80% at 64), with one beautiful hole — Vraygon’s all-round arcs and armour weather the strikes (30% at 24). A tune-and-verify workflow is bringing it into band.
Maiden battle (dreadnought fleet vs carrier fleet, logged): the cannon charged 20/40/60/72, fired its first historic bolt at point-blank range — and missed (its worst band; the game teaching its own doctrine). Mutual near-annihilation; Krelath’s last ship held the field. Both new systems log fully for the arena.
Merged via git merge-file three-way (both prototypes shared the pristine base): zero conflicts, harness green, both hulls coexist in one engine.
Open: carrier tuning in flight; arena replays to re-record after it lands; models for the two new hulls (the retired command ship model is available for repurposing, Chris’s call); the stale strategic-layer factions.json still awaits its bridge to the tactical roster.
Tune-and-verify workflow, adopted with the verifier’s four conditions. All 72 cells (4 factions × 6 sizes × 3 seed sets) inside 35–65% at 600 battles/pairing, with the dreadnought present — the combined state is the verified state. Data-only: resolver byte-identical.
The diagnosis corrected our story again:
fire() targets the
nearest enemy, and the formation leash held the whole fleet back with the
carrier — it wasn’t hiding behind the line; the line was chained to it.strikeCraft.minFleetPoints: 24 — a carrier requires a 24-point fleet.Honest numbers per the verifier: the carrier is break-even at 24 and 32 points (+1.5 to +3.4pp) and genuinely positive only at 64 (+11pp). It pays for itself at fleet scale; it is not a bargain. Vraygon still beats it (armour + all-round arcs weather strikes) — the matchup texture survived.
KNOWN OPEN (documented in strikeCraft._capCouplingNote): with the
missile screen nerfed, flying CAP is now a strictly dominated AI stance, and
the band depends on the AI continuing to fly it — tubeThreat 0 puts Krelath
at 62–67%. The next strike-system pass must make CAP earn its cost or re-tune
the stance weights. The verifier flagged this as the one finding that could
have changed the verdict.
Thinnest margins on record: ZAN 37.2% mean at 64 points; ZAN ~63% at 32 (pre-existing). Also open: Chris’s pending ruling on dreadnought charge-immobility (§22 follow-up); models for dreadnought and carrier.
Ruling: the dreadnought is immobile except for turning to aim. Implemented
with the five defaults Chris accepted: planted while charging and while
holding a full bank; free to move while venting; turns at the normal rate;
and the bank is not lit until an enemy is within chargeStartRangeHexes
(20) — without that gate the ship would plant at its deployment hex on turn
one. Flags on weapons.photonic-cannon; guarded on ship.spinal; determinism
byte-identical. Measured but NOT tuned (content-first directive): Earth 44%
at 24 points and 38% at 32 — the rule costs roughly 5–11pp and stays in band.
Maiden battle under the rule: cold → four planted turns → a hit on the
Krelath battleship at 17 hexes → venting → reconnected.
Process directive (Chris): content first, tune once. No more rolling balance passes; the consolidated tuning pass waits until the roster settles.
Visual pivot (Chris): schematic icons in place of 3D assets until the core
game is complete. scripts/gen-icons.js generates 44 SVGs to
assets/icons/ (+ manifest + contact sheet): faction = colour + hull family
(Earth lozenge, Vraygon crystal, Zandrax arrowhead, Krelath carapace); class
= footprint + rank bars (FF 1 … BB 5) with glyphs for the specials (spinal
line, flight deck, fortress, missile, dot). Nose up; the viewer rotates by
facing. Icons are the arena’s default; sprites remain as a toggle.
Also found and handed to Codex: the arena recorder carried a stale private
roster copy, so no replay yet contained a dreadnought or carrier; it now
imports test/comp.js.
battle.map {shape: "rect", widthHexes, heightHexes} with in-bounds
by hex-pixel extents; deployment on the long axis; start distance widened.
Viewer side: draw the rectangle, fit to width. Applied after the current
Codex arena task lands (it holds write access to the resolver).strength (craft count) that depletes
under point defence and enemy CAP, and its striking power scales with what
is left — the wing thins as planes die. Squadrons carry no map position in
v1 (they fly from the parent carrier within a radius); giving them map
positions is the v2 step if the playfield needs it. Icons for both craft
types (interceptor: slim dart; bomber: broad wedge with payload) are in the
icon set for the viewer to place.As in the FASA original, a ship occupies a single hex and is far smaller than it; ships may share a hex and pass through one another without collision. Only the largest objects (planets) will ever span more than one hex. This fixes the game at fleet-battle scale. Engine audit: already true — there is no occupancy or collision rule, and zero-range fire resolves (a co-located attacker registers as bearing east; a harmless deterministic fallback). Verified by stacking four ships in one hex and running a full battle. The perceived deviation was visual only: sprites scaled past a hex. Viewer rule from here: an icon’s footprint fits inside one hex; co-located ships are drawn offset within the hex so each remains visible. Deployment spacing and formation stations are doctrine, not physics, and are unaffected.
battle.map {shape: "rect", widthHexes: 72, heightHexes: 40}; in-bounds is
|q + r/2| ≤ W/2 and |r| ≤ H/2 in pointy-top axial. Deployment needed no
change — the fleets already stood west and east with the line of battle
north–south; only the edges were hexagonal. Verified: harness green, zero
draws in sixty 24-point battles, determinism byte-identical. Instructive
number: fleets used 15 of the 36 available columns and 6 of 20 rows — the
room exists; the helm AI does not yet seek it (see §24, maneuver incentive).
A maneuver index (share of hits landing on flank/rear faces) is being added
to the trial harness so the incentive is measured, not hoped.
Added to the trial harness (stats.hitsForward/hitsRear, counted in
resolveHit; printed after the size sweep and in --scale mode): the share
of a faction’s landed hits that strike flank/rear faces (4/5/6). Baseline on
the landscape map, 60 battles/pairing:
points EAR VRA ZAN KRE
8 19% 19% 31% 41%
24 24% 25% 32% 26%
64 14% 16% 27% 35%
Reading: three hits in four land on the nose. Zandrax (fast, emergency burst) and Krelath (warp behind targets) reach the rear most; Earth, the line fighter, least — 14% at fleet scale. This is the number the maneuver incentive work must move; the map now has the room, the helm AI does not yet seek the flank. Strike-craft damage bypasses resolveHit and is not counted.
Research (Sonnet agent, from the rulebook’s page images): FASA STTCS p.16, “Additional Rules” — “Two or more starships may occupy the same hex, but they may not fire at one another while they are in that hex. Ships may neither ram nor collide with one another.” No stacking limit, no ramming, no point-blank fire. And p.7–8: the Starfield Mapsheet is 22×33 inches with the fleets deployed “at the center of opposite short sides” — the landscape ruling (§24c) is the original’s own layout.
Chris’s concern — nothing to stop ships parking in an enemy’s hex and
slugging it out — is answered by the source: parking there forfeits the
shot at that ship, mutually, while both may still fire at others. Restored
as battle.sameHexNoFire (mayEngage() in the resolver, applied to beams,
missiles and the spinal gun; the helm stops one hex short when closing).
Verified: a frozen stacked pair exchanges zero shots; harness green;
determinism byte-identical. Not balance-tuned (content-first).
Recorder now imports the shared roster (test/comp.js — untracked; must be
committed with it) and echoes the map shape; replay meta v3; all four bundled
replays re-recorded and finally field the dreadnought and the carrier.
Viewer: landscape rectangle fitted to width (hexagon fallback kept), icons by
default with a sprites toggle, icon footprint capped inside one hex, stacked
ships ringed within the hex, and log-driven effects for the photonic cannon
(cold/charging/held/bolt/venting) and the air group (orbit, strike run,
attrition). Verified in a real browser, zero errors; engine hashes unchanged.
Consequence of the map ruling: ~6 px ships at full-map fit — pan/zoom with
auto-framing handed to Sol (first task on the repaired stdin invocation).
Cursor-centred wheel zoom (min whole map, max ~60 px hex), drag panning with
a click/drag threshold, transformed hit-testing, a smooth auto-frame on the
living fleets (default on; any manual zoom or drag disengages it; “Frame
fleets” re-engages; “Fit map” shows the whole rectangle), camera-aware grid
culling, one canvas transform for every element and effect. Verified in
headless Chromium on all four replays, no errors. Smoke test not extended
(test/ was declared read-only in the brief); camera assertions were run as
temporary checks — extending test/arena-smoke.js for the camera is a small
open item. The viewer is now complete for the playtest phase.
Camera fix (Sol, same day): zoom initialised on load and resize; auto-frame
engages immediately; playback hardened against NaN timestamps and a render
failure no longer stops the loop; round matching unified across shots,
effects and the log panel. Verified in headless Chrome on all four replays
(finite zooms ~2.0–2.4, playback to the end at 1× and 4×). Script at
?v=camera2.
Per the content-first directive, observations are logged here and NOT acted on until the roster settles. Each entry: what was seen, what the harness says.
B-carrier-9 destroyed … goes down with 15
craft). Already measured by the carrier tuning pass: the deck trails its
line by 0.2–1.4 hexes because formation.cohesionRadius leashes the whole
fleet to its centre of mass, and the withdrawal exemption cannot act
against the leash. This is a FORMATION-ROLE gap (content), not a number:
a carrier needs a rear station behind the line, screened, with the line
advancing without it. Candidate for the roster-settled pass or a small
content change before it.Chris: a game editor to set up fleets and scenarios — composition and the position of every element under the player’s control, all four factions, basic planets and moons, then run in a simulator (same product or separate).
Engine side, built: moons are one impassable hex; planets are a
seven-hex rosette (the footprint the old sprites spilled over). Both block
movement, warp landings and deployment, and both block line of fire
along the hex line (FASA: large bodies block fire) for beams, missile
launches and the spinal cannon. buildScenario() places every element
explicitly and falls back to the line deployment for unplaced ships;
runBattle takes terrain via opts.terrain. Contract in
docs/scenario-format.md. Verified: a planet between two frozen frigates
yields zero shots; the same geometry without it yields fire; a moon is never
entered; placement and facing honoured; terrain placement refused; a full
mixed scenario with terrain is deterministic. Client side (Sol): the editor
page, an in-browser runner (the engine is dependency-free ES modules), and
the hand-off to the viewer.
arena/editor.html (+ editor.js, editor-core.js, editor.css): two sides
with all four factions, roster with points and running totals, drag
placement with snapping and facing, moon/planet tools, map size, seed and
name, save/load of scenario JSON, validation, Random line deployment, and
Run battle — the engine runs in the browser (dependency-free ES modules)
and hands the replay to the viewer through sessionStorage
(orion-wars:scenario-replay:v3; index.html?replay=session; “Back to
editor” link). One shared recording module (arena/record.js) serves both
the browser runner and test/record-battle.js --scenario, byte-identical.
The viewer renders terrain from meta.terrain under ships and effects.
Sample: arena/scenarios/twin-moons.json (a planet, two moons, placed and
unplaced ships, EAR vs KRE). Seen in the pane: the planet as a large body,
a laser crossing past it, the carrier’s wing orbiting the deck, wrecks,
zero console errors. Sonnet verification pending at time of writing.
Verification (Sonnet, same day): adopt-with-fixes. Byte-identity between the
browser runner and the CLI confirmed; protected hashes unchanged; three
defects: no facing check in validation, Save/Run usable before data loads,
and — the important one — the CONTRACT ITSELF was wrong: I had written that
a faction fields “the keys of its loadouts entry”, but loadouts lists only
faction-specific fits, so the editor offered Earth no frigate or battleship
and still offered the retired command ship. Fixed at the source: a
rosters key in data/tactical-tuning.json is now the single source of
truth (five common hulls plus each power’s uniques); the editor, docs and
smoke test follow it. A reminder that the contract is code too.
Cache lesson, again (2026-09-02): after the rosters key was added, the
editor still offered every hull to every faction — the browser served a
cached tactical-tuning.json without the key, so the roster fallback ran.
Data and manifest fetches in the arena now use cache: "no-store", and the
script tags are re-versioned (editor.js?v=editor3, arena.js?v=terrain4).
Rule for the client: game data must never come from the browser cache — a
stale tuning silently changes rosters and battles.
Follow-up verification (Sonnet): adopt. Suites green and identical to
the pre-patch run (the 48-turn deterministic campaign reproduces to the
treasury); byte-identity holds with the new data; all six roster/facing
checks pass; resolver hash unchanged; tuning hash changed by design (the
rosters key). Practice adopted from the verifier: snapshot a protected
file before an expected change so the diff is exact, not inferential.
The editor is adopted.
Chris opened arena/editor.html from disk in two browsers: no map, dead
buttons, “Loading tactical data…” forever. Cause: browsers block data
fetches and ES-module imports on file:// pages, and the editor runs the
engine in the browser, so it cannot work from disk (the viewer only seemed
to, thanks to its file-drop fallback). Fixes: Start Distant Sectors.cmd at the
repo root (serves on 8642 and opens the editor), npm run arena, a plain
error message when the editor is opened from disk, README instructions
first, and a permanent “Scenario editor” link in the viewer header (the
back link had been conditional on a scenario replay). Lesson for briefs:
“no server required” applies to the viewer only; state it explicitly.
arena/scenarios/
first-obstacles.json): a planet flanked by two moons across Earth’s line
of advance, 30 vs 30. Earth 18–12 on the 20-turn clock. The terrain
exposed the routing gap completely: the Yamato never moved and never fired
(57 rounds motionless), two Earth light cruisers and a destroyer sat 38–49
rounds behind the gate, the Krelath carrier idled 26 rounds; only light
hulls got through. Obstacle avoidance is now the first engine content
item for the next pass (helm: when the forward step is blocked, steer to
the neighbouring bearing that still closes; when the line of fire is
blocked, reposition rather than wait). Also: the photonic cannon’s hold
logic meant a planted, blocked Yamato spent the whole battle charged and
silent.arena/scenarios/small-action.json)
found an engine bug: any lone ship never moved. The cohesion leash
compared the ship’s range to fleetGap - leash with fleetGap = Infinity
when a ship has no living mates, so a lone ship always read as “too far
ahead of the fleet” and held. Consequences: one-ship scenarios were a
20-turn stare-down, and the LAST SURVIVOR of any fleet stopped advancing
the moment its last friend died — present in every trial, invisible to the
sweep. Fixed (the leash binds only when mates exist). Balance effect: the
endgame changes slightly; re-measured in the consolidated pass.Points now represent observed power: corvette 1, frigate 2, destroyer 5
(it carries a torpedo now), strike cruiser 8, light cruiser 12, heavy
cruiser 20, battleship 28; the big specials — dreadnought, carrier, monitor
— at 32, limit one per fleet. Old ladder: 0.5 / 1 / 2 / 4 / 4 / 8 / 16 /
8 / 8 / 16. Stated aim: “more correctly represent the power of the ship
types relative to each other” and see what it does to fleet composition.
Applied in hullClasses.<class>.points (+ limit); the harness keeps the
same six hull lists (now costed 4 / 22 / 38 / 62 / 70 / 138) so faction
results stay comparable, with every unique-hull swap re-expressed as an
equal-points trade on the new ladder (a special = BB + 2 FF or CA + CL;
strike cruiser + 2 FF = CL; two corvettes = a frigate). The concentration
matrix is re-cut at 60 points a side: 2 BB + 2 FF / 3 CA / 5 CL / 12 DD /
30 FF.
Carrier doctrine: “carriers are standoff ships that use their strike craft and their long-range weapons.” Standoff 16 and launch 18 hexes set for the doctrine, explicitly untuned (the earlier cut to 9 was tuning around the in-line behaviour). The viewer stops drawing the wing orbiting the deck.
Measured, not tuned, per content-first — results in the ledger.
Chris: two price sets tried; now “run some numbers on the ships themselves, the battle findings under both price regimes, and come to a refined set that balances toward freedom of choice in fleet compositions, letting the player choose as a skill rather than a stark min-max choice.”
Definition of success used by the search (the freedom index): across many equal-points fleet shapes — pure stacks and realistic mixes — every shape lands between 35% and 65% against the field and no single pairing is beyond 25/75; intransitive cycles are choice and are welcome, dominance is not. Mean and max |win − 50| per budget are the reported numbers.
Method: a three-agent search (Opus). One analyst fits line-hull prices iteratively against the shape matrix (raise what wins, lower what loses, re-cut the shapes, repeat to convergence) and explains each price in prose; one prices the specials and uniques by buy value (the price at which fielding one is neutral to mildly positive); a referee reconciles one ladder, applies it, and measures the shape matrix, the faction sweep and every buy delta on its own seeds. Ship stats are frozen throughout — this is pricing what exists, not tuning. Results below when the search lands.
Ruling-in-waiting. The Zandrax special ship is the Hypershield Wall. When active, ships behind it are protected from all incoming damage the wall blocks. It is overcome by mass volley firepower (saturation) or by going around it to attack the flanks or rear. Reference: the Gamilas shield wall of Star Blazers 2202, which stopped damage and also kept enemy ships from warping past it.
Why it fits: it closes the roster gap the re-pricing measurement exposed — Zandrax had no 32-point special to buy, so their line stayed whole while every other power paid for one. And it is the first special whose whole purpose is maneuver incentive: a wall makes flanking the only cheap answer.
First mechanical sketch, using systems we already have (to be built after the ladder settles; nothing implemented yet):
wall system that projects a barrier
segment ahead of it — a line of hexes perpendicular to its facing at short
range (say 5–7 hexes wide, 2 hexes out), rotating with the ship’s facing,
so the wall’s turn rate is the ship’s turn rate.Open for Chris: price and fleet-floor (the price search now running does not include it), whether the wall costs the corvette swap its place as the Zandrax unique, and the wall’s width and range. An icon glyph (an arc) is needed in the icon set.
Design intent, revised (Chris, same day): “my first notion was that specials should be expensive, but it seems that while they add flavor they are not necessarily so decisive as to warrant the highest price.” So the specials are priced at their measured worth — a real option, neither trap nor must-buy — and their flavor is the reason to take them. If a special should later become decisive (a stronger cannon, a real wing), that is a stats decision for the tuning pass, and its price follows the measurement.
Two more tiles for scenarios. Asteroid field (asteroids): one hex,
passable but slow — entering costs twice the normal movement power — and it
blocks fire in and out: a ship inside can neither shoot nor be shot, and
no line of fire crosses a field (cover, at a price in tempo). Large
asteroid (asteroid): one impassable hex that blocks fire, a small moon
in the rules and a craggy rock in the picture. Engine: a second terrain set
for fields, a per-hex step cost in the helm (the movement budget now looks
at the cost of the hex ahead; the Zandrax burst refunds what the hex cost),
and the line-of-fire test extended to endpoints for fields. Contract in
docs/scenario-format.md; editor tools and rendering with the client agent.
Chris asked whether FASA had nebula rules. It did not — nothing on nebulae, gas clouds, ion storms, dust or energy fields anywhere (table of contents and every sensors/movement/fire/equipment section read directly). What the book defines:
Reading for us: our moons/planets/large asteroids are FASA’s obstacles exactly (blocked fire is the sensor shadow, and it was mutual there too); our asteroid field’s movement cost and its in-and-out blocking are our own additions. A nebula would be a Distant Sectors invention — a natural design is a multi-hex region that casts a sensor shadow (mutual, no fire in or out) and perhaps degrades shields or absorbs beam power, priced by playtest. Mines and outposts are FASA content the editor could carry later.
Nebula, Mutara pattern (Chris, same day): rather than a sensor shadow that blocks fire outright, a nebula degrades — reduced visibility and reduced hit chance, as at the Battle of the Mutara Nebula. Sketch: a multi-hex region; ships inside it (or firing into or through it) suffer a to-hit penalty and can only be detected/targeted at short range; shields are weakened or useless inside (“shields will be useless” — the film’s rule); missiles and strike craft may lose their locks. Fire is not blocked, so the fog is a place to take a fight where gunnery counts for less and nerve for more. Distinct from the obstacle rule; both can coexist as tiles.
“We can’t follow them into the nebula, Sir. Our shields would be useless.”
(Joachim, to Khan.) A nebula hex is passable and does not block fire; it
degrades. Inside one, a ship can engage and be engaged only within
visibilityHexes (3); any shot with a ship in the fog at either end takes a
toHitPenalty (2 pips, applied to beams and the spinal gun alike); and
shields are useless inside — every hit on a ship in a nebula bypasses
its shields (the photonic cannon’s bypass path, reused). Paint several tiles
for a cloud. Untuned; the numbers are dials. Verified by the terrain check:
unengageable at 6 hexes, engageable at 2, fire across a nebula between two
ships outside it unaffected, more internal damage in the fog than in clear
space for the same exchange, deterministic. Missiles and strike craft do
not yet lose their locks in the fog — a later dial.
range and damage (0 on a
miss), launches carry the warhead, and missile arrivals carry the shooter.
Movement narration comes from the recorder’s per-round positions. The
viewer’s round log will be built from these events plus the engine’s own
lines, with filters (movement / fire / damage / special).Refinement (Chris, same day): weapons fired from outside a nebula penetrate no further than its first hex — absorption decoheres beams and missiles lose their sensor locks. So nothing crosses a nebula and nothing reaches its interior from outside; a ship in the first fog hex can still be hit from outside, one deeper cannot. From inside, the visibility rule governs. Verified: through-fire blocked; first hex reachable; second not.
Five terrain brushes in the editor (moon, planet, large asteroid, asteroid field, nebula — the nebula brush stays active so a cloud is painted a hex per click), the same deterministic per-hex art in editor and viewer, ships drawn with the icon set on the map, the fleet-builder buttons and the tray cards, and the chevron fallback removed everywhere (“no need for little triangles”) — a coverage assertion proves every roster class has an icon. Verified in the pane with Chris’s first scenario plus every tile type; no console errors. Committed. Sol now has the beam-connect, missile-target and narrative-log brief.
Shot effects are now drawn between the shooter’s and target’s recorded positions for the round the shot occurred, shown while that round plays (movement and firing phases separated), so beams connect; missiles fly a dashed line from shooter to target with a persistent reticle and an arrival label; the round log is a narrative built from the shot events (range, damage, shooter) and the per-round positions — moves with from/to and compass facing, holds, warps, fire with hit/miss and damage, launches with warhead, arrivals with outcome, strikes, cannon phases, detonations and deaths — with Movement / Fire / Damage / Specials filters and a raw-lines toggle. Verified in the pane with the 62-point Earth–Krelath replay; no console errors. Follow-up: effect widths and labels scaled with the camera.
Ladder (frigate = 2 is the unit of account): corvette 1 · frigate 2 · destroyer 4 · strike cruiser 8 · light cruiser 10 · heavy cruiser 16 · dreadnought 16 · carrier 16 · monitor 20 · battleship 32; the three big specials limit one, fielded from a 52-point fleet (the reference line’s cost). Every harness swap is equal-points.
Freedom index (mean / max |field − 50| over 13 shapes, Earth mirror, 160 battles a pairing): 15.5 / 48 at 52 points as shipped, 13.6 / 20.7 once oversized fleets deploy in ranks; the 32-point ladder measured 20.3 / 39. Specials at their prices are neutral to mildly positive buys (mirror 50–53% at fleet sizes; the monitor a little rich at +9 at 52).
Two bugs the search found — both fixed with the ladder:
hull.points (the class-
interaction “heavy” thresholds, the cannon’s capital and battle-line
thresholds, interceptor and bomber target points, plus timeout scoring
and deployment order). Chris’s 32-point ladder had silently promoted
light and strike cruisers to “heavy” and let bombers hunt destroyers —
part of §27’s measurement was a rules change in disguise. The dials are
now pinned to hull classes (heavy = CA 16; capital 16; battle line 32;
interceptors ≤ 4; bombers ≥ 8) and must be re-pinned on any re-pricing.What the ladder does not fix (the referee, plainly): no ladder gets the worst pairing under 90/10 — at exactly equal points combined arms beats monocultures structurally, because capitals carry no screen or point defence and light hulls do (3 CA + 2 FF lose 9/91 to the reference line). Raising a capital’s price only makes the mixed list buy fewer capitals and keep its escort. If a capital line is to be a viable shape, the lever is a rule — intrinsic screening or point defence on capitals, or a cap on how much screening a fleet may stack — not a price. Faction sweep under the ladder is out of band at fleet sizes (stats frozen): that is the tuning pass’s job.
Per-hull rationale (the referee’s prose, for Chris to read as design):
THE LADDER IN ONE LINE, on the frigate: corvette ½, frigate 1, destroyer 2, strike cruiser 4, light cruiser 5, heavy cruiser 8, dreadnought 8, carrier 8, monitor 10, battleship 16. Every rung is a doubling or a simple sum, and every price except the Zandrax corvette is EVEN — which is not decoration. The frigate at 2 is the smallest hull three of the four powers own, so an odd price anywhere makes some equal-points trade impossible. That single constraint decided three of the arguments below.
2 corvettes = a frigate. 2 frigates = a destroyer. 2 destroyers = a strike cruiser. A strike cruiser and a frigate = a light cruiser. 8 frigates = a heavy cruiser. 2 light cruisers = a monitor. A dreadnought = a carrier = a heavy cruiser. 2 heavy cruisers = a battleship.
WHY THE LADDER IS SHAPED LIKE THIS, and it is not what the paper stats suggest. Per point, a frigate buys twice the guns and twice the hull of a battleship. The price ladder is close to the inverse of that, and the reason is the SHIELD THRESHOLD. Absorption is capped per facing per round, and a beam lands 7 damage (Earth’s laser at max power inside 6 hexes) to 9 (Vraygon’s heavy blaster inside 5). Against a corvette, frigate or destroyer — caps 3, 4, 4 — every single shot in the game puts 3 to 5 through. Against a light cruiser at cap 9, one shot puts through nothing; it takes two hits on the same facing in the same round. Against a heavy cruiser at 13 and a battleship at 18 it takes two heavy hits or three light ones. You are not buying guns or hull. You are buying the number of enemy ships that must bear on one facing at once before anything happens at all.
CORVETTE 1 — two to a frigate. Not half a frigate: it is a frigate’s worth of gun in two bodies you will lose, on 6 superstructure and cap 3, and its weaponReach of 0.70 drags the whole fleet’s standoff down because the corvette is nearly always the nearest enemy. Measured at ½ point the Zandrax screen re-bought as corvettes wins its own mirror 61-73% and is a +6 to +28pp buy; at 1 point, 36-53% and −13 to +1pp; at 1½, 11-46% and −8 to −32pp. One point, and Chris’s shipped price stands.
FRIGATE 2 — the unit of account. One all-round beam, 8 superstructure, cap 4. Everything else is priced against it and it does not move.
DESTROYER 4 — two frigates, and knowingly the one dear hull on the ladder. Its measured value is about 3½ and I can bracket it very sharply: at 3 points a pure destroyer flotilla wins 86% of the field at 52 points, 97% at 80 and 99% at 104; at 4 it wins 21-32%. The reason it is worth so little more than a frigate is that it does NOT buy the shield threshold — cap 4, the same as the frigate — and it trades the frigate’s all-round beams for forward and starboard-aft. What it buys is a torpedo tube, six superstructure and a point of screen. A price of 3½ is unpayable on a ladder whose smallest common hull is 2, so 4 is delivered as the lesser of two errors and the destroyer stack is the shape most out of band (20-32%). If Chris will accept a doubled scale, corvette 2 / frigate 4 / destroyer 7 / strike cruiser 16 / light cruiser 20 / heavy cruiser 32 / dreadnought 32 / carrier 32 / monitor 40 / battleship 64 prices the destroyer at its measured value with every trade still exact — at the cost of doubling every point value in the game.
STRIKE CRUISER 8 — four frigates, two destroyers, or a light cruiser less a frigate. Three tubes and two beams on a 22-point hull with screen 0: a light capital the fleet screens, not a picket. Unchanged from the shipped price, and see the buy-delta note for the one place my two instruments disagree.
LIGHT CRUISER 10 — five frigates. This is the hull the whole ladder turns on: cap 9 is the cheapest place in the game where a single shot from any gun bounces. That threshold, not the third beam, is what the fifth frigate buys. Priced at 12 it was over; at 9 the cruiser pack runs away with the small budgets; 10 is where both ends sit.
HEAVY CRUISER 16 — eight frigates, two strike cruisers, four destroyers. Cap 13, five beams, three tubes — and screen 0 and point defence 0, which is the whole story of the top of the ladder. It needs a fleet around it. Escorted it is worth 16; massed it is worth about 10, and at exactly equal points three heavy cruisers lose to two heavy cruisers with a screen 14/86.
BATTLESHIP 32 — two heavy cruisers. Cap 18, eight beams, five tubes, the same screen 0 and PD 0. The same story, doubled. Raised from 28 rather than lowered, because at the reference size a battleship with a screen around it is the strongest thing on the board (1BB+2DD+6FF reads 68.6% against seven other 52-point shapes).
DREADNOUGHT 16, limit 1 — exactly a heavy cruiser, and that identity is the design. The Yamato is not a bigger battleship: it is a heavy cruiser that gives up two lasers and two tubes and buys the photonic cannon, eleven superstructure, two points of shield cap and four points of screen. At 32 it was a −30 to −56pp purchase and the power that fielded one collapsed; at 16 its owner’s mirror reads 53/50/45 across the three fleet-action sizes.
CARRIER 16, limit 1 — the same rung. A heavy cruiser’s worth of flight deck, and the price is stable across five different standoff settings. It is the strongest matchup piece in the game and the one hull whose price is conditional on a doctrine ruling.
MONITOR 20, limit 1 — two light cruisers, or a heavy cruiser and two frigates. 110 superstructure, guns on every bearing, and by a wide margin the slowest hull in the game. It is the anti-swarm piece and it is what makes Vraygon competitive at 68 points at all.
COMMAND SHIP 16 — retired, parked on the dreadnought’s rung purely so an old replay does not load a hull whose class weight is an outlier.
Independent measurement after applying (150 battles/pairing at 52; 50 per pairing per size). Shape matrix at 52 a side, row beats column: the monocultures are the weak shapes (3 CA + 2 FF beat by the reference line 92/8 and by 1 BB + 2 DD + 6 FF 98/2; 13 DD lose to 3 CA 92/8) while the combined-arms lists sit near the top, and there are real cycles — 5 CL + 1 FF beat 1 BB + 2 CL 84/16 and lose to 16 FF + 5 DD 22/78; 13 DD lose to the light mix 20/80 and beat it 40/60 against the battleship line. Choice, with combined arms as the skill. Faction sweep (stats frozen): 4: 58/49/43/47 · 18: 53/51/59/37 · 32: 45/43/44/67 · 52: 47/68/57/27 · 68: 45/45/52/58 · 132: 74/37/32/57 — out of band at 52 and 132; that is the consolidated tuning pass’s brief, now on an honest ladder and a map that holds a swarm.
arena/scenarios/formation-
column/echelon/loose.json: 2 Earth destroyers vs 4 Krelath frigates,
8 vs 8, differing only in the frigates’ deployment). 40 seeds each:
column 19–21 (even), echelon 40–0 Earth (the frigates arrive
piecemeal and are defeated in detail), loose 30–10. Formation decides the
fight — and the arc analysis shows the AI never manoeuvres for arcs:
flank/rear hits 0–4% in all three. Chris’s intent — defend weak shield
arcs, attack the enemy’s, move out of firing arcs when possible — is not
something the helm does yet. Engine content: an arc-aware helm, measured
by the maneuver index and these three scenarios.Chris: “make it possible for me to give commands to one of the fleets from turn to turn; this will enable me to teach through scenarios by combatting the scripted opponent behaviour, allowing for analysis of what human players are likely to do” — with a selected ship’s firing arcs, ranges, shield and power levels shown graphically, and speed, movement and changes of direction both controllable and visualised on the map.
Contract: docs/playfield-contract.md (createBattle / battleView /
shipPlan / stepTurn; per-round orders of turn-then-forward clamped by the
flight rules and power; target or auto; shield reserve; every clamp logged;
the recording keeps the human’s orders per turn beside the replay).
Sol built arena/play.html against a mock adapter (arena/play-engine.js)
with the contract’s exact surface: setup (bundled scenarios incl. the
formation trio, or a scenario from the editor; choose the side; seed),
planning on the map with arcs as range-band wedges, the shield hexagon, the
power bar, per-round plans with Q/E/W/S and buttons, targets by click, End
turn with playback, the narrative log, record/save/open-in-viewer. Verified
in the pane: the loop runs turn to turn on the mock.
Fable’s polish notes (first pass, before the real engine): auto-frame the fleets on Take command and make Frame fleets visibly zoom (the map opens at whole-map fit with tiny ships); waypoint labels on the planned path; check the power bar’s numbers read at a glance once real costs flow; make the planning-to-playback-to-planning rhythm unmistakable (a phase banner); evaluate the arc wedge shading and range rings against real engagements. Full pass after the engine API replaces the mock.
Engine API: to be built once the arc-aware helm lands (both rewrite the
same movement code). runBattle becomes createBattle + a stepTurn loop
with no orders — byte-identical on the trial harness — and the human’s
orders drive move()/fire() for ordered ships only.
Chris’s four behaviours, built faction-neutral behind tuning.helm:
defend weak arcs (a heading is scored by weight of fire minus a threat-
weighted penalty for the face it would present, 1 intact / 0.5 damaged /
0 down); attack weak arcs (steer for the enemy whose face toward us is
softest; among targets a mount already bears on, shoot the one showing a
hole or a bare quarter — the single largest mover); step out of arcs (an
evasion step when a heavy battery out-throws us through the face it sees,
taken only when it keeps our own shot); orbit while holding (a ship in
position no longer stands still — one lateral step a round toward the
target’s softest quarter); and arrive together (until first contact a
hull closes on its nearest mate rather than the enemy when the gap exceeds
cohesion.mutualSupportHexes). Instrumentation (helmStats) is inert
unless switched on and touches no rng.
Verified adversarially on fresh seeds: every maneuver-index cell rises
(mean 27% → 35%); damaged-face exposure halves; Chris’s echelon rout goes
from 91.5% to 51%; nothing collapses; helm.enabled=false reproduces the old
engine byte-for-byte; cost ×1.65. Adopted with the verifier’s changes: a
per-battle reset of helm state; measured costs recorded honestly in the
tuning notes (cohesion ≈ 12pp of spread at 18 points; orbit costs Vraygon
~11pp at 4 points and buys ~1 point of index at 52 — Chris’s trade).
Open rulings for Chris: (1) the evasion step lets a hull that cannot withdraw fighting open the range by up to 2 hexes — an interaction that should be a ruling; (2) the helm shifted the shape matrix (the 16 FF + 5 DD list gained ~10pp overall), so the refined ladder wants a re-check on this helm; (3) orbit-while-holding on or off at small sizes.
Engine API landed and the mock retired (2026-09-03): createBattle /
createBattleFromFleets / stepTurn / battleView / shipPlan /
battleResult in the resolver; runBattle is now create + a stepTurn loop
and reproduces the trial harness byte-for-byte. Human orders: a round with
movement in the plan is spent moving (turn then forward, every clamp
logged); a planned hold fires if a mount bears, at the ordered target where
that mount bears; the reserve order overrides doctrine. Parity with the AI’s
move-or-fire round is deliberate — whether a round may hold both is a ruling
for Chris. arena/play-engine.js now adapts the real engine; the page did
not change.
Fable’s polish pass (real engine): the “Frame fleets” button had been wired to the same handler as “Fit map” and never framed anything — the map opened on the whole 72×40 board with six-pixel ships. A real framing routine now fits the living fleets with a margin, runs on Take command and after every playback, and the wheel zoom cap rises to match. The power bar reads cleanly (movement / guns / reserve of the pool); the phase pill flips Planning → Playback → Planning; the narrative log narrates the ordered move. Left for the next pass: waypoint labels on the planned path, and the move-and-fire ruling above.
Chris’s verdict on the first playfield: unclear what to do; the three “Phase” buttons unexplained; firing arcs indistinguishable from movement; which weapon covers which arc unclear; could not fire, and the enemy’s fire left no visual trace; scenario preset; wanted Star Trek-style readouts and a top-down schematic with per-weapon arc markers; and “turn order is whack — make it make sense.” Rebuilt by hand:
Two engine-facing findings from the rebuild: (1) the first page drew the
arcs mirrored — it assumed face 1 lay counter-clockwise of the bow, but
the engine’s table (SHIELD_BY_OFFSET = [2,3,4,5,6,1]) puts face 3 there;
the page now uses the engine’s table. (2) Consequence for naming: with icons
drawn nose-up and rotated by facing, the engine’s “front-right” (3) appears
on the icon’s left. Gameplay is symmetric so nothing is wrong in the
fights, but the labels contradict the picture — a ruling for Chris:
rename faces 1/3 and 4/6 to match the picture, or flip the table (and the
per-facing damage tables) so starboard is starboard. (3) Icons were rotated
90° in the playfield — a nose-up sprite rotated by the facing alone; fixed.
Chris: “with so few weapons, our dreadnought isn’t really a dreadnought” —
new designation Gunstar Battlecruiser (hull key gunstar-battlecruiser;
the Yamato class keeps its class name; the model files keep theirs until
the art session renames them). Everything live is renamed — data, rosters,
harness swaps, scenarios, icons, tests, the playfield — and the engine’s
comments; earlier sections of this log keep “dreadnought” as history.
Seeing the destroyer schematic (“forward and forward-starboard? makes no
sense”): every faction’s destroyer now carries a forward turret, a rear
turret and one forward torpedo tube. The turrets overlap on the quarters —
Chris: “the beams overlap at 1, 3, 4 and 6” — so the arcs are bow
(everything but dead astern: faces 6,1,2,3,4; it fires dead ahead at face 2)
and stern (everything but dead ahead: 3,4,5,6,1; it fires dead astern at
face 5). On faces 1, 3, 4 and 6 both turrets bear: the two-turret broadside,
which is the maneuver incentive Chris named — “a blow from the torpedoes,
then turning to deliver a two-beam broadside.” Faction fits set weapon types
only; the Earth and Vraygon arc overrides are gone. Untuned, content-first.
Shield faces number clockwise (“it ought to be clockwise”): 1 front-left,
2 forward, 3 front-right, 4 rear-right, 5 rear, 6 rear-left around the bow.
The engine’s face table flips from [2,3,4,5,6,1] to [2,1,6,5,4,3], which
closes the mirrored-naming ruling of §30a — the viewer had been drawing
clockwise all along; the engine now agrees with the picture. Gameplay is a
mirror image of before (faces 1/3 and 4/6 swap), statistically identical,
not byte-identical; the per-facing damage tables are unchanged.
Audit correction, 2026-09-05: the historical claim immediately above that
the viewer already drew clockwise was incorrect. The engine’s [2,1,6,5,4,3]
table follows Chris’s ruling; the replay viewer retained the older mirrored
mapping. The correctness pass now makes replay pips/flash offsets derive from
the authoritative engine convention, and new events record actual hit faces.
This is a viewer correction, not a new face-numbering or arc-layout ruling.
Missile destroyer (missile-destroyer, all rosters): two forward tubes
(arc f, magazine 8) and one all-round beam, on the destroyer hull at the
destroyer’s price until measured. Icon “DM”.
Six EAR-vs-KRE destroyer duels, Earth under human orders, Krelath on the helm. Holding at range 11 won twice (once without the Krelath firing at all, to a twin neutronic salvo); closing to range 2-3 lost or traded four times (blaster 8 + plasma 18 at point blank). Diagnosis: (1) HELM DEFECT - the Krelath destroyer opens with a 15-hex dash that spends 11.7 of 16 power and parks at range 11, its worst band and Earth’s best; next turn it fires from there BEFORE closing. Dash-and-park plus fire-then-move gives Earth a fight at Earth’s range. Fix in the helm: plan the turn, close early, fire late from the best band, open with a dash that leaves power to shoot, use the warp. (2) MOVEMENT PRICE - 1 power per hex on a 16-point pool with 5-point beams and 2-3-point missiles: ten hexes cost a turn’s gunnery. FASA charged 1 per hex on pools two to three times larger relative to weapon costs. Candidate ruling: halve the power per hex, or raise pools. Measure first. (3) Plasma at range 3 doing 18 is flavour working; leave it.
Price: 4, adopted as measured. Sixteen price crossings (four powers × two budgets × two controls, 300 symmetrised battles a cell) put the hull’s value at a mean of 4.15 points; crossings by instrument 4.39 / 3.94 / 4.08 / 3.80. At 4 the pure-exchange buy is +1.25pp and the real-list swap (the reference fleet’s two destroyers for missile destroyers, all three foes) is +1.75pp at 52 and +1.00pp at 132 — inside the 0-to-+6 band. At 5 the buy collapses (24% at 52, 4% at 132 against destroyers); at 3 it runs to 98%. Independent reproduction agreed to two decimal places.
Two conditions on the price. (1) It is conditional on the current fire
control: both tubes fire at the same target on 90-100% of two-tube turns, and
35-44% of the salvo arrives at a target already destroyed (17-21% for the
single-tube destroyer). fire() never reads the in-flight list. Fixing that
makes the hull better and the curve must be re-measured. (2) It is
conditional on the class weight staying 4: the engine still compares
hull.points at seven sites (capital / battle-line / interceptor-target /
heavy thresholds and scoring), so a price of 5 would silently make the hull
invisible to interceptors. Measurement separated what a list pays from what
the engine reads.
What it is. A matchup piece in two directions. By owner: worth ~5 points to Earth (the laser is the weakest beam, the tube the best weapon), ~4.4 to Vraygon, under 4 to Krelath and Zandrax (a plasma torpedo decays past 8 hexes and is intercepted more). By enemy shape: superb against a few big hulls, hopeless against numbers — a frigate wall intercepts 37-53% of missiles and another 26-42% land on corpses; Vraygon missile destroyers beat frigates 99-100%, Earth’s lose 2% at 132. Legible rock-paper-scissors; keep it.
It does not stand off. Mean gap to the nearest enemy is identical to the
gun destroyer’s in every power (9.1 v 9.3, 9.9 v 9.9, 5.1 v 5.0, 5.9 v 6.0):
preferredRange is computed from beam bands only, so a two-tube hull fights
at knife range with one gun and throws its salvo at 7-13 hexes when the tubes
reach 14-17. The lever for a missile boat that feels like one is a hull-level
preferred range, not a price.
The magazine buys rate, not endurance. In a long action Earth’s missile destroyer fights 52% of its ship-turns dry (its gun destroyer 6%): the magazine doubled, the launch rate went up sevenfold. Dry, it is worse than a one-beam frigate (2.4 beam damage a turn against the destroyer’s 3.4). An alpha-strike piece whose case is spent in four turns.
Second tube starved by power on 9-15% of ship-turns: the mount loop walks beams first, the beam takes its full maxPower, and the second tube cannot arm.
Vraygon’s missile destroyer is a magazine variant, because the Vraygon standard destroyer already carries two tubes (loadout override, magazine 6); it measures well only because the Vraygon second turret fires on 45% of its turns and costs nothing to give up. Ruling wanted: a distinct fit, or the note.
Freedom. Nothing dead at 4 (weakest DM shape 45%). Two shapes hot: the Earth missile-destroyer stack at 73% against the standard eight (the Earth gun-destroyer stack was the weakest shape at 36% — a 37-point swing), and the Vraygon missile-destroyer stack at 85%, the strongest shape in any panel measured. A faction-balance reading, not a pricing one: a price of 5 would make the hull a bad buy for all four powers and kill the Vraygon swarm outright. Levers are the loadout or the fire-control defect, not the ladder.
Harness findings that touch earlier numbers. (a) The harness is not
side-symmetric: identical fleets, mirrored deployment, same seeds give side A
36-58% depending on size, and side A lands 15-20% of hits on flank/rear faces
against side B’s 2-3% — a factor of six that follows POSITION, not label, and
survives helm.enabled:false. Lead: bestHeading, evadeStep and
preferredApproachDir break ties by absolute hex-direction index (east
first), which is not invariant under the 180° rotation relating the fleets.
Fix: break ties in the ship’s own frame. The §28a shape matrix, the faction
sweep and the §29 formation-trio manoeuvre-index reading (0-4%) all stand on
one edge. Every number in this section was symmetrised. (b) Composition key
order is load-bearing: {frigate:16, destroyer:5} and the reverse measure
6-16pp apart, because array order breaks distance ties in target selection.
Canonical key order and intrinsic tie-breaks wanted in comp.js/fleet-trial.js.
Chris explicitly approved both recommendations in Astra’s decision brief:
Implemented in src/tactical/hex.js and the resolver’s shared line-of-fire
test. New recordings identify ccw-seams-grazing-blocks-v1. See
docs/correctness-2026-09-05/approved-geometry/ for tests and seeded comparison
evidence. These are approved outcome-changing rules, not loadout edits or
an outcome-preserving patch. Older balance measurements remain historical.
Chris also requested a starship/component construction editor with direct
control over mounts, arcs, custom weapons, power, shields and other meaningful
systems. The researched architectural proposal is in
docs/starship-construction-editor-plan.md; workspace placement remains for
Chris’s choice. No stock designs were redesigned by that proposal.
Made after the C0.1 acceptance, from the outstanding-decisions rundown. All eleven agreed as recommended; none is implemented by this entry. Astra owns live integration; the balance sweep that follows them is one consolidated pass, not piecemeal.
Chris’s stated flavour, now the authority for weapon layouts, captain doctrine and the coming balance discussion:
Chris authored the 29 corrected-arc layouts to read that way, and Astra promoted them to stock. Measured on the frozen candidate .tmp-fable-captains-c01-20260906-DcNGYW (bearing slots summed per face across each roster; a slot is one mount able to fire on that face):
| Faction | Mounts | Slots per face 1..6 | Forward (1–3) | Rear (4–6) | Dead astern (5) | Broadside faces (1, 3, 4, 6) | Blind faces |
|---|---|---|---|---|---|---|---|
| Earth | 40 | 16/28/16/14/8/14 | 63% | 38% | 8% | 63% | gunstar astern only |
| Krelath | 45 | 12/37/12/5/7/5 | 78% | 22% | 9% | 44% | destroyer, carrier (5); missile destroyer, strike cruiser (4–6); battleship (4, 6) |
| Vraygon | 47 | 17/24/17/15/10/15 | 59% | 41% | 10% | 65% | none |
| Zandrax | 36 | 10/34/10/1/2/1 | 93% | 7% | 3% | 38% | every hull; frigate, destroyer, light cruiser blind on 4–6; corvette forward only |
The two Vraygon revisions of the same day (heavy-cruiser rear beam confined to face 5; destroyer second tube removed) are not yet in this candidate and will lower Vraygon’s rear share slightly.
All recommendations in the outstanding-decisions rundown are agreed and deferred to a later time: show both definitions labelled by pack of origin on a same-id collision; show both the reactor lost and the pool change on the ship card; accept the in-panel scroll at 1000x900; keep the monotonic catalogue counter; bump new recordings to replay version 4; fix the sorted-CSV re-import by a canonical comparison in the importer. Drydock remains paused; no schedule is set.
All recommendations agreed: ship positions require detection, implemented as a per-side detection radius by sensor rating with a terrain shadow (the first C1 engine change); damage detail is per observer, from the best operational sensor rating within range, not a side-wide maximum; scan locks are observer-owned and revoked when the acquiring ship is lost; the legacy scan gate is brought into line with the contact lock (sensor damage honoured in both) before captains are compared with the scripted AI; globally unique ship ids are asserted at session creation. Warp and burst as explicit packet commands (section 34, item 9) remain the gate before any leaderboard.
Ruled: every published balance number predates the approved geometry change, the promoted arc layouts and the Vraygon option-A list, so none is a current oracle. The ladder, the specials and the faction sweep are re-measured in ONE thorough, consolidated sweep after all the necessaries have landed: the two Vraygon revisions and the arc-entry trim, the eleven engine rulings of section 34 (warp and burst as explicit commands first), and the C0.1 defect and gap fixes. Not piecemeal. Until then, historical numbers are cited as historical.
Ruled: the strict contract stands. An action carries the warp key only when the warp is ordered, and then only as warp: true; warp: false is invalid, not a synonym for omission. The engine refusing a direct packet that carries warp: false with movement (Fable special-commands review, note W12) is therefore correct behaviour against an invalid packet, not a defect, and no hardening is requested. Captain validation already rejects warp: false; the playfield UI omits the key when unused.
Ruled: point defence stays a dedicated close-in system, separate from the beam battery, as the engine already models it (hull pointDefence rating summed over uncloaked friendly hulls within pointDefence.rangeHexes, one roll per arriving missile, chancePerPoint per point capped at maxChance, plus any fighter patrol bonus). Beam mounts never intercept and are never precluded from anti-ship fire on a missile impact turn, so there is no double use of a weapon: main batteries shoot ships, the point-defence gun shoots missiles. The alternative, precluding a beam that intercepted from firing at ships that turn, is rejected. A possible later addition, not requested, is an explicit per-turn order assigning one beam mount to point defence (adds to the rating, loses that mount’s anti-ship fire), which would change no current outcome until chosen and would fold into the consolidated re-measure of 34e.
Art consequence: qualifying hulls (those with a non-zero point-defence rating, currently frigate, destroyer and light cruiser) will carry a small visible point-defence gun in the ship models as they are made; hulls with rating 0 carry none. Model check for the art pipeline: the presence of the gun should track the rating, per faction and class.