ui/phase-27: mass-based circles + cloud cluster + height fit
Three Phase-27 BattleViewer refinements on top of the radial scene:
1. Height fit. The viewer is pinned to `calc(100dvh − 80px)` so it
never pushes the in-game shell past the viewport. `.active-view`
gains `overflow: hidden` + flex column; `.viewer` becomes a
`flex: 1` child; the always-visible text log shrinks to a 30 dvh
ceiling with its own scroll. A global `body { margin: 0 }`
reset (added to `app.html`) plugs the 16 px the browser's
default body margin used to leak.
2. Mass-based ship-class circles. New `lib/battle-player/mass.ts`
carries the radius formula and the per-battle FullMass compute:
`MIN_RADIUS + (MAX_RADIUS − MIN_RADIUS) * sqrt(mass / max)`,
clamped to `[6, 24] px`. FullMass goes through the existing
wasm bridge (`emptyMass` → `carryingMass` → `fullMass`) — no
new wire fields. The viewer page resolves a
`(race, className) → ShipClassRef` lookup from the parent
GameReport's `localShipClass` + `otherShipClass` tables and
passes it to the viewer via context. Unknown class or
degenerate (weapons/armament) params fall back to MAX_RADIUS
so the bucket stays visible.
3. Cloud cluster layout. Cluster key shifts from per-group
`g.key` to `(raceId, className)` so tech-variants of the same
hull collapse into one visual bucket. The horizontal
classCircleX row is replaced by a Vogel sunflower spiral in
the local `(u, v)` basis — `u` points from the race anchor to
the planet, `v` is `u` rotated 90° clockwise. Buckets are
sorted by NumberLeft desc; the cluster anchor is pushed inward
by a quarter step so rank-0 sits closest to the planet. The
step is adaptive (`min(baseStep, MAX_CLUSTER_RADIUS / sqrt(N))`)
so clusters with many classes do not spill into neighbours.
Tests:
- Vitest: `radiusForMass` covering zero / max / quarter-mass /
out-of-range cases (6 cases).
- Playwright: new `battle-viewer.spec.ts` case asserts
`document.documentElement.scrollHeight - window.innerHeight ≤ 4`
at a 1280×720 desktop viewport. The existing fixture gains
`localShipClass` + `otherShipClass` so the lookup has data to
render proportional circles.
Docs: `ui/docs/battle-viewer-ux.md` rewrites the "Radial scene"
section (cloud layout, mass-based radius, height fit) and adds
a "Height fit" subsection. `docs/FUNCTIONAL.md` §6.5 (+ ru
mirror) get the one-line story about per-mass sizing, cluster
aggregation, and the viewport-locked layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+13
-5
@@ -729,11 +729,19 @@ Battle Viewer — отдельное представление, заменяю
|
||||
`GET /api/v1/battle/:turn/:uuid`.
|
||||
|
||||
Визуальная модель — радиальная: планета в центре, расы по внешней
|
||||
окружности на равных угловых интервалах, внутри расы — горизонтальный
|
||||
кластер маленьких кружков по классам кораблей с подписями
|
||||
`<className>:<numLeft>` под каждым. Наблюдатели (`inBattle: false`)
|
||||
не рисуются. Выбывшие расы убираются из сцены, оставшиеся
|
||||
перераспределяются на следующем кадре.
|
||||
окружности на равных угловых интервалах, внутри расы — облако
|
||||
кружков по классам кораблей, выложенное Vogel-спиралью с биасом к
|
||||
планете (самая многочисленная группа по NumberLeft — ближе к
|
||||
планете, остальные раскручиваются спиралью позади). Tech-варианты
|
||||
одного `(race, className)` схлопываются в один визуальный нод
|
||||
`<className>:<numLeft>`; детали по тех-уровням остаются в Reports.
|
||||
Радиус кружка масштабируется по FullMass корабля (диапазон
|
||||
`[6, 24] px`, нормировка на самую тяжёлую группу в битве), так что
|
||||
тяжёлые корабли визуально доминируют. Наблюдатели (`inBattle:
|
||||
false`) не рисуются. Выбывшие расы убираются из сцены, оставшиеся
|
||||
перераспределяются на следующем кадре. Viewer закреплён по высоте
|
||||
viewport-а: сцена растягивается, лог скроллит внутри — никаких
|
||||
скроллов на уровне страницы.
|
||||
|
||||
Каждый кадр — одна запись протокола; выстрел рисуется тонкой линией
|
||||
от атакующего к защитнику, красной при `destroyed`, зелёной иначе.
|
||||
|
||||
Reference in New Issue
Block a user