Skip to content

Latest commit

 

History

81 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Incinerator Engine

Incinerator is a game-specific 3D engine with a completed single-player sandbox and an accepted Apple Silicon macOS multiplayer foundation. MP0-MP5/M4 prove a server-authoritative direct-IP session with characters, vehicles, carry interaction, district relevance, NPCs, prediction, reconnect, bounded delta replication, and open room admission. M5 client/authority cohesion is accepted: solo is a cohesive placement of the same client/authority model. M6 is also accepted: authority ingress, mutation, durable disposition, and derivative publication now follow one bounded fail-stop atomic-publication cycle. MP6 is accepted as well: graphical clients now use one generation-safe room lifecycle across constrained private listen and dedicated direct-IP placements. The S10 damage/death/respawn slice is accepted: players and NPCs share bounded authoritative vitals, clients request server-validated melee, death tears down the disposable physical avatar while retaining the participant, and explicit safe respawn creates a new avatar incarnation. S11 is accepted as well: an authority-owned hostile NPC perceives, pursues, attacks through vitals, reacts, dies, and is safely replaced with a new generation and visible client and developer feedback. The intended experience supports solo play as a local placement of the same authority model used by optional private listen/invite and canonical public dedicated sessions. The selected network transport is the open-source GameNetworkingSockets flat C API over direct IP; Steam networking remains an optional non-vendored integration. It uses Zig, SDL3, Jolt Physics, Flecs, and ImGui.

The engine is intended to become open source and the game will be licensed separately. No engine license has been selected yet, so this repository currently grants no license. The overhaul is greenfield: prototype APIs and file formats may change without compatibility shims. See OVERHAUL_PLAN.md for the main roadmap, ARCHITECTURE_REVIEW.md for the living architectural assessment, MULTIPLAYER_PLAN.md for the completed MP0-MP5/M4 foundation and accepted M5 cohesion gate, and CLEANUP_PLAN.md for the completed post-M3 consolidation record. M6 transactional authority hardening, MP6 playable room flow, and S10 damage/death/respawn are complete and accepted: M6 (accepted)MP6 (accepted)S10 (accepted)S11 (accepted). Post-S11 manual real-window acceptance exposed a missing temporal gameplay validation and causal-observability layer. IV0-IV5 are now complete and accepted, including shared solo/listen/dedicated scenarios, deterministic fault/fuzz/reconnect coverage, routine and long soaks, and semantic Metal visibility. The continuing contract is recorded in the interaction validation design, with durable rationale in ADR-020 and phase evidence in the validation ledger. Human acceptance further tightened that contract: physical controller teardown on death now leaves a red, noninteractive replicated death proxy until respawn; the hostile presentation separates from that proxy so it cannot hide the corpse; primitive material tints are enforced by the real product shader; carried objects are visibly released; drop placement stays within a valid world coordinate; and gameplay trace schema 2 preserves typed rejection reasons and semantic presentation membership transitions. The current correction also reserves incident capacity for notes/replay/ handoff, keeps spatial objects independent of streamed-content residency, retains NPC death presentation until replacement registration, and clamps the follow camera to the target side of world blockers. Human testing now accepts the recipe-5 open traversal, sustained vehicle/NPC contact, carry/drop continuity, and schema-4 incident workflow. The default product uses a 1600×900 window, wider follow cameras, separated sandbox spawns, district/navigation intent overlays, and the measured vehicle profile recorded in docs/validation/vehicle-dynamics.md. S12 destination-driven NPC navigation/replanning and S13 authored population are accepted after automated native evidence and the product-owner checkpoint. S13 builds authored sandbox activity on that boundary: twelve stable population members own explicit roles, combat disposition, deterministic cyclic activity, exclusive slots, safe generational replacement, and readable Population Lab plus incident evidence. The implementation, bounded higher-fidelity map, and automated evidence are recorded in ADR-023, the S12 plan, and the S12 evaluation world, with executed results in the S12 validation ledger, then ADR-024, S13 authored-population plan, S13 population evaluation world, S13 validation ledger, and S13 performance baseline. The repository also retains a completed neural-rendering proof-of-concept lineage through RF10. RF10 proved a direct native 256×144 → 1280×720 Core ML/Metal trial, but it remains external, unpromoted, and is not installed or selected as game content. On 2026-08-17 the product owner paused neural-rendering implementation indefinitely and returned product focus to the conventional deterministic renderer. The existing boundary still matters: ADR-025 keeps learned output presentation-only, and ADR-026 governs any explicit future restart. The authoritative current disposition is the neural-rendering pause; the detailed north star, historical implementation plan, and research index remain preserved evidence, not an active backlog. The ED1 structured developer workspace is complete and organizes the existing ImGui tools into a deterministic docked workspace with descriptive panel metadata, LLM-addressable startup layouts, and incident-aligned time identity; see its validation record. The DR1 playable deterministic visual-fidelity slice is implemented through agent-native acceptance. It provides one explicit lit normal-bearing product path, bounded renderer-neutral light/material values, a more readable evaluation-world composition, Render Lab, schema-5 render-state evidence, and a repaired full native gameplay/incident journey. See the DR1 validation record. The product-owner DR1 visual walkthrough is accepted. DR1 is complete. S14 implements one authoritative hitscan handgun across solo, private-listen, and dedicated placements with finite ammunition, final-shot automatic reload, manual tactical reload, current-state semantic targeting plus Jolt obstruction, vitals-owned damage/death, reconnect/replay, client-owned HUD/weapon/tracer presentation, and schema-5 firearm evidence. Its focused, two-client real-GNS, two-rate installed Metal, ordinary-product, and continuous mouse-look gates pass. S14 is accepted. S15 now expands the deterministic sandbox into one exact four-district 2×2 cohort with cross-axis navigation, north-row activity, singular flat support ownership, and measured four-scene residency. Its automated gate, two-rate Metal acceptance, measured baseline, and product-owner four-district walkthrough pass. S15 is accepted. The active Engine Authoring Foundation sequences practical materials/textures, vehicle archetypes and local AI tuning, authored lighting, game-owned map construction, and the separately built game proof under ADR-029. EA0 and EA0.5 are accepted. The local typed endpoint and canonical CLI passed focused/aggregate, installed Metal, LLM-agent, architecture, human usability, and product-owner review. Phase 7 now makes that CLI a first-class agent contract with a machine-readable catalog, guided results, and repository-owned skill; the planned MCP adapter was eliminated because local coding agents have shell access. Its implementation/automated/native/clean-context/comprehensive- manual-agent candidate passes; product-owner stop review remains and EA1 has not started. The combined-tree deterministic-rendering resumption audit passes and records the correction that restored the ordinary product from an RF10-fixed centered viewport to the full drawable. Broader Steam/public-service infrastructure remains deferred.

