476 lines
41 KiB
Markdown
476 lines
41 KiB
Markdown
# Architecture
|
||
|
||
This document follows the structure of the arc42 architecture documentation template.
|
||
|
||
## 1. Introduction and Goals
|
||
|
||
### Functional goals
|
||
|
||
- Simulate believable security work at multiple public-facing venues.
|
||
- Provide clear, low-pressure deterrence options before verbal or physical escalation.
|
||
- Make access verification a meaningful gameplay decision.
|
||
- Support distinct NPC behaviors and scenario events.
|
||
- Make emergency response rare, consequential, and justified by observable danger.
|
||
- Provide shift-level feedback so players can learn from decisions.
|
||
|
||
### Quality goals
|
||
|
||
- **Clarity:** Players should understand why an NPC is allowed, denied, or escalated.
|
||
- **Extensibility:** New venues should reuse shared systems and primarily provide configuration and content.
|
||
- **Testability:** Rules and outcomes should be testable without rendering or real-time input.
|
||
- **Consistency:** Similar situations should follow predictable venue and escalation rules.
|
||
- **Respectful representation:** Mental-health crises and public interactions should not be reduced to stereotypes or treated as automatic threats.
|
||
- **Realism:** The game world should look like the real world and NPC behaviors should feel consistent and believable within the established setting.
|
||
|
||
## 2. Constraints
|
||
|
||
- The first implementation should be small enough for a playable vertical slice.
|
||
- The engine is Godot 4.7.2 with GDScript; a playable prototype vertical slice is implemented. CI, local development and exported builds use 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build.
|
||
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
|
||
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
|
||
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
|
||
- The project follows [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`).
|
||
|
||
### Version management
|
||
|
||
- **MAJOR** — incompatible changes to the game's core systems, save format, or public-facing behavior.
|
||
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
|
||
- **PATCH** — bug fixes and small polish that do not change behavior.
|
||
|
||
The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.8`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
|
||
|
||
## 3. Context and Scope
|
||
|
||
The player interacts with NPCs, venue entrances, access artifacts, equipment, staff, and response services. The game itself owns the simulated world, rules, scoring, events, and shift review. External services are currently out of scope; radio, body camera, and emergency response are simulated systems.
|
||
|
||
## 4. Solution Strategy
|
||
|
||
- Use a shared simulation core with venue-specific scenario data.
|
||
- Represent NPC behavior using state machines or behavior trees with configurable traits.
|
||
- Model escalation as explicit, auditable state transitions.
|
||
- Separate access verification from NPC identity and presentation details.
|
||
- Keep scoring and reputation event-driven so every action can be reviewed.
|
||
- Use authored scenario events alongside procedural routine traffic.
|
||
- Make the first playable target one venue and one complete shift before adding breadth.
|
||
|
||
## 5. Building Block View
|
||
|
||
### Level 1: Major components
|
||
|
||
- **Presentation layer:** Camera, UI, prompts, interaction feedback, queues, and shift review.
|
||
- **Input and interaction layer:** Player gestures, dialogue choices, access checks, equipment use, and radio controls.
|
||
- **Simulation layer:** NPC movement, perception, intent, navigation, crowd behavior, and venue state.
|
||
- **Rules layer:** Access policy, escalation policy, prohibited items, response thresholds, and venue configuration.
|
||
- **Incident layer:** Incident lifecycle, evidence, radio reports, consequences, reputation, and review.
|
||
- **Content layer:** Venue definitions, NPC profiles, dialogue, events, visual/audio assets, and shift schedules.
|
||
|
||
### Level 2: Key components
|
||
|
||
- `ShiftCoordinator` starts, advances, and ends a shift.
|
||
- `VenueScenario` provides venue rules, locations, event pools, and access policies.
|
||
- `NPCController` manages an NPC’s intent, movement, compliance, and reaction.
|
||
- `InteractionSystem` resolves gestures, dialogue, warnings, and physical positioning.
|
||
- `AccessVerifier` evaluates recognition, wristbands, IDs, tickets, credentials, and guest lists.
|
||
- `EscalationManager` tracks the current response level and available actions.
|
||
- `RadioSystem` receives reports and schedules security or emergency responses.
|
||
- `IncidentRecorder` stores actions, observations, evidence, and outcomes.
|
||
- `ReputationEvaluator` converts incidents and shift outcomes into performance feedback.
|
||
- `CrowdSystem` models queues, attention, congestion, and public reaction.
|
||
- `ShiftReview` presents decisions, consequences, and improvement opportunities.
|
||
- `SurfaceMaterials` (`src/game/materials.gd`) holds the surface profiles, textured albedo/normal recipes, baked-AO wiring, glass/emissive recipes, and the environment tune-up (tonemapping, glow, fog, grading) that the phase lighting applies.
|
||
- `WorldBuilder` assembles the procedural venue from a per-venue `VENUE_SPECS` table (facade, windows, stairs, street, nav bounds, guard spawn, feature flags and prop placements), prefers the Blender prop library in `assets/models/blender/props/`, and falls back to `assets/models/generated/` or primitives. `GameManager` rebuilds only the `World` container when the venue changes, so the guard/UI and their state survive. It also wires the phase-driven library emissives and street dressing.
|
||
- `src/game/ui/art.gd` loads runtime UI/scene art from `assets/images/ui/` and `assets/images/scenes/`, with null fallbacks so panels keep their procedural layouts.
|
||
- `tools/model_pipeline.py` builds and audits the street-prop `.glb` models and packs their colour atlases.
|
||
- `tools/npc_pipeline.py` builds and audits the skinned NPC base model (`assets/models/generated/npc_base.glb`) and its per-slot material maps, with an optional AI fabric override (ADR-0013). The active character migration bakes the CC0 Quaternius base onto the same contract (ADR-0017); the procedural base remains the fallback.
|
||
- `tools/blender_assets.py` builds, renders and audits the Blender asset library (`assets/models/blender/{npc,npc_gear,props}/` + `manifest.json`): NPC character variants that are drop-in for `npc_base`, attach-point gear, and street/venue props. `NpcAvatar` selects variants/gear by role/seed and `WorldBuilder` loads the prop replacements and new street dressing, with procedural fallbacks (see `docs/blender-assets.md`).
|
||
- `tools/scene_concepts.py` generates realism-pass references (`docs/screens/concepts/`), skyline backdrops and surface tiles (raw `assets/textures/ai/v2/raw/` → candidates `assets/textures/ai/game_ready/v2/`), promotes the validated ones to the tracked `v2/picks/` that `SurfaceMaterials`/`WorldBuilder` preload, audits them, and scores `src/test/capture_realism.gd` A/B captures (six stages, runtime texture swaps) against the concepts (`docs/screens/realism/<run>/`).
|
||
- `tools/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures; `tools/check_screenshots.sh` renders the staged gallery and runs the compare gate.
|
||
|
||
Confirmed game assets live in `assets/textures/ai/game_ready/` (audited surface, UI, and card textures), `assets/models/generated/` (prop and NPC `.glb` models plus their texture atlases), and `assets/textures/npc/` (NPC material maps and `palette.json`). Development-only outputs — AI concept sheets, Blender sources, raw AI fabrics — are gitignored and regenerated by the tools.
|
||
|
||
### Asset storage conventions
|
||
|
||
The canonical rules live in [ADR-0014](adr/0014-runtime-image-root.md). In short:
|
||
|
||
| Location | Contents | Loaded at runtime? |
|
||
| --- | --- | --- |
|
||
| `assets/images/ui/` | Composed screen/panel art (start menu, HUD chrome, mockup-derived backgrounds) | Yes |
|
||
| `assets/images/scenes/` | Composed full-frame scene/background art | Yes |
|
||
| `assets/textures/ai/game_ready/` (+ `v2/`) | Tiled/PBR surface textures, model maps, skyline strips | Yes, as materials |
|
||
| `assets/models/generated/`, `assets/models/blender/` | 3D props/characters and manifests | Yes |
|
||
| `docs/screens/designs/`, `docs/screens/concepts/` | Reference mockups and art-direction sets | No (reference only) |
|
||
| `docs/screenshots/`, `docs/screens/realism/` | README/catalogue captures and QA reports | No (generated QA) |
|
||
| `assets/textures/ai/v2/raw/`, Blender `.blend` sources | Raw AI output / editable sources | No (gitignored or `.gdignore`d) |
|
||
|
||
When reference art becomes runtime art, copy or process it into `assets/images/` with a
|
||
new descriptive name (never overwrite an existing image) and keep a procedural fallback
|
||
in code.
|
||
|
||
### Content and asset pipeline architecture
|
||
|
||
The asset/content pipeline is part of the architecture, not an external build detail:
|
||
|
||
| Stage | Producer | Committed artifact | Runtime consumer | Failure fallback |
|
||
| --- | --- | --- | --- | --- |
|
||
| Scenario data | `ScenarioFactory` / editor export | `content/venues/*.tres`, event/profile data | `VenueScenario` → `ShiftCoordinator` | built-in scenario defaults |
|
||
| NPC library | Blender flatpak + `tools/blender_assets.py` | `assets/models/blender/npc/*.glb`, manifest, baked AO | `NpcAvatar` | `npc_base.glb` → procedural rig |
|
||
| Gear/props | Blender flatpak + tool + bake | `npc_gear/*.glb`, `props/*.glb`, `*_ao.png` | `NpcAvatar`, `WorldBuilder` | primitive assets / generated props |
|
||
| Surface/UI art | Python pipelines / AI-assisted references | `assets/textures/ai/game_ready/`, `assets/images/` | `SurfaceMaterials`, `UiArt` | neutral material / procedural UI |
|
||
| Screenshots/QA | capture scripts + `scene_concepts`/`screen_designs` | `docs/screenshots/`, `docs/screens/realism/` | reviewers and CI gates | regenerate; never runtime input |
|
||
| Local map data (planned) | OSM/3D building extract + licensed reference photos + AI/splat evaluation | derived map assets with provenance sidecars | `WorldBuilder` venue specs | current stylized venue geometry |
|
||
| Release | Gitea workflow + build/publish scripts | platform binaries, Web zip, Desktop HQ zip | players | source build |
|
||
|
||
Contracts that keep the pipeline replaceable:
|
||
|
||
- `npc_base` armature/bone names, five tint slots and front direction are frozen by tests; gear is authored in attach-point space and measured against the character silhouette.
|
||
- Library characters, gear and props are audited for grounding, UVs, triangle budgets, degenerate triangles and manifest coverage; Blender is a developer tool, never a CI runtime dependency.
|
||
- `WorldBuilder.VENUE_SPECS` drives geometry, navigation, features and prop placements; `GameManager` rebuilds only the world container on a venue change.
|
||
- UI/scene art is loaded through `UiArt` with a null/neutral fallback; composed images live in `assets/images/`, not in the docs reference tree (ADR-0014).
|
||
- CI stays offline: only committed `.glb`/`.png`/`.tres` and Godot are needed; optional AI/Blender steps are reproducible development tools.
|
||
|
||
### Character and gear asset contract
|
||
|
||
The runtime NPC contract is intentionally narrow. It is enforced by
|
||
`tools/blender_assets.py audit`, the GLB `inspect` path and the GDScript tests:
|
||
|
||
| Contract | Rule |
|
||
| --- | --- |
|
||
| Mesh node | `npc_base`, skinned under an armature imported as `Skeleton3D`. |
|
||
| Core bones | `Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`, `Spine`, `Neck` at the frozen rest positions. Optional extra bones (fingers, face, toes) are allowed if they do not move the core rest positions or break `NpcAvatar` proxies. |
|
||
| Tint slots | `skin`, `cloth`, `pants`, `accessory`, `hair`; fixed detail materials keep their authored colours. |
|
||
| Orientation | Blender −Y / Godot +Z front, feet grounded near `y = 0`, metre scale. |
|
||
| Budget | 24,000 triangles / 24,000 glTF vertices per character; 1,500 per gear piece; 4,000 per prop. The low-poly `npc_base` remains a fallback, not a second contract. |
|
||
| Textures | 256² albedo + normal + packed ORM per slot; cloth/pants use the 4× `NPC_FABRIC_UV_SCALE` and skip per-character baked AO, while skin/hair/gear keep AO. |
|
||
| Gear attach | Authored in attach-point space: head `Rig/Head` (0, 1.62, 0), back (0, 1.10, 0), chest (0, 1.30, 0), hand (±0.27, 0.78, 0.02); grip 5 cm below the origin. `GEAR_OFFSETS` and `HAND_ITEM_FORWARD` are runtime fit corrections, not authored-geometry changes. |
|
||
| Fallback chain | Library variant → `npc_base.glb` → procedural `NpcAvatar` mesh. Committed GLBs and maps must keep CI offline and Blender-free. |
|
||
|
||
Asset types and their consumers:
|
||
|
||
- Library characters, gear and props: `assets/models/blender/**`, generated by
|
||
`tools/blender_assets.py`; loaded by `NpcAvatar`/`WorldBuilder` with
|
||
generated/procedural fallbacks.
|
||
- Frozen base: `assets/models/generated/npc_base.glb`, generated by
|
||
`tools/npc_pipeline.py`; the procedural avatar remains the last-resort path.
|
||
- Maps: `assets/textures/npc/*_{albedo,normal,orm}.png` and baked AO maps; the
|
||
mesh budgets and material wiring are checked by `audit`/`fit`/`texels` and the
|
||
headless suite.
|
||
- Editable `.blend` sources are development-only; only exported GLBs, AO/maps,
|
||
manifests and committed review sheets are runtime/repository assets.
|
||
|
||
### Venue implementation contract
|
||
|
||
The three venues are authored by `WorldBuilder.VENUE_SPECS` and rebuilt through
|
||
the `World` container when the venue changes; the guard, UI and checkpoint state
|
||
survive. Venue data is content, while the following runtime rules are fixed:
|
||
|
||
| Venue | Real reference | Game implementation | Budget |
|
||
| --- | --- | --- | --- |
|
||
| Hollywood Boulevard | 6840 Hollywood Blvd / 1921 Masonic Temple | Six-column Masonic facade, eight steps, Walk of Fame, boulevard, Ovation arcade and neighbours | 58,884 tris / 409 meshes |
|
||
| The Joke Shop | Fictional stand-in for 8433 Sunset Blvd | 27 m black hall, signature canopy, circular blade sign, red curtain bays, west entrance, hillside and neighbours | 25,828 tris / 518 meshes |
|
||
| Late Night TV Studio | Same El Capitan block as Hollywood | Reuses the Masonic facade and steps with bulb canopy, car, barriers and studio-arrival staging | shares the Hollywood block; TV spec is a 30.0 m variant |
|
||
|
||
Venue rules:
|
||
|
||
- Coordinates are Godot metres; the guard's front is +Z. `VENUE_SPECS` owns
|
||
facade dimensions, street/nav bounds, guard spawn, feature flags and prop
|
||
placements; tests enforce the map budgets.
|
||
- Collision and navigation remain mesh-based. Props that block walking need a
|
||
`StaticBody3D` plus `NavigationObstacle3D`; the marquee, handrail, lantern and
|
||
door are documented non-blocking exceptions.
|
||
- Day/night is a phase offset on one geometry/scenario, not a second baked map.
|
||
The venue menu's Night row starts in `LATE` while the checkpoint stores the
|
||
offset.
|
||
- Real-site references are evidence for shape/materials, not shipped assets.
|
||
Licensed boards live under `docs/screens/refs/` with sidecars; local-only
|
||
research stays in `tmp/research/` and is never committed.
|
||
- The stylized geometry remains the runtime fallback if a future data-backed
|
||
block or facade kit fails budget, navigation, visual or provenance gates.
|
||
|
||
### Persistence and save contract
|
||
|
||
Persistence is local-only under Godot's `user://` directory. The architecture
|
||
owns the schema; operational locations and reset/rollback steps live in
|
||
[`getting-started.md`](getting-started.md#save-data-and-migration).
|
||
|
||
| File | Contents | Compatibility |
|
||
| --- | --- | --- |
|
||
| `settings.json` | Camera/HUD/bindings/difficulty/audio/accessibility/tutorial flags | Schema-less compatible growth; missing keys merge from `Save.DEFAULT_SETTINGS`. |
|
||
| `campaign.json` | Campaign index, completed venues, difficulty, shift number, last grade | Missing fields fall back to safe campaign defaults. |
|
||
| `shift_results.json` | Completed-shift review history (array) | Append-only; unknown fields are ignored by readers. |
|
||
| `shift_state.json` | Resumable checkpoint: version `1`, venue, guard/door/flashlight/body-camera state, coordinator snapshot, NPC rows | Versioned; unknown/missing state falls back rather than blocking boot. |
|
||
|
||
Writes go to a `.tmp` file and are renamed after the complete JSON is written.
|
||
Corrupt or partial files are ignored on load; a failed replace leaves the prior
|
||
valid file intact. The checkpoint deliberately excludes the tutorial overlay and
|
||
transient input state.
|
||
|
||
### Character development tooling
|
||
|
||
Characters have one active migration, two committed fallbacks and one procedural last
|
||
resort. The Quaternius base migration (ADR-0017) bakes the CC0 Quaternius mesh and
|
||
Idle/Walk clips onto the existing 13-core contract and produces the next 12-variant
|
||
library. Until that ships, the 12-variant Blender library
|
||
(`assets/models/blender/npc/`) is the normal presentation path, the older skinned
|
||
`npc_base` (`assets/models/generated/npc_base.glb`) is the frozen contract fallback,
|
||
and `NpcAvatar`'s procedural rig is the offline last resort. Blender and Quaternius are
|
||
developer tools only — runtime, tests and CI consume committed GLBs and maps.
|
||
|
||
| Tool | Role | Committed artifact | Verification gate |
|
||
| --- | --- | --- | --- |
|
||
| `tools/npc_pipeline.py` | Builds the skinned base avatar, five-slot material maps, palette and AI-fabric preparation (`prepare`/`palette`) | `npc_base.glb`, `assets/textures/npc/*_{albedo,normal,orm}.png`, `palette.json` | `audit_glb` against the 24,000-triangle / 24,000-vertex base contract (13 core bones required; extras allowed) |
|
||
| `tools/blender_assets.py` | Builds/renders the library: 12 characters, 15 gear pieces, 20 props, plus `manifest.json`; stdlib `audit`/`fit`/`sheet`/`list` | `assets/models/blender/{npc,npc_gear,props}/*.glb` | Character cap 24,000 tris / 24,000 verts, 1,500 per gear, 4,000 per prop; grounding, UV, degenerate-triangle, attach-fit and manifest coverage checks |
|
||
| `tools/bake_ao.py` | Bakes per-asset AO maps | `<asset>_ao.png` (256²) | Wired through `Materials.apply_ao()`/`SurfaceMaterials`; cloth/pants opt out (see below) |
|
||
| `tools/npc_proportions.py` | Measures exported GLB rest pose (height, head, shoulders, hips, torso, limbs, feet) against the stylized guide | report / JSON in `docs/npc-visual-review.md#proportion-audit` | All eight variants must stay inside the guide after a body change |
|
||
| `tools/npc_baseline.py` | Assembles neutral-baseline sheets and before/after comparisons | `docs/blender_previews/sheet_npc_baseline*.jpg` | Human review against `docs/npc-visual-review.md` |
|
||
| `src/test/capture_npc_baseline.gd` | Fixed-camera studio baseline, 8 variants × 6 views | local `tmp/` frames | Neutral silhouette/face/gear review |
|
||
| `src/test/capture_npc_review.gd` | Final-context gate: 8 variants × 2 venues × day/night × 3 distances = 96 frames, crowd hidden, review-only `character_override` for the guard | local `tmp/` frames | Pre-build acceptance gate for gear fit and venue lighting |
|
||
| `src/test/capture_realism.gd` | Venue realism stages plus a frozen portrait and surface close-ups | `docs/screens/realism/<run>/` | Optional vision judge; portrait is the only avatar-detail capture |
|
||
|
||
Runtime contracts that must survive any character change:
|
||
|
||
- `NpcAvatar.character_model_for(role, seed)` selects the library variant; `character_override`
|
||
exists only to stage roles without a spawned model (for example the guard).
|
||
- The armature node names, `Rig/Head`, the Hip/Knee/Shoulder/Elbow/Hand proxies and the
|
||
**+Z visual front** are frozen; animation and `yaw_towards()` depend on them.
|
||
- Only the five contract slots are tinted. Fixed detail materials (eyes, reflective bands,
|
||
rubber) stay untouched, gear is placed by `GEAR_ATTACH`, and `GEAR_OFFSETS` plus
|
||
`HAND_ITEM_FORWARD` are runtime attach-space corrections, not authoring changes.
|
||
- Cloth/pants use `Materials.NPC_FABRIC_UV_SCALE` (4×) and skip the baked per-character AO;
|
||
skin/hair/gear keep AO. Do not reintroduce the blotchy cloth AO.
|
||
- `apply_lod()` swaps to an impostor at 26 m; the 24-NPC budget smoke (6.94 ms, 168 meshes,
|
||
152,464 triangles) is the performance gate. Changing either triangle cap requires
|
||
re-measuring that smoke and the Web/Compatibility path.
|
||
- Rebuild only the assets whose geometry changed (Blender GLB export is byte-nondeterministic),
|
||
then run `godot --headless --path . --import`; never commit a no-op full rebuild.
|
||
|
||
Evidence and detailed contracts live in [`blender-assets.md`](blender-assets.md),
|
||
[`npc-visual-review.md`](npc-visual-review.md) and
|
||
[`npc-visual-review.md#proportion-audit`](npc-visual-review.md#proportion-audit); command-level usage is in
|
||
[`asset-tooling.md`](asset-tooling.md).
|
||
|
||
### Local map development tooling (planned)
|
||
|
||
The current venues are hand-authored procedural reconstructions in
|
||
`src/game/world_builder.gd`. The local map workstreams (**H–M**) in
|
||
[`TODO.md`](../TODO.md#3d-model-re-evaluation) are unversioned and planned: they will
|
||
test whether licensed data and reference photography can replace or supplement the
|
||
stylized geometry without moving map data, AI composition or splat rendering into
|
||
the runtime.
|
||
|
||
Planned stages and gates:
|
||
|
||
| Stage | Source | Output | Gate |
|
||
| --- | --- | --- | --- |
|
||
| Footprints and massing | Offline OpenStreetMap extract + licence-compatible 3D building data (OSM Buildings, Overture, CityGML/LOD1–2) | Local footprint/massing scenes, extract date and query pinned | ODbL attribution/share-alike review; scale/orientation and venue-footprint comparison |
|
||
| Reference imagery | Wikimedia Commons, own/team photos or other clearly licensed images | Reference boards and material candidates | Written author/licence/attribution, privacy redaction, no unlicensed Street View or scraped commercial imagery |
|
||
| AI-assisted composition | Project image tooling | Palette/facade-rhythm boards and material candidates | Model/prompt/output recorded; human review; never treated as licensed map data |
|
||
| Photoreal facade kit | Project-authored geometry and derived materials | Committed facade modules and PBR maps | WorldBuilder budget, collider/nav coverage, Compatibility-readability and screenshot review |
|
||
| Gaussian splatting | Licensed/permissioned photo sets + pinned offline toolchain | Development-only splat, texture or proxy experiments | Per-path ADR; runtime only if performance, collision/navigation and provenance are proven |
|
||
|
||
Contracts for any future map source:
|
||
|
||
- Runtime consumes committed, derived assets only; no online OSM, photo or splat
|
||
service is a build or play dependency.
|
||
- OSM ODbL, photo licences, capture permissions and privacy redaction are recorded
|
||
in a provenance sidecar before an asset enters the repository.
|
||
- Collision and navigation stay mesh-based; a splat may never become the playable
|
||
floor or the access/occlusion authority.
|
||
- The stylized venue geometry remains the fallback until a data-backed block passes
|
||
the venue budget, navigation, visual and provenance gates.
|
||
|
||
### Content authoring and runtime data flow
|
||
|
||
`ScenarioFactory` is the source of truth for the three authored venues. `tools/export_venues.gd`
|
||
writes `content/venues/<id>.tres` for editor inspection; the factory remains the canonical
|
||
scenario definition. At runtime `GameManager` selects a `VenueScenario`, `ShiftCoordinator`
|
||
schedules events and phases, and `NPCController`/`AccessVerifier`/`EscalationManager` produce
|
||
incidents. `IncidentRecorder` is the authoritative event history; body-camera review,
|
||
reputation, crowd reaction and shift review read it rather than resolving gameplay separately.
|
||
|
||
## 6. Runtime View
|
||
|
||
### Routine interaction
|
||
|
||
1. An NPC selects or receives an intent such as taking a photo, entering, waiting, or trespassing.
|
||
2. The player observes the NPC and chooses whether to intervene.
|
||
3. A gesture or verbal interaction changes the NPC’s state.
|
||
4. The NPC complies, negotiates, refuses, or escalates.
|
||
5. The rules layer validates access and determines available next actions.
|
||
6. The incident recorder stores the interaction.
|
||
7. Reputation and crowd systems react to the outcome.
|
||
|
||
### Venue switch
|
||
|
||
1. The player selects a venue from the start menu or cycles with the debug shortcut.
|
||
2. `GameManager` loads the matching `VenueScenario` and keeps the guard/UI state.
|
||
3. `WorldBuilder` rebuilds only `world_root` from `VENUE_SPECS`, including geometry, props and the navigation mesh.
|
||
4. Shift state, NPCs and incidents are reset for the new venue; phase lighting and the door state are reapplied.
|
||
5. The menu's **Hollywood Night** row resolves to `hollywood_building`, then sets `ShiftCoordinator.phase_offset_s` so elapsed time starts at 0 but phase lookup starts at `LATE`. The offset is part of the checkpoint snapshot, so a resumed night shift stays at night.
|
||
|
||
### Asset fallback
|
||
|
||
1. A runtime loader asks for the library scene or texture.
|
||
2. If the imported asset is missing, the loader uses the generated/procedural fallback rather than failing the boot.
|
||
3. Contracts and audits ensure the fallback and library paths expose the same observable behaviour; CI runs headless against whichever path is available.
|
||
|
||
### Access check
|
||
|
||
1. The player stops or receives an approaching person.
|
||
2. The player recognizes the person or inspects a wristband, ID, credential, ticket, or guest-list record.
|
||
3. The access verifier checks the artifact against the venue policy.
|
||
4. The player admits, redirects, holds, or refuses entry.
|
||
5. The decision is recorded for shift review.
|
||
|
||
### Emergency response
|
||
|
||
1. NPC behavior crosses the configured immediate-threat threshold.
|
||
2. The player holds and confirms the emergency-radio action.
|
||
3. The player submits a concise report describing location and behavior.
|
||
4. The response system dispatches an appropriate responder.
|
||
5. Crowd, venue, reputation, and incident systems apply consequences.
|
||
6. The shift review evaluates whether the call was justified.
|
||
|
||
## 7. Deployment View
|
||
|
||
The game is a single-player local client containing presentation, simulation, rules, content, and persistence for local settings and shift results. No online backend is required. A non-threaded Web export ships alongside the desktop builds and can be served from any static host without special headers. The default renderer is GL Compatibility; an optional Desktop HQ zip uses Forward+ with volumetric fog/SDFGI on Vulkan-capable desktops. CI, local development and exported builds use Godot 4.7.2; the light-falloff code keeps a compatibility branch for older editors but the supported baseline is unified.
|
||
|
||
Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture.
|
||
|
||
### CI/CD build pipeline
|
||
|
||
A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases.
|
||
|
||
- **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job installs Godot 4.7.2, imports the project, and runs `res://src/test/test_runner.gd`; it fails on a non-zero exit code or any `SCRIPT ERROR` in the output.
|
||
- **Build job:** runs for tags and manual dispatches. It installs export templates, exports Linux/Windows/macOS and the non-threaded Web build, packages the NSIS installer, Linux AppImage and optional Desktop HQ zip, verifies the installer contents, and uploads the artifacts.
|
||
- **Publish job:** tag builds call `tools/publish_release.sh` to create the Gitea release and upload the standard artifacts plus the optional Desktop HQ zip. The script uses `GITEA_TOKEN` when configured and otherwise reuses the runner's checkout extraheader credentials.
|
||
- **Hosting:** the repository lives on Gitea (`https://git.allucanget.biz/zwitschi/security-game`). Export templates must match the pinned Godot version; macOS builds are unsigned and need quarantine guidance or notarization for wider distribution.
|
||
|
||
### Release management
|
||
|
||
Releases are produced from a tagged commit and published to the repository host's release page, where the README "Downloads" links point.
|
||
|
||
- `export_presets.cfg` — committed Linux, Windows, macOS, and Web export presets so builds are reproducible.
|
||
- `tools/build_releases.sh` — exports the desktop binaries and Web zip into `build/`, named `gig-line-<platform>-<version>.<ext>`.
|
||
- `tools/publish_release.sh` — creates a release and uploads the artifacts via the Gitea API, using `GITEA_TOKEN` or the checkout extraheader fallback.
|
||
- Packaging — NSIS builds the Windows installer; `packaging/linux/build_appimage.sh` builds the AppImage.
|
||
- [`RELEASING.md`](RELEASING.md) — step-by-step guide and release checklist.
|
||
|
||
The release process is: bump the version, run the full test suite and `tools/check_screenshots.sh`, run `tools/build_releases.sh`, tag and push (CI publishes), then verify the README "Downloads" links and the release artifacts.
|
||
|
||
## 8. Cross-Cutting Concepts
|
||
|
||
- **Event-based incident recording:** Important actions emit records consumed by evidence, reputation, and review systems.
|
||
- **Data-driven venue rules:** Access, escalation, equipment, and event differences live in scenario data.
|
||
- **State transitions:** NPCs, incidents, and shifts expose explicit states for debugging and testing.
|
||
- **Accessibility:** Input alternatives should exist for gestures, dialogue, visual alerts, and audio cues.
|
||
- **Safety and proportionality:** The rules layer prevents ordinary noncompliance from automatically becoming a violent encounter.
|
||
- **Determinism where useful:** Scenario tests should be able to use fixed seeds and scripted NPC behavior.
|
||
- **Localization:** Dialogue and prompts should be externalized from logic.
|
||
- **Observability:** Debug overlays show NPC intent, access status, escalation level, active incidents, and response timers during development.
|
||
- **Visual regression:** Staged captures are compared against the runtime reference art (`screen_designs.py compare`) and optionally judged by a vision model; `tools/check_screenshots.sh` makes the pass repeatable.
|
||
- **Asset provenance and AI usage:** AI-assisted images/concepts are development inputs only; validated outputs are committed, audited and loaded through the same runtime asset contracts. Generated content must not become an offline/CI dependency.
|
||
- **Campaign and checkpoint state:** `Campaign` owns venue order/progression; settings, campaign, completed shift history and a versioned pause checkpoint are separate JSON documents. The checkpoint snapshots coordinator systems, scheduler RNG and NPC presentation/access state; it deliberately does not serialize the tutorial overlay or transient input state.
|
||
- **Difficulty:** easy/normal/hard only scale spawn pacing, NPC compliance tolerance and report-credibility strictness; access/escalation rules and emergency rarity are invariant.
|
||
- **Settings and accessibility:** volume/motion/caption settings persist through `settings.json`; Help is generated from the input-binding catalogue and the HUD log is the text caption surface. CI/release, local development and exported builds are unified on Godot 4.7.2.
|
||
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/gameplay.md` owns playable mechanics; `docs/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
|
||
|
||
## 9. Architecture Decisions
|
||
|
||
Architecture decisions are recorded as ADRs:
|
||
|
||
- [ADR-0001: Venue-driven simulation architecture](adr/0001-venue-driven-simulation-architecture.md)
|
||
- [ADR-0002: De-escalation-first escalation model](adr/0002-de-escalation-first-escalation-model.md)
|
||
- [ADR-0003: Explicit access-verification system](adr/0003-explicit-access-verification-system.md)
|
||
- [ADR-0004: Local single-player first](adr/0004-local-single-player-first.md)
|
||
- [ADR-0005: Event-based incident recording](adr/0005-event-based-incident-recording.md)
|
||
- [ADR-0006: Godot 4 with GDScript](adr/0006-godot-4-gdscript.md)
|
||
- [ADR-0007: Locomotion and input layers](adr/0007-locomotion-and-input-layers.md)
|
||
- [ADR-0008: Cone focus and focus circle](adr/0008-cone-focus-and-head-ring.md)
|
||
- [ADR-0009: Radial action menu](adr/0009-radial-action-menu.md)
|
||
- [ADR-0010: Procedural NPC presentation](adr/0010-procedural-npc-presentation.md)
|
||
- [ADR-0017: Quaternius NPC base](adr/0017-quaternius-npc-base.md)
|
||
- [ADR-0011: Aim-free selection and precision walk](adr/0011-aim-free-selection-and-precision-walk.md)
|
||
- [ADR-0012: Surface materials and generated props](adr/0012-surface-materials-and-generated-props.md)
|
||
- [ADR-0013: Blender-authored NPC characters and baked materials](adr/0013-blender-authored-npc-characters.md)
|
||
- [ADR-0014: Canonical runtime image root and image conventions](adr/0014-runtime-image-root.md)
|
||
|
||
## 10. Quality Requirements
|
||
|
||
| Requirement | Target |
|
||
| --- | --- |
|
||
| Player comprehension | Players can identify the reason for an access or escalation decision through UI and feedback. |
|
||
| Response proportionality | Routine NPC behavior should be resolvable without emergency response. |
|
||
| Extensibility | A new venue can be added primarily through scenario data and content. |
|
||
| Performance | The target venue should support a believable crowd without harming input or simulation responsiveness. |
|
||
| Testability | Access and escalation rules can be tested independently of presentation. |
|
||
| Accessibility | Core actions are available through clear input alternatives and readable feedback. |
|
||
| Reliability | A fresh checkout, missing optional asset, invalid AI key, or unavailable Forward+ renderer must not prevent a normal Compatibility/Web/headless boot. |
|
||
| Performance | A busy venue should hold its budget at the target NPC cap on desktop and Web; the current 24-NPC check is a baseline, not a release guarantee. |
|
||
| Documentation integrity | Every released version has a changelog entry, current status/roadmap, and architecture/ADR references that match the build. |
|
||
|
||
## 11. Risks and Technical Debt
|
||
|
||
- NPC behavior may feel artificial if traits and reactions are too deterministic.
|
||
- Crowd simulation may become expensive around busy studio or comedy-club entrances.
|
||
- Access verification can become frustrating if the UI does not clearly show what the player is checking.
|
||
- Emergency response can overshadow the core game if it is too powerful or too frequent.
|
||
- Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation.
|
||
- The choice of engine may affect navigation, crowd scale, tooling, and content authoring.
|
||
- Reference mockups can outpace the runtime art style; compare/judge catch gross drift but not composition errors, so the staged gallery needs human review after large visual changes.
|
||
- Godot 4.7.2 is the unified CI/local/project baseline; future engine bumps still require import, visual and export smoke checks before changing that baseline.
|
||
- Content volume and authoring tools are still thin; adding venues/events by editing the factory can become error-prone without schema validation and preview tooling.
|
||
- Save data currently covers settings and shift history, not mid-shift resume; adding saves/replays requires a versioned schema and migration policy.
|
||
- The optional judge and image-generation paths depend on an external key, model availability and budget; CI cannot make them a release gate, and keys must never be committed.
|
||
- Accessibility and localization coverage is partial; a public release needs subtitles/captions, colour-independent cues, remapping, text expansion tests and at least a documented localization workflow.
|
||
- Unsigned macOS builds, AI asset provenance and any storefront/legal requirements are release blockers for a public release.
|
||
- Documentation drift has already occurred (release version, implemented status and obsolete plan docs); the ownership map and roadmap must be kept current in the same change as the implementation.
|
||
- Character quality is only partly automatable: proportions, budgets and gear fit are measured, but face realism and venue-lighting readability still need the baseline/review sheets and human sign-off after any mesh, map or material change.
|
||
- Local-map data and photo-derived assets add a second provenance and privacy risk: OSM share-alike, photo rights, faces/plates, property permission and rapidly churning splat tooling must be resolved before any derived asset ships.
|
||
|
||
## 12. Documentation Consolidation and Ownership
|
||
|
||
The documentation set is intentionally layered. Architecture-level material is consolidated here;
|
||
specialized operational detail remains in focused pages so commands do not rot inside the
|
||
architecture document.
|
||
|
||
| Document | Canonical role | Relationship to this architecture |
|
||
| --- | --- | --- |
|
||
| [`PLAN.md`](../PLAN.md) | Product/design intent, pillars, venues and success criteria | Design source; architecture realizes it |
|
||
| [`docs/gameplay.md`](gameplay.md) | Playable loop, escalation, tutorial, venue mechanics | Runtime/behavioral view |
|
||
| [`docs/venues.md`](venues.md) | Real-site evidence, mapping decisions and deliberate simplifications | Runtime venues' evidence companion to §5 |
|
||
| [`docs/architecture.md`](architecture.md) | System boundaries, data flow, constraints, deployment, cross-cutting decisions, quality risks | Single architecture source |
|
||
| [`docs/adr/`](adr/) | Immutable decision records with context and consequences | Decision history linked from §9 |
|
||
| [`docs/asset-tooling.md`](asset-tooling.md) | Build/audit/capture commands, optional Blender MCP and pipeline usage | Operational appendix to the pipeline section |
|
||
| [`docs/blender-assets.md`](blender-assets.md) | Blender library art direction, roles, layout and checks | Operational asset appendix; contract lives here in §5 |
|
||
| [`docs/npc-visual-review.md`](npc-visual-review.md) | NPC baseline views, acceptance criteria, visual gaps and proportion audit | Visual-QA appendix to the character tooling section |
|
||
| [`docs/3d-model-review.md`](3d-model-review.md) | Scorecard, measurements and ranked asset gaps | Working review companion to §5 |
|
||
| [`docs/npc-model-sourcing.md`](npc-model-sourcing.md) | Character-source evaluation and licence/prototype outcome | Supports the character tooling section and ADR-0015 |
|
||
| [`docs/getting-started.md`](getting-started.md) | Setup, commands, controls | Developer onboarding |
|
||
| [`docs/RELEASING.md`](RELEASING.md) | Release checklist and CI/publishing steps | Deployment appendix to §7 |
|
||
| [`docs/release-qa.md`](release-qa.md) | Manual smoke checklist and balance protocol | QA appendix to §10 |
|
||
| [`docs/accessibility.md`](accessibility.md) | Accessibility features, statement and known gaps | Player-facing quality statement |
|
||
| [`docs/known-limitations.md`](known-limitations.md) | Release blockers and accepted limitations | Player/release-facing risk statement |
|
||
| [`docs/ui-copy.md`](ui-copy.md) | Screen/button inventory, copy audit and screen-judge report | Presentation appendix |
|
||
| [`docs/development-status.md`](development-status.md) | Implemented features and current gaps | Status companion to the roadmap |
|
||
| [`TODO.md`](../TODO.md) | Priority-ordered active tasks, unversioned development tracks and versioned roadmap | Planning source; no architecture duplication |
|
||
| [`CHANGELOG.md`](../CHANGELOG.md) | User-facing release history | Release/version companion |
|
||
|
||
Consolidation decisions:
|
||
|
||
- **Architecture owns the "how"** (components, contracts, data flow, constraints, quality gates); **PLAN/gameplay own the "what"**; **ADRs own the "why"**. Links replace duplicated prose.
|
||
- **Asset and release documents remain separate** because they are command-heavy operational procedures; their architecture-relevant contracts and failure modes are summarized in §5 and §7.
|
||
- **Completed plans are removed, not kept as competing roadmaps.** Historical graphics work is summarized by ADR-0013, the asset pipeline section and the v0.6.0 changelog; new work belongs in TODO.
|
||
- **Status and roadmap are separate from architecture.** `docs/development-status.md` records what exists; `TODO.md` records what remains, ordered as unversioned development tracks, versioned milestones and deferred work.
|
||
- **Documentation drift is a tracked risk:** release/version, test counts, renderer status, and stale plans must be corrected in the same commit as the change that invalidates them.
|
||
|
||
## 13. Glossary
|
||
|
||
- **Access artifact:** A wristband, ID, ticket, credential, or other item used to verify entry.
|
||
- **Authorized person:** Someone permitted to enter under the current venue policy.
|
||
- **Door person:** The entrance security worker in The Joke Shop scenario.
|
||
- **Incident:** A recorded interaction or event requiring player judgment.
|
||
- **NPC:** Non-player character.
|
||
- **Scenario:** A venue-specific configuration of rules, content, locations, and events.
|
||
- **Shift:** One playable work period, normally 10–15 minutes.
|
||
- **Simple deterrence:** A low-pressure gesture such as raising a hand, making eye contact, or pointing.
|