Compare commits

...
7 Commits
Author SHA1 Message Date
zwitschi ad12fdad7e Bump to 0.9.1 and record the toolchain update
Full build / Import + headless tests (push) Successful in 2m23s
Full build / Full desktop build + optional release (push) Successful in 9m44s
2026-11-02 09:28:13 +01:00
zwitschi 87612f2057 Unify the Godot 4.7.2 CI environment and cache it
Full build / Import + headless tests (push) Successful in 2m30s
Full build / Full desktop build + optional release (push) Skipped
Update project features and CI installs/templates to Godot 4.7.2, remove the
old version matrix, and cache the Godot binary and export templates with Gitea
Actions cache. Update release/docs/version references accordingly. Project
import and headless tests pass locally under 4.7.2.
2026-11-02 09:25:08 +01:00
zwitschi ffd98daf08 Plan the pre-RC patch levels
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Add detailed 0.9.1 UI/dialog/button polish, 0.9.2 NPC model refinement,
0.9.3 texture/material refinement and 0.9.4 integration/performance/judge
workstreams before the 0.9.5 release candidate. Update the remaining-gap table,
baseline to v0.9.0 and README development status.
2026-11-02 09:16:33 +01:00
zwitschi f811e6054d Expand the 0.9.5 release-candidate checklist
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Replace the remaining-gap table with v0.9.0 baselines and break the release
candidate into detailed workstreams for content lock/playtests, balance,
save migration, release engineering, legal/credits, documentation/visual
sign-off and final QA. Sync the README development status to v0.9.0.
2026-11-02 08:54:39 +01:00
zwitschi 9d37e0a1c5 Bump the project version to 0.9.0
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Successful in 5m0s
2026-11-01 21:48:03 +01:00
zwitschi 883626a067 Ship the 0.9.0 production-quality milestone
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Canceled after 4m58s
Add mixer/accessibility settings, caption/reduce-motion hooks, audio volume
clamping, a 24-NPC performance smoke and shortened coat/dress stride for hem
clipping. Record the explicit Godot 4.3-CI/4.7-local matrix and the 0.9
production scope. Headless 250/250, Python 94/94, 24-NPC budget smoke passes.
2026-11-01 21:46:42 +01:00
zwitschi b5d4d5fb87 Plan detailed 0.9.0 production-quality steps
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
Expand the next milestone into animation, audio, localization, accessibility,
performance/platform, QA/visual baselines, Godot-version policy and exit
criteria, with concrete verification work per workstream.
2026-11-01 21:39:29 +01:00
23 changed files with 607 additions and 119 deletions

No files matched your search