Toolchain Cohort

These versions are one tested compatibility cohort and should be upgraded together rather than package-by-package:

Component Pinned version Integration
Zig 0.16.0 exact Recorded in .zigversion; enforced by the build guard (the package manifest records the same minimum floor)
SDL 3.4.14 castholm/SDL wrapper 0.5.3 at an exact commit
Jolt Physics 5.5.0 Engine-owned JoltC build package with exact Jolt, JoltC, and Zig wrapper commits
Flecs Exact development commit zflecs wrapper pinned with an explicit ABI/feature cohort and one C-source owner
ImGui Exact development commit Optional zgui editor; its SDL3 backend is compiled by the engine against the selected SDL 3.4.14 headers
GameNetworkingSockets 1.5.1 exact commit Open-source direct-IP transport behind an engine-owned C ABI shim; Steamworks remains optional and absent

The complete dependency identities live in build.zig.zon and third_party/joltc-zig/README.md. Dependency features that affect linkage, ABI, or compiled capabilities are selected explicitly; they are not inherited silently from wrapper defaults. The shared simulation build graph generates the replay cohort from those pins and physics limits, and an automatic verifier rejects manifest drift. Flecs is compiled as private ECS storage with only the OS API implementation addon, excluding its HTTP, REST, script, metrics, module, and pipeline surfaces. Jolt's cross-platform deterministic build mode is deliberately disabled. The future network model is an authoritative server, not client lockstep; enabling that mode would need a measured requirement and performance evaluation.

The pinned SDL 3.4.14 Metal backend has a known inverted SDL_QueryGPUFence implementation, fixed upstream after that release. The macOS adapter centralizes the cohort-specific inversion and names the exact upstream removal commit; renderer consumers share the fence from the real download-bearing frame submission. This workaround must be removed, not carried forward, when SDL advances to a release containing that fix.

Platform Priority

Status Platform Architecture Graphics path Contract
Current macOS Apple Silicon (aarch64) Metal / MSL The only build, test, runtime, performance, editor, packaging, and CI target
Future/deferred Linux / SteamOS Undecided Likely Vulkan / SPIR-V No current support claim, build gate, CI job, or compatibility requirement
Future/deferred Windows Undecided Likely D3D12 / DXIL No current support claim, build gate, CI job, or compatibility requirement

The active build retains no Linux, Windows, Vulkan, or D3D12 path. Porting resumes only after a separate product decision selects a second platform; that work will establish a new tested target cohort instead of constraining current design around removed prototype branches. Mobile, web, consoles, and Intel macOS are also outside the current contract.

The vendored third_party/joltc-zig package still contains upstream OS/compiler conditionals for JoltC itself. Those are dependency-internal portability code, not an Incinerator target, build option, test gate, or support claim. The top-level client and cold-headless graphs reject every non-native Apple Silicon macOS target before resolving that package.

Developer Environment Setup (macOS)

Prerequisites

1. Zig Compiler

Install Zig 0.16.0 exactly using the official archive or a version manager. Do not use an unpinned package-manager latest as the project toolchain contract.

zig version  # Must print 0.16.0

2. Shader Compilation Tools

The maintained build compiles GLSL 4.50 to MSL for macOS and generates canonical SPIR-V reflection data to validate the shader/renderer contract. No secondary-platform shader branch is part of the active graph.

For local convenience on macOS, tools may come from PATH:

brew install shaderc spirv-cross
glslc --version
spirv-cross --revision

CI and release validation use the exact-pinned macOS manifest. Future platform work must introduce its own reviewed toolchain cohort. See tools/shader-toolchain/README.md. Generated shaders, reflection JSON, and embedding modules remain in the Zig cache; builds do not write generated artifacts into the source tree.

3. Multiplayer Transport Build Tools

The MP2 direct-IP products build pinned GameNetworkingSockets from source. On Apple Silicon macOS install its build-time dependencies with:

brew install cmake ninja protobuf openssl@3

The open engine does not require Steamworks, a Steam login, a cloud provider, or a lobby service.

Building

# Build the engine
zig build

# Build and run
zig build run

# The normal product creates one playable hostile encounter after the local
# player and west district are authority-ready. Use Q for melee and R to request
# respawn after death; this is ordinary product composition, not a validation
# scenario flag. A separate narrow product owner correlates NPC-caused player
# death, character despawn, cooldown, respawn, and the new avatar projection.

# Compile the cold MP2 authority and presentation-only graphical client, then
# run the real-GNS two-client acceptance proof and binary boundary audit.
zig build check-mp2
zig build verify-mp2 --summary all

# Run MP2.1/MP3 lifecycle, prediction, deterministic latency/jitter/loss/
# duplicate/reorder/blackout, accepted-ingress replay, real-GNS regression,
# and independent authority-stop process acceptance.
zig build verify-mp3 --summary all

