Editorial pass over site/ru/rules.md (on top of the verbatim port):
- moved the lore intro to the RU home page, rewritten in a modern voice;
- fixed typos, replaced the TODO/WTF cargo-tech note and the abandoned
(---ссылка---) marker with the verified mechanic and a real cross-link,
dropped the report TODO row;
- wove organic intra-page cross-links (#combat, #movement, #victory, ...);
- documented engine nuances verified against the code: ore auto-farming
and the capital / "запасы промышленности" store (industry capped at
population); cargo lost with ships destroyed in battle; and that a
losing race's colonists at a neutral planet are NOT lost — they stay
aboard (this corrects the audit note, verified in route.go).
Migration: delete game/rules.txt (its content now lives, authoritative,
in site/ru/rules.md) and repoint every reference to it (ui/frontend code
comments + tests, ui/docs, tools, ui/PLAN.md links). Record the
RU-authoritative rule in site/README.md and CLAUDE.md. The English
site/rules.md mirror follows in a separate stage.
Engine emits Floats at Fixed3 quantisation; UI now renders them as 3-decimal
fixed-point strings without thousand separators, monospaced via var(--font-mono)
on .numeric cells, and right-aligned in tables so columns line up on the
decimal point. Integer counts render with 0 decimals and no separators;
science fractions render as 1-decimal percent (matches the engine's third
decimal of precision).
Bug fixes from #51 (umbrella #43):
- Player Status drive/weapons/shields/cargo: were tech LEVELS rendered
through formatPercent (x100) — now use formatFloat (raw level).
- Races table: same bug, same fix.
Style/UX cleanups:
- Inspector field labels lose "stockpile" word ($ / M suffix carries it).
- Coordinates drop the parentheses (just "x, y").
- Inspector + report tables unify font sizes with calculator-tab
(values 0.85rem mono, labels 0.8rem).
Files:
- new util: ui/frontend/src/lib/util/number-format.ts
- report/format.ts becomes a thin re-export to keep section imports compact
- inspector planet / ship-group / actions: drop inline formatNumber,
mark numeric <dd> with class="numeric"
- table-races (+ bug fix), table-sciences, table-ship-classes,
designer-science: drop inline formatters, switch to util, add
class="numeric" on numeric <th>/<td>
- 17 report section files: class="numeric" on numeric th/td +
scoped CSS rule for mono+right-align
- i18n en/ru: drop "stockpile" word, drop "%" from tech-level column
headers in races + player_status (the "%" was the misleading bit
from the bug)
- tests/inspector-planet + tests/table-races: update assertions to
match the new format
Verification: pnpm test (814 passed), pnpm check (0 errors/warnings),
pnpm build clean.
Refs: #51 (#43 umbrella).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- lib/error/: classify any caught error into a stable ErrorKind from the
transport signal (HTTP status / Connect Code / fetch TypeError /
navigator.onLine); map to translated error.* messages via reportError
(sticky Retry toast for retryable kinds) or errorMessageKey (inline).
Mail compose now surfaces the translated 403/error inline.
- lib/ui/view-state.svelte: shared loading/empty/error placeholder with
the right live-region role + optional action; entity tables
(races/sciences/ship-classes) migrated, rest adopt incrementally.
- map/selection-ring.ts: accent ring around the selected planet, fed into
the map buildExtras alongside the reach circles.
- lib/ui/sheet-dismiss.ts: tap-outside + drag-handle swipe-down dismissal
for the planet/ship-group bottom-sheets (hand-rolled pointer events).
Tests: error, view-state, selection-ring, sheet-dismiss (761 total).
Docs: ui/docs/error-state-ux.md (+ index); F4 marked done.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tokenize every remaining component <style> — calculator, order tab,
inspectors, tables, report sections, lobby, auth, mail, battle viewer,
toasts, map overlays. A scripted pass handled the unambiguous core
palette (text/bg/surface/border/accent/danger/muted), the rest were
mapped to the semantic/grey tokens by role.
Remaining colour literals are the documented exceptions only: the
battle-scene SVG data-visualisation palette (fixed dark, like the WebGL
map canvas), overlay scrims (modal / map-canvas), and directional or
deliberate drop shadows. The default theme stays dark until light
coherence is signed off across the views.
Updates ui/docs/design-system.md (migration status + exceptions).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Clicking the already-active WAR/PEACE button still appended a
\`setDiplomaticStance\` whose \`relation\` matched the row's current
value. The engine would accept the duplicate harmlessly, but the
order tab inflates with rows that say nothing and every auto-sync
re-ships the redundant payload. Compare against the overlayed
stance (so a queued-but-not-applied change suppresses a re-click
that matches the *intended* state, not just the server snapshot)
and short-circuit when they agree. Mirrors the vote picker, which
already had the same guard.
vitest.config.ts: \`mergeConfig\` refuses callback-form base
configs, so resolve \`vite.config.ts\`'s callback with the test
context first and merge the plain object. Surfaced after the
\`loadEnv\` migration switched the root config to the callback
form.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the Races View in the in-game shell. The table lists every
non-extinct other race with tech levels (percent), totals,
planets, votes received, and a per-row WAR | PEACE segmented
control. A single vote-recipient slot above the table queues a
`CommandRaceVote`; per-row buttons queue `CommandRaceRelation`.
Both commands flow through the existing order draft store with
collapse-by-acceptor (stance) and singleton (vote) rules.
`GameReport` widens with `races`, `myVotes`, `myVoteFor`; the
decoder walks `report.player[]` once for the richer projection.
The optimistic overlay flips stance and vote target immediately;
`votesReceived`, `myVotes`, and the alliance summary stay
server-authoritative — alliance grouping and the 2/3 victory
check are tallied on the server at turn cutoff and explicitly
not surfaced client-side (`rules.txt` keeps foreign races'
outgoing vote targets private).
Includes Vitest component coverage of stance and vote
collapse rules + a Playwright e2e that drives both commands
through the dispatcher route and verifies the gateway saw the
expected `CommandRaceRelation` / `CommandRaceVote` payloads.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>