Simulation-first factory game built on a true 3D grid. The core differentiator is compact, layered machine architecture where ports, facing, altitude, support, and adjacency materially affect throughput and stability.
This repository now contains a real graybox vertical slice. The immediate goal is to tighten the shell, balance, and art-blockout pipeline before expanding the content surface.
- Genre: systems-heavy factory/simulation game with arcane-industrial presentation and a bio-industrial secondary layer
- Engine/runtime: Rust + Bevy
- Architecture: authoritative simulation in plain Rust, engine state derived from simulation state
- Camera/interaction: constrained 3D orbit camera with slicing, overlays, and mouse-first placement
- Milestone focus: prove that dense 3D machine logic is readable and fun before expanding content scope
- Game Spec: working product and architecture spec
- First Slice: current defaults for the prototype scope
- Decision Log: locked, provisional, and open design decisions
- Implementation Plan: active execution tracker for the first playable
- Development Process: implementation cadence, verification bar, and commit policy
- Playtest Checklist: what to watch during internal graybox sessions
- Agent Playtesting: JSON observation, command scripting, and trace export for automation/debugging
- Pre-Asset UI Pass: the remaining player-facing UI scope to lock before Blender work
- Art Blockout Spec: Blender/blockout constraints for the current machine set
- Content Authoring: how to add resources, machines, recipes, and scenarios safely
- Worlds And Saves: start-page flow, persistent world layout, autosave/manual-save behavior, and app-data paths
- Lock the product shell around persistent worlds, start-page navigation, and app-data saves
- Run balance passes on starter inventories, machine timings, and scenario thresholds
- Keep the first playable slice small, inspectable, deterministic, and easy to debug
cargo testvalidates deterministic simulation behavior, scripted scenario completion, and content loadingcargo run -p app_bevynow boots to a start page withContinue,New World,Load World, andScenario Browsercargo run -p app_bevy -- --scenario first_slicestill jumps straight into a transient preview session for iteration/debuggingcargo run -p app_headless -- --scenario first_slice --ticks 200runs the same simulation without any GPU/window dependencycargo run -p app_headless -- --load /tmp/three_d_systems_debug_save.json --inspect-part 12prints sim-owned bottleneck traces for a chosen part from a savecargo run -p app_headless -- --scenario first_slice --ticks 1 --jsonemits a machine-readable observation bundle with summary data, optional inspections, and the validated world snapshotcargo run -p app_headless -- --scenario first_slice --ticks 1 --json --json-profile summaryemits a thinner machine-readable summary without the full world snapshotcargo run -p app_headless -- --scenario first_slice --command-file docs/examples/agent-script.json --emit-trace /tmp/agent-trace.jsonl --jsonapplies a JSON step script and records per-step JSONL checkpoints for agent/debug workflowsF4toggles the stepwise tutorial,Htoggles the controls help,Escreturns to the start page, andVcycles slice-view modesF10toggles a cinematic full-factory view with wider framing, all layers visible, and the in-game panels hidden for cleaner screenshots/inspection- In persistent worlds,
F5manually saves andF8reloads from the current world save/autosave - In preview sessions,
F5saves to/tmp/three_d_systems_debug_save.json,F8reloads the preview scenario,F9loads that preview save, andF6/F7cycle preview scenarios Bextends a belt forward from the belt under the cursor, reusing its facing and safely stopping on blockersGtoggles optional placement hints for the current ghost so port-adjacent connection cells become visible when you get stuckZandXnow rotate the camera while held instead of stepping a single increment per key press- Power uses
wireparts as the actual transport layer. Yellow power ports show directionality, but touching machine-to-machine power ports does not create a live connection by itself. - Belts now accept item input from their back or side faces and still output only through their forward orange face, which makes turning and merging layouts possible without adding a separate corner-belt part.
- Connectivity overlay now supports focused network inspection from the hovered or selected part
- Overlay cycling now includes contamination and structural support views
- Scenario objectives can now be
stockpile_onlyorstockpile_and_sustain - Inspect-panel port-link tracing now comes from
sim_core, so the client is reading authoritative compatibility and blockage state instead of duplicating route rules - HUD and inspect state summaries now come from
sim_coreas well, including link counts, support summaries, and validated local contamination values - Inspect/readout flows now include end-to-end upstream and downstream item-path traces for starvation and congestion chains
- The Bevy client now renders solid graybox cube meshes instead of line-only debug cells, with the active slice emphasized and deeper layers faded by slice-view mode
- Slice changes now animate: the cut plane eases between floors and visible layers fade instead of snapping instantly
- Slice modes now keep a faint hint of structure above the active floor while keeping arrows, highlights, and other diagnostic markers focused on the current/below view
- Above-floor terrain hints now render as faint structural ghosts instead of heavy dark blocks, and the lower panels reserve stable space so item switching does not make them jump
- Machine defs can now optionally point at GLB blockouts through
render.model, withrender.model_scaleandrender.model_offsetavailable for minor correction while keeping cube fallback rendering intact - Terrain/support volumes now render as fuller blocks so machines feel seated on structure instead of visually hovering above thin slabs
- The Bevy client now draws a small compass rose on the active slice so world north/east/south/west stay visible during building
- Tutorial targets now render as volumetric highlighted cells instead of flat-only markers, and machines get cheap contact pads to make support contact easier to read without real shadow maps
- Newly placed parts now settle in with a short drop animation, and transport cells use a subtle flow pulse so conveyors/lifts read as active without needing full authored animation
- The
first_slicescenario now has a live step-by-step tutorial that advances off real sim state and paints in-world highlight markers on current targets such as resource nodes or the next machine group - The default UI is intentionally slimmer now: compact status HUD, concise inspect panel, and an optional tutorial/help panel instead of always-on prompt walls
- The Bevy UI now uses panelized cards with calmer always-on text, a focused tutorial card, and contextual overlay legends so the player-facing screen is less crowded during normal play
- The client now has a dedicated build palette panel with hotbar counts and a persistent placement-block reason, so build mistakes are visible without relying on the transient status line
- The build palette can now expand into selected-part details with
C, and the inspect panel now exposes selected-machine configuration options more concretely instead of only showing generic state - The current graybox identity now leans into warm industrial machinery with earthy bio accents: darker iron terrain, brass/copper highlights, verdigris transport, and industrial-console UI cards
- Starter scenario inventories are intentionally more generous on belts and wires so early tutorial/layout mistakes are less punishing during playtests
- The Bevy client now treats a
worldas a persistent scenario instance, not a procedural overworld. - By default, saves live under:
- macOS:
~/Library/Application Support/three_d_systems_game/ - XDG/Linux fallback:
$XDG_DATA_HOME/three_d_systems_game/or~/.local/share/three_d_systems_game/
- macOS:
- Layout:
profiles/default/settings.jsonworlds/<world_id>/meta.jsonworlds/<world_id>/state.jsonworlds/<world_id>/autosave.json
meta.jsontracks display name, scenario, tick, victory state, and summary text for the start page.- Set
THREE_D_SYSTEMS_APPDATA=/custom/pathto override the app-data root for testing or portable runs.
- The Bevy client still requires a graphics backend. A MacBook Air should be able to run it through its integrated GPU and Metal support.
- On macOS, the Bevy client now prefers the Metal backend and a low-power adapter by default unless you override
WGPU_BACKENDorWGPU_POWER_PREF. WGPU_FORCE_FALLBACK_ADAPTER=1is a best-effort software-rendering attempt exposed by Bevy/wgpu, but availability depends on the platform and installed drivers. For guaranteed no-GPU execution, useapp_headless.- The in-game HUD now shows the active renderer backend, device type, and adapter name once the renderer initializes.
- Headless environments such as CI, remote shells, or this sandbox should use
app_headless. - Example:
cargo run -p app_headless -- --scenario dual_lift_spine --ticks 200 - Example:
cargo run -p app_headless -- --load /tmp/three_d_systems_debug_save.json --ticks 100 - Example:
cargo run -p app_headless -- --load /tmp/three_d_systems_debug_save.json --inspect-part 12 - Example:
cargo run -p app_headless -- --list-scenarios
- The simulation is the product; presentation exists to clarify it
- 3D complexity is only acceptable when inspection tools keep it legible
- Support, occupancy, ports, and adjacency rules should be strict early
- Anything that weakens readability or determinism gets pushed out of scope