# Run MP4-A authoritative vehicle replication plus bounded local prediction,
# correction/collision/lifecycle evidence, faults, replay, and GNS regressions.
zig build verify-mp4 --summary all

# Add authoritative carry interaction, disconnect cleanup, acknowledged
# district baselines, relevance hysteresis, JIP/reconnect, and GNS contention.
zig build verify-mp4b --summary all
zig build verify-mp4c --summary all
zig build verify-mp4d --summary all
zig build verify-mp4e --summary all
zig build verify-mp4-complete --summary all

# Run the focused open room/invite proof, or the full MP5 gate. Steamworks is
# not required; direct GNS IP remains the executable route.
zig build run-mp5-acceptance --summary all
zig build verify-mp5 --summary all

# Run the complete Apple Silicon macOS multiplayer-foundation gate.
zig build verify-m4 -j1 --summary all

# Run the accepted M5 cohesion aggregate. Its contract and measured evidence
# matrix are linked below.
zig build verify-m5 -j1 --summary all

# Run the accepted M6 transactional-authority gate, then the complete playable
# MP6 room gate (listen, dedicated, fault lifecycle, architecture, and inherited
# regressions).
zig build verify-m6 -j1 --summary all
zig build verify-mp6-room -j1 --summary failures

# Run the accepted authoritative damage/death/respawn slice. This starts two
# real graphical clients in both listen and dedicated placements.
zig build verify-s10 -Deditor=false -j1 --summary failures

# Run the accepted hostile-NPC encounter slice. This composes focused
# authority/persistence/replay/fault/scale gates, the normal-product host
# encounter lifecycle, installed solo Metal combat presentation, and graphical
# listen and dedicated death-and-replacement proofs. Characterize the declared 64-NPC/
# 16-participant synthetic ceiling separately in ReleaseFast.
zig build verify-s11 -Deditor=true -j1 --summary failures
zig build measure-s11 -Deditor=false -Doptimize=ReleaseFast

# Verify that the filtered Zig source package retains the M5/M6/MP6/S11
# architecture and can compile/run its product bootstrap, headless,
# persistence, snapshot, replay, and session closure.
zig build verify-source-package -Deditor=false --summary all

# Native SDL proof that the first scene click captures without firing, a
# captured click reaches gameplay, Escape follows interaction/capture/menu
# priority, and only an explicit lifecycle request quits.
zig build test-mouse-capture-macos --summary all

# Manual three-terminal multiplayer test. Build/install once, then launch one authority
# and two graphical clients with distinct development accounts.
zig build install-mp2
./zig-out/bin/incinerator_mp2_server --port 27020
./zig-out/bin/incinerator_mp2_client --connect 127.0.0.1:27020 --account 1
./zig-out/bin/incinerator_mp2_client --connect 127.0.0.1:27020 --account 2

# Client controls: WASD move, Space jump, E enter/exit, F collect/drop,
# Q melee, R request respawn after death, click the playable area to capture
# continuous mouse-look, and Escape to release it. Close the window to quit an
# editor-disabled client. Right mouse + drag remains available without capture. While
# driving, W/S are throttle/reverse, A/D steer, Space brakes, and Left Shift is
# the hand brake. P toggles vehicle prediction for live A/B comparison. F8
# manufactures a transport loss and reconnect while playing. Recoverable
# transport loss uses monotonic capped retry; rejection and authority shutdown
# terminate cleanly without reconnecting.
# The authority binds loopback by default. `--allow-remote` is only for trusted
# LAN/development testing because MP2 AccountId values are not authenticated.

# Manual MP6 listen-room test. The host writes a permission-restricted guest
# ticket and prints its path; launch the graphical guest with that exact path.
zig build install-mp6
./zig-out/bin/incinerator_mp6_listen --port 27020 --ticket /tmp/incinerator-guest.room
./zig-out/bin/incinerator_mp2_client --ticket /tmp/incinerator-guest.room

# Manual MP6 dedicated-room test. The server writes one signed ticket per
# configured account; launch one graphical client for each printed ticket path.
./zig-out/bin/incinerator_mp6_server --port 27020 --ticket-dir /tmp/incinerator-room
./zig-out/bin/incinerator_mp2_client --ticket /tmp/incinerator-room/account-1.room
./zig-out/bin/incinerator_mp2_client --ticket /tmp/incinerator-room/account-2.room

# MP6 controls add C to cancel the active room operation and L to leave/close;
# Q performs authoritative melee, R requests respawn after death, and F8 still
# manufactures guest transport loss and bounded reconnect.

# Compile or explicitly install the separate visual-validation host. Normal
# `zig build` does not install validation; validation lives in libexec.
zig build check-validation -Deditor=false
zig build install-validation -Deditor=false
zig build verify-validation-boundary -Deditor=false

# Run the full kernel, feature, host, adapter, and shader contract
zig build test

# Run the SDL-free real Flecs/Jolt sandbox lifecycle suite
zig build test-headless -Deditor=false

# Build and test the genuinely cold operational headless product. This branch
# does not resolve SDL, GPU/editor packages, shaders, or visual content.
zig build -Dproduct=headless test --summary all

# Run the deterministic M3 authority soak (32,768 ticks) or its opt-in long
# cohort (131,072 ticks). Both require a ReleaseFast Apple Silicon macOS build.
zig build -Dproduct=headless -Doptimize=ReleaseFast measure-m3 --summary none
zig build -Dproduct=headless -Doptimize=ReleaseFast measure-m3-long --summary none

# Install only the operational binary plus its exact config/content manifests,
# then verify that allowlist and Mach-O boundary.
prefix=$(mktemp -d /tmp/incinerator-headless.XXXXXX)
zig build -Dproduct=headless -Doptimize=ReleaseFast \
  --prefix "$prefix" install-headless-product verify-installed-headless-product

