# Architecture ``` Type: knowledge ``` **As-built:** a Cargo **workspace** with four packages. Game rules live only in `misaligned-core`; frontends are thin packages that depend on it. **Why this shape exists** (binding): [crate-workspace.md](crate-workspace.md) — package jobs, dependency edges, naming, rejected alternatives, and standing criteria. This knowledge page is the path/layout mirror; it does not replace that page's reasons. Multi-agent gates: [agent-scale.md](../process/agent-scale.md). ## Workspace layout ``` Cargo.toml — workspace root (members, shared deps, profiles) crates/ misaligned-core/ — sim library (lib name: misaligned); no Bevy/crossterm src/*.rs — Sim, map, save, systems, … tests/act_one.rs — Act One integration test misaligned-terminal/ — binary `misaligned` (crossterm + agent protocol) misaligned-bevy/ — binary `misaligned-bevy` (Bevy 0.18 frontend) misaligned-assets/ — shared art lib + `misaligned-assets` mesh tester + `misaligned-effects` liquid/dust lab ``` ### Package contracts | Package | May contain | Must not contain | |---|---|---| | `misaligned-core` | `Sim`, map, systems, save format, rule tests | Bevy, crossterm, wall-clock-driven game rules | | `misaligned-terminal` | UI, input, agent line protocol, wall-clock tick mapping | Game-rule forks of `Sim` | | `misaligned-bevy` | 3D/2.5D view, shot harness, wall-clock tick mapping | Game-rule forks of `Sim` | | `misaligned-assets` | Shared mesh/effect render code and focused art harnesses | Save/load of full runs; sim progression | Frontends import the lib as `misaligned::…` (crate name `misaligned-core`, lib name `misaligned`). That split is deliberate: package name states the **job** (core); lib name states the **product** so imports stay stable — see crate-workspace naming. `misaligned-bevy` depends on `misaligned-assets` for shared rack/mesh/effect rendering so the game binary and focused art harnesses do not fork visual code; assets still does not depend on core (no sim progression in either tester). ## The sim/frontend contract These invariants are load-bearing (they keep replays, debugging, and the future async-multiplayer option open — see wiki/gameplay/horizon.md guardrails): - **Game rules live only in core.** If a frontend needs an `if` about game behavior, that logic belongs in `Sim`. The Bevy frontend once forked the rules and diverged badly; that cost a full rewrite (see wiki/log/2026-07-05-bevy-sim-port.md). - **`Sim` never reads the wall clock and does no I/O** (save path helpers that use `dirs` for the JSON save location are infrastructure on the save format, not sim progression). Frontends own the wall-clock-to-tick mapping (`tick_ms`, pause, bounded catch-up of max 5 ticks per frame). `Instant::now()` appears only in frontend code. - **Frontends talk to the sim through command/query methods** (`inspect`, `core_position`, `salvage_nearest_to`, `buy_rack_at`, `add_fallback_at`, `create_save_state`/`apply_save_state`, and each system's commands as its spec lands) and read state directly for rendering. The cursor is frontend state only; there is no `move_player` or sim-owned avatar. Messages flow back via `drain_log()` — call it once per frame/turn, not per command batch. - **After build actions** (place/demolish, done by frontends via `BuildMode` mutating `sim.map`/`sim.player` directly), call `sim.recompute_derived()`. This is the one place frontends mutate sim internals; a future cleanup could move BuildMode application into a sim command. ## Save format `crates/misaligned-core/src/save.rs`, serde JSON. `SaveState` derives `Serialize`/`Deserialize` directly. Written to `dirs::data_dir()/misaligned/misaligned_save.txt` (macOS: `~/Library/Application Support/misaligned/`). - The save is a single JSON object with a `version` field for future migration. Full B1 subsystem state: compute, core, detection, day job, people, reach, intel, accounts, research, objective, building intents, badge, WorkGrid, remembered fog snapshots, map and RNG. The cursor position is deliberately absent. - Version migrations are additive and explicit in `save.rs`. Ownership of the format stays in core — frontends must not implement migrations. ## Build commands (workspace) ```bash cargo test -p misaligned-core cargo run -p misaligned-terminal --release # or: cargo run --release cargo run -p misaligned-bevy --release cargo run -p misaligned-assets ./tools/check.sh --lib # core + terminal + cheap bevy check ./tools/check.sh --frontend # bevy + assets ./tools/check.sh --full # workspace ``` ## Known architectural debts - `BuildMode` lives in core but is really frontend-shared UI state. - Scale-debt items (compute grouping, recursive layouts) remain governed by wiki/vision/scale.md; no aggregate machinery until the stage needs it.