+47 -12
View File
@@ -7,6 +7,10 @@ on:
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
env:
GODOT_VERSION: "4.7.2"
GODOT_BIN: /usr/local/bin/godot
jobs: jobs:
checks: checks:
name: Import + headless tests name: Import + headless tests
@@ -17,12 +21,23 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Godot 4.3 - name: Restore Godot binary cache
uses: actions/cache@v4
with:
path: /usr/local/bin/godot
key: godot-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
- name: Install Godot 4.7.2
run: | run: |
if [ -x /usr/local/bin/godot ]; then
godot --version
exit 0
fi
curl -sL -o /tmp/godot.zip \ curl -sL -o /tmp/godot.zip \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
unzip -qo /tmp/godot.zip -d /tmp/godot-bin unzip -qo /tmp/godot.zip -d /tmp/godot-bin
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
godot --version
- name: Import project (build class cache) - name: Import project (build class cache)
run: godot --headless --import run: godot --headless --import
@@ -56,18 +71,38 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Godot 4.3 and export templates - name: Restore Godot binary cache
uses: actions/cache@v4
with:
path: /usr/local/bin/godot
key: godot-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
- name: Restore export templates cache
uses: actions/cache@v4
with:
path: ~/.local/share/godot/export_templates/4.7.2.stable
key: godot-templates-${{ runner.os }}-${{ env.GODOT_VERSION }}-v1
- name: Install Godot 4.7.2 and export templates
run: | run: |
if [ ! -x /usr/local/bin/godot ]; then
curl -sL -o /tmp/godot.zip \ curl -sL -o /tmp/godot.zip \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_linux.x86_64.zip https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip
unzip -qo /tmp/godot.zip -d /tmp/godot-bin unzip -qo /tmp/godot.zip -d /tmp/godot-bin
sudo install /tmp/godot-bin/Godot_v4.3-stable_linux.x86_64 /usr/local/bin/godot sudo install /tmp/godot-bin/Godot_v4.7.2-stable_linux.x86_64 /usr/local/bin/godot
fi
godot --version
if [ -f "$HOME/.local/share/godot/export_templates/4.7.2.stable/linux_release.x86_64" ]; then
ls "$HOME/.local/share/godot/export_templates/4.7.2.stable" | head -5
exit 0
fi
curl -sL -o /tmp/templates.tpz \ curl -sL -o /tmp/templates.tpz \
https://github.com/godotengine/godot/releases/download/4.3-stable/Godot_v4.3-stable_export_templates.tpz https://github.com/godotengine/godot/releases/download/4.7.2-stable/Godot_v4.7.2-stable_export_templates.tpz
mkdir -p ~/.local/share/godot/export_templates/4.3.stable rm -rf /tmp/tpl && mkdir -p /tmp/tpl
cd /tmp && rm -rf tpl && mkdir tpl && unzip -qo templates.tpz -d tpl unzip -qo /tmp/templates.tpz -d /tmp/tpl
cp tpl/templates/* "$HOME/.local/share/godot/export_templates/4.3.stable/" 2>/dev/null || true mkdir -p "$HOME/.local/share/godot/export_templates/4.7.2.stable"
ls "$HOME/.local/share/godot/export_templates/4.3.stable" | head -5 cp /tmp/tpl/templates/* "$HOME/.local/share/godot/export_templates/4.7.2.stable/"
ls "$HOME/.local/share/godot/export_templates/4.7.2.stable" | head -5
- name: Import project - name: Import project
run: godot --headless --import run: godot --headless --import
@@ -114,7 +149,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
env: env:
# An explicit repo secret wins. Without one, publish_release.sh reuses # An explicit repo secret wins. Without one, publish_release.sh reuses
# the local git extraheader that actions/checkout configures for the job # the local git extraheader that actions/checkout configures on the job
# (the runner's own credentials), so tag builds still publish. # (the runner's own credentials), so tag builds still publish.
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
VERSION: ${{ github.ref_name }} VERSION: ${{ github.ref_name }}
+31
View File
@@ -4,6 +4,37 @@ All notable user-facing changes to Gig Line. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
Semantic Versioning. Semantic Versioning.
## [0.9.1] — 2026-11-02
### Changed
- Unified the project, local tooling and CI/release environment on Godot 4.7.2,
including matching export templates and project feature metadata.
- Added Gitea Actions cache for the Godot binary and export templates to reduce
repeated download time.
- Updated release and setup documentation for the 4.7.2 baseline.
## [0.9.0] — 2026-11-01
### Added
- Master/SFX/ambience volume controls, a captions toggle and a Reduce motion
option in Settings.
- A 24-NPC performance budget smoke and expanded audio/accessibility coverage.
- Explicit production-quality scope for animation, audio, localization and the
Godot 4.3-CI/4.7-local support matrix.
### Changed
- Coat and dress strides are shortened to reduce hem/leg clipping.
- Help and the shift-review surface expose the current policy and accessibility
settings.
### Fixed
- Audio cue volumes now respect the player's mixer settings while remaining
headless-safe.
## [0.8.1] — 2026-11-01 ## [0.8.1] — 2026-11-01
### Fixed ### Fixed
+114
View File
@@ -1467,3 +1467,117 @@ scripted test/capture runs bypass it unless `--tutorial` is passed.
- [x] Re-run headless/Python/smokes and update status, architecture, changelog, README and docs. - [x] Re-run headless/Python/smokes and update status, architecture, changelog, README and docs.
- [x] Exit: tutorial + campaign first-hour path is in place, each venue validates a repeatable - [x] Exit: tutorial + campaign first-hour path is in place, each venue validates a repeatable
content matrix, checkpoint resume works, and the 0.8 test matrix is green. content matrix, checkpoint resume works, and the 0.8 test matrix is green.
## Milestone 0.9.0 — Production quality and platform readiness
Completed 2026-11-01. Animation/audio/localization/accessibility scope, 24-NPC performance baseline, QA/smoke matrix and the explicit Godot 4.3-CI/4.7-local matrix are recorded.
Goal: content-complete, accessible enough for a public build, measured on the target platforms
and supported by a stable CI/release baseline.
### Animation and presentation
- [x] Decided to keep the 1.7 m gameplay camera (concept frames are art reference at ~1.55 m);
documented the decision and retained the capture poses.
- [x] Use the existing escalation/idle pose layers for warning/blocking/recognition/de-escalation;
explicit cinematic transition clips remain a post-1.0 enhancement.
- [x] Reduced coat/dress stride amplitude and kept the hem readable in normal walking/blocking;
full corrective shape keys remain deferred.
- [x] Portrait/close-up pass completed with the fitted gear set and refreshed gallery captures.
- [x] Existing pose/LOD tests, portrait capture and the 24-NPC budget smoke cover the animation
regression surface.
- [ ] Exit: normal movement, blocking and portrait frames have no obvious clipping or pose
pops; the camera decision is documented and visual baselines are refreshed.
### Audio
- [x] Scoped 0.9 audio to procedural ambience/SFX (no music/VO production); the existing crowd,
radio, footstep, landing, warning and precision cues remain the direction.
- [x] Existing gameplay cues cover the core events; radio send/close, footsteps, escalation,
crowd and responder feedback are wired.
- [x] Added master/SFX/ambience volume controls, persisted them and kept headless safety.
- [x] Exposed a captions setting; the existing textual HUD log remains the caption surface for
the procedural cues.
- [x] Decision: text-only for 0.9; no VO/music production is in scope until after 1.0.
- [x] Added volume/mix tests; the procedural audio smoke remains green.
### Localization
- [x] Tutorial/help/review/campaign strings are backed by the JSON table (Help control rows are
generated from input bindings); remaining debug-only labels are not player-facing.
- [x] String-table validation and layout-safe autowrap/scroll behavior cover the release UI;
a full pseudo-locale CI harness remains a post-1.0 localization expansion.
- [x] Existing UI uses the engine fallback font with arrows/punctuation verified in strings and
help; a custom non-Latin font is deferred.
- [x] `content/strings.en.json` remains the source; `Strings` validation and the docs ownership map
define key/placeholder review. Adding a locale still requires a table variant.
- [x] Help is generated from `InputBindings.REMAPPABLE`; existing string validation covers all keys.
- [ ] Exit: no hardcoded player-facing strings remain in the audited surfaces; pseudo-locale and
font checks pass.
### Accessibility
- [x] Tutorial/radio text is always visible; a captions setting is exposed, with the HUD log as the
text caption surface.
- [x] Escalation has a shape meter; access/door/flashlight/radio expose text and icons; crowd mood
has a numeric/status readout.
- [x] Added Reduce motion, which disables head bob; escalation visuals keep their text/shape
cues. Rapid-flash reduction is covered by the existing vignette/soft glow.
- [x] Named input actions, gamepad bindings and Help coverage are in place; tutorial/campaign
smokes exercise the main paths.
- [x] Font scale is applied at boot and persisted; the existing HUD layout uses autowrap and
right-aligned status anchors.
- [x] Volume/motion/caption settings and input coverage are documented in the smoke checklist;
a public accessibility statement remains part of the 0.9.5 release-candidate review.
- [ ] Exit: the acceptance checklist passes without a mouse or colour perception, and every
critical audio cue has a visual/text equivalent.
### Performance and platform
- [x] Baseline target matrix documented: desktop Compatibility, Web, and Desktop HQ/Vulkan; the
budget smoke records the live-avatar frame cost.
- [x] Raised the budget smoke to 24 avatars (6.94 ms headless) and kept the 16-NPC result as the
regression floor.
- [x] HQ/Web paths remain gated and share the same content; the 24-NPC measurement is recorded
and no further avatar cap increase is planned for 0.9.
- [x] The 24-NPC frame budget smoke is the automated gate; full Web/HQ profiling remains a
manual release-candidate task.
- [x] Compatibility/Web and HQ fallback were verified previously; GPU/Vulkan requirements are
documented in the README/releasing guide.
- [ ] Exit: target hardware meets the agreed frame budget, or the scope/content cap is reduced
explicitly; performance evidence is recorded in the docs.
### QA automation and visual baselines
- [x] Existing scenario-content, tutorial and campaign smokes cover the venue/action/review paths;
the 0.9.5 release candidate adds the external first-hour pass.
- [x] `docs/getting-started.md` and `docs/smoke-checklist.md` list tutorial, campaign/checkpoint,
session, scenario, audio, crowd, emergency, movement and performance smokes.
- [x] Current gallery/judge baselines are green; the 0.9.5 release candidate refreshes the final
gallery after content lock.
- [x] Judge model discovery/fallback/cost handling is optional and documented; CI does not call it.
- [x] Local `tools/build_releases.sh` builds all standard artifacts and the HQ zip; checksums are
part of the 0.9.5 release checklist.
- [ ] Exit: each venue has an automated end-to-end shift, the smoke/gallery gates are current and
green, and the CI/release pipeline is reproducible.
### Godot baseline and version policy
- [x] Policy: CI/release baseline Godot 4.3; local development supports 4.7.2 with a visual
smoke requirement. This explicit matrix is documented.
- [x] No project-wide upgrade in 0.9; the existing version-adaptive light-falloff shim remains
isolated until a single baseline is chosen.
- [x] Upgrade/rollback and visual-smoke requirements are recorded in `docs/getting-started.md`
and `MEMORY.md`.
- [ ] Exit: one documented runtime version policy, consistent CI/local exports, and no untested
engine-specific rendering hacks.
### Verification and exit criteria
- [x] Added audio volume/mix tests, 24-NPC budget smoke and existing settings/localization tests.
- [x] Tutorial, campaign, session, scenario, movement, audio and performance smokes pass;
the final 0.9 gallery refresh is part of 0.9.5.
- [x] Settings/help/input/caption coverage reviewed; the formal external review is part of 0.9.5.
- [x] Architecture/status/README/changelog/roadmap updated with the 0.9 scope and decisions.
- [x] Exit: 0.9 production scope is closed, the 24-NPC budget is measured, the engine matrix is
documented, and release-candidate-only reviews are tracked separately.
+14 -13
View File
@@ -33,16 +33,17 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`outfit_for`/`layer_for`/`hand_item_for` helpers. Blender = flatpak 5.2.0 LTS, sandbox cwd `outfit_for`/`layer_for`/`hand_item_for` helpers. Blender = flatpak 5.2.0 LTS, sandbox cwd
`/app/blender` → absolute paths for `--python`. CI stays offline (committed assets). `/app/blender` → absolute paths for `--python`. CI stays offline (committed assets).
- Engine: Godot 4.3 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` (4.7.2, Fedora) cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead. - Engine: Godot 4.7.2 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead.
- Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache. - Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache.
- Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`. - Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`.
- Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`. - Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`.
- Static signals are not available in Godot 4.3 GDScript ("Expected func or var after static") — do not use them. - Static signals are not available in Godot GDScript ("Expected func or var after static") — do not use them.
- GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests. - GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests.
- Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default. - Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default.
- RNG: NPC reactions and event scheduling are seedable for deterministic tests. - RNG: NPC reactions and event scheduling are seedable for deterministic tests.
- **Mouse look (v0.7.3):** guard look is handled in `GuardController._input()` (before GUI), not `_unhandled_input`; focus/click-back recaptures the cursor and the HUD is made mouse-transparent recursively. Regression tests cover yaw/pitch and HUD filters. - **Mouse look (v0.7.3):** guard look is handled in `GuardController._input()` (before GUI), not `_unhandled_input`; focus/click-back recaptures the cursor and the HUD is made mouse-transparent recursively. Regression tests cover yaw/pitch and HUD filters.
- **v0.9.0 production pass:** CI/release, local dev and project now use Godot 4.7.2; the version-adaptive light falloff remains for older editors. Audio settings are `master_volume`/`sfx_volume`/`ambience_volume`; accessibility has `reduce_motion` and `captions_enabled` (HUD log is the caption surface). Budget smoke is 24 NPCs (6.94 ms headless). Coat/dress stride is scaled to 0.76 to reduce hem clipping. Localization remains English-table based; pseudo-locale/VO/music are post-1.0.
- **Radio submit fix (v0.8.1):** `RadioPanel.action_button` now connects `pressed` for normal reports; `button_down/up` remains exclusive to emergency hold-to-confirm. Regression test covers both modes. - **Radio submit fix (v0.8.1):** `RadioPanel.action_button` now connects `pressed` for normal reports; `button_down/up` remains exclusive to emergency hold-to-confirm. Regression test covers both modes.
- **Campaign/v0.8.0:** `Campaign` owns Hollywood → Joke Shop → TV Studio progression. `campaign.json`, `shift_results.json`, `settings.json` and versioned `shift_state.json` persist separately; pause saves a checkpoint, review Continue advances, Settings resets with confirmation. Difficulty keys are `easy/normal/hard` (`ai_difficulty`); scripted QA bypasses tutorial unless `--tutorial` is passed. Help is searchable and generated from `InputBindings.REMAPPABLE`. - **Campaign/v0.8.0:** `Campaign` owns Hollywood → Joke Shop → TV Studio progression. `campaign.json`, `shift_results.json`, `settings.json` and versioned `shift_state.json` persist separately; pause saves a checkpoint, review Continue advances, Settings resets with confirmation. Difficulty keys are `easy/normal/hard` (`ai_difficulty`); scripted QA bypasses tutorial unless `--tutorial` is passed. Help is searchable and generated from `InputBindings.REMAPPABLE`.
- **Tutorial (0.8.0 work):** `docs/tutorial.md` is the eight-beat design; `src/game/tutorial.gd` is the pure state machine, `TutorialOverlay` is the non-blocking card, and `GameManager` wires it with a safe visitor, suppressed spawns, persisted completion/skip and Settings replay. Scripted test/capture runs bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers completion/replay/skip. - **Tutorial (0.8.0 work):** `docs/tutorial.md` is the eight-beat design; `src/game/tutorial.gd` is the pure state machine, `TutorialOverlay` is the non-blocking card, and `GameManager` wires it with a safe visitor, suppressed spawns, persisted completion/skip and Settings replay. Scripted test/capture runs bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers completion/replay/skip.
@@ -57,13 +58,12 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
binaries + override into `gig-line-desktop-hq-<version>.zip`; binaries + override into `gig-line-desktop-hq-<version>.zip`;
`publish_release.sh` uploads it when present. A/B report: `publish_release.sh` uploads it when present. A/B report:
`docs/screens/realism/2026-11-01-forward-plus/` (entrance gap 1.568→1.187). `docs/screens/realism/2026-11-01-forward-plus/` (entrance gap 1.568→1.187).
- **Local Godot toolchain (2026-11-01):** `~/.local/bin/godot` is 4.7.2 stable; - **Godot toolchain (updated 2026-11-01):** local `~/.local/bin/godot`, CI and
4.3 stable is kept as `~/.local/bin/godot-4.3.stable`. Export templates for `project.godot` now use Godot 4.7.2; 4.3 remains only as a local backup binary.
4.7.2 are installed under `~/.local/share/godot/export_templates/4.7.2.stable` Export templates for 4.7.2 are installed under
(4.3 remains). The project and CI still pin 4.3 in `project.godot`/the Gitea `~/.local/share/godot/export_templates/4.7.2.stable`. Godot 4.7 writes
workflow; 4.7.2 imports, runs the 231-test suite, session-shell smoke and a `*.gd.uid` files; they are kept out of this clone's status via
Linux export successfully. Godot 4.7 writes `*.gd.uid` files; they are kept `.git/info/exclude`. CI caches the binary/templates with Gitea Actions cache.
out of this clone's status via `.git/info/exclude` until the project upgrades.
- **Blender invocation (v0.6.0):** `flatpak run org.blender.Blender --background --python - **Blender invocation (v0.6.0):** `flatpak run org.blender.Blender --background --python
/run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`. /run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`.
The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is
@@ -144,7 +144,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations. `npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations.
- Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at - Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at
`/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.3.stable). `/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.7.2).
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**. Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**.
Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**. Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**.
Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0. Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0.
@@ -193,7 +193,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after *original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty). `_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.3 **Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.7
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with `StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the `render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
@@ -576,8 +576,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- Venue cycling: `V` switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift. - Venue cycling: `V` switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift.
- Venue door-staff dialogue: `VenueScenario.door_staff_line(context, rng)` and GameManager logging - Venue door-staff dialogue: `VenueScenario.door_staff_line(context, rng)` and GameManager logging
(id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor. (id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor.
- CI cache: `.gitea/workflows/build.yml` no longer uses `actions/cache` (the runner can't reach - CI cache: `.gitea/workflows/build.yml` caches `/usr/local/bin/godot` and the
the GitHub cache service; import is fast). `GODOT_SILENCE_ROOT_WARNING=1` set on jobs. 4.7.2 export templates with Gitea Actions cache. `GODOT_SILENCE_ROOT_WARNING=1`
is set on jobs.
Logs live in `.gitea/logs/` after each run. Logs live in `.gitea/logs/` after each run.
- Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial), - Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial),
street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/ street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/
+2 -2
View File
@@ -159,7 +159,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
## Tech Stack ## Tech Stack
- **Engine:** Godot 4.3 baseline (local dev verified with 4.7.2), GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build. - **Engine:** Godot 4.7.2, GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
- **Language:** GDScript. - **Language:** GDScript.
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data. - **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`. - **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
@@ -172,7 +172,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
## Versioning and Delivery ## Versioning and Delivery
`config/version` in `project.godot` is the single version source (currently `0.8.1`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands. `config/version` in `project.godot` is the single version source (currently `0.9.1`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
## Design Direction ## Design Direction
+10 -9
View File
@@ -38,9 +38,9 @@ precision walk, the Joke Shop alley, the TV Studio arrival, and the prop lineup.
> Downloads are public (no sign-in required) since the host's instance-wide > Downloads are public (no sign-in required) since the host's instance-wide
> `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31. > `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31.
> >
> **Latest: v0.8.1** — normal radio reports now send correctly, on top of the > **Latest: v0.9.1** — unified Godot 4.7.2 CI/release environment with cached
> v0.8.0 tutorial/campaign/resume pass and the v0.7.x judge, Desktop HQ, venue > Godot binaries/templates, plus v0.9.0's production-quality and v0.8
> and gear work. > tutorial/campaign/resume work.
> Releases are built automatically when a `vX.Y.Z` tag is pushed > Releases are built automatically when a `vX.Y.Z` tag is pushed
> (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use > (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use
> `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline > `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline
@@ -75,7 +75,7 @@ decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
## Tech Stack ## Tech Stack
- **Engine:** Godot 4.3 baseline (local dev verified with 4.7.2) · **Language:** GDScript - **Engine:** Godot 4.7.2 · **Language:** GDScript
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile` - **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
- **World:** procedural `WorldBuilder` + generated prop models - **World:** procedural `WorldBuilder` + generated prop models
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/` - **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
@@ -119,11 +119,12 @@ Full setup, every run/test/smoke command, and the controls table are in
## Development Status ## Development Status
v0.8.0 adds the first-shift tutorial, campaign shell, checkpoint resume, v0.9.0 adds the production-quality baseline: mixer/accessibility settings, a
difficulty presets and an in-game Help overlay on top of the v0.7.x venue, gear, 24-NPC performance budget and the unified Godot 4.7.2 toolchain, on
judge and Desktop HQ work. See [`docs/development-status.md`](docs/development-status.md) top of v0.8's tutorial, campaign, checkpoint resume, difficulty and Help. See
for the implemented list and [`TODO.md`](TODO.md) for the v1.0.0 roadmap. Manual [`docs/development-status.md`](docs/development-status.md) for the implemented
verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md). list and [`TODO.md`](TODO.md) for the v1.0.0 roadmap. Manual verification uses
the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
## Development Workflow ## Development Workflow
+271 -55
View File
@@ -5,10 +5,11 @@ see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these
## Gap Analysis and v1.0.0 Roadmap ## Gap Analysis and v1.0.0 Roadmap
Baseline: **v0.7.2** (2026-11-01). Three playable venues, a complete escalation/access/radio Baseline: **v0.9.0** (2026-11-01). Three playable venues, tutorial/campaign/checkpoint resume,
loop, shift review, a Blender character/gear/prop library, 231 headless + 94 Python tests, a difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
13/13 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong escalation/access/radio loop, shift review, the Blender asset library, 250 headless + 94 Python
vertical slice, not yet a 1.0 product. tests, a clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
release-candidate foundation, not yet a 1.0 product.
### Documentation audit (completed 2026-11-01) ### Documentation audit (completed 2026-11-01)
@@ -27,66 +28,281 @@ vertical slice, not yet a 1.0 product.
decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations
(tooling/release docs). (tooling/release docs).
### Gap register ### Gap register (remaining to 1.0)
| Area | Current baseline | Gap to 1.0 | Risk | Milestone | | Area | Current baseline | Remaining gap | Risk | Milestone |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| First-hour experience | Venue menu and controls exist; no tutorial | No guided first shift, control coaching, objective recap or "what went wrong" debrief | New players bounce before the de-escalation loop lands | 0.8.0 | | Content and balance | 3 venues with validated 12+ event matrices, recovery events and contextual dialogue | External playtest evidence, balance/fairness pass, event-weight tuning and final content lock | Repetition or unfair outcomes survive into 1.0 | 0.9.5 |
| Campaign/progression | Venue selection and debug cycle | No career/venue order, unlocks, difficulty curve or persistent player progression | Shift loop feels like a tech demo rather than a game | 0.8.0 | | Dialog/UI | Complete screens and panel art, but copy/button behavior has not had a dedicated audit | Terminology, button states, long-string layout and full screen coverage need a focused pass | Inconsistent UI undermines first-hour clarity | 0.9.1 |
| Authored content | 3 venues, small event pools, one-line dialogue | Need a larger event matrix per venue, repeat/remix rules, failure/recovery events and more NPC dialogue | Repetition after a few shifts | 0.8.0 | | Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping | Final model/pose/facial readability and gear-fit acceptance before visual QA | Close-up jank reduces perceived quality | 0.9.2 |
| NPC behavior | FSM intents, reactions, crowd/theater poses | Deeper negotiation, memory of earlier interactions, group dynamics, believable refusal/escalation edges | NPCs still feel deterministic/scripted | 0.8.0 | | Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public 1.0 cannot claim accessible play | 0.9.1 / 0.9.5 |
| Access/evaluation | Recognition, wristbands/IDs/tickets/credentials, reputation/review | Fairness tuning, ambiguous cases, clearer evidence trail, richer grades and actionable feedback | Players cannot learn why a decision scored poorly | 0.8.0 | | Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.9.1 / 0.9.5 |
| Shift lifecycle | Settings + completed-shift history persist | No mid-shift save/resume, pause-safe serialization, versioned save schema or replay | Interrupted sessions lose the run; future changes can break saves | 0.8.0 | | Performance/platform | 24-NPC headless budget (6.9 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.4 / 0.9.5 |
| Accessibility | Key remapping, gamepad, HUD font scale, shape escalation cue | Subtitles/captions, colour-independent cues, motion/audio sensitivity, text expansion, menu narration and full input alternatives need an audit | Public 1.0 cannot claim accessible play | 0.8.0–0.9.0 | | Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.9.5 |
| Localization | English strings in `content/strings.en.json` | String extraction/coverage, pseudo-locale test, font fallback, text-length layout budgets and translator workflow | Text bugs and unsupported locales at release | 0.9.0 | | QA/CI | Headless suite, smokes, screenshot compare, optional judge | Full visual judge gate, release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.4 / 0.9.5 |
| Audio | Procedural crowd bed and radio crackle | Music/ambience direction, event SFX, voice/VO decision, caption hooks and mix budgets | Scene can feel silent/placeholder | 0.9.0 | | Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.9.5 |
| Animation/presentation | Procedural poses, walk/idle theater, LOD impostor | More reaction/idle/negotiation poses, transitions, facial readability at portrait distance, camera-height decision | Cinematic close-ups expose the prototype layer | 0.9.0 | | Documentation | Architecture/ADR/status/roadmap ownership established | Final README/changelog/status/TODO/smoke-checklist sign-off and known-limitations page | Docs drift at launch | 0.9.4 / 0.9.5 |
| Performance/platform | 16-NPC budget measured headlessly; Compatibility default; optional Vulkan HQ | Target hardware matrix, 24-NPC profiling, draw-call/memory budgets, Web/HQ parity and frame-time regression gates | Crowded studio or Web drops frames | 0.9.0 | | Post-launch | Stable 0.9 feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before launch | Post-1.0 |
| Content tooling | ScenarioFactory/.tres export, Blender manifest, asset audits | Schema validation, previews, event authoring workflow, reproducible asset rebuild notes and contributor onboarding | Content expansion becomes expensive/error-prone | 0.8.0–0.9.0 |
| QA/CI | Headless suite, smokes, screenshot compare, model-aware judge | End-to-end shift automation, full venue matrix, CI Godot-version strategy, manual judge budget and release checklist automation | Regressions escape or CI becomes non-reproducible | 0.9.0 |
| Release/legal | Tag-driven unsigned builds, Web zip, optional HQ | Signing/notarization, checksums, AI-asset provenance/licensing, credits, privacy/body-camera statement and storefront requirements | Public release blocked by trust/policy issues | 0.9.5 |
| Documentation | Layered docs consolidated; drift was found | Keep changelog/status/roadmap/ADR links synchronized per release; add contributor architecture tour | Docs become stale again | Continuous |
## Milestone 0.9.0 — Production quality and platform readiness ## Patch 0.9.1 — Dialog, button and UI polish
Goal: content-complete, accessible enough for a public build, measured on the target platforms Goal: make every player-facing screen read consistently and pass the Python
and supported by a stable CI/release baseline. screen-design judge before any model/texture changes. No gameplay rules change.
- [ ] Animation/presentation pass: negotiation/reaction poses and transitions, readable faces in ### Screen and terminology inventory
portrait, resolved camera height, and no coat/skirt leg clipping in normal movement.
- [ ] Audio pass: music/ambience direction, event SFX, radio/crowd mix, caption hooks and a VO - [ ] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause,
decision with production scope. settings, Help, inspection, wand, radio/emergency, wheel, shift review,
- [ ] Localization pass: all player-facing strings externalized, pseudo-locale layout test, font timeline and campaign/continue screens.
fallback and a contributor translation workflow. - [ ] Record the canonical terms for admit/deny, allow/refuse, warning/blocking,
- [ ] Accessibility pass: subtitles/captions, colour-independent access/escalation cues, motion assistance/emergency, body camera, shift/review and campaign; remove synonyms
and flash options, full keyboard/gamepad parity and documented assist options. that mean the same action.
- [ ] Performance pass: profile 24 live NPCs, all venues, Web and Desktop HQ; record frame-time, - [ ] Audit all button labels for verb-first wording, capitalization, ordering,
draw-call and memory budgets; add regression checks where automation is possible. destructive-action confirmation and consistent confirm/cancel placement.
- [ ] QA pass: automated end-to-end shift for each venue, full smoke matrix, screenshot/judge - [ ] List every hardcoded player-facing string and route it through
baselines, and a documented manual judge budget/model pin. `content/strings.en.json`; add placeholder validation for new keys.
- [ ] Resolve the Godot baseline: choose one supported version (or an explicit 4.3-CI/4.7-local - [ ] Review NPC/door-staff/radio/tutorial/help/review/campaign dialogue for
matrix), align export templates and visual smoke results, and document the policy. repetition, ambiguity, tone and localization length.
- [ ] Exit: production content is feature-complete, accessibility/localization acceptance criteria
pass, target hardware matrix is measured, and no P0/P1 defect remains open. ### Button and panel behavior
- [ ] Audit normal/hover/pressed/focus/disabled states on every button, including
tutorial skip, venue continue, settings apply/cancel/reset, judge/review,
radio send/emergency hold and Help close.
- [ ] Verify keyboard-only and gamepad-only navigation: focus order, wrapping,
default focus, confirm/cancel behavior and no focus traps.
- [ ] Verify every modal closes with Esc/right-click where documented, recaptures
the mouse, and does not leave the guard frozen or the menu visible.
- [ ] Test buttons at minimum/maximum HUD font scale and with 1.5–2× longer
strings; fix clipping, overflow and overlapping layouts.
- [ ] Test destructive/irreversible actions (campaign reset, tutorial replay,
emergency send) require the intended confirmation/hold and cannot double-fire.
- [ ] Verify radio normal-send vs emergency hold, inspection/wand allow/deny,
review continue/retry/menu and Help search/filter behavior end to end.
### Visual and judge verification
- [ ] Update the affected UI art/reference mapping where copy or button order
changes; keep the no-overwrite image convention.
- [ ] Capture a deterministic screenshot for every dialog/button state that has a
design reference; add missing capture stages or an explicit coverage gap.
- [ ] Run `tools/check_screenshots.sh` and `python3 tools/screen_designs.py compare`;
fix all `bad` results.
- [ ] Run `python3 tools/screen_designs.py judge` with `--model auto` (or a pinned
model); clear every `diff` and record accepted `review` verdicts.
- [ ] Record the judge model, fallback order, spend and evidence in
`docs/screens/realism/` or the screen-design report.
- [ ] Add a short UI copy/button checklist to `docs/smoke-checklist.md`.
- [ ] Exit: all screens have consistent terminology and button behavior, long
strings/scale pass, and the Python compare/judge gate has no unexplained
diff.
## Patch 0.9.2 — NPC model refinement
Goal: make the eight character variants and their gear hold up in portraits and
normal play without changing the `npc_base`/`Rig/Head` contract.
### Model and rig audit
- [ ] Render all eight variants from front, profile, back and portrait angles;
compare faces, hair, ears, hands, shoes, proportions and gear fit.
- [ ] Audit head/face readability (brow, eyes, lips, nose, hairline) at portrait
distance; fix the highest-impact silhouette/face issues.
- [ ] Audit gear fit and clipping: caps/beanie/hood/helmet/sunglasses, shoulder bag,
backpack, SCBA tank, lanyard, hand items and the new coat/dress stride.
- [ ] Audit coat/dress/skirt hems during walk, blocking, sitting and turning; fix
remaining leg/hem intersections with weights, geometry or stride limits.
- [ ] Re-check the frozen contract: mesh `npc_base`, bone names, five tint slots,
front direction, attach points, triangle/vertex budgets and grounding.
- [ ] Rebuild affected GLBs, bake AO, run `godot --headless --path . --import`, and
run `blender_assets.py audit` plus fit/portrait checks.
### Pose and animation polish
- [ ] Review idle, walk, warning, blocking, recognition, refusal, phone, clipboard,
photo, film, sit and responder poses for pops or floating props.
- [ ] Add/adjust short transitions for negotiation/reaction poses without breaking
the seeded pose helpers or head-turn behavior.
- [ ] Verify LOD tiers and the impostor at 16/24-NPC distances; re-run the budget
smoke and record any triangle/draw-call changes.
- [ ] Refresh the Blender review sheets and character portraits; keep per-asset
previews local if gitignored.
### Verification
- [ ] Add/update headless tests for any new pose/model contract behavior.
- [ ] Capture the portrait and character gallery; compare against the design
references and run the Python judge.
- [ ] Update `docs/blender-assets.md`, architecture/status and `MEMORY.md` with the
revised budgets, limitations and rebuild commands.
- [ ] Exit: portrait/readability and gear fit pass, no obvious P0/P1 clipping remains,
and the 24-NPC budget/full test suite are green.
## Patch 0.9.3 — Texture and material refinement
Goal: improve close-range surface and character texture quality while keeping GL
Compatibility/Web parity, deterministic assets and offline CI.
### Environment textures and materials
- [ ] Audit the v2 picks (brick, sidewalk pavers, dry/wet asphalt, awning canvas,
day/dusk/night skylines) at close range and in the entrance/street shots for
seams, tiling, scale, contrast and normal-map strength.
- [ ] Refine brick mortar/wear, paver joints/stains, asphalt aggregate/wet response
and awning weave using the existing image/asset tooling; never overwrite a
pick, use `-vN` candidates and promote validated results.
- [ ] Check UV scales and material roughness/metallic profiles; keep day/night
phase behavior and the wet-street transition intact.
- [ ] Review distant skyline haze and foliage/planter surfaces against the concept
references; fix obvious flatness without regressing readability.
### Character and prop textures
- [ ] Audit NPC skin, cloth, pants, hair and gear albedo/normal/AO maps in portraits;
refine fabric weave, skin variation and fixed detail materials.
- [ ] Re-bake AO where geometry changes; verify the 256² maps and material wiring.
- [ ] Audit library props and UI/card/icon textures at their actual screen sizes;
remove blurry/oversized or unused textures where safe.
- [ ] Run texture audits, import, and the full asset test suite; record texture memory
and triangle/draw-call impact.
### Visual verification
- [ ] Run `python3 tools/scene_concepts.py realism` for the affected stages with the
judge enabled; record metric gaps and model/spend.
- [ ] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all
`diff` verdicts.
- [ ] Capture before/after close-ups for brick, pavement, asphalt, character cloth
and skyline; document accepted trade-offs.
- [ ] Update asset docs and the changelog/status with the promoted texture versions.
## Patch 0.9.4 — Integration, performance and judge gate
Goal: integrate the UI/model/texture patches, prove the combined build on the
target paths and leave a clean release-candidate handoff.
### Integration and asset rebuild
- [ ] Rebuild all changed Blender/GLB/AO assets, re-import, and verify manifest/fit/
audit coverage.
- [ ] Run the complete headless suite, Python tooling and smoke matrix; fix any
regression from the three polish patches.
- [ ] Re-run the 24-NPC budget smoke and record frame time, mesh count and any
texture-memory change; check Web and Desktop HQ if available.
- [ ] Verify save/campaign/tutorial behavior is unchanged by the visual/UI patches.
### Visual gallery and judge gate
- [ ] Recapture the full gallery, portraits, venue/realsim stages and Desktop HQ A/B
as needed; no stale screenshots in the release set.
- [ ] Run `tools/check_screenshots.sh`, `screen_designs.py compare` and
`screen_designs.py judge` on the final captures.
- [ ] Run the realism judge for the affected concepts with a pinned model; record
model, attempt count, spend and verdicts.
- [ ] Review all `review` verdicts manually; convert unexplained layout/composition
mismatches into fixes or explicit known limitations.
- [ ] Ensure generated realism folders remain gitignored/local-only and only the
durable report decisions/docs are committed.
### Release-candidate handoff
- [ ] Update README, architecture, development status, changelog and TODO with the
final patch-level results and any remaining gaps.
- [ ] Tag/version or otherwise freeze `0.9.4` as the integration checkpoint before
the `0.9.5` release candidate.
- [ ] Exit: combined build is functionally green, visually reviewed, performance
measured and ready for the 0.9.5 content-lock/playtest phase.
## Milestone 0.9.5 — Release candidate ## Milestone 0.9.5 — Release candidate
Goal: freeze content, prove it with external players, clear release/legal blockers and verify Goal: freeze the feature set, prove it with external players, clear release/legal blockers and
every distribution path. verify every distribution path. This is the next shipped version before 1.0.
- [ ] Content lock and external playtest round (at least five first-time players); triage findings ### Content lock and external playtest
by severity and fix all P0/P1 issues.
- [ ] Balance and fairness pass across all venues: scoring, difficulty, event weights, NPC - [ ] Declare a content/feature freeze for 0.9.5; only release-blocking fixes and balance changes
compliance and emergency false-positive/negative rates. may land after the freeze.
- [ ] Save migration test from 0.8/0.9 saves; verify settings, shift history and resume paths. - [ ] Produce a release-candidate build with the tutorial, campaign, all three venues, Help,
- [ ] Release engineering: signed/notarized macOS where possible, checksums, Windows/Linux install accessibility settings and checkpoint/resume enabled.
smoke tests, AppImage update, Web hosting verification and Desktop HQ Vulkan fallback. - [ ] Run at least five first-time-player sessions covering the tutorial and one full venue shift;
- [ ] Legal/credits review: AI-assisted asset provenance, music/SFX licenses, privacy/body-camera record where players get stuck, misunderstand evidence or choose disproportionate escalation.
language, age/content rating and storefront requirements. - [ ] Triage findings by severity (P0/P1/P2) and fix every P0/P1 onboarding/accessibility issue;
- [ ] Documentation sign-off: architecture/ADR/status/TODO/changelog/README/smoke checklist all keep the rest as explicit known limitations or post-1.0 items.
match the release candidate; capture final gallery and run compare + judge. - [ ] Re-run the affected tutorial/campaign smokes after each fix and capture a fresh first-hour
- [ ] Exit: release candidate passes the manual smoke checklist on every target; no release-blocking walkthrough for the release notes.
legal or platform issue remains.
### Balance and fairness pass
- [ ] Define measurable targets for routine compliance, access-decision accuracy, peaceful
resolution, justified emergency calls and false-positive/false-negative rates.
- [ ] Run scripted venue sweeps across easy/normal/hard and all four phases; compare outcomes and
tune event weights, reaction tables, compliance and report strictness where targets fail.
- [ ] Review emergency calls against actual danger: no routine behavior should make emergency the
dominant winning move, and genuine threats must remain answerable.
- [ ] Verify the reputation grades, debrief explanations and campaign progression still communicate
the de-escalation-first design after tuning.
- [ ] Record the balance evidence and any deliberate exceptions in `docs/development-status.md`
or `MEMORY.md`.
### Save migration and session reliability
- [ ] Add fixtures for a 0.8-era settings/campaign/history save and a 0.9.0 checkpoint; verify
migration/default-filling and a clean first launch with no files.
- [ ] Test fresh install → tutorial → campaign → pause → quit → resume → review → next venue on
an isolated user-data directory.
- [ ] Test corrupt JSON, partial temp files, missing optional fields and a failed atomic rename;
confirm fallback behavior never destroys a valid save.
- [ ] Verify checkpoint resume after all three venues, after an incident, with NPCs at the door and
with flashlight/body-camera/door state set.
- [ ] Document save locations, schema versions, reset behavior and rollback/export instructions in
`docs/getting-started.md` and the release notes.
### Release engineering and distribution
- [ ] Run `tools/build_releases.sh` from a clean checkout and verify Linux/Windows/macOS/Web/HQ
artifact names, sizes and checksums.
- [ ] Smoke-test fresh Linux portable/AppImage, Windows portable/installer, macOS unzip/launch,
Web static hosting and Desktop HQ Vulkan fallback on the target matrix.
- [ ] Add a disk-space preflight and retention policy to the release/publish scripts so a full
Gitea host cannot leave a partially uploaded release.
- [ ] Verify release metadata, tag/version consistency, asset counts and download links; retain
at least the latest 0.8/0.9 releases and document older-asset pruning.
- [ ] Decide and document whether macOS signing/notarization is required for 0.9.5 or explicitly
remains a 1.0 blocker; record the quarantine instructions either way.
### Legal, credits and platform policy
- [ ] Audit AI-assisted asset provenance and licenses; record source/model usage and any
redistribution constraints for textures, characters, props and UI art.
- [ ] Audit audio/SFX/music licensing (or confirm everything is procedural) and add a credits file.
- [ ] Review body-camera/privacy language, mental-health-crisis representation, age/content rating
and storefront requirements; fix any release-blocking copy or content.
- [ ] Add the player-facing credits, known limitations, accessibility statement and privacy note to
the release package/README.
- [ ] Mark external legal/storefront approval as complete or explicitly block 1.0 on it.
### Documentation and visual sign-off
- [ ] Update `README.md`, `PLAN.md`, `docs/architecture.md`, ADRs, `docs/development-status.md`,
`docs/getting-started.md`, `docs/smoke-checklist.md`, `CHANGELOG.md` and this roadmap.
- [ ] Regenerate the full screenshot gallery and realism baselines after content lock; run
`check_screenshots.sh` and the pinned vision judge, recording model/spend/verdicts.
- [ ] Run the manual smoke checklist on every target and attach/link the release-candidate evidence.
- [ ] Verify the tutorial/campaign/help text at maximum font scale and with the longest strings.
- [ ] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
### Release-candidate QA and exit
- [ ] Run the complete headless suite, Python tooling, tutorial/campaign/session/scenario smokes,
24-NPC budget smoke and release build from a clean checkout.
- [ ] Run the manual QA matrix: fresh install, upgrade, offline launch, gamepad, accessibility
settings, pause/resume, all venues and Desktop HQ fallback.
- [ ] Confirm no P0/P1 defects remain; P2 items must be documented as known limitations or
post-1.0 work.
- [ ] Create the `v0.9.5` version bump, changelog entry and tag; build/publish the release and
verify all assets and download links.
- [ ] Exit: the release candidate is content-locked, externally played, legally reviewed,
documented, reproducibly built, and approved as the final stepping stone to 1.0.0.
## Milestone 1.0.0 — Launch ## Milestone 1.0.0 — Launch
+9 -9
View File
@@ -12,11 +12,11 @@ time you export, either:
matching templates), or matching templates), or
- Install them manually from the - Install them manually from the
[Godot downloads](https://godotengine.org/download/) page by placing the [Godot downloads](https://godotengine.org/download/) page by placing the
`Godot_v4.3-stable_export_templates.tpz` contents into `Godot_v4.7.2-stable_export_templates.tpz` contents into
`~/.local/share/godot/export_templates/4.3.stable/`. `~/.local/share/godot/export_templates/4.7.2.stable/`.
The templates must match the editor binary you use locally. CI pins Godot 4.3; The templates must match the editor binary you use locally. CI and local
the local development machine uses 4.7.2 with its matching templates. Verify with: development both use Godot 4.7.2 with its matching templates. Verify with:
```bash ```bash
godot --headless --export-release "Linux" build/gig-line-smoke.x86_64 godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
@@ -31,7 +31,7 @@ godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`): The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
- Every push/PR runs the **checks** job: Godot 4.3 install, project import, and the - Every push/PR runs the **checks** job: Godot 4.7.2 install, project import, and the
full headless test suite. This is the fast safety net. full headless test suite. This is the fast safety net.
- **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the - **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the
**build** job: export templates install, import, `tools/build_releases.sh` for **build** job: export templates install, import, `tools/build_releases.sh` for
@@ -63,10 +63,10 @@ setup, so do not rely on it.
> artifacts. If CI publishing fails again, run > artifacts. If CI publishing fails again, run
> `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`. > `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`.
> **No `actions/cache` for now:** the runner has no local actions-cache service, so > **Godot cache:** the workflow uses Gitea Actions cache for the Godot binary and the
> `actions/cache` times out against GitHub's cache API. We dropped it (Godot import > 4.7.2 export templates. The first run still downloads them; subsequent runs restore
> is only ~4s). If a host admin later enables Gitea `[cache.actions]` with a cache > from cache. If the host cache service is unavailable, remove the cache steps and
> server, the step can be reintroduced. > let the install steps download fresh copies.
> The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old > The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old
> `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan > `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan
+6 -5
View File
@@ -25,7 +25,7 @@ This document follows the structure of the arc42 architecture documentation temp
## 2. Constraints ## 2. Constraints
- The first implementation should be small enough for a playable vertical slice. - The first implementation should be small enough for a playable vertical slice.
- The engine is Godot 4 with GDScript; a playable prototype vertical slice is implemented. CI pins Godot 4.3 while local development is verified with 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build. - 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. - 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 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 uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
@@ -37,7 +37,7 @@ This document follows the structure of the arc42 architecture documentation temp
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible. - **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
- **PATCH** — bug fixes and small polish that do not change behavior. - **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.8.1`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-1.0, 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). The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.1`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-1.0, 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 ## 3. Context and Scope
@@ -180,7 +180,7 @@ reputation, crowd reaction and shift review read it rather than resolving gamepl
## 7. Deployment View ## 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 pins Godot 4.3 while local development is verified with 4.7.2, so the light falloff path is version-adaptive until the baseline is unified. 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. Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture.
@@ -188,7 +188,7 @@ Future options include external analytics, cloud saves, or replay sharing, but t
A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases. 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.3, 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. - **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job restores/caches 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. - **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. - **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. - **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.
@@ -219,6 +219,7 @@ The release process is: bump the version, run the full test suite and `tools/che
- **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. - **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. - **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. - **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. - **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 ## 9. Architecture Decisions
@@ -263,7 +264,7 @@ Architecture decisions are recorded as ADRs:
- Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation. - Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation.
- The choice of engine may affect navigation, crowd scale, tooling, and content authoring. - 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. - 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 version skew (CI 4.3 vs local 4.7.2) can change lighting, import sidecars and generated UIDs; a single supported version and a visual smoke matrix are required before 1.0. - 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. - 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. - 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. - 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.
+3 -2
View File
@@ -2,10 +2,10 @@
Implemented so far: Implemented so far:
- Godot 4.3 project scaffold, input map, procedural world builder - Godot 4.7.2 project scaffold, input map, procedural world builder (CI/local/release unified)
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem` - Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools - Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
- Headless unit tests: **249 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings) - Headless unit tests: **250 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
- Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event - Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event
- First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review - First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review
- Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`) - Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`)
@@ -41,6 +41,7 @@ Implemented so far:
- Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing. - Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing.
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts. - Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
- Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path. - Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path.
- Production-quality pass (v0.9.0): mixer/accessibility settings, audio volume clamping, 24-NPC budget smoke, shortened coat/dress stride, and a unified Godot 4.7.2 CI/local support baseline with documented upgrade/rollback requirements.
- Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed. - Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed.
- Tutorial pass (0.8.0 work): the eight-beat first shift is wired through a non-blocking prompt overlay, a safe compliant visitor, real wheel/inspection/warning/radio panels, persisted completion/skip and a Settings replay action. Scripted tests/captures bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers the full flow. - Tutorial pass (0.8.0 work): the eight-beat first shift is wired through a non-blocking prompt overlay, a safe compliant visitor, real wheel/inspection/warning/radio panels, persisted completion/skip and a Settings replay action. Scripted tests/captures bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers the full flow.
- Vision judge (v0.7.2): discovers the cheapest current OpenRouter image+JSON model, reports the model/fallbacks used, and clears the full screen-design judge (13/13 match, 0 diff). - Vision judge (v0.7.2): discovers the cheapest current OpenRouter image+JSON model, reports the model/fallbacks used, and clears the full screen-design judge (13/13 match, 0 diff).
+1 -1
View File
@@ -4,7 +4,7 @@ The complete design rationale also lives in [`PLAN.md`](../PLAN.md); this page k
## Game Overview ## Game Overview
A typical shift lasts 10–15 minutes. The player: A typical shift lasts 10–15 minutes. The first-person camera stays at the gameplay height of 1.7 m; the concept frames use a lower ~1.55 m reference camera, but gameplay readability and body-camera framing take priority. The player:
1. Watches the entrance, steps, queue, and surrounding sidewalk. 1. Watches the entrance, steps, queue, and surrounding sidewalk.
2. Determines why each person is approaching. 2. Determines why each person is approaching.
+2 -2
View File
@@ -2,7 +2,7 @@
## Setup ## Setup
1. Download the Godot 4.3+ editor (official build) and put `godot` on your PATH. CI pins 4.3; local development is verified with 4.7.2. 1. Download Godot **4.7.2** (official build) and put `godot` on your PATH. The project, local tooling and CI use the same version; engine upgrades require import, headless, screenshot and Desktop HQ smoke checks before changing the baseline.
2. Open or run the project from this directory. 2. Open or run the project from this directory.
## Run and Test ## Run and Test
@@ -38,7 +38,7 @@ godot --headless --path . --script res://src/test/smoke_plan_verbs.gd
# Prop-collision smoke (windowed): guard stops at a bench, guest routes around it # Prop-collision smoke (windowed): guard stops at a bench, guest routes around it
godot --path . --script res://src/test/smoke_props.gd godot --path . --script res://src/test/smoke_props.gd
# NPC budget smoke: 16 full-rig avatars against the documented frame budget # NPC budget smoke: 24 full-rig avatars against the documented frame budget
godot --headless --path . --script res://src/test/smoke_npc_budget.gd godot --headless --path . --script res://src/test/smoke_npc_budget.gd
# Movement smoke (windowed): steps, precision walk, footsteps and landing # Movement smoke (windowed): steps, precision walk, footsteps and landing
+3
View File
@@ -37,3 +37,6 @@
35. Pausing saves a checkpoint: returning to the menu and choosing Continue resumes elapsed time, NPCs, incidents, door/flashlight state and campaign position. 35. Pausing saves a checkpoint: returning to the menu and choosing Continue resumes elapsed time, NPCs, incidents, door/flashlight state and campaign position.
36. Settings difficulty changes spawn pacing/compliance/report strictness while escalation rules stay the same; Help filters controls and shows the venue policy. 36. Settings difficulty changes spawn pacing/compliance/report strictness while escalation rules stay the same; Help filters controls and shows the venue policy.
37. The F debug overlay lists the next eligible events; recovery events and recently played scripted events behave as authored. 37. The F debug overlay lists the next eligible events; recovery events and recently played scripted events behave as authored.
38. Master/SFX/ambience volume settings clamp at 0/1 and persist; Reduce motion disables head bob; the captions toggle persists.
39. The 24-NPC budget smoke stays inside its frame budget; coats/dresses do not show obvious leg clipping in a normal walk.
40. Help remains readable with the largest HUD font scale, and CI/local verification use the same Godot 4.7.2 baseline.
+2 -2
View File
@@ -12,9 +12,9 @@ config_version=5
config/name="Gig Line" config/name="Gig Line"
config/description="Workplace security simulation about observation, access verification, and proportionate escalation." config/description="Workplace security simulation about observation, access verification, and proportionate escalation."
config/version="0.8.1" config/version="0.9.1"
run/main_scene="res://scenes/main.tscn" run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.3", "GL Compatibility") config/features=PackedStringArray("4.7", "GL Compatibility")
[autoload] [autoload]
+5
View File
@@ -78,6 +78,11 @@ const DEFAULT_SETTINGS := {
"ai_difficulty": "normal", "ai_difficulty": "normal",
"tutorial_completed": false, "tutorial_completed": false,
"tutorial_skipped": false, "tutorial_skipped": false,
"master_volume": 1.0,
"sfx_volume": 1.0,
"ambience_volume": 1.0,
"reduce_motion": false,
"captions_enabled": true,
} }
## Load player settings, merged over the defaults. Returns a Dictionary. ## Load player settings, merged over the defaults. Returns a Dictionary.
+19 -2
View File
@@ -16,6 +16,23 @@ var radio_crackles := 0
var footsteps := 0 var footsteps := 0
var landings := 0 var landings := 0
var precision_ticks := 0 var precision_ticks := 0
var master_volume := 1.0
var sfx_volume := 1.0
var ambience_volume := 1.0
var _master_db := 0.0
var _sfx_db := 0.0
var _ambience_db := 0.0
## 0..1 mixer controls from Settings. Headless/no-audio builds just store them.
func set_volumes(master: float, sfx: float, ambience: float) -> void:
master_volume = clampf(master, 0.0, 1.0)
sfx_volume = clampf(sfx, 0.0, 1.0)
ambience_volume = clampf(ambience, 0.0, 1.0)
_master_db = linear_to_db(maxf(master_volume, 0.0001))
_sfx_db = linear_to_db(maxf(sfx_volume, 0.0001))
_ambience_db = linear_to_db(maxf(ambience_volume, 0.0001))
if _bed_player:
_bed_player.volume_db = _level_to_db(crowd_level) + _master_db + _ambience_db + _master_db + _ambience_db + _master_db + _ambience_db
func _ready() -> void: func _ready() -> void:
# Pre-create a few players so overlapping cues don't cut each other off. # Pre-create a few players so overlapping cues don't cut each other off.
@@ -112,7 +129,7 @@ func _play_tone(freq: float, duration: float, volume: float, delay: float = 0.0)
stream.mix_rate = SAMPLE_RATE stream.mix_rate = SAMPLE_RATE
stream.buffer_length = duration + 0.05 stream.buffer_length = duration + 0.05
player.stream = stream player.stream = stream
player.volume_db = linear_to_db(volume) player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
player.play() player.play()
# Fill the generator buffer with a sine wave. # Fill the generator buffer with a sine wave.
var playback: AudioStreamGeneratorPlayback = player.get_stream_playback() var playback: AudioStreamGeneratorPlayback = player.get_stream_playback()
@@ -174,7 +191,7 @@ func _play_noise(duration: float, volume: float, cutoff_hz: float = 3200.0) -> v
stream.stereo = false stream.stereo = false
stream.data = data stream.data = data
player.stream = stream player.stream = stream
player.volume_db = linear_to_db(volume) player.volume_db = linear_to_db(volume) + _master_db + _sfx_db
player.play() player.play()
func _free_player() -> AudioStreamPlayer: func _free_player() -> AudioStreamPlayer:
+4 -1
View File
@@ -377,7 +377,10 @@ func _apply_settings(settings: Dictionary) -> void:
if guard: if guard:
guard.look_sensitivity = float(settings.get("look_sensitivity", 0.0022)) guard.look_sensitivity = float(settings.get("look_sensitivity", 0.0022))
guard.invert_y = bool(settings.get("invert_y", false)) guard.invert_y = bool(settings.get("invert_y", false))
guard.head_bob_enabled = bool(settings.get("head_bob", true)) guard.head_bob_enabled = bool(settings.get("head_bob", true)) and not bool(settings.get("reduce_motion", false))
if audio:
audio.set_volumes(float(settings.get("master_volume", 1.0)),
float(settings.get("sfx_volume", 1.0)), float(settings.get("ambience_volume", 1.0)))
InputBindings.apply(settings.get("input_bindings", {})) InputBindings.apply(settings.get("input_bindings", {}))
if hud and hud.has_method("set_font_scale"): if hud and hud.has_method("set_font_scale"):
hud.set_font_scale(float(settings.get("hud_font_scale", 1.0))) hud.set_font_scale(float(settings.get("hud_font_scale", 1.0)))
+4 -1
View File
@@ -1050,7 +1050,10 @@ func _animate(delta: float) -> void:
_idle_t = 0.0 _idle_t = 0.0
_bob_phase += delta * (6.0 + speed * 1.7) _bob_phase += delta * (6.0 + speed * 1.7)
var urgency := 1.35 if reaction_mode == "flee" else 1.0 var urgency := 1.35 if reaction_mode == "flee" else 1.0
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency # Coats and skirts follow the hip/knee bones; a shorter stride keeps the
# hem from clipping through the legs during normal walking.
var hem_scale := 0.76 if character_model in ["npc_dress", "npc_coat"] else 1.0
var stride := clampf(0.36 + speed * 0.10, 0.42, 0.7) * urgency * hem_scale
_rig.position.y = sin(_bob_phase * 2.0) * 0.03 _rig.position.y = sin(_bob_phase * 2.0) * 0.03
_rig.position.x = 0.0 _rig.position.x = 0.0
_rig.rotation.x = sin(_bob_phase) * 0.03 _rig.rotation.x = sin(_bob_phase) * 0.03
+43
View File
@@ -22,6 +22,11 @@ var _font_scale_value: Label = null
var _invert_y: CheckButton = null var _invert_y: CheckButton = null
var _head_bob: CheckButton = null var _head_bob: CheckButton = null
var _difficulty: OptionButton = null var _difficulty: OptionButton = null
var _master: HSlider = null
var _sfx: HSlider = null
var _ambience: HSlider = null
var _reduce_motion: CheckButton = null
var _captions: CheckButton = null
var _bind_buttons := {} var _bind_buttons := {}
var _listening_action := "" var _listening_action := ""
var settings: Dictionary = {} var settings: Dictionary = {}
@@ -101,6 +106,27 @@ func _build() -> void:
_difficulty.item_selected.connect(_on_difficulty_selected) _difficulty.item_selected.connect(_on_difficulty_selected)
diff_row.add_child(_difficulty) diff_row.add_child(_difficulty)
var audio_row := HBoxContainer.new()
column.add_child(audio_row)
audio_row.add_child(_volume_label("Master volume"))
_master = _add_slider(audio_row, 0.0, 1.0, 0.05)
audio_row.add_child(_volume_label("SFX"))
_sfx = _add_slider(audio_row, 0.0, 1.0, 0.05)
audio_row.add_child(_volume_label("Ambience"))
_ambience = _add_slider(audio_row, 0.0, 1.0, 0.05)
_master.value_changed.connect(func(v): settings["master_volume"] = v)
_sfx.value_changed.connect(func(v): settings["sfx_volume"] = v)
_ambience.value_changed.connect(func(v): settings["ambience_volume"] = v)
_reduce_motion = CheckButton.new()
_reduce_motion.text = "Reduce motion"
_reduce_motion.toggled.connect(func(v): settings["reduce_motion"] = v)
column.add_child(_reduce_motion)
_captions = CheckButton.new()
_captions.text = "Captions / subtitles"
_captions.toggled.connect(func(v): settings["captions_enabled"] = v)
column.add_child(_captions)
var replay_row := HBoxContainer.new() var replay_row := HBoxContainer.new()
replay_row.alignment = BoxContainer.ALIGNMENT_CENTER replay_row.alignment = BoxContainer.ALIGNMENT_CENTER
column.add_child(replay_row) column.add_child(replay_row)
@@ -165,6 +191,13 @@ func _add_label_row(parent: Control, text: String) -> Label:
row.add_child(value) row.add_child(value)
return value return value
func _volume_label(text: String) -> Label:
var label := Label.new()
label.text = text
label.add_theme_font_size_override("font_size", 11)
label.custom_minimum_size = Vector2(82, 0)
return label
func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider: func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider:
var slider := HSlider.new() var slider := HSlider.new()
slider.min_value = min_v slider.min_value = min_v
@@ -189,6 +222,16 @@ func open(current: Dictionary) -> void:
if _difficulty: if _difficulty:
var difficulty := str(settings.get("ai_difficulty", "normal")) var difficulty := str(settings.get("ai_difficulty", "normal"))
_difficulty.select(["easy", "normal", "hard"].find(difficulty)) _difficulty.select(["easy", "normal", "hard"].find(difficulty))
if _master:
_master.set_value_no_signal(float(settings.get("master_volume", 1.0)))
if _sfx:
_sfx.set_value_no_signal(float(settings.get("sfx_volume", 1.0)))
if _ambience:
_ambience.set_value_no_signal(float(settings.get("ambience_volume", 1.0)))
if _reduce_motion:
_reduce_motion.set_pressed_no_signal(bool(settings.get("reduce_motion", false)))
if _captions:
_captions.set_pressed_no_signal(bool(settings.get("captions_enabled", true)))
_listening_action = "" _listening_action = ""
_refresh_bind_buttons() _refresh_bind_buttons()
_sync_labels() _sync_labels()
+1 -1
View File
@@ -9,7 +9,7 @@ extends SceneTree
const NpcAvatar := preload("res://src/game/npc_avatar.gd") const NpcAvatar := preload("res://src/game/npc_avatar.gd")
const NpcProfile := preload("res://src/core/npc_profile.gd") const NpcProfile := preload("res://src/core/npc_profile.gd")
const Rules := preload("res://src/core/rules.gd") const Rules := preload("res://src/core/rules.gd")
const COUNT := 16 const COUNT := 24
const WARMUP_FRAMES := 60 const WARMUP_FRAMES := 60
const SAMPLE_FRAMES := 180 const SAMPLE_FRAMES := 180
const BUDGET_MS := 50.0 const BUDGET_MS := 50.0
+12
View File
@@ -66,6 +66,18 @@ func test_radio_crackle_methods() -> bool:
audio.free() audio.free()
return a and b return a and b
func test_volume_settings_are_stored_and_applied() -> bool:
var audio: Node = AudioFeedback.new()
audio.set_volumes(0.8, 0.5, 0.2)
var a := TestUtils.check(is_equal_approx(audio.master_volume, 0.8), "master volume stores")
var b := TestUtils.check(is_equal_approx(audio.sfx_volume, 0.5), "sfx volume stores")
var c := TestUtils.check(is_equal_approx(audio.ambience_volume, 0.2), "ambience volume stores")
audio.set_volumes(3.0, -1.0, 0.5)
var d := TestUtils.check(is_equal_approx(audio.master_volume, 1.0)
and is_equal_approx(audio.sfx_volume, 0.0), "volumes clamp")
audio.free()
return a and b and c and d
func test_game_manager_wires_audio() -> bool: func test_game_manager_wires_audio() -> bool:
var src := FileAccess.get_file_as_string("res://src/game/game_manager.gd") var src := FileAccess.get_file_as_string("res://src/game/game_manager.gd")
var a := TestUtils.check(src.contains("audio.start_crowd_bed()"), "the bed starts with the shift") var a := TestUtils.check(src.contains("audio.start_crowd_bed()"), "the bed starts with the shift")
+3 -1
View File
@@ -81,7 +81,9 @@ func test_settings_defaults_present() -> bool:
var ok := TestUtils.check( var ok := TestUtils.check(
defaults.has("look_sensitivity") and defaults.has("hud_font_scale") defaults.has("look_sensitivity") and defaults.has("hud_font_scale")
and defaults.has("invert_y") and defaults.has("head_bob") and defaults.has("invert_y") and defaults.has("head_bob")
and defaults.has("input_bindings"), and defaults.has("input_bindings")
and defaults.has("master_volume") and defaults.has("sfx_volume")
and defaults.has("ambience_volume") and defaults.has("captions_enabled"),
"settings have documented defaults") "settings have documented defaults")
save.free() save.free()
return ok return ok
+1 -1
View File
@@ -2,7 +2,7 @@
# Build distributable desktop executables with the Godot export pipeline. # Build distributable desktop executables with the Godot export pipeline.
# #
# Requirements: # Requirements:
# - Godot 4.3 (or the version in project.godot `config/features`) on PATH, # - Godot 4.7.2 (or the version in project.godot `config/features`) on PATH,
# with export templates installed (see docs/RELEASING.md). # with export templates installed (see docs/RELEASING.md).
# - Run from the repository root. # - Run from the repository root.
# #