# Run the installed product. Inputs must be absolute paths. The optional
# producers exercise bounded external work and exact completion delivery.
"$prefix/bin/incinerator_headless" \
  --config "$prefix/etc/incinerator/headless/config.example.json" \
  --content-manifest "$prefix/share/incinerator/headless/content.json" \
  --synthetic-producers

# Exercise the S4-B same-cohort replay contracts and compile the standalone
# SDL/editor/GPU-free replay verifier.
zig build test-replay -Deditor=false
zig build check-replay -Deditor=false

# Record and verify the installed cooked-content scenario from /tmp. This
# proves normal replay plus an exact district-ingress divergence.
zig build smoke-installed-s4-replay-macos \
  -Doptimize=ReleaseFast -Deditor=false

# Exercise bounded physics extraction, persistent Metal uploads/draws, and the
# fixed host profiler in the complete sandbox scenario.
zig build smoke-installed-s4-physics-debug-macos \
  -Doptimize=ReleaseFast -Deditor=false

# Exercise real editor relocation/undo/redo/save, then cold-restore that exact
# slot in a fresh installed SDL/editor/GPU-free process.
zig build smoke-installed-s5-authoring-macos \
  -Doptimize=ReleaseFast -Deditor=true

# Exercise the standalone two-process durable save/restart path.
zig build smoke-installed-s5-save-macos \
  -Doptimize=ReleaseFast -Deditor=false

# Exercise the complete carry lifecycle in the installed Metal host at both
# cadence extremes, then run the SDL-free 128-cycle ownership measurement.
zig build smoke-installed-s7-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build measure-s7 \
  -Doptimize=ReleaseFast -Deditor=false --summary none

# Run the current SDL-free 64-NPC/65-controller scale characterization.
zig build measure-s8 \
  -Doptimize=ReleaseFast -Deditor=false --summary none

# Run the renderer-free Jolt integration test
zig build test-physics

# Run shader reflection contract tests directly
zig build test-shaders

# Verify the release configuration
zig build -Doptimize=ReleaseFast

# Build without development editor dependencies
zig build -Deditor=false

# Verify the build-installed cooked content without initializing a window or
# GPU. This command runs Zig's cache artifact; use the installed smokes below
# when executable relocation is part of the proof.
zig build run -- --verify-install

# Exercise only the cooked bundle/catalog/admission and installed /tmp gates
zig build test-content -Deditor=false
zig build test-content-cooker -Deditor=false
zig build test-district-content-catalog -Deditor=false
zig build smoke-installed-content -Deditor=false

# Run the serialized Tier-1 installed-runtime readiness gate. This launches
# the separately named installed validation Mach-O from /tmp, not the normal
# product or Zig's cache artifact.
zig build test-macos-readiness \
  -Doptimize=ReleaseFast -Deditor=true

# The native gates can also be run independently. The historical S1 visual
# gate remains available as a regression check.
zig build smoke-installed-s1-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s2-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s3-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s6-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s7-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s8-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s11-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build test-s12-navigation \
  -Doptimize=Debug -Deditor=false
zig build measure-s12 \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s12-macos \
  -Doptimize=ReleaseFast -Deditor=true
zig build verify-s12 \
  -Doptimize=ReleaseFast -Deditor=true
zig build test-s13-population \
  -Doptimize=Debug -Deditor=false
zig build measure-s13 \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s13-macos \
  -Doptimize=ReleaseFast -Deditor=true
zig build verify-s13 \
  -Doptimize=Debug -Deditor=true
zig build smoke-installed-s4-diagnostics-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s4-replay-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s4-physics-debug-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-installed-s5-authoring-macos \
  -Doptimize=ReleaseFast -Deditor=true
zig build smoke-installed-s5-save-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-window-lifecycle-macos \
  -Doptimize=ReleaseFast -Deditor=false
zig build smoke-init-failures-macos \
  -Doptimize=ReleaseFast -Deditor=false

The installed S11 validation additionally performs four validation-only, fenced Metal object-ID captures at contact, player death, respawn, and NPC death. It asserts semantic pixel occupancy/bounds above and below the 60 Hz authority cadence, including a meaningful minimum footprint for the retained dead player. Shader reflection separately proves that primitive material tint reaches the real color pass; the ID oracle is not treated as proof of product swapchain color. The normal incinerator_engine binary contains none of the oracle or first-failure artifact path; those remain in incinerator_validation.

incinerator_engine is the normal interactive client. Scripted slice scenarios, lifecycle probes, initialization failpoints, and deliberate faults are compiled only into incinerator_validation, which is installed under libexec/incinerator only when a validation step requests it. The installed smoke/readiness steps select that artifact automatically; validation-only command-line flags are rejected by the normal client.

Content Boundary

The engine package and repository intentionally exclude game-owned assets. The retired unreferenced demo GLBs were removed; only the small self-authored, provenance-recorded engine conformance fixtures under fixtures/ participate in cooking, packaging, or startup.

The runtime consumes versioned renderer-neutral cooked bundles from an explicit absolute content root. Source glTF and image decoding exist only in the host cooker; the runtime executable does not import the former prototype glTF loader, zmesh, or zstbi. The build cooks two self-authored adjacent fixtures and a canonical exact-identity catalog into the Zig cache, then installs them beneath share/incinerator/content/district/ with both provenance records. The checked-in dependency closure is west -> east -> catalog; identical inputs produce byte-identical outputs. zig build run configures the installed content root explicitly, while a relocated installed executable derives the same root from its application prefix. --content-root=/absolute/path overrides either behavior.

Before logical or GPU activation, the shared admission boundary loads only district/catalog.icat, validates both bundles and coordinate-specific logical checksums, and creates the content fingerprint used by replay and durable saves. Runtime scene requests recheck the exact admitted bundle identity, so a bundle replaced after startup cannot publish ready content under the original cohort.

