Skip to content

Architecture

KNOWLEDGE Current-state fact

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 — 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.

Cargo.toml — workspace root (members, shared deps, profiles)
crates/
misaligned-core/ — sim library (lib name: misaligned); no Bevy/crossterm
src/sim/mod.rs — Sim aggregate root (types, state, advance, facade)
src/sim/perception.rs — senses, fog, inspect, anchors, labels, spatial queries
src/sim/communications.rs — messages, filings, recording/intel, hearing capture
src/sim/reach_build.rs — reach/device verbs, links, builds, badges, hall/racks
src/sim/work.rs — machine controls, WorkGrid, Thought sinks and readouts
src/sim/economy.rs — accounts, allocation, detection, research, income
src/sim/social_plot.rs — social/assets, plots, world acts, institutional ledger
src/sim/persistence.rs — Sim/SaveState bridge and transient reconstruction
src/sim/tests/ — behavior-grouped unit/integration tests + support
src/*.rs — map, save, domain systems (account, reach, …)
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

Public imports stay misaligned::sim::*; the sim/ file split is internal.

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).

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 (ui_projection, 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.

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. The field bridge and transient reconstruction live in sim/persistence.rs; save.rs retains the schema, serde defaults, versions, migrations, and I/O.
Terminal window
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
  • 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.