The reusable district contract owns bounded payload shapes, structural validation, checksums, tickets, and loader/navigation capabilities. The sandbox-owned src/sandbox/district_recipe.zig owns the installed west/east coordinates, collision fixtures, recipe cohort, and exact route topology consumed by cooking, admission, streaming, restore, replay, and preflight. Concrete game-world policy is therefore not part of the engine feature contract.

The normal sandbox samples the character or occupied vehicle position at fixed ticks through host-owned proximity hysteresis. Exactly two catalog-backed stream slots share one joined content worker and one bounded GPU registry. Entering a district reads and validates its exact cooked bundle, activates logical collision, and immediately draws every mandatory blocking proxy. Authored decorative scene instances are added after the Metal fence signals; they never replace collision presentation. Adjacent hysteresis permits both west and east districts to overlap while per-generation recycling lets either drain without releasing its neighbor. --verify-install validates installed cooked content without initializing SDL or a GPU. The installed S3 smoke preserves the single-district cancellation regression; the S6 smoke proves three complete forward/reverse overlap cycles, truthful production diagnostics, both render cadences, and complete two-slot drain from /tmp.

Controls

The normal macOS sandbox opens at 1600×900. Character and vehicle follow distances are 9 m and 12 m respectively.

Key Action
Click scene in Character mode Capture the mouse for continuous turn/look; the first click only captures and does not fire
ESC Cancel an active gizmo drag, cancel Free Camera look, release Character mouse capture, close an open system menu, or open the system menu—in that order
W / A / S / D Move the character or drive in Character mode; fly while holding right mouse in Free Camera
E Enter or exit the sandbox vehicle in Character mode
F Collect/drop in Character mode; frame the shared World Outliner/viewport selection in Free Camera
Q Request authoritative melee in Character mode
1 Equip or holster the authoritative handgun in Character mode
Left mouse Fire while captured in Character mode; select the nearest world object in Free Camera
R In Character mode, manually tactical-reload while alive or request respawn after death/cooldown
Space Jump on foot or service-brake while driving in Character mode
Left Shift Handbrake while driving; accelerate Free Camera flight
Right mouse + drag Turn/look without capture in Character mode; own Free Camera fly/look input
Q / E while right-dragging Move Free Camera down/up
Mouse wheel over scene Adjust Free Camera flight speed
F1 Toggle editor UI
F2 Toggle ImGui demo
F3 Toggle Character / Free Camera viewport mode
Command+Option+I Recommended macOS shortcut to flag a human-test anomaly
F9 / Fn+F9 Optional shortcut when macOS delivers the function key to SDL
Command+Shift+9 Optional alternate anomaly shortcut

The editor now opens as one docked developer workspace around the central game view. Use Workspace to select a task layout, Panels to toggle individual tools, and Help → Workspace Guide to inspect each panel's purpose, source data, typed request boundary, example values, and audit identities. Automated or LLM-guided visual sessions can select the initial workspace explicitly:

zig build run -- --editor-layout=navigation --editor-focus=navigation_lab --editor-guide
zig build run -- --editor-panels=gameplay_inspector,diagnostics,incident_capture --editor-focus=incident_capture

The scene toolbar makes Character versus Free Camera explicit. Free Camera is editor-local presentation state: it releases SDL relative mouse mode, suppresses local gameplay actions, and does not pause the simulation or enter authority snapshots, replication, replay, or world saves. The World Outliner lists current crate and gameplay instances by stable semantic identity. Search or filter the list, click a row, or left-click the rendered object in Free Camera; all editor panels share that one selection. A yellow bounding box and XYZ marker show the selected object, F/Frame Selection frames it, and Clear Selection or an empty scene click clears it. Panel, toolbar, menu, bottom-bar, and status-bar clicks never pick through the UI. During an active gizmo drag, Escape restores the complete position draft and dirty state retained at mouse-down. Outside an active interaction or pointer capture, Escape opens the system menu; Escape/Resume closes it, and only its explicit Quit action exits. Opening this local menu clears held gameplay input but does not pause simulation or multiplayer authority.

The reserved top status strip presents player health, handgun state and firing controls, threat/action feedback, incident status, and mouse-capture state in responsive ImGui columns. The macOS window title remains the stable product name instead of duplicating live status. The persistent bottom bar shows UTC, wall_unix_ms, authority tick, presentation frame, and active layout so screenshots align with incident evidence. Open the editor with F1, then use Panels → Physics Debug & Profiler. Its master switch and category checkboxes control bounded shapes, bounds, contacts, centers of mass, and velocity evidence. The same panel shows persistent Metal upload/draw state, visible capacity loss, fixed phase spans, and per-frame draw/upload/stream/resource counts. These are host-only typed controls; they do not mutate simulation state. Use Instruments and Metal capture for deeper platform profiling.

The bounds category also draws active 16 m streamed district cells and NPC navigation targets/routes. A red NPC target reports 120 ticks of potential no-progress; it is diagnostic telemetry and does not alter authority.

Panels → Gameplay Inspector explains the selected local player or NPC across its durable/replicated identity, authority and presentation pose, health/life, encounter deadline, separation, and last action disposition. It cannot mutate gameplay authority. Panels → Event Log is a separate bottom-wide tab for the bounded runtime journal and selected-entity gameplay event history. Both histories are collapsed by default and scroll inside the wide panel when opened. Gameplay events record requests, authority admission, outcomes, replication, and presentation; their pause/resume buttons control recording only, not gameplay. Panels → Diagnostics is reserved for runtime health, an explicitly labelled gameplay pause checkbox, single-tick control, and collapsed queue, authority-cycle, world-streaming, and residency details. Durable incident streams replace the removed giant terminal JSON export.

The top status strip remains visible as one responsive ImGui box when F1 hides the docked developer workspace. It gives plain-language health, damage, handgun controls (1 equip/holster, left mouse fire, R tactical reload), attack, cooldown, death, respawn, rejected-action, incident, and mouse-capture feedback. A dead player remains visible in red until respawn, rather than disappearing as an implicit representation of authority teardown.

Every Debug product run records a bounded schema-5 diagnostic bundle under ~/Library/Logs/Incinerator/runs. Press Command+Option+I near an anomaly (or use F9/Fn+F9 when macOS actually delivers it), then open Panels → Incident Capture, add a note, and click Save note + Copy for LLM. The note is persisted before the handoff is refreshed and copied. The clipboard contains the run path, current health, anomaly index, and evidence limits—not a giant JSON payload. Each finalized anomaly has a 15-second typed pre-roll, four typed materialized windows, a 15 FPS product-only trail from five seconds before through two seconds after the flag, eight human-visible anchors at every whole second in that window stored at no more than 1280x720, a product-only flag frame, and a semantic-ID image/map. Source and stored dimensions are indexed separately. A reserved 128 MiB nonvisual lane keeps notes, replay, manifests, and LLM handoff working even after the bounded visual lane is exhausted; the UI reports whether the durable handoff has landed. Use visual-index.ndjson actual timestamps rather than filenames to order images. To review a long trail chronologically without mutating the bundle:

zig build incident-visual-report -- <run-folder> <separate-output-folder>

Use an isolated root or run the graphical acceptance workflow with:

INCINERATOR_INCIDENT_ROOT=/tmp/incinerator-incidents \
  zig build run -- --incident-smoke

# Full scripted product journey: carry/drop, vehicle, both district crossings,
# death/respawn, NPC death/replacement, resize, rapid flags, and handoff.
INCINERATOR_INCIDENT_ROOT=/tmp/incinerator-journey \
  zig build run -- --incident-journey

# Same journey plus real SDL minimize/restore event acceptance.
INCINERATOR_INCIDENT_ROOT=/tmp/incinerator-window-journey \
  zig build run -- --incident-journey-window

# Paired installed-product capture cost measurement. Run both commands under
# comparable foreground conditions and compare the emitted p50/p95/p99 line.
INCINERATOR_INCIDENT_ROOT=/tmp/incinerator-capture-benchmark \
  zig build run -- --incident-benchmark
zig build run -Dincident-capture=false -- --incident-benchmark

# Five full installed-content Metal journeys with deterministic queue,
# visual-budget, writer-budget, screenshot-submission, and fence failures.
# Each bundle must be honestly partial, inspect cleanly, and semantically replay.
zig build verify-incident-hardening -Deditor=true --summary all

zig build inspect-incident -- /absolute/path/to/run
zig build replay-incident -- /absolute/path/to/run \
  /Users/matt/repos/incinerator-engine/zig-out/share/incinerator/content

# Best-effort graphical control/camera re-execution; semantic replay above is
# the deterministic authority claim.
zig build run -- --replay-incident=/absolute/path/to/run

See ADR-021, the incident design, and the validation record.

Local developer endpoint and CLI

An editor-enabled build installs both the graphical product and the canonical typed developer client:

zig build -Deditor=true -Dincident-capture=true
mkdir -p /tmp/incinerator-saves
./zig-out/bin/incinerator_engine --save-root=/tmp/incinerator-saves

In a second terminal, incinerator-dev discovers the current local editor at $HOME/Library/Logs/Incinerator/developer/discovery.json and writes complete JSON responses. Start with the installed binary's own grammar, then record the run ID reported by discovery and confirm every later response belongs to it:

./zig-out/bin/incinerator-dev help
./zig-out/bin/incinerator-dev agent bootstrap
./zig-out/bin/incinerator-dev agent catalog
./zig-out/bin/incinerator-dev discovery
./zig-out/bin/incinerator-dev describe
./zig-out/bin/incinerator-dev schema list
./zig-out/bin/incinerator-dev world list
./zig-out/bin/incinerator-dev content list

Coding agents must begin with agent bootstrap, record its run identity and catalog digest, then read agent catalog rather than relying on remembered commands. The repository workflow is defined by skills/incinerator-developer-cli/SKILL.md. Each endpoint command returns a CLI envelope containing agent_contract_revision, stable operation, explicit terminal, structured next operations, and the complete typed endpoint response. Structured next operations identify polling and reinspection requirements; they are guidance, not authorization for broader work. Successful and pending operations exit zero. Typed endpoint failures, rejected terminal transactions, failed results, and missing correlated results are still printed as JSON but exit nonzero, so shell automation cannot silently continue through a rejected operation. Every non-help operation emits JSON; help remains human-readable text and --json is an optional explicit flag. Phase 7 implementation and acceptance evidence is recorded in the CLI agent-contract validation ledger.

Copy a real target such as persistent-entity:N:L from world list; do not guess or hard-code a run's identity. Inspect it to record the initial revision, then use that exact revision in a distinctive relocation. Authoring, save, and capture requests report admission separately from terminal completion: poll their returned IDs to terminal results and re-inspect the target after an authoring transaction. Selection and camera responses are synchronous. The transaction's committed_position is the exact pose applied at its authority tick. Crate inspection reports the dynamic body's current simulated position, which can change afterward under gravity and collision even though the committed revision remains authoritative. The concrete workflow is:

./zig-out/bin/incinerator-dev inspect --target persistent-entity:N:L
./zig-out/bin/incinerator-dev select --target persistent-entity:N:L
./zig-out/bin/incinerator-dev camera inspect
./zig-out/bin/incinerator-dev camera mode free-camera
./zig-out/bin/incinerator-dev camera pose \
  --x N --y N --z N --yaw RADIANS --pitch RADIANS
./zig-out/bin/incinerator-dev camera focus --target persistent-entity:N:L
./zig-out/bin/incinerator-dev crate set-position --target persistent-entity:N:L \
  --expected-revision N --x N --y N --z N
./zig-out/bin/incinerator-dev transaction inspect --id N
./zig-out/bin/incinerator-dev inspect --target persistent-entity:N:L

# Repeat set-position with the old revision and verify stale_revision.
./zig-out/bin/incinerator-dev crate set-position --target persistent-entity:N:L \
  --expected-revision OLD_N --x N --y N --z N
./zig-out/bin/incinerator-dev transaction inspect --id N

./zig-out/bin/incinerator-dev undo \
  --target persistent-entity:N:L --expected-revision N
./zig-out/bin/incinerator-dev transaction inspect --id N
./zig-out/bin/incinerator-dev inspect --target persistent-entity:N:L
./zig-out/bin/incinerator-dev redo \
  --target persistent-entity:N:L --expected-revision N
./zig-out/bin/incinerator-dev transaction inspect --id N
./zig-out/bin/incinerator-dev inspect --target persistent-entity:N:L

./zig-out/bin/incinerator-dev camera focus --target persistent-entity:N:L
./zig-out/bin/incinerator-dev capture-frame
./zig-out/bin/incinerator-dev capture inspect --id N
./zig-out/bin/incinerator-dev save-world
./zig-out/bin/incinerator-dev save result --id N

Authoring, save, and capture admission responses do not necessarily report terminal completion. Poll until each transaction/capture/save reports a terminal disposition; a failed save stops the acceptance sequence and its typed detail must be recorded. A committed save proves that the ordinary graphical product wrote the fixed durable slot. The save result reports canonical snapshot payload_bytes; generation is null because the fixed sandbox slot does not expose storage generations. Under the accepted S5 architecture, cold restore is performed by a separate fresh SDL/editor/GPU-free verifier whose expected world/content cohort matches the slot; the EA0.5 ordinary-product slot has not yet been claimed as cold-verified. Stopping and relaunching the ordinary graphical product with the same save root starts a fresh world and a new endpoint run; graphical startup does not load the committed slot. world list contains live instances; content list contains only durable cooked AssetId entries and is truthfully empty until EA1 creates them, so the runtime crate is never an asset. Frame capture uses the existing incident screenshot path and requires incident capture to be enabled. Use --discovery /absolute/path/to/discovery.json to override discovery.

This is a local developer-only Unix socket, not a remote service. It is absent from editor-disabled and ordinary headless compositions. The CLI is the sole agent-control, automation, and diagnostic client; no MCP adapter is planned. See the EA0.5 validation ledger.

The sandbox contains one persistent runtime physics test crate. It is not an imported asset or a reusable content definition. The current ImGui proof authors only its XYZ position; size, collider shape, material, duplication, and general object placement are not part of this tool.

To author and persist that crate, supply an existing absolute save root and enable the editor explicitly:

mkdir -p /tmp/incinerator-saves
zig build run -Deditor=true -- --save-root=/tmp/incinerator-saves

--save-root is startup configuration for the process-owned filesystem write destination; it neither loads a committed slot nor enables graphical auto-restore, and it is not a command-line authoring workflow. Switch to Free Camera, then select Crate through the World Outliner or viewport. The Inspector automatically opens and focuses for the new selection. Its axis-colored sliders and adjacent exact meter inputs share one local position draft with the only red/green/blue axis display: the interactive translate gizmo. Revert Draft discards that draft; Apply Position emits one typed revisioned relocation; Undo and Redo use the same owner history. Gizmo release never applies or saves by itself. Escape during a drag restores the pre-drag draft, including whether earlier unapplied edits already made it dirty.

A Save World Snapshot is a restorable snapshot of authoritative sandbox world state, not a source asset or a content commit. The save directory is the folder passed to --save-root; the fixed logical slot in the example is /tmp/incinerator-saves/sandbox.isav. A dirty draft must first be applied or reverted. S5 intentionally exposes one relocation producer and one fixed slot; autosave, migration, and multiple writers are future work.

Open Panels → Interaction to inspect the immutable carryable/holder state and emit the same typed collect/drop requests used by F. A carryable is either owned by one district, held by one character, or dormant because its owner is unloaded; it never has both a world body and a holder. Pressing E while carrying is a healthy typed rejection recorded in developer diagnostics, not an application failure.

Architecture

The engine uses a thin kernel, feature-owned vertical slices, narrow capability contracts, backend adapters, and explicit host composition roots. See:

The embedded-product loop separates input, fixed-rate authority, and presentation:

input pump (per frame) -> authority ticks (fixed 60 Hz) -> presentation

Embedded and dedicated placement now share the accepted 60 Hz authority rate; rendering remains independently paced and embedded replication remains 20 Hz. The embedded product routes character, vehicle, carry, melee, firearm, respawn, and NPC encounter gameplay through the shared session behavior and consumes replicated client state. M5 acceptance records the owner, regression, native, package, and independent- review evidence.

The current overhaul boundary is intentionally concrete rather than a future asset/framework abstraction. S3-A owns logical simulation, S3-B owns cooked visual content and streamed GPU residency, and S3-C keeps focus selection and proximity policy in the host while exercising the complete lifecycle:

  • GPU textures have explicit OwnedTexture owners and copy-safe borrowed views;
  • glTF/resource initialization unwinds transactionally with checked upload sizes;
  • Jolt process lifetime is leased across worlds, while BodyId values are world-qualified and use an engine-owned 64-bit serial so Jolt's finite native generation cannot revive stale handles;
  • physical input is maintained independently from ImGui capture and main-window focus loss, preventing captured releases from becoming stuck gameplay state;
  • a sandbox-owned action latch preserves edges across zero-tick frames and consumes them once across multi-tick frames before emitting device-independent character commands;
  • renderer failures propagate separately from benign unavailable frames, and scene/ImGui pipelines use the actual SDL swapchain and supported depth formats.
  • CrateFeature owns typed commands/outcomes, Flecs components, coordinated body/entity lifecycle, V1 records, and immutable interpolated presentation records;
  • CharacterFeature independently owns locomotion commands, grounded-state events, Jolt CharacterVirtual lifecycle, canonical V1 records and persisted simulation tuning, and interpolated capsule/camera presentation without importing crates, SDL, or renderer code;
  • VehicleFeature owns typed spawn/enter/drive/exit/despawn commands, explicit driver authority, logical vehicle records, and chassis/four-wheel extraction through backend-neutral vehicle and driver ports;
  • DistrictFeature owns the current four-entry asynchronous logical lifecycle cohort over one worker, up to four persistent district entities, transactional static-body ownership, typed outcomes/events, and renderer-neutral extraction through loader/static-body ports; the real worker publishes only fixed plain data and never touches Runtime, Flecs, Jolt, SDL, or renderer state;
  • InteractionFeature owns the one carryable's spatial/held logical state, physical lifetime, and transactional collect/drop lifecycle through a narrow carrier port; streamed district residency does not gate dynamic-object existence or dropping;
  • NpcFeature owns bounded autonomous-character authority, semantic goals, district-aware navigation state, persistence, diagnostics, and presentation; a separate fixed population planner is only a producer;
  • VitalsFeature owns bounded player/NPC health, damage application, and exactly-once death facts; NpcEncounterFeature owns hostile perception, target choice, attack timing, and locomotion/damage proposals without owning transforms or health;
  • sandbox replacement policy owns durable delayed NPC replacement, while the normal-product encounter owner only submits the initial hostile after its player and west-district prerequisites are authority-ready;
  • the normal graphical product's separate character-lifecycle owner correlates authority-owned local death, character despawn, respawn, and new replicated avatar state without owning those transitions;
  • the automatic listen/dedicated product cohort is six NPCs, one per authored route node. The 64-NPC value remains a synthetic scale ceiling, not the automatic room population. The installed S8 graphical smoke uses one actor to prove route/residency lifecycle; dedicated scale measurements retain the complete 64-NPC/65-controller capacity claim;
  • a private snapshot module owns the current schema-15 snapshot value, canonical codec, cold preflight, cross-feature identity validation, and exact build/world fingerprints; the live sandbox authority owns transactional capture/restoration of feature-owned tuning, relationships, district, interaction, and NPC state;
  • exactly one composition-owned physics step advances crates, characters, and vehicles; no feature adapter privately advances the shared Jolt world;
  • the public engine module exposes feature-authoring contracts and a type-erased startup-only runtime/registry, while the concrete sandbox/Jolt Simulation remains an internal conformance composition rather than engine API;
  • the headless artifact and its extracted-package tests contain no SDL, ImGui, renderer, asset-loader, or shader-tool edge.

The visual sandbox and headless host construct the same owned logical Simulation; the visual host additionally composes S3-B content and residency. M4 deliberately retained a broad local_solo authority-administration facade. M5 replaces it with an opaque embedded placement over the shared authority core, role-scoped capabilities, replicated player-facing presentation, explicit streaming/persistence owners, and one opaque heap-stable developer owner. The complete aggregate regression and independent acceptance review are recorded in the M5 acceptance document. M5 records separate completion-aware placement and authority traces plus the nested runtime phase observer. M6 completes the next boundary with class-reserved ingress, an eight-stage fail-stop cycle, double-buffered publication metadata, delivery leases and application receipts, bounded reconnect replay, and stage-seven durable dispositions. Physical transport and blocking storage remain outside the fixed tick, and M6 does not claim rollback of an already stepped Jolt world. The current S11 cohort derives a conservative 172-publication participant-cycle bound, retains two cycles/344 records, and drains them under the separate 16-message wire ceiling; a slow consumer that exhausts the window is retired without faulting the room. MP6 composes that authority through one generation-safe room coordinator in a constrained listen owner and a ticketed dedicated owner. The host uses the typed local link, guests use real GNS, graphical presentation remains client-owned, and room closure deliberately provides no host migration. S10 adds a backend-neutral bounded vitals feature plus authority-owned melee, death cleanup, dead reconnect, safe explicit respawn, and disposable avatar incarnation. The same protocol semantics are playable in local/listen and dedicated placements; health and hit confirmation are never client authority. S11 adds feature-owned hostile decisions, NPC melee proposals through vitals, durable delayed replacement, explicit streamed-route restore modes, and one renderer-neutral combat presentation owner. Automatic listen/dedicated bootstrap uses six distinct authored route nodes; the normal embedded product seeds one encounter through its host-managed authority; 64 NPCs remain a synthetic scale ceiling rather than the default playable population. The persistent headless host consumes restored encounter damage/death only through exact attack correlation and preserves unrelated FIFO heads as fault evidence. The former GameWorld, borrowed Flecs/Jolt composition, direct ECS render query, and editor mutation path have been removed. The editor keeps stats, camera, render, diagnostics, gameplay inspection, incident capture, physics-debug, crate-authoring, and interaction panels. Persistent crate relocation now uses typed feature commands and exact undo/redo change sets; the editor never receives raw Flecs/Jolt access. Fixed-rate simulation is not a claim of bitwise or cross-platform deterministic lockstep. The current zflecs wrapper permits one owned world per process. M3 accepts that as the operational model: replacement is a validated process restart, while any future multi-world process requires a new architecture decision.

License

The engine is intended to be open source and the game will be licensed separately. The engine license has not been selected yet; no license is granted by this repository at present.

About

A specialized 3D game engine built using Zig, SDL3, Jolt Physics, and ImGui.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages