Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51f537720f | ||
|
|
08e9044593 | ||
|
|
ad14410337 | ||
|
|
876fb59882 | ||
|
|
979c6ad789 | ||
|
|
1921bfae91 | ||
|
|
78485259b7 | ||
|
|
fef3af44c0 | ||
|
|
bfe3c5a701 | ||
|
|
46f1e41874 | ||
|
|
f48d87c84f | ||
|
|
a9658ecd81 | ||
|
|
b8507df346 | ||
|
|
60bf9a8ef6 | ||
|
|
b51bdc8efe | ||
|
|
a7b2852253 | ||
|
|
4bb2896819 | ||
|
|
f5b8ef2e70 | ||
|
|
0044f5f065 | ||
|
|
4bc6390e9f | ||
|
|
fb3da52438 | ||
|
|
d7220c1a0a | ||
|
|
31574b8d82 | ||
|
|
b60f67548d | ||
|
|
a57b86cd48 | ||
|
|
dfe5056303 | ||
|
|
58cf12fd1d | ||
|
|
7150bd7673 | ||
|
|
12e70357c5 | ||
|
|
7dc3d3c873 | ||
|
|
cd5e0e0ff7 | ||
|
|
8ce62e7556 | ||
|
|
24c939d388 | ||
|
|
48082c3dfa | ||
|
|
03c355e7c1 | ||
|
|
15ab8c686d | ||
|
|
ab9c67d266 | ||
|
|
7c1a4bfd69 | ||
|
|
e7ee177c31 | ||
|
|
c1cd4898e8 | ||
|
|
e805a91ad3 | ||
|
|
7315166361 | ||
|
|
f6aa26e6ca | ||
|
|
26e6dd6413 | ||
|
|
8f65751975 | ||
|
|
9692f262f1 | ||
|
|
98c31fe44c | ||
|
|
daf0926d91 | ||
|
|
f71a36faa1 | ||
|
|
37f925c7ad | ||
|
|
74dc1fdc1d | ||
|
|
3f335481d6 | ||
|
|
af923b1483 | ||
|
|
3a74cedee0 | ||
|
|
844e39246a | ||
|
|
7c48183410 | ||
|
|
64590fe797 | ||
|
|
49bfccc808 | ||
|
|
7401d4bca0 | ||
|
|
e79a37beba | ||
|
|
fbd2ab2cb3 | ||
|
|
9b8f513f9f | ||
|
|
ad12fdad7e | ||
|
|
87612f2057 | ||
|
|
ffd98daf08 | ||
|
|
f811e6054d | ||
|
|
9d37e0a1c5 | ||
|
|
883626a067 | ||
|
|
b5d4d5fb87 | ||
|
|
fac9b002c3 | ||
|
|
aa51ee331e | ||
|
|
86332cd401 | ||
|
|
76eb5e3a79 | ||
|
|
f4a53e2d4f | ||
|
|
806fe78688 | ||
|
|
6a3066d763 | ||
|
|
f4cce28454 | ||
|
|
7d39523e49 | ||
|
|
7e084192ce | ||
|
|
6c367e8c7e | ||
|
|
659b0e35b2 | ||
|
|
28f2a48811 | ||
|
|
64f0c6a198 | ||
|
|
8b0845bcce | ||
|
|
4cca2af2dd | ||
|
|
99f390078d | ||
|
|
a9fe6b9944 | ||
|
|
d4201caa62 | ||
|
|
6100d19a25 | ||
|
|
a7ca698f73 | ||
|
|
26d64baa01 | ||
|
|
151630e957 | ||
|
|
1b319c48b7 | ||
|
|
a478bfbf35 | ||
|
|
702f54ae53 | ||
|
|
bbf4693475 | ||
|
|
d7b0203502 | ||
|
|
da876e3545 | ||
|
|
1ee32215b0 | ||
|
|
2624b54b23 | ||
|
|
85d67ff8b1 | ||
|
|
47c57ddc76 | ||
|
|
3c07525351 | ||
|
|
4a672025a2 | ||
|
|
6acbc2b3a4 | ||
|
|
d7e523f63c | ||
|
|
26ecb93fd4 | ||
|
|
8997f59819 | ||
|
|
79270795a8 | ||
|
|
dc4bc6c511 | ||
|
|
c8b98fdb30 | ||
|
|
d96f53c285 | ||
|
|
b39fee6176 | ||
|
|
c2c93c28a5 | ||
|
|
3030c60ae1 | ||
|
|
cb65a5a601 | ||
|
|
06a4f5479f | ||
|
|
8032999a4d | ||
|
|
8582e496ff | ||
|
|
ae326ce970 | ||
|
|
00faf45e83 | ||
|
|
41d3511fc7 | ||
|
|
1efa5bc7d9 | ||
|
|
4745adeb13 | ||
|
|
15deb58b73 | ||
|
|
6a0bf70fdf | ||
|
|
f458551594 | ||
|
|
8f228b0c56 | ||
|
|
d307746351 | ||
|
|
d872034388 | ||
|
|
d8cfddbf89 | ||
|
|
d513e0b82c | ||
|
|
7efb5024ec | ||
|
|
a231f7588a | ||
|
|
3989d7b2e5 | ||
|
|
0eb17e3bb4 | ||
|
|
a7daae8a14 | ||
|
|
3f4a8e5f9f | ||
|
|
91b10e0f94 | ||
|
|
4943dbff16 | ||
|
|
b24d0aeb61 |
No files matched your search
@@ -17,12 +17,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Godot 4.3
|
- name: Install Godot 4.7.2
|
||||||
run: |
|
run: |
|
||||||
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 +57,24 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Godot 4.3 and export templates
|
- name: Install Godot 4.7.2 and export templates
|
||||||
run: |
|
run: |
|
||||||
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
|
||||||
|
TEMPLATE_DIR="$HOME/.local/share/godot/export_templates/4.7.2.stable"
|
||||||
|
NEEDED="version.txt icudt_godot.dat linux_release.x86_64 windows_release_x86_64.exe macos.zip web_nothreads_release.zip web_dlink_nothreads_release.zip"
|
||||||
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 "$TEMPLATE_DIR"
|
||||||
ls "$HOME/.local/share/godot/export_templates/4.3.stable" | head -5
|
for file in $NEEDED; do
|
||||||
|
cp "/tmp/tpl/templates/$file" "$TEMPLATE_DIR/$file"
|
||||||
|
done
|
||||||
|
ls "$TEMPLATE_DIR" | head -10
|
||||||
|
|
||||||
- name: Import project
|
- name: Import project
|
||||||
run: godot --headless --import
|
run: godot --headless --import
|
||||||
@@ -84,19 +91,19 @@ jobs:
|
|||||||
# NOTE: on Linux, makensis uses -D defines (the /D form is Windows-only
|
# NOTE: on Linux, makensis uses -D defines (the /D form is Windows-only
|
||||||
# and is rejected as a script path), and it resolves relative paths
|
# and is rejected as a script path), and it resolves relative paths
|
||||||
# against the script directory — pass absolute paths from the workspace.
|
# against the script directory — pass absolute paths from the workspace.
|
||||||
cp assets/textures/icon.ico packaging/windows/step-line.ico
|
cp assets/textures/icon.ico packaging/windows/gig-line.ico
|
||||||
makensis \
|
makensis \
|
||||||
-DVERSION="$VERSION" \
|
-DVERSION="$VERSION" \
|
||||||
-DARTIFACT="$PWD/build/step-line-windows-$VERSION.exe" \
|
-DARTIFACT="$PWD/build/gig-line-windows-$VERSION.exe" \
|
||||||
-DICON="$PWD/packaging/windows/step-line.ico" \
|
-DICON="$PWD/packaging/windows/gig-line.ico" \
|
||||||
-DOUT="$PWD/build/step-line-setup-$VERSION.exe" \
|
-DOUT="$PWD/build/gig-line-setup-$VERSION.exe" \
|
||||||
packaging/windows/step-line.nsi
|
packaging/windows/gig-line.nsi
|
||||||
|
|
||||||
- name: Verify Windows installer contents
|
- name: Verify Windows installer contents
|
||||||
run: |
|
run: |
|
||||||
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
||||||
ls -la build/step-line-setup-$VERSION.exe
|
ls -la build/gig-line-setup-$VERSION.exe
|
||||||
7z l build/step-line-setup-$VERSION.exe | grep -E "step-line.exe|uninstall.exe"
|
7z l build/gig-line-setup-$VERSION.exe | grep -E "gig-line.exe|uninstall.exe"
|
||||||
|
|
||||||
- name: Package Linux AppImage
|
- name: Package Linux AppImage
|
||||||
run: |
|
run: |
|
||||||
@@ -106,7 +113,7 @@ jobs:
|
|||||||
if: github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: step-line-build
|
name: gig-line-build
|
||||||
path: build/*
|
path: build/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
@@ -114,7 +121,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 }}
|
||||||
|
|||||||
@@ -37,10 +37,40 @@ Thumbs.db
|
|||||||
*.new
|
*.new
|
||||||
|
|
||||||
# Logs and temp
|
# Logs and temp
|
||||||
|
tmp/
|
||||||
*.log
|
*.log
|
||||||
user://
|
user://
|
||||||
# CI runner workflow logs (written into the checkout by the Gitea runner)
|
# CI runner workflow logs (written into the checkout by the Gitea runner)
|
||||||
.gitea/logs/
|
.gitea/logs/
|
||||||
build/
|
build/
|
||||||
|
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# AI / asset-development outputs (regenerated by the tools; not shipped in the game)
|
||||||
|
assets/models/concepts/
|
||||||
|
assets/models/npc/*.blend1
|
||||||
|
assets/textures/npc/ai/
|
||||||
|
assets/textures/ai/*
|
||||||
|
!assets/textures/ai/game_ready/
|
||||||
|
# Godot extracts embedded glTF textures next to the source on import
|
||||||
|
assets/models/generated/npc_base_*_albedo.png
|
||||||
|
assets/models/generated/npc_base_*_normal.png
|
||||||
|
|
||||||
|
# Local AppImage extraction
|
||||||
|
squashfs-root/
|
||||||
|
# Blender asset library: per-asset Cycles renders are local review output (the
|
||||||
|
# committed review artefacts are docs/blender_previews/sheet_*.jpg), and Godot
|
||||||
|
# extracts the GLB-embedded textures next to the models on import.
|
||||||
|
docs/blender_previews/*.png
|
||||||
|
assets/models/blender/**/*.png
|
||||||
|
!assets/models/blender/**/*_ao.png
|
||||||
|
assets/models/blender_src/*.blend1
|
||||||
|
# Editable Blender sources are developer-only; keep the .gdignore marker tracked.
|
||||||
|
assets/models/blender_src/*.blend
|
||||||
|
# Realism pass (tools/scene_concepts.py): candidate pools, per-run captures and
|
||||||
|
# generated reports stay local; validated picks are tracked under
|
||||||
|
# game_ready/v2/picks/ (ADR-0014). Concept references are committed in
|
||||||
|
# docs/screens/concepts/, but generated QA lives outside the repository.
|
||||||
|
assets/textures/ai/game_ready/v2/*
|
||||||
|
!assets/textures/ai/game_ready/v2/picks/
|
||||||
|
docs/screens/realism/
|
||||||
@@ -14,6 +14,27 @@ The project should be developed in small, reviewable steps. Agents must keep pla
|
|||||||
- `MEMORY.md` — Persistent session memory for important decisions, discoveries, unresolved questions, constraints, and useful implementation context.
|
- `MEMORY.md` — Persistent session memory for important decisions, discoveries, unresolved questions, constraints, and useful implementation context.
|
||||||
- `README.md` — Root-level documentation for the project. It should explain what the game is, how to work on it, how to run it, and where to find project information.
|
- `README.md` — Root-level documentation for the project. It should explain what the game is, how to work on it, how to run it, and where to find project information.
|
||||||
- `AGENTS.md` — This collaboration and agent workflow guide.
|
- `AGENTS.md` — This collaboration and agent workflow guide.
|
||||||
|
- `CHANGELOG.md` — The version history of user-facing changes. Keep an entry for each patch, minor, and major version.
|
||||||
|
- `docs/development-status.md` — The implemented-features list and what is not yet implemented. Update it whenever a feature lands, is renamed, or is removed.
|
||||||
|
- `docs/architecture.md` — The arc42-style architecture documentation (goals, constraints, building blocks, runtime views, decisions, risks).
|
||||||
|
- `docs/gameplay.md` — Gameplay systems, venues, and the escalation model.
|
||||||
|
- `docs/asset-tooling.md` — Asset pipelines, model tools, and screenshot gates.
|
||||||
|
- `docs/npc-model-sourcing.md` — Character-source evaluation, licence rules and the character-development plan.
|
||||||
|
- `docs/getting-started.md` — Setup, run/test commands, and the controls table.
|
||||||
|
- `docs/smoke-checklist.md` — The manual smoke-test checklist.
|
||||||
|
- `docs/adr/` — Architecture Decision Records.
|
||||||
|
|
||||||
|
## Priority and Versioning
|
||||||
|
|
||||||
|
`TODO.md` is the priority source. The active order is:
|
||||||
|
|
||||||
|
1. unversioned development tracks (currently character development and local map development);
|
||||||
|
2. versioned release milestones, in version order;
|
||||||
|
3. future/unversioned candidates and deferred work.
|
||||||
|
|
||||||
|
Do not assign a version number to an unversioned track until its scope is accepted into a
|
||||||
|
release. When a version is assigned, it must be the next semantic version that matches the
|
||||||
|
scope (major/minor/patch), not a placeholder.
|
||||||
|
|
||||||
## Required Workflow
|
## Required Workflow
|
||||||
|
|
||||||
@@ -36,9 +57,22 @@ Do not assume that a task is unimplemented without checking the code and documen
|
|||||||
All planned implementation work must be represented in `TODO.md`.
|
All planned implementation work must be represented in `TODO.md`.
|
||||||
|
|
||||||
- Use headings to group related work into sections.
|
- Use headings to group related work into sections.
|
||||||
- Use checkbox items for each concrete task.
|
- Use level-2 headings (`##`) for milestones or stable themes. A milestone should state its goal
|
||||||
|
and an explicit exit criterion; a theme groups small related work that does not need a
|
||||||
|
milestone.
|
||||||
|
- Order level-2 sections by current priority: unversioned development tracks first, then
|
||||||
|
versioned release milestones in version order, then future/deferred work. Do not assign a
|
||||||
|
version number to an unversioned track until it is scheduled for a release.
|
||||||
|
- Use level-3 headings (`###`) for workstreams inside a milestone (for example, `0.8.1
|
||||||
|
First-shift tutorial`). Keep the hierarchy to three levels: milestone → workstream → checkbox.
|
||||||
|
- Use checkbox items for each concrete task, normally under a level-3 workstream. Direct
|
||||||
|
checkboxes under a level-2 section are acceptable for small, single-workstream sections.
|
||||||
- Keep tasks small enough to complete and review independently.
|
- Keep tasks small enough to complete and review independently.
|
||||||
- Add new tasks when discoveries expand the scope.
|
- Add new tasks when discoveries expand the scope.
|
||||||
|
- When starting a task, claim it for the agent workflow by changing `[ ]` to `[-]`. Keep it `[-]`
|
||||||
|
while implementation or verification is in progress; only change it to `[x]` after the work and
|
||||||
|
relevant checks are finished. If work is abandoned or blocked, leave a clear note and return the
|
||||||
|
item to `[ ]` (or add a follow-up task).
|
||||||
- Mark a task complete only after the implementation and relevant verification are finished.
|
- Mark a task complete only after the implementation and relevant verification are finished.
|
||||||
- If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary.
|
- If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary.
|
||||||
- Do not use prose status updates as a substitute for checkboxes.
|
- Do not use prose status updates as a substitute for checkboxes.
|
||||||
@@ -49,27 +83,52 @@ Recommended format:
|
|||||||
```md
|
```md
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## Core Gameplay
|
## Milestone 0.8.0 — First hour and content depth
|
||||||
|
|
||||||
- [ ] Add player movement controls.
|
### 0.8.1 First-shift tutorial
|
||||||
- [ ] Implement NPC approach behavior.
|
|
||||||
- [x] Define escalation levels.
|
- [x] Write the tutorial beat sheet.
|
||||||
|
- [-] Implement the tutorial state machine. (claimed; implementation/verification in progress)
|
||||||
|
- [ ] Add the tutorial smoke test.
|
||||||
|
|
||||||
|
### 0.8.2 Campaign shell
|
||||||
|
|
||||||
|
- [ ] Define campaign data.
|
||||||
|
- [ ] Persist campaign progress.
|
||||||
|
|
||||||
|
**Exit:** a first-time player completes a shift without external documentation.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [ ] Document the test procedure in `README.md`.
|
- [ ] Document the test procedure in `README.md`.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Order the actual file as described in "Priority and Versioning": unversioned development tracks
|
||||||
|
first (for example character and local-map development), then versioned milestones in version
|
||||||
|
order, then future/deferred work.
|
||||||
|
|
||||||
### 3. Move Completed Sections to `DONE.md`
|
### 3. Move Completed Sections to `DONE.md`
|
||||||
|
|
||||||
When every task in a `TODO.md` section is complete:
|
`TODO.md` uses nested sections. Apply these completion rules:
|
||||||
|
|
||||||
1. Verify the work and update the checkbox items to `[x]`.
|
1. **Level-3 workstream:** verify the work, mark every checkbox `[x]`, and add a short completion
|
||||||
2. Move the entire completed section, including its heading and checklist, to `DONE.md`.
|
note. Leave the completed workstream under its parent milestone; do not move an isolated
|
||||||
3. Remove that section from `TODO.md`.
|
level-3 section to `DONE.md`.
|
||||||
4. Add a short completion note or date when useful.
|
2. **Level-2 milestone/theme:** it is complete only when its direct checkboxes and **all** of its
|
||||||
|
level-3 workstreams are complete. Verify the whole milestone, record its capabilities in
|
||||||
|
`docs/development-status.md` when it represents shipped functionality, and write the matching
|
||||||
|
`CHANGELOG.md` entry.
|
||||||
|
3. Move the **entire level-2 section**, including all level-3 headings and checklists, to
|
||||||
|
`DONE.md`. Remove it from `TODO.md` and add a completion date/note.
|
||||||
|
4. **Planning/overview sections** such as a gap analysis, roadmap overview, dependencies or
|
||||||
|
deferred ideas are not completion milestones. Do not move them merely because their checkboxes
|
||||||
|
are empty or complete; update or supersede them as the roadmap changes.
|
||||||
|
5. Do not move partially completed milestones. Leave them in `TODO.md` until every nested task is
|
||||||
|
complete, or split the unfinished work into a new smaller level-2 milestone first.
|
||||||
|
|
||||||
Do not move partially completed sections. Leave them in `TODO.md` until all of their tasks are complete, or split the section into smaller sections first.
|
When a completed milestone represents shipped functionality, also record the new capability in
|
||||||
|
`docs/development-status.md` so the implemented-features list stays accurate, and write a matching
|
||||||
|
entry in `CHANGELOG.md` (see "Maintain `CHANGELOG.md`" below).
|
||||||
|
|
||||||
### 4. Maintain `MEMORY.md`
|
### 4. Maintain `MEMORY.md`
|
||||||
|
|
||||||
@@ -78,7 +137,7 @@ Use `MEMORY.md` for information that should persist between sessions but does no
|
|||||||
Record items such as:
|
Record items such as:
|
||||||
|
|
||||||
- Important design and architecture decisions
|
- Important design and architecture decisions
|
||||||
- Current implementation state
|
- Notable implementation state and gotchas (the canonical implemented-features list lives in `docs/development-status.md`, not here)
|
||||||
- Known bugs and workarounds
|
- Known bugs and workarounds
|
||||||
- Commands needed to run, test, or build the project
|
- Commands needed to run, test, or build the project
|
||||||
- Decisions that future agents should not revisit unnecessarily
|
- Decisions that future agents should not revisit unnecessarily
|
||||||
@@ -128,9 +187,29 @@ The root-level `README.md` is the project’s public-facing technical and projec
|
|||||||
- Links to `PLAN.md`, `TODO.md`, `DONE.md`, `MEMORY.md`, and this file where appropriate
|
- Links to `PLAN.md`, `TODO.md`, `DONE.md`, `MEMORY.md`, and this file where appropriate
|
||||||
- Known limitations and contribution guidance
|
- Known limitations and contribution guidance
|
||||||
|
|
||||||
Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes.
|
Update `README.md` whenever setup instructions, commands, project structure, or user-facing behavior changes. The README is intentionally concise and links to the `docs/` files; keep `docs/development-status.md` (and the other docs it links to) synchronized with the implementation rather than pasting detail back into the README.
|
||||||
|
|
||||||
### 7. Implement in Small Increments
|
### 7. Maintain `CHANGELOG.md`
|
||||||
|
|
||||||
|
The root-level `CHANGELOG.md` records the user-facing changes for every release. It exists so players and contributors can see what changed between versions without reading the commit log.
|
||||||
|
|
||||||
|
- Add an entry for every patch, minor, and major version change.
|
||||||
|
- Follow Semantic Versioning (`major.minor.patch`): bump major for breaking or vision-level changes, minor for new features, and patch for fixes and small polish.
|
||||||
|
- A version increment is not complete until its `CHANGELOG.md` entry, `config/version` update and
|
||||||
|
matching local release build have all been produced and verified.
|
||||||
|
- Group each entry under `Added`, `Changed`, `Fixed`, and `Removed` headings, and date every entry.
|
||||||
|
- Describe changes in user-facing terms, not as raw commit messages.
|
||||||
|
- Add the entry when its work ships. If the version number is not yet known, record it under `Unreleased` and move it into a numbered version when the version is tagged.
|
||||||
|
|
||||||
|
When a full executable level-2 milestone/theme in `TODO.md` is implemented, completed, and moved to `DONE.md`:
|
||||||
|
|
||||||
|
1. Verify the work and mark every checkbox in the section `[x]`.
|
||||||
|
2. Use the section heading and its completed items to describe the changes and write a `CHANGELOG.md` entry under the next appropriate version.
|
||||||
|
3. Move the section to `DONE.md`.
|
||||||
|
|
||||||
|
Do not move a completed section to `DONE.md` without adding its `CHANGELOG.md` entry.
|
||||||
|
|
||||||
|
### 8. Implement in Small Increments
|
||||||
|
|
||||||
For each task:
|
For each task:
|
||||||
|
|
||||||
@@ -138,12 +217,36 @@ For each task:
|
|||||||
2. Inspect the relevant files and dependencies.
|
2. Inspect the relevant files and dependencies.
|
||||||
3. Make the smallest coherent change that completes the task.
|
3. Make the smallest coherent change that completes the task.
|
||||||
4. Run the relevant tests, checks, or manual verification.
|
4. Run the relevant tests, checks, or manual verification.
|
||||||
5. Update documentation and `MEMORY.md` if the change creates lasting context.
|
5. Update documentation if the change creates lasting context: add features to `docs/development-status.md`, adjust the README links or other `docs/` files as needed, and record decisions/gotchas in `MEMORY.md`.
|
||||||
6. Mark the task complete.
|
6. Mark the task complete.
|
||||||
7. Move its section to `DONE.md` when the entire section is complete.
|
7. Keep completed level-3 workstreams in place until the parent milestone is complete; then move the entire level-2 milestone to `DONE.md` after recording its `CHANGELOG.md` entry.
|
||||||
|
8. Commit each coherent, verified change as it is completed. Do not wait until a whole
|
||||||
|
milestone is finished; keep commits small and descriptive and push them when the branch is
|
||||||
|
shareable.
|
||||||
|
9. On every major, minor or patch version increment: update `config/version`, add the
|
||||||
|
`CHANGELOG.md` entry, run the local release build (`tools/build_releases.sh`), verify the
|
||||||
|
artifacts and checksums, then commit, tag and push the version.
|
||||||
|
10. If a level-2 milestone from `TODO.md` has been fully completed, ensure its `CHANGELOG.md`
|
||||||
|
entry and matching build are in place, then create the next semantic version or tag.
|
||||||
|
11. Push committed changes to the shared repository if applicable.
|
||||||
|
12. Note the new version, build artifacts or tag in the relevant documentation and handoff
|
||||||
|
summary.
|
||||||
|
|
||||||
Avoid unrelated refactors unless they are required for the task or explicitly approved.
|
Avoid unrelated refactors unless they are required for the task or explicitly approved.
|
||||||
|
|
||||||
|
### 9. Commit, Build and Version Discipline
|
||||||
|
|
||||||
|
- **Commit often.** Make a commit after each coherent change or verified task, not only when a
|
||||||
|
milestone or release is finished. Keep the working tree clean between tasks where possible.
|
||||||
|
- **Push regularly.** Push shareable commits to the shared repository; do not accumulate a long
|
||||||
|
local-only history.
|
||||||
|
- **Build every version.** Major, minor and patch increments each require a local release build
|
||||||
|
and artifact/checksum verification before tagging. A changelog entry alone is not a release.
|
||||||
|
- **CI is a second gate, not a substitute.** Tag builds remain automated, but the local build is
|
||||||
|
the required pre-tag check for every version.
|
||||||
|
- **Unversioned tracks stay unversioned.** Character, map and other development tracks do not get
|
||||||
|
a placeholder version; the version is assigned when the work is scoped into a release.
|
||||||
|
|
||||||
## Collaboration Rules
|
## Collaboration Rules
|
||||||
|
|
||||||
- Prefer clear, reversible changes over broad rewrites.
|
- Prefer clear, reversible changes over broad rewrites.
|
||||||
@@ -152,6 +255,8 @@ Avoid unrelated refactors unless they are required for the task or explicitly ap
|
|||||||
- Do not claim a task is complete without verification.
|
- Do not claim a task is complete without verification.
|
||||||
- Keep documentation synchronized with the implementation.
|
- Keep documentation synchronized with the implementation.
|
||||||
- Mention files changed and checks run in handoff summaries.
|
- Mention files changed and checks run in handoff summaries.
|
||||||
|
- Commit coherent increments as you go; do not wait until the end of a milestone.
|
||||||
|
- Run a release build whenever a major, minor or patch version is incremented.
|
||||||
- Leave follow-up work as checkbox items in `TODO.md` rather than hiding it in prose.
|
- Leave follow-up work as checkbox items in `TODO.md` rather than hiding it in prose.
|
||||||
- If blocked, document the blocker in `MEMORY.md` and add a corresponding task to `TODO.md`.
|
- If blocked, document the blocker in `MEMORY.md` and add a corresponding task to `TODO.md`.
|
||||||
- Avoid overwriting another contributor’s work; inspect recent changes before editing shared files.
|
- Avoid overwriting another contributor’s work; inspect recent changes before editing shared files.
|
||||||
|
|||||||
@@ -0,0 +1,550 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable user-facing changes to Gig Line. The format follows
|
||||||
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
|
||||||
|
Semantic Versioning.
|
||||||
|
|
||||||
|
## [0.10.0-rc.1] — 2026-11-03
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Prepared the release-candidate packages for Linux, Windows, macOS, Web and the
|
||||||
|
optional Desktop HQ zip. The Web/HQ archives now include the credits, privacy,
|
||||||
|
accessibility and known-limitations pages, and release publishing writes
|
||||||
|
SHA-256 checksums and rolls back partial uploads.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Corrupt or partial save files now fall back to safe defaults without logging a
|
||||||
|
parse error, and a failed atomic replace leaves the previous valid settings
|
||||||
|
intact. Added migration coverage for 0.8-era profiles and 0.9.0 checkpoints
|
||||||
|
across all three venues.
|
||||||
|
|
||||||
|
## [0.9.6] — 2026-11-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The UI, model and texture passes are now integrated into a verified checkpoint
|
||||||
|
build. The gallery, NPC portraits, realism captures, asset audits, smoke
|
||||||
|
matrix, 24-NPC budget and Web/Desktop HQ packages were regenerated and
|
||||||
|
re-checked; no gameplay or content changes were introduced.
|
||||||
|
|
||||||
|
## [0.9.5] — 2026-11-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- NPC albedo, normal and ORM maps are now 256² instead of 128², giving the
|
||||||
|
face, fabric and gear materials more detail at portrait distance.
|
||||||
|
- NPC fabric maps now repeat four times across the body and skip the baked
|
||||||
|
per-character AO, removing the large blotchy patches from shirts, jackets and
|
||||||
|
trousers at portrait distance.
|
||||||
|
- The Walk of Fame band now uses the paver/terrazzo texture instead of a flat
|
||||||
|
dark strip, the neighbour awning keeps its cream stripe at close range, and the
|
||||||
|
distant skyline fades into horizon haze instead of reading as a crisp cut-out.
|
||||||
|
|
||||||
|
## [0.9.4] — 2026-11-02
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Character meshes now have an 8,000-triangle / 8,000-vertex library budget
|
||||||
|
(up from 6,000 / 5,000) to support the remaining face, grip and clothing
|
||||||
|
detail; the `npc_base` fallback keeps its original 6,000 / 4,000 contract.
|
||||||
|
- Character necks are fuller and shoulders slope from the neck instead of
|
||||||
|
reading as a thin post on a hanger.
|
||||||
|
- Character eyes sit in the socket behind a thin upper lid, and the chin and
|
||||||
|
cheekbones are sculpted into the head instead of reading as separate spheres.
|
||||||
|
- Character torsos taper from the chest to the waist and flare slightly into
|
||||||
|
the hips, so shirts and jackets sit less like straight tubes.
|
||||||
|
- Character hands now have a wider palm, bent fingers with rounded tips and a
|
||||||
|
separate thumb instead of flat bars.
|
||||||
|
- Character noses gained ala wings and a smaller bridge/tip, the mouth is a
|
||||||
|
rounded slot, and the ears have a darker inner concha.
|
||||||
|
- Hand-held items now sit forward in the open palm instead of being partly
|
||||||
|
buried inside the hand.
|
||||||
|
- Shoes and responder boots now have rounded toes and heels instead of reading
|
||||||
|
as flat blocks.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Tourists no longer appear to carry two backpacks: the photo-pose camera bag is
|
||||||
|
hidden except while they are actually taking a picture.
|
||||||
|
- Backpack shoulder straps are now flattened bands that sit outside the chest
|
||||||
|
instead of thin rods partly buried in the torso.
|
||||||
|
|
||||||
|
## [0.9.3] — 2026-11-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Eight committed gallery captures now cover the start menu, pause, settings,
|
||||||
|
shift review, emergency radio, action wheel, crowd panic and responder
|
||||||
|
arrival, so every screen-design reference has a deterministic current-build
|
||||||
|
capture.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- All session, settings, radio, Help, review and timeline action buttons now
|
||||||
|
share explicit normal, hover, pressed, focus and disabled styles. Timeline
|
||||||
|
Previous/Next disable at their boundaries.
|
||||||
|
- Keyboard and gamepad focus rings now wrap through every modal, with explicit
|
||||||
|
default focus and A/B accept/cancel bindings; hidden Continue and disabled
|
||||||
|
timeline controls are skipped.
|
||||||
|
- Esc and right-click now close the top panel consistently, restore the venue
|
||||||
|
menu after menu Settings, and recapture the mouse without leaving the guard
|
||||||
|
frozen. Help no longer opens Pause behind itself.
|
||||||
|
- The HUD target chip grows and caps with the selected font scale, top labels
|
||||||
|
clip safely, and long action-button labels ellipsize instead of pushing panels
|
||||||
|
wider than the screen.
|
||||||
|
- Campaign reset and tutorial replay now share a guarded confirmation dialog;
|
||||||
|
repeated presses cannot stack dialogs or fire the action twice. Emergency
|
||||||
|
hold-to-send still submits once and ignores the release after submission.
|
||||||
|
- NPC reason answers now use role-specific dialogue contexts, so staff, guests,
|
||||||
|
delivery workers, performers and other archetypes answer instead of silently
|
||||||
|
deflecting the Reason verb.
|
||||||
|
- Hollywood and the TV Studio now have door-staff lines for their wristband,
|
||||||
|
ticket, credential and guest-list checks.
|
||||||
|
- Clarified the emergency radio cancellation message, the Ask verb in Help/HUD
|
||||||
|
hints, the start-menu key hint and the campaign-reset confirmation.
|
||||||
|
|
||||||
|
## [0.9.2] — 2026-11-02
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A stylized reconstruction of the real El Capitan Entertainment Centre block at
|
||||||
|
6840 Hollywood Boulevard: six Ionic columns, eight stone steps, the Masonic
|
||||||
|
parapet motto and medallions, red event banners, central and side entrances,
|
||||||
|
the El Capitan Theatre and retail neighbours, the Ovation Hollywood arcade,
|
||||||
|
the Walk of Fame and four-lane street markings.
|
||||||
|
- Real-site reference notes and AI art-direction frames for the Hollywood block.
|
||||||
|
- The Joke Shop is now a Sunset Strip comedy-club block based on The Comedy Store at
|
||||||
|
8433 Sunset Blvd: a 27 m black hall under a signature-covered canopy, a circular
|
||||||
|
**THE JOKE SHOP** blade sign, red velvet curtain bays, a west-end entrance, cream
|
||||||
|
and white neighbours, a dry hillside of stucco houses and palms, and a low retail
|
||||||
|
and billboard frontage across Sunset.
|
||||||
|
- Real-site reference notes and AI art-direction frames for the Joke Shop block,
|
||||||
|
including day, night and across-the-street concepts.
|
||||||
|
- A separate day capture stage for the Joke Shop, so the club can be compared in
|
||||||
|
both lighting states.
|
||||||
|
- Completed the UI string migration: start menu, settings, pause, Help, HUD,
|
||||||
|
radio and shift-review labels now come from the English string table.
|
||||||
|
- Separate **Hollywood Boulevard — Day** and **Hollywood Boulevard — Night**
|
||||||
|
rows in the venue menu. Night starts directly in the late phase and keeps the
|
||||||
|
full shift after dark.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The default Hollywood venue is no longer a generic brick entrance; the venue
|
||||||
|
name and policy copy now identify the El Capitan Entertainment Centre.
|
||||||
|
- Night lighting on the landmark uses low-energy practical washes rather than
|
||||||
|
the street-lamp brightness, so the facade reads without blowing out.
|
||||||
|
- The Joke Shop lighting now uses warm sconces, canopy downlights and ground
|
||||||
|
uplights; the hillside stays a dark silhouette at night instead of a lit wall.
|
||||||
|
- The Joke Shop venue copy and gallery captions describe the Sunset Strip block,
|
||||||
|
not the old brick alley.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The Ovation Hollywood sign faces the boulevard instead of rendering mirrored.
|
||||||
|
- Local night lights use linear attenuation instead of constant falloff, so
|
||||||
|
sconces and street lamps pool on the ground and stone rather than washing the
|
||||||
|
whole facade flat and yellow.
|
||||||
|
- The captured HUD clears stale objectives and target prompts between staged
|
||||||
|
screenshots.
|
||||||
|
- The Joke Shop beauty capture closes a stale wand/inspection panel before shooting
|
||||||
|
and frames the entrance and sign instead of a nearby target.
|
||||||
|
- Multiline HUD and wand strings now render real line breaks instead of a literal
|
||||||
|
`\n`; the wand panel also lists the guest's carried items.
|
||||||
|
- Final-context NPC gear fit: authorized-guest lanyards now show their badge in
|
||||||
|
front of the jacket, and responder helmets sit above the eyes instead of across
|
||||||
|
the brow.
|
||||||
|
|
||||||
|
## [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.
|
||||||
|
- Evaluated Gitea Actions cache for the Godot binary/templates; disabled it after
|
||||||
|
cache saves timed out or were rejected, pending a healthy host cache service.
|
||||||
|
- 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
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Normal radio reports now send on click. The button was wired only to the
|
||||||
|
emergency hold-to-confirm handlers, so a non-emergency press did nothing.
|
||||||
|
|
||||||
|
## [0.8.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A first-shift tutorial with contextual prompts, a safe visitor and replay/skip.
|
||||||
|
- A three-venue campaign shell with shift progression and a Continue action.
|
||||||
|
- Resume-from-checkpoint for paused shifts, including NPC, incident and system state.
|
||||||
|
- Easy/normal/hard difficulty presets for spawn pacing, compliance tolerance and
|
||||||
|
report strictness.
|
||||||
|
- A searchable in-game Help overlay with controls and the current venue policy.
|
||||||
|
- Recovery events, contextual NPC dialogue and an eligible-event debug preview.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The shift review now includes venue policy, campaign next steps and continued
|
||||||
|
review controls.
|
||||||
|
- Event scheduling suppresses recently played scripted events and respects the
|
||||||
|
difficulty spawn multiplier.
|
||||||
|
- Save data is written atomically and split into settings, campaign, shift
|
||||||
|
history and versioned checkpoint files.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Missing/older settings migrate through defaults; a partial write cannot
|
||||||
|
replace a valid save.
|
||||||
|
- The HUD debug overlay now refreshes and shows the next eligible events.
|
||||||
|
|
||||||
|
## [0.7.3] — 2026-11-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Mouse look now reads relative motion at the `_input` stage, so a full-screen
|
||||||
|
HUD or focused control cannot swallow it while the cursor is captured.
|
||||||
|
- Mouse capture is restored after window/compositor focus returns, and clicking
|
||||||
|
back into a gameplay window recaptures it instead of opening the radial menu.
|
||||||
|
- The HUD is mouse-transparent; its presentation controls no longer block
|
||||||
|
gameplay mouse input.
|
||||||
|
|
||||||
|
## [0.7.2] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Automatic OpenRouter model selection for the screenshot judges: the cheapest
|
||||||
|
currently available image+JSON-capable model is used, with ordered fallbacks
|
||||||
|
and a pinned `GIG_LINE_JUDGE_MODEL`/`--model` override.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The judge reports the model that produced each verdict and fails clearly on an
|
||||||
|
invalid API key instead of retrying other models.
|
||||||
|
- The screen-design and realism reports now include the fresh judge results.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The blocked screenshot judge now runs with the valid `OPENROUTER_API_KEY`
|
||||||
|
(`13/13` screen designs match, `0` diff).
|
||||||
|
|
||||||
|
## [0.7.1] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- An optional Desktop HQ build for Windows and Linux that uses Forward+,
|
||||||
|
volumetric fog and SDFGI, packaged with an `override.cfg` beside the
|
||||||
|
executable.
|
||||||
|
- Volumetric flashlight haze in the Desktop HQ build, with a LATE-phase preset
|
||||||
|
tuned so the entrance facade stays readable.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The normal Compatibility build remains the default; the preset only affects
|
||||||
|
the extracted Desktop HQ copy.
|
||||||
|
- Night-time light falloff adapts to Godot 4.7 while keeping the 4.3 baseline
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The flashlight no longer disappears at night on Godot 4.7 under the old
|
||||||
|
attenuation curve.
|
||||||
|
- Headless and Web builds stay non-volumetric and boot normally when Forward+
|
||||||
|
is unavailable.
|
||||||
|
|
||||||
|
## [0.7.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Distinct venue geometry: the Joke Shop is now a narrow brick alley with a
|
||||||
|
shuttered facade, warm wall lantern, dumpster and AC clutter; the TV Studio
|
||||||
|
has a stone facade, bulb-lit canopy, glossy black car and a stanchion/barrier
|
||||||
|
line at the door.
|
||||||
|
- The README gallery includes captured Joke Shop and TV Studio views.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Venue geometry is data-driven through `WorldBuilder.VENUE_SPECS`; switching
|
||||||
|
venues rebuilds the world while keeping the guard and UI intact.
|
||||||
|
- Each venue has its own navigation bounds and concept-gallery mapping.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The Joke Shop no longer renders the Hollywood skyline or marquee.
|
||||||
|
- The TV Studio no longer uses the boulevard marquee or palm-lined layout.
|
||||||
|
|
||||||
|
## [0.6.1] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Per-phase AI skyline panoramas (day, dusk, night) replacing the flat box skyline.
|
||||||
|
- Higher-detail surface textures with normal maps (brick, concrete, asphalt, awning, and more).
|
||||||
|
- A runtime image root (`assets/images/`) with a UI and scene art loader; the start menu,
|
||||||
|
pause, settings, shift review, radio, wand, inspection, and radial menu are styled against
|
||||||
|
their mockups.
|
||||||
|
- NPC face and hand detail: eyes, nose, lips, ears, fingered hands, and cuffed sleeves.
|
||||||
|
- A staged NPC portrait capture for judging avatar quality up close.
|
||||||
|
- Gear-fit checks (`tools/blender_assets.py fit`) and regression tests for head and back gear.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Scene lighting, fog, sun angle, and night glow retuned to match the AI concept frames;
|
||||||
|
the Late phase uses wet asphalt.
|
||||||
|
- The flashlight is a tighter forward spot that reads in the dark.
|
||||||
|
- Sunglasses narrowed to sit inside the face silhouette; shoulder bag moved clear of the
|
||||||
|
coat and dress skirts; firefighter helmet lifted off the brow.
|
||||||
|
- The README now links to focused docs pages for gameplay, architecture, setup, asset
|
||||||
|
tooling, development status, and the manual smoke checklist; `PLAN.md` was compacted
|
||||||
|
into a design plan.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Sidewalk overexposure at the entrance reduced to match the concept target.
|
||||||
|
- The body-camera overlay no longer overlaps the shift/reputation/crowd status.
|
||||||
|
- Selecting a venue releases the menu input lock and recaptures the mouse.
|
||||||
|
- The shoulder bag no longer clips through the coat's skirt; the firefighter helmet no
|
||||||
|
longer cuts into the brow ridge; the portrait subject now faces the camera.
|
||||||
|
- `--portrait-type` is now parsed and applied instead of being ignored.
|
||||||
|
|
||||||
|
## [0.6.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Blender-authored character, gear and prop library with baked ambient occlusion.
|
||||||
|
- Higher-resolution environment textures with tangent normal maps.
|
||||||
|
- Phase-driven emissive details on library props, characters and street dressing.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The game was renamed from "Step Line" to "Gig Line".
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- NPCs now face their movement direction instead of walking backwards.
|
||||||
|
|
||||||
|
## [0.5.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Articulated NPC characters with layered outfits, hand items, face/hair variety,
|
||||||
|
idle behaviour, reaction symbols, queue offsets and three LOD tiers.
|
||||||
|
- Player acceleration/braking, step-up assist, head bob, landing dip,
|
||||||
|
precision-walk feedback and surface-aware footsteps.
|
||||||
|
- Remappable keyboard and gamepad controls.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Crowd roles now select deterministic character variants and props.
|
||||||
|
|
||||||
|
## [0.4.0] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Collision and navigation footprints for every street prop.
|
||||||
|
- Zoned prop placements with deterministic variants and small clutter.
|
||||||
|
|
||||||
|
## [0.3.3] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Staged in-game captures for the wand screening, escalation HUD, and body-camera timeline screens.
|
||||||
|
|
||||||
|
## [0.3.2] — 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- AI reference mockups for the seven remaining catalogue screens.
|
||||||
|
|
||||||
|
## [0.3.1] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Prop models drawn with a single texture atlas (one material per prop).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The Web build is listed in the README downloads table.
|
||||||
|
|
||||||
|
## [0.3.0] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Surface-material profiles, ACES tonemapping, glow, aerial fog and phase-based
|
||||||
|
colour grading.
|
||||||
|
- Framed facade windows, door trim, curb and lane markings.
|
||||||
|
- Generated street-furniture models and the Web export.
|
||||||
|
- Aim-free targeting, a focus cone and precision walk.
|
||||||
|
|
||||||
|
## [0.2.16] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Venues authorable as editor `.tres` resources.
|
||||||
|
|
||||||
|
## [0.2.15] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A vision-model judge for comparing screenshots against reference designs.
|
||||||
|
|
||||||
|
## [0.2.14] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Anonymous release downloads enabled on the host.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `Strings.fmt` keeps positional placeholders stable when new keys are added.
|
||||||
|
|
||||||
|
## [0.2.13] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Missing scenario content: Joke Shop reservation/ID cases, wand refusal and late
|
||||||
|
arrival events, the studio filming-boundary repeat, and a celebrity-arrival crowd spike.
|
||||||
|
|
||||||
|
## [0.2.12] — 2026-10-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Release uploads fail loudly instead of leaving an empty release with a green job.
|
||||||
|
- Pruned releases restored and CI publishing verified end to end.
|
||||||
|
|
||||||
|
## [0.2.11] — 2026-10-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Releases publish using the runner's checkout credentials when no token or git
|
||||||
|
credentials exist.
|
||||||
|
|
||||||
|
## [0.2.10] — 2026-10-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Release publishing fixed with a CI token fallback.
|
||||||
|
|
||||||
|
## [0.2.9] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Accessibility pass: escalation feedback that reads in grayscale and a working HUD font scale.
|
||||||
|
|
||||||
|
## [0.2.8] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Procedural crowd ambience that rises with crowd mood, and a radio crackle.
|
||||||
|
|
||||||
|
## [0.2.7] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- NPC theater poses: sitting, taking photos, filming, and performing.
|
||||||
|
|
||||||
|
## [0.2.6] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A body-camera timeline on the shift review for stepping through recorded events.
|
||||||
|
|
||||||
|
## [0.2.5] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Emergency aftermath: evacuation clears the entrance, and unjustified calls write
|
||||||
|
an investigation note with a false-report reputation hit.
|
||||||
|
|
||||||
|
## [0.2.4] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Crowd presentation: onlookers rubberneck at incidents and clear out during panic.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- NPC navigation issues resolved.
|
||||||
|
|
||||||
|
## [0.2.3] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Remaining PLAN actions: eye contact, "I recognize this person", a formal-warning
|
||||||
|
body-camera flag, blocking that stations the guard in front of the door, and
|
||||||
|
requesting a reason for entry.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- A dead incident-recording path.
|
||||||
|
|
||||||
|
## [0.2.2] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Session shell: startup menu with venue selection, pause overlay, settings
|
||||||
|
persistence, and a "run another shift" flow back to the menu.
|
||||||
|
- Control pass: focus cone, head ring, radial action menu, and named input actions.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Release publishing now uploads the installer and AppImage.
|
||||||
|
|
||||||
|
## [0.2.1] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Windows NSIS installer and Linux AppImage packaging; all exports embed the PCK.
|
||||||
|
- An AI texture generation mode in the asset pipeline.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- NSIS build fixed for Linux (absolute defines, space-free installed exe, BMP icon).
|
||||||
|
- Runtime hygiene: RefCounted cycle cleanup, full-length shifts, and a wand cooldown.
|
||||||
|
|
||||||
|
## [0.2.0] — 2026-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- First playable build of the security-guard simulation at the Hollywood Boulevard entrance.
|
||||||
|
- Core simulation: shift coordination, venue scenarios, event scheduling, NPC movement
|
||||||
|
and states, and escalation from observation through deterrence, warnings, and blocking.
|
||||||
|
- Access verification for wristbands, IDs, tickets, credentials, and guest lists, with
|
||||||
|
admit/redirect/hold/refuse decisions and feedback scoring.
|
||||||
|
- Escalation levels 0–5 with radio assistance and a hold-to-confirm emergency call.
|
||||||
|
- Incident recording, body-camera evidence, reputation scoring, crowd reactions, and
|
||||||
|
an end-of-shift review.
|
||||||
|
- Scenario content for Hollywood Boulevard, The Joke Shop, and the TV Studio, including
|
||||||
|
a mental-health crisis event.
|
||||||
|
- A protester NPC, the "call someone else" reaction, a lockable door, and a flashlight.
|
||||||
|
- Save/persistence, navmesh pathfinding, and JSON localization.
|
||||||
|
- Visual polish: phase lighting, street lamps, marquee, street dressing, and NPC variety.
|
||||||
|
- Detailed graphics: authored textures, a humanoid NPC rig, and HUD/inspection feedback.
|
||||||
|
- Downloadable Linux, Windows, and macOS builds published by CI.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- The dialogue tone-of-voice picker (reactions now depend on escalation level and NPC profile).
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# Credits and Provenance
|
||||||
|
|
||||||
|
Gig Line is a local, single-player security-shift game built with Godot 4 and
|
||||||
|
GDScript. This file records the asset provenance needed for the release review;
|
||||||
|
it is not a legal opinion or a claim that every provider licence has already
|
||||||
|
been cleared for public distribution.
|
||||||
|
|
||||||
|
## Game, code and design
|
||||||
|
|
||||||
|
- Game design, systems, scenarios, dialogue and UI code: the Gig Line project.
|
||||||
|
- Engine: [Godot Engine 4.7.2](https://godotengine.org/), MIT licence.
|
||||||
|
- The game bundles no third-party fonts; it uses Godot's default theme font.
|
||||||
|
- No third-party music, sound effects or voice recordings are bundled. Crowd
|
||||||
|
ambience and radio cues are generated procedurally at runtime.
|
||||||
|
|
||||||
|
## 3D characters, gear and props
|
||||||
|
|
||||||
|
The character, gear and prop library is generated by project-owned scripts
|
||||||
|
(`tools/blender_assets.py`, `tools/npc_pipeline.py`, `tools/model_pipeline.py`)
|
||||||
|
using Blender. The `.blend` working sources are developer artifacts and are not
|
||||||
|
shipped. The exported `.glb` files and baked AO maps are project assets; they do
|
||||||
|
not embed third-party models or purchased asset packs.
|
||||||
|
|
||||||
|
### Development-only research previews
|
||||||
|
|
||||||
|
Two review sheets under `docs/blender_previews/` compare source candidates for
|
||||||
|
the future NPC variety work. They are development documentation and are not
|
||||||
|
bundled with the game or its release packages. The underlying source models are
|
||||||
|
kept outside version control.
|
||||||
|
|
||||||
|
- [`sheet_npc_sources_research.jpg`](docs/blender_previews/sheet_npc_sources_research.jpg)
|
||||||
|
includes renders of **Quaternius Ultimate Modular Characters** (CC0 1.0,
|
||||||
|
<https://quaternius.com/>), **Kenney Blocky Characters 2.0** (CC0 1.0,
|
||||||
|
<https://kenney.nl/assets/blocky-characters>), and **CesiumMan** and
|
||||||
|
**RiggedFigure** (CC BY 4.0, © 2017 Cesium,
|
||||||
|
<https://github.com/KhronosGroup/glTF-Sample-Assets>).
|
||||||
|
- [`sheet_npc_crowd_prototypes.jpg`](docs/blender_previews/sheet_npc_crowd_prototypes.jpg)
|
||||||
|
contains renders of project-owned generator prototypes.
|
||||||
|
|
||||||
|
The CC-BY preview images are included only as development evidence. Any future
|
||||||
|
shipped derivative of CesiumMan or RiggedFigure must keep the attribution above.
|
||||||
|
|
||||||
|
The venue geometry is authored procedurally in `src/game/world_builder.gd` as a
|
||||||
|
stylized reconstruction. The Joke Shop is a fictional stand-in for the real
|
||||||
|
Sunset Strip block; the game does not claim endorsement by, or an exact replica
|
||||||
|
of, any real venue or tenant.
|
||||||
|
|
||||||
|
## AI-assisted images
|
||||||
|
|
||||||
|
Surface textures, skyline panoramas, UI art and concept references were produced
|
||||||
|
with image-generation calls from the project's tooling. The default model slugs
|
||||||
|
recorded in the source are:
|
||||||
|
|
||||||
|
- `bytedance-seed/seedream-4.5` — `tools/generate_textures.py`
|
||||||
|
- `openai/gpt-5-image-mini` — `tools/asset_pipeline.py`,
|
||||||
|
`tools/model_pipeline.py`, `tools/scene_concepts.py` and
|
||||||
|
`tools/screen_designs.py`
|
||||||
|
- Judging/review calls use the model selected by `tools/openrouter_judge.py` and
|
||||||
|
are development-only; they do not ship in the game.
|
||||||
|
|
||||||
|
The prompts and generation workflow live in those tools. Per-file generation
|
||||||
|
metadata is not stored with every image, so the exact provider, model version and
|
||||||
|
generation date of each committed bitmap cannot be reconstructed from the
|
||||||
|
repository alone. Before a public 0.10.0 release, the provider terms and
|
||||||
|
commercial-use/redistribution rights for those generated outputs must be
|
||||||
|
reviewed and recorded. **This is a release blocker, not an assumed clearance.**
|
||||||
|
|
||||||
|
Reference photographs linked from the venue documents are hosted on Wikimedia
|
||||||
|
Commons and were used for proportion/material study only. They are not included
|
||||||
|
in the game or its release packages. If any future derivative asset copies a
|
||||||
|
reference more directly, its attribution and licence must be added here.
|
||||||
|
|
||||||
|
## Audio
|
||||||
|
|
||||||
|
All runtime audio is procedural (crowd bed, radio crackle and interface cues).
|
||||||
|
There are no external audio files, so there is no separate music/SFX licence to
|
||||||
|
clear. See `docs/accessibility.md` for caption and volume behaviour.
|
||||||
|
|
||||||
|
## Third-party names
|
||||||
|
|
||||||
|
The game is a work of fiction. Real place names and public references are used
|
||||||
|
for orientation and satire/stand-in geography; no real person, venue or brand
|
||||||
|
endorses the game. Review the storefront and trademark language before release.
|
||||||
@@ -4,19 +4,394 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
|
|
||||||
## Decisions
|
## Decisions
|
||||||
|
|
||||||
- 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.
|
- **Priority order (2026-11-03):** `TODO.md` now leads with the unversioned **Character
|
||||||
|
development** and **Local map development** tracks, then the versioned 0.10.0 release
|
||||||
|
candidate and later releases. Do not attach a placeholder version to an unversioned track;
|
||||||
|
assign one only when its scope enters a release. Character development is generator-first
|
||||||
|
(ADR-0015); local map development evaluates OSM/3D data, licensed reference imagery,
|
||||||
|
AI-assisted composition and development-only Gaussian splatting.
|
||||||
|
- **Commit/build discipline (2026-11-03):** commit each coherent verified change as it lands, not
|
||||||
|
only at milestone end, and push shareable commits. Every major, minor and patch version requires
|
||||||
|
a `CHANGELOG.md` entry, a local `tools/build_releases.sh` build and artifact/checksum
|
||||||
|
verification before tagging. CI tag builds are the second gate, not a substitute.
|
||||||
|
- **Gaussian splatting / photo-derived maps (unversioned local track):** expanded in
|
||||||
|
`TODO.md` "Gaussian splatting evaluation". Accepted photo channels are team captures,
|
||||||
|
permissioned user/volunteer photos and clearly licensed downloads; every set needs a
|
||||||
|
provenance/consent sidecar. Sparse web photos are reference/training supplements, not a splat
|
||||||
|
source. Five enhancement paths are ranked (reference/QA, texture bake, mesh proxy, distant
|
||||||
|
backdrop, single-facade user-photo supplement). Splats stay offline/development-only until the
|
||||||
|
ADR proves licence, privacy, Godot Compatibility/Web cost and mesh-based collision; no runtime
|
||||||
|
splat dependency in 0.10.0.
|
||||||
|
|
||||||
|
- **NPC model variety decision (2026-11-03, ADR-0015):** CC0 is acceptable for shipped
|
||||||
|
assets; CC-BY only with attribution in `CREDITS.md`; no service assets with redistribution
|
||||||
|
restrictions. The **procedural generator is the primary path**. Four crowd-variety specs were
|
||||||
|
prototyped with the existing builder (`npc_crowd_a` bun/slim/sunglasses, `npc_crowd_b`
|
||||||
|
bald/broad/beard/shoulder bag, `npc_crowd_c` coat/umbrella, `npc_crowd_d` hood/cup); all audit
|
||||||
|
clean at 4,550–5,258 tris / 4,356–5,086 verts. Prototype assets stay in
|
||||||
|
`tmp/npc-research/generator_proto/`; do not add them to the current release candidate.
|
||||||
|
**Quaternius is a reference, not a shipped base:** welding brings `Casual_Hoodie` from 12,518
|
||||||
|
to 3,199 verts and a 0.75 decimate to 2,423 verts / 4,654 tris, and its Idle/Walk clips read
|
||||||
|
well, but the T-pose 62-bone realistic rig/proportions do not match the arm-down 13-bone
|
||||||
|
contract. A contract rebuild is a no-go without a body proportion warp; a second
|
||||||
|
rig/animation path needs its own ADR. **MakeHuman is deferred** to a separate local pipeline:
|
||||||
|
the CC0 base is 19,158 verts / 36,972 tris and decimates to 3,780 / 6,468 at 0.35, but needs
|
||||||
|
retopology, a custom rig and project clothing. Research previews are committed under
|
||||||
|
`docs/blender_previews/sheet_npc_{sources_research,crowd_prototypes}.jpg`; the CC-BY entries
|
||||||
|
(CesiumMan/RiggedFigure, © Cesium) are attributed in `CREDITS.md` and are development-only.
|
||||||
|
|
||||||
|
- **0.10.0 balance protocol:** `docs/balance-acceptance.md` defines targets and
|
||||||
|
denominator/cohort rules for the 36 venue/difficulty/phase cells, seeds 1–100,
|
||||||
|
access/emergency error rates and matched calm vs emergency-first comparisons.
|
||||||
|
These are acceptance criteria, not measured results; sweeps/playtests remain open.
|
||||||
|
Inspection found `_read_npc_truth()` is type-derived, not behavior-derived;
|
||||||
|
the pending emergency fairness review must cover this oracle mismatch rather
|
||||||
|
than treating internal truth as independent evidence.
|
||||||
|
|
||||||
|
- The visual-alignment path/loader/panel/HUD work and the realism lighting pass are complete and
|
||||||
|
recorded in `DONE.md`; remaining visual items are the realism follow-ups in `TODO.md`.
|
||||||
|
- **Character mesh cap (2026-11-02):** the eight library variants now use **8,000 triangles /
|
||||||
|
8,000 glTF vertices** per character (`CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in
|
||||||
|
`tools/blender_assets.py`), up from 6,000/5,000. The frozen `npc_base` fallback keeps its
|
||||||
|
6,000/4,000 contract. This headroom is specifically for the remaining face, hand-grip and
|
||||||
|
clothing realism work; re-run the 24-NPC and Web/Compatibility budgets as geometry lands. Do not
|
||||||
|
add detail without measuring, and do not silently lower the cap back to 5,000.
|
||||||
|
- `PLAN.md` is a compact product/design document, not an implementation log. Historical control
|
||||||
|
and v0.3.0 specs were folded into its Presentation and Controls section; put new step-by-step
|
||||||
|
work in `TODO.md`, not the plan.
|
||||||
|
- Editable Blender sources under `assets/models/blender_src/` are gitignored and untracked
|
||||||
|
(46 `.blend` files removed from the index on 2026-11-01); the `.gdignore` marker stays tracked.
|
||||||
|
- `screen_designs.py judge` default `google/gemini-2.5-flash-lite` worked on 2026-11-01
|
||||||
|
(7 match / 4 review / 0 diff); `--model` remains available.
|
||||||
|
- `capture_realism.gd` parses `--portrait-type=N`; it was documented but ignored before the gear
|
||||||
|
pass. Portrait captures need the requested NPC type to have spawned, otherwise the stage can
|
||||||
|
finish with an empty frame; use the Blender character previews (`render --only npc_coat`) for
|
||||||
|
deterministic gear checks.
|
||||||
|
- Headgear: the firefighter helmet was lifted 2 cm after the brow/face pass; cap and hood were
|
||||||
|
visually checked on `npc_vest`/`npc_hoodie`. The beanie is unused and shares the cap shell.
|
||||||
|
- Gear fit is measured with `python3 tools/blender_assets.py fit` (stdlib, reads the GLBs):
|
||||||
|
head width uses skin vertices weighted to Head in y 1.55–1.81; clothing radius is the cloth
|
||||||
|
skirt in y 0.30–0.52 with a pants hip fallback. The command reports per-character gear boxes,
|
||||||
|
head-band status and x/radial skirt clearance; `test_blender_assets` covers its shape.
|
||||||
|
- Post-realism work is split by theme, not by date: finished items are archived in `DONE.md`, and
|
||||||
|
`TODO.md` carries the 0.x gap register and milestone roadmap. New work belongs there, not in
|
||||||
|
a revived historical plan document.
|
||||||
|
|
||||||
|
- Graphics v0.6.0 plan (completed 2026-11-01; ADR-0013): NPCs move to Blender-authored skinned meshes. `tools/npc_pipeline.py` builds
|
||||||
|
`assets/models/generated/npc_base.glb`; `NpcAvatar` keeps the procedural `_build_body()`
|
||||||
|
fallback. Preserve `Rig/Head`, the limb node names, and the seed-deterministic
|
||||||
|
`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).
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
- **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-0.10.
|
||||||
|
- **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`.
|
||||||
|
- **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.
|
||||||
|
- **Pre-build NPC revisit (2026-11-02):** the final-context harness is
|
||||||
|
`src/test/capture_npc_review.gd` (8 library models, 3 distances, 2 venues,
|
||||||
|
day/night). It found two P1 gear-fit issues: the lanyard badge was hidden
|
||||||
|
under the jacket and the firefighter helmet brim sat over the eyes. Both are
|
||||||
|
fixed at runtime with `NpcAvatar.GEAR_OFFSETS` (`lanyard` forward 4 cm,
|
||||||
|
`firefighter_helmet` up 3 cm); the authored GLBs and the fit report remain
|
||||||
|
asset-space measurements. The guard model is staged through the review-only
|
||||||
|
`character_override` because it has no spawned NPC role. **Signed off
|
||||||
|
2026-11-02:** 96 final-context captures, no P0; lanyard/helmet P1 fixes; the
|
||||||
|
backpack straps, caps, low-poly hands/faces and optional close-range
|
||||||
|
flashlight wash were accepted or deferred. The 24-NPC budget is 6.94 ms, the
|
||||||
|
gallery is 13 good / 0 bad, the screen-design judge is 13/13 and a clean
|
||||||
|
portrait measured a 0.732 vision gap against the photoreal concept. No
|
||||||
|
release build, version bump or tag was created at this gate.
|
||||||
|
- **NPC texture resolution (0.9.5, 2026-11-02):** `tools/npc_pipeline.py` now generates 256²
|
||||||
|
albedo/normal/ORM maps instead of 128² (AI shirt/trousers are resized to 256). The base and all
|
||||||
|
eight library GLBs plus AO maps were rebuilt; texture files total ~0.5 MB, eight GLBs ~5.75 MB,
|
||||||
|
and the 24-NPC smoke is 6.94 ms.
|
||||||
|
- **0.9.5 texture/UI audit (2026-11-02):** all 21 screen-art textures are
|
||||||
|
1280×720 and referenced by their screens; access cards are 256×128 and HUD
|
||||||
|
icons 64×64, with no oversized or unused runtime texture. The 24-NPC smoke now
|
||||||
|
reports **168 meshes / 131,616 triangles / 6.94 ms** (50 ms budget). Compressed
|
||||||
|
payloads are picks **24.55 MB**, UI art **22.67 MB**, NPC maps **0.48 MB**.
|
||||||
|
Legacy root textures remain only for `generate_textures.py` and the asset test.
|
||||||
|
- **Environment surface audit (0.9.5, 2026-11-02):** `capture_realism.gd` gained
|
||||||
|
`surfaces` (Hollywood pavers/asphalt/limestone/facade) and `surfaces_joke`
|
||||||
|
(neighbour awning, canopy, pavers) stages with the HUD hidden. The Walk of Fame
|
||||||
|
band now uses `T_CONCRETE` as dark terrazzo; the neighbour awning uses a neutral
|
||||||
|
tint (`0.62`) and 4× UV so the red/cream stripes survive; the skyline shader
|
||||||
|
fades its lower 42 m toward a per-phase haze colour. Brick/asphalt picks needed
|
||||||
|
no replacement. No seams or broken UV scales found.
|
||||||
|
- **NPC fabric UV/AO (0.9.5, 2026-11-02):** cloth/pants use
|
||||||
|
`Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1)`, and `NpcAvatar` skips the baked per-character
|
||||||
|
AO on those two slots. The 256² AO was magnifying into large blotches; the fabric now reads as a
|
||||||
|
fine weave. Skin/hair/gear keep baked AO. Test `test_fabric_uv_scale_avoids_the_baked_ao_pattern`
|
||||||
|
guards this. Current suite is 272/272.
|
||||||
|
- **NPC visual baseline (0.9.4, 2026-11-02):** `src/test/capture_npc_baseline.gd` is the
|
||||||
|
neutral-studio 8-variant × 6-view baseline (front, three-quarter, profile, back, full body,
|
||||||
|
crowd). It uses a fixed orbit camera, mid-grey studio backdrop, key/fill lights, no HUD/crowd/animation;
|
||||||
|
raw frames stay in `tmp/`, and `tools/npc_baseline.py sheet` builds the committed
|
||||||
|
`sheet_npc_baseline.jpg`. Criteria and measurements are in `docs/npc-visual-review.md`. The first
|
||||||
|
ranked gaps were: tourist photo prop duplicates the backpack silhouette; shallow/faceted face;
|
||||||
|
backpack straps read as rigid bars. The tourist prop now hides outside photo/film poses and the
|
||||||
|
backpack straps were refit as flat forward bands (GLB + AO rebuilt); the face remains P1. Before/
|
||||||
|
after sheet: `sheet_npc_baseline_compare.jpg`.
|
||||||
|
- **NPC proportion audit (0.9.4, 2026-11-02):** `tools/npc_proportions.py` measures the exported
|
||||||
|
GLBs (height, skin-head size, upper-chest shoulder silhouette, pants hip width, Spine-to-shoulder
|
||||||
|
torso, Spine-to-ground leg, shoulder-to-hand arm, shoe foot length). All eight variants pass the
|
||||||
|
stylized guide in `docs/npc-proportion-audit.md`; head ~0.190 (upper 0.22) and broad-build
|
||||||
|
shoulders ~0.370/hip ~0.225 are near the upper bounds, not outliers. No skeleton/mesh rescale was
|
||||||
|
needed; run the report after any body change.
|
||||||
|
- **NPC neck/shoulder transition (0.9.4, 2026-11-02):** the body graph uses a fuller neck base
|
||||||
|
(1.43 m, radius 0.074/0.072), a taller/thicker neck top and a shoulder root lowered from 1.39 to
|
||||||
|
1.37 m. A final triangulate + tiny-face delete in `build_character` removes zero-area triangles
|
||||||
|
that the new neck branch exposed in jacket/hoodie. All eight GLBs and AO maps were rebuilt;
|
||||||
|
`npc_proportions.py` still passes and `sheet_npc_baseline_compare-body.jpg` is the review image.
|
||||||
|
- **NPC face-depth pass (0.9.4, 2026-11-02):** recessed the sclera to `ey=-0.134` and added a
|
||||||
|
thin upper lid; removed the separate jaw/cheek spheres and instead sculpt front head vertices
|
||||||
|
(`_shape_head_mesh`) around a chin plate and cheekbones. This avoids dark AO intersection rings.
|
||||||
|
Moved lips forward to stay on the reshaped surface. Latest review sheet:
|
||||||
|
`sheet_npc_baseline_compare-face.jpg`; max character is now 4,754 tris / 4,574 verts.
|
||||||
|
- **NPC torso/hip transition (0.9.4, 2026-11-02):** pelvis radius 0.165→0.168, waist
|
||||||
|
0.150→0.146, chest 0.170→0.168, upper chest 0.172→0.170. This is a subtle shirt taper, not a
|
||||||
|
skeleton change; all proportions pass and `sheet_npc_baseline_compare-torso.jpg` records it.
|
||||||
|
Max character is 4,754 tris / 4,584 verts.
|
||||||
|
- **NPC footwear pass (0.9.4, 2026-11-02):** added `ShoeToe`/`ShoeHeel` spheres to the casual shoe
|
||||||
|
and `BootToe`/`BootHeel` to responder boots; both stay above the sole/boot contact plane. Current
|
||||||
|
counts are 4,482–5,474 tris / 4,260–5,494 verts under 8,000/8,000. Sheet:
|
||||||
|
`sheet_npc_baseline_compare-shoes.jpg`.
|
||||||
|
- **NPC hand-item forward offset (0.9.4, 2026-11-02):** `NpcAvatar.HAND_ITEM_FORWARD =
|
||||||
|
Vector3(0,0,0.04)` is added in `_attach_gear()` for every `GEAR_ATTACH` hand item after the
|
||||||
|
head/chest offsets. Hand gear is authored around the wrist proxy; without this, phone,
|
||||||
|
flashlight, cup and clipboard were partly inside the palm. Fingers are still open, so true
|
||||||
|
curl/thumb contact and umbrella/sign grips stay open. Comparison:
|
||||||
|
`sheet_npc_hands_grip_compare.jpg`; regression assertions cover camera and flashlight positions.
|
||||||
|
- **NPC headgear clearance (0.9.4, 2026-11-02):** after the face-detail pass, the 96
|
||||||
|
final-context frames confirm the cap, firefighter helmet, hood and sunglasses clear the refined
|
||||||
|
brow/eyes; `blender_assets.py fit` stays clean, so no gear was rebuilt. The broad helmet brim is
|
||||||
|
intentional turnout language, not a fit failure.
|
||||||
|
- **NPC face-detail pass (0.9.4, 2026-11-02):** Nose tip radius reduced to 0.022 with ala wings,
|
||||||
|
the two dark lip boxes became one shallow `Mouth` sphere (two blobs read as a moustache), and the
|
||||||
|
ears gained a dark `EarInner` concha. All eight rebuilt; current counts are 4,226–5,218 tris /
|
||||||
|
4,119–5,240 verts under the 8,000/8,000 cap. Sheet:
|
||||||
|
`sheet_npc_baseline_compare-face-detail.jpg`.
|
||||||
|
- **NPC hand pass (0.9.4, 2026-11-02):** palm radius 0.046 at z .742, scale (.80,.62,.88);
|
||||||
|
fingers are `tube` paths from z .758 to .681–.694 with tip spheres, thumb is a bent tube. The
|
||||||
|
optional hand capture is `capture_npc_baseline.gd -- --view=hand` (8 frames, baseline stays 48).
|
||||||
|
`npc_firefighter` is at 5,240 verts after the face-detail pass; the library cap is 8,000 (see
|
||||||
|
the character-mesh-cap decision above), so grip/clothing detail still has headroom. Grip offsets
|
||||||
|
remain open.
|
||||||
|
- **UI flow smoke (2026-11-02):** `smoke_ui_flows.gd` boots the real scene and
|
||||||
|
exercises inspection allow/deny, normal vs emergency radio, Help filtering,
|
||||||
|
wand allow/deny and review return-to-menu. Keep this smoke in the 0.9.6
|
||||||
|
handoff; it complements the unit tests that only exercise panels.
|
||||||
|
- **Destructive actions (2026-11-02):** `SettingsPanel._open_destructive_dialog()`
|
||||||
|
owns one confirmation instance for reset/replay; repeated presses focus the
|
||||||
|
existing dialog, OK emits once, Cancel is inert. Emergency send remains the
|
||||||
|
RadioPanel hold path; `_holding` clears before submit so button-up cannot
|
||||||
|
double-send. Tests cover both.
|
||||||
|
- **Font/layout limits (2026-11-02):** HUD scale is clamped to 0.75–1.75 and only
|
||||||
|
applies to HUD labels. `Hud.set_target_label()` measures the scaled font, widens
|
||||||
|
the chip to 180–420 px and re-measures after a scale change; top labels clip.
|
||||||
|
`UiStyles.apply_button()` sets `clip_text` + ellipsis so long localized labels
|
||||||
|
cannot force a panel past the viewport. Do not replace these with Control.scale.
|
||||||
|
- **Modal close (2026-11-02):** `GameManager._close_top_modal()` is the single
|
||||||
|
Esc/right-click path for radial, inspection, wand, radio, timeline, Help,
|
||||||
|
Settings, Pause and review. Settings remembers whether it came from the menu and
|
||||||
|
restores it on apply/cancel; `_refresh_freeze()` recaptures the mouse and
|
||||||
|
`_show_start_menu()` keeps it visible. Do not add a new modal without adding it
|
||||||
|
to this close path.
|
||||||
|
- **UI focus (2026-11-02):** `src/game/ui/ui_focus.gd` links visible/enabled
|
||||||
|
controls into a wrapping ring; each modal sets default focus on open. Start menu
|
||||||
|
uses its own focus-target list so Continue, venue rows and footer actions share
|
||||||
|
one ring. `GuardController._ensure_gamepad_bindings()` adds A/B to
|
||||||
|
`ui_accept`/`ui_cancel` so pad-only users can confirm/cancel; hidden Continue and
|
||||||
|
disabled timeline buttons never enter the ring.
|
||||||
|
- **Button states (2026-11-02):** `src/game/ui/ui_styles.gd` owns the five action-button
|
||||||
|
states and font colours for the dark session/UI shell. Use `UiStyles.apply_button()`
|
||||||
|
for every new `Button`; CheckButton/OptionButton keep the engine theme. Timeline
|
||||||
|
Previous/Next disable at the ends; F1 tutorial skip is keyboard-only by design.
|
||||||
|
- **Version and roadmap renumber (2026-11-02):** source was **0.9.3** at the UI
|
||||||
|
polish milestone, **0.9.4** after the NPC pass, now **0.9.5** after the texture
|
||||||
|
and material pass, and **0.9.6** as the integration checkpoint. Next work is
|
||||||
|
the **0.10.0** minor release candidate. `TODO.md` plans only 0.x patch/minor increments; no
|
||||||
|
major-version scope is defined yet. The `v0.9.6` tag is the release trigger; no
|
||||||
|
tag was created for 0.9.3.
|
||||||
|
- **Priority change (2026-11-02):** the map optimization, pre-build NPC revisit,
|
||||||
|
0.9.3 UI polish, 0.9.4 NPC visual optimization, 0.9.5 texture/material pass and
|
||||||
|
0.9.6 integration are complete and in `DONE.md`. 0.10.0 release-candidate work
|
||||||
|
is next. The source version is 0.10.0-rc.1.
|
||||||
|
- **0.10.0-rc.1 build (2026-11-03):** clean worktree `a9658ec` produced five
|
||||||
|
artifacts (Linux 161.5 MB, Windows 197.2 MB, macOS 148.0 MB, Web 97.8 MB, HQ
|
||||||
|
241.6 MB); Web/HQ include player docs, SHA-256 manifests are local, Linux/HQ
|
||||||
|
launch headless and Web files serve HTTP 200. Not published: external playtest,
|
||||||
|
AI/legal approval, macOS signing and the Windows/macOS matrix are still open.
|
||||||
|
- **Release/legal blockers (0.10.0 work, 2026-11-03):** macOS remains unsigned
|
||||||
|
(quarantine instructions only); AI image provider terms/commercial rights and
|
||||||
|
external storefront/rating approval are not cleared; external playtests and the
|
||||||
|
full hardware matrix are pending. `CREDITS.md`, `PRIVACY.md`, `docs/accessibility.md`
|
||||||
|
and `docs/known-limitations.md` record these explicitly rather than claiming
|
||||||
|
approval. Do not tag 0.10.0 as final until these are accepted or cleared.
|
||||||
|
- **Save migration (0.10.0 work, 2026-11-03):** fixtures in `src/test/fixtures/saves/`
|
||||||
|
cover 0.8 settings/campaign/history and a 0.9.0 checkpoint. `_load_json` uses
|
||||||
|
`JSON.new().parse()` so corrupt player files fall back silently instead of
|
||||||
|
logging a parse error; atomic writes leave the old file intact when the temp
|
||||||
|
path cannot be written. The migration suite is 9 tests; total 272.
|
||||||
|
- **0.9.6 integration (2026-11-03):** no gameplay/content changes. A clean
|
||||||
|
detached worktree at `f5b8ef2` rebuilt Linux/Windows/macOS/Web/HQ without the
|
||||||
|
dirty tree's ignored `tmp/`/`build/` payload; the in-repo build was 1.6–3.1 GB
|
||||||
|
per artifact because those folders were packed, so always build release
|
||||||
|
artifacts from a clean checkout/worktree. Verification: 263/263 tests,
|
||||||
|
101/101 Python, 14 smokes, 24-NPC 6.90 ms / 168 meshes / 131,616 triangles,
|
||||||
|
gallery 21/0, screen judge 21/21, realism judge overall 2.1 / gap 0.291.
|
||||||
|
- **Release v0.9.6 (2026-11-03):** commit `4bb2896` tagged `v0.9.6`; Gitea
|
||||||
|
Actions run 1296 passed checks and the full build and published seven assets
|
||||||
|
(Linux, Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
||||||
|
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.6`. This is
|
||||||
|
the integration checkpoint before 0.10.0; do not reuse the tag.
|
||||||
|
- **Release v0.9.5 (2026-11-02):** commit `4bc6390` tagged `v0.9.5`; Gitea Actions run
|
||||||
|
922 passed checks and the full build and published seven assets (Linux, Windows,
|
||||||
|
macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
||||||
|
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.5`. Do not
|
||||||
|
reuse the tag; future fixes need a new patch tag.
|
||||||
|
- **Release v0.9.4 (2026-11-02):** commit `a57b86c` tagged `v0.9.4`; Gitea Actions
|
||||||
|
run 916 passed checks and the full build and published seven assets (Linux,
|
||||||
|
Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page:
|
||||||
|
`https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.9.4`. Do not
|
||||||
|
reuse the tag; future fixes need a new patch tag.
|
||||||
|
- **Hollywood landmark map (2026-11-02):** the default venue is the real El Capitan
|
||||||
|
Entertainment Centre block at 6840 Hollywood Blvd, not a generic brick entrance. Its
|
||||||
|
reference/mapping notes live in `docs/hollywood-boulevard-map.md`; the map-budget test
|
||||||
|
(`test_hollywood_geometry_stays_inside_the_map_budget`) currently measures 58,884 triangles
|
||||||
|
across 409 meshes. The facade uses the shared smooth limestone (`stone_steps`) texture; the
|
||||||
|
noisier granite pick was removed.
|
||||||
|
- **Light falloff gotcha (2026-11-02):** in Godot 4.7 `omni_attenuation = 0.0` is constant
|
||||||
|
falloff, not physical falloff. It made the night facade a flat yellow wall and the street
|
||||||
|
lamps wash the set. All local lights now use `1.0`; the Hollywood facade was retuned with
|
||||||
|
0.50/0.28 washes, 1.3 sconces and 2.2 street lamps; the Joke Shop uses 1.8 sconces,
|
||||||
|
2.8 canopy downlights, 3.0 entrance, 1.35 ground uplights and 2.2 sign. Flashlight spot
|
||||||
|
attenuation is also `1.0`. Do not reintroduce `0.0` as a "modern" branch.
|
||||||
|
- **Joke Shop map (2026-11-02):** the venue is now a 27 m Sunset Strip club based on The
|
||||||
|
Comedy Store at 8433 Sunset Blvd, not the old brick alley. `docs/joke-shop-map.md` carries
|
||||||
|
the OSM/Commons references and simplifications; `docs/screens/concepts/joke_shop/` holds the
|
||||||
|
new day/night/across-street frames. The map-budget test measures 22,680 triangles / 454
|
||||||
|
meshes. The hill behind the club is a custom hand-built ramp with an unshaded, fog-disabled
|
||||||
|
shader: a rotated `PlaneMesh` was edge-on and scene fog erased it from the street camera.
|
||||||
|
Local light names are `JokeSign`, `JokeCanopy_*`, `JokeEntrance`, `JokeSconce_*`,
|
||||||
|
`JokeGround_*`; `set_night_mode()` owns their energies and the hill tint.
|
||||||
|
The latest local realism judge reports a 0.454 reference gap on the night entrance;
|
||||||
|
the concept is photoreal while the map keeps stylized materials, so texture/foliage
|
||||||
|
detail stays with the 0.9.5 texture pass rather than the map milestone.
|
||||||
|
- **Docs validation (2026-11-02):** `python3 tools/check_docs.py` requires a README
|
||||||
|
only in directories containing tracked files, verifies local links and requires
|
||||||
|
every tracked image in a folder to be linked from its README. Gitignored
|
||||||
|
generated files (notably `docs/screens/realism/`) are exempt; the tool also has
|
||||||
|
unit tests in `tools/test_check_docs.py`.
|
||||||
|
- **Documentation ownership (2026-11-01):** `docs/architecture.md` §12 defines the source-of-truth map and consolidation rules. Obsolete/historical plan documents are removed rather than kept; current work belongs in `TODO.md`. README/development-status/Blender AO/Forward+ stale claims were corrected. The 0.x gap register and roadmap live in `TODO.md`.
|
||||||
|
- **Vision judge (v0.7.2):** `tools/openrouter_judge.py` reads `/api/v1/models`, filters image-input models with `response_format`, and ranks by advertised prompt/image/completion prices. `--model auto` (default) uses the cheapest (`z-ai/glm-5.3-flash` on 2026-11-01) with fallbacks; explicit `--model`/`GIG_LINE_JUDGE_MODEL` wins. Auth errors abort, provider/model errors fall through. Full screen judge 13/13 match, 0 diff; A/B judge ~$0.006.
|
||||||
|
- **Desktop HQ preset (v0.7.1):** `packaging/desktop_hq/override.cfg` switches a
|
||||||
|
copied executable to Forward+; `Materials.forward_plus_active()` gates
|
||||||
|
volumetric fog/SDFGI and `light_volumetric_fog_energy`, and
|
||||||
|
`Materials.modern_light_falloff()` compensates for Godot 4.7's much harsher
|
||||||
|
local-light falloff. LATE volumetric density is 0.020 with flashlight
|
||||||
|
volumetric energy 3.0. `tools/build_releases.sh` packages the Linux/Windows
|
||||||
|
binaries + override into `gig-line-desktop-hq-<version>.zip`;
|
||||||
|
`publish_release.sh` uploads it when present. A/B report:
|
||||||
|
`docs/screens/realism/2026-11-01-forward-plus/` (entrance gap 1.568→1.187).
|
||||||
|
- **Godot toolchain (updated 2026-11-01):** local `~/.local/bin/godot`, CI and
|
||||||
|
`project.godot` now use Godot 4.7.2; 4.3 remains only as a local backup binary.
|
||||||
|
Export templates for 4.7.2 are installed under
|
||||||
|
`~/.local/share/godot/export_templates/4.7.2.stable`. Godot 4.7 writes
|
||||||
|
`*.gd.uid` files; they are kept out of this clone's status via
|
||||||
|
`.git/info/exclude`. CI downloads the binary/templates directly; Gitea
|
||||||
|
Actions cache is currently unreliable (see CI cache evaluation below).
|
||||||
|
- **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`.
|
||||||
|
The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is
|
||||||
|
required, otherwise Godot's editor tries to import the committed `.blend` and hangs during
|
||||||
|
`--import` (also add `.gdignore` to local build/squashfs folders when scanning is slow).
|
||||||
|
- **Skinned NPC integration (v0.6.0):** `NpcAvatar._build_skinned_body()` loads
|
||||||
|
`npc_base.glb` and keeps `_build_body()` as fallback (`use_skinned_model=false` in tests).
|
||||||
|
Bone pose rotation is the **absolute local orientation**, not an offset from rest: compose with
|
||||||
|
`get_bone_rest(i).basis` or the whole body snaps to a broken pose. Proxies named Hip/Knee/
|
||||||
|
Shoulder/Elbow/Hand + Head marker preserve the old animation math; `Rig/Head` is the marker.
|
||||||
|
Five material slots are tinted via `SurfaceMaterials.npc_slot()`; keep `_rig.scale` uniform on
|
||||||
|
the skinned path. Budget: 16 avatars = **144 meshes**, ~6.9 ms headless.
|
||||||
|
- **NPC facing (fixed after v0.5.0):** the avatar's visual front is **+Z** (procedural eyes
|
||||||
|
and the Blender model's face). Godot `look_at()` aims **-Z**, which made every NPC walk
|
||||||
|
backwards. Use `NpcAvatar.yaw_towards(dir)` and set `rotation.y`; do not call `look_at()` on
|
||||||
|
avatars. Head-turn offsets use `+basis.z` for the same reason. Covered by
|
||||||
|
`test_yaw_faces_the_movement_direction`.
|
||||||
|
|
||||||
|
- **Image root (ADR-0014, 2026-11-01):** `assets/images/` is the runtime root for composed
|
||||||
|
interface/scene art (`ui/`, `scenes/`); tiled PBR textures stay under `assets/textures/`;
|
||||||
|
`docs/screens/designs/` and `docs/screens/concepts/` stay reference-only; QA captures stay in
|
||||||
|
`docs/screenshots/`. When a mockup becomes runtime art, copy/process it into `assets/images/`
|
||||||
|
with a new name (no overwrites) and keep a fallback in code.
|
||||||
|
**Mockup copies:** 21 design references live in `assets/images/ui/`; `docs/screens/designs/`
|
||||||
|
remains the reference-only copy. `tools/screen_designs.py` reads/writes the runtime root.
|
||||||
|
|
||||||
## Handoff (read this first)
|
## Handoff (read this first)
|
||||||
|
|
||||||
|
- **Status (2026-11-01, after the venue-geometry pass):** v0.7.0 is released. Post-v0.6.0 the
|
||||||
|
realism pass, the visual-alignment pass and the NPC face/hand pass all landed. Headless
|
||||||
|
**229/229**, Python tooling **87/87**, `tools/check_screenshots.sh` **11 good / 0 bad**,
|
||||||
|
`screen_designs.py compare` 11 good / 0 bad, `scene_concepts.py audit` all GOOD,
|
||||||
|
`blender_assets.py audit` exit 0, `smoke_npc_budget` OK (16 avatars, 6.94 ms of 50 ms).
|
||||||
|
`PLAN.md` is compact; README/architecture track the current controls, asset pipeline, CI and
|
||||||
|
release artifacts. The historical notes below remain useful for implementation gotchas; for
|
||||||
|
current tasks use `TODO.md`.
|
||||||
|
|
||||||
|
- **Phase 2 — AI texturing (this agent, DONE 2026-11-01).** Phase 1 assets were
|
||||||
|
already in the tree (untracked) and are preserved. Generated six seamless AI
|
||||||
|
clothing albedos into `assets/textures/npc/ai/{shirt,trousers,jacket,vest,
|
||||||
|
coat,dress}.png` (512×512, `--role tile`, gpt-5-image-mini; audit 6 good).
|
||||||
|
**Gotcha:** `asset_pipeline.py generate` defaults to `GEN_SIZE=2048`, which
|
||||||
|
gpt-5-image-mini rejects (HTTP 400); pass `--request-size 1024` for 1:1 roles.
|
||||||
|
`generate --role tile` already applies `make_seamless`, so a separate
|
||||||
|
`seamless` pass is redundant. Added to `tools/npc_pipeline.py`: `prepare`
|
||||||
|
(layers AI shirt→cloth, trousers→pants albedos at 256px) and `palette`
|
||||||
|
(writes `assets/textures/npc/palette.json` via `model_pipeline.dominant_colors`).
|
||||||
|
`write_slot_textures()` now skips the albedo for slots with an AI override
|
||||||
|
(normal/ORM stay procedural). Blender `build` re-run: GLB audit ok, 1204 tris /
|
||||||
|
2488 verts, AI albedo embedded for cloth+pants. Phase 2 completed and shipped with
|
||||||
|
the v0.6.0 asset library.
|
||||||
|
**Import concurrency:** a parallel agent is running
|
||||||
|
`timeout 300 godot --headless --editor --quit --path .` and then checks
|
||||||
|
`assets/models/generated/npc_base.glb.import` — treat that as the canonical
|
||||||
|
import. My own `godot --headless --path . --import` hung with no output past
|
||||||
|
the engine banner (two Godot instances contended on `.godot`); I killed the
|
||||||
|
orphan (PID 2482934). Do not run a second import while that `--editor --quit`
|
||||||
|
is active.
|
||||||
|
Next: Phase 3 (`NpcAvatar._load_model` + slot tinting) consumes
|
||||||
|
`palette.json` and the GLB; Phase 2's capture/judge item is blocked on that.
|
||||||
|
|
||||||
|
- **Git hygiene + tooling (2026-11-01):** dev asset folders are now gitignored
|
||||||
|
and untracked: `assets/models/concepts/`, `assets/models/npc/` (Blender
|
||||||
|
sources), `assets/textures/npc/ai/` (raw AI fabrics), and the raw
|
||||||
|
`assets/textures/ai/*` outputs (only `assets/textures/ai/game_ready/` stays).
|
||||||
|
Kept in the repo: `assets/textures/npc/*_{albedo,normal,orm}.png` +
|
||||||
|
`palette.json`, `assets/models/generated/*` (props + npc_base.glb), and the
|
||||||
|
authored `assets/textures/*` set. `tools/asset_pipeline.py generate` gained
|
||||||
|
`--variants N` — generates N alternatives saved as `<stem>-1..N.png` (N=1
|
||||||
|
keeps the unsuffixed path). Python tooling tests still pass (exit 0).
|
||||||
|
|
||||||
|
- **Screenshots + docs (2026-11-01):** regenerated the eleven README captures
|
||||||
|
(`capture_screenshots.gd` + `capture_prop_gallery.gd`) — ten changed, the
|
||||||
|
prop gallery is byte-identical (props unchanged). README gained an NPC
|
||||||
|
character-model subsection, a "Confirmed game assets" section (linked
|
||||||
|
`game_ready` textures, generated models, NPC maps), and refreshed
|
||||||
|
dev-status / not-yet lines; `docs/architecture.md` Level 2 now lists
|
||||||
|
`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.
|
||||||
@@ -29,7 +404,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
aim-free selection with wheel cycling and Shift precision walk (ADR-0011/0012), and a **Web**
|
aim-free selection with wheel cycling and Shift precision walk (ADR-0011/0012), and a **Web**
|
||||||
export target. `export_presets.cfg` gains a `Web` preset with `variant/thread_support=false`
|
export target. `export_presets.cfg` gains a `Web` preset with `variant/thread_support=false`
|
||||||
(static hosting, no COOP/COEP); `tools/build_releases.sh` exports `build/web/` and zips it to
|
(static hosting, no COOP/COEP); `tools/build_releases.sh` exports `build/web/` and zips it to
|
||||||
`build/step-line-web-<ver>.zip`, and `publish_release.sh` uploads it. Covered by
|
`build/gig-line-web-<ver>.zip`, and `publish_release.sh` uploads it. Covered by
|
||||||
`src/test/tests/test_web_export.gd`.
|
`src/test/tests/test_web_export.gd`.
|
||||||
- **Prop atlas (v0.3.1):** `model_pipeline.atlas_for()` builds a per-prop power-of-two PNG with
|
- **Prop atlas (v0.3.1):** `model_pipeline.atlas_for()` builds a per-prop power-of-two PNG with
|
||||||
one 8×8 cell per palette role, plus a metallic/roughness atlas (G=roughness, B=metallic). The
|
one 8×8 cell per palette role, plus a metallic/roughness atlas (G=roughness, B=metallic). The
|
||||||
@@ -37,21 +412,125 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
material (`baseColorTexture` + `metallicRoughnessTexture`, NEAREST sampling). Colours are sRGB in
|
material (`baseColorTexture` + `metallicRoughnessTexture`, NEAREST sampling). Colours are sRGB in
|
||||||
the texture, so the old `srgb_to_linear`/`_linear_rgba` helpers were removed. `audit_glb` fails
|
the texture, so the old `srgb_to_linear`/`_linear_rgba` helpers were removed. `audit_glb` fails
|
||||||
if a prop is not exactly one material or misses TEXCOORD_0/images.
|
if a prop is not exactly one material or misses TEXCOORD_0/images.
|
||||||
- **Mockups complete (v0.3.2):** `docs/screens/designs/` holds AI references for all 19
|
- **Mockups complete (v0.3.2, updated 0.9.3):** `docs/screens/designs/` holds AI references for
|
||||||
catalogue screens. Only the six staged captures (01–06) are compared/judged; the other 13
|
all 21 catalogue screens, and every entry now has a committed current-build capture.
|
||||||
have no `capture`, so adding staged captures for the wand panel, timeline and escalation HUD
|
`capture_screenshots.gd` covers scenes 01–13, `capture_ui_states.gd` covers UI states 14–21,
|
||||||
would extend automated visual checks. `generate` now calls `_load_env_file()`.
|
and `capture_prop_gallery.gd` covers the prop gallery. `generate` now calls `_load_env_file()`.
|
||||||
- **Staged captures (v0.3.3):** `capture_screenshots.gd` now emits nine shots. States 7–10 switch
|
- **Staged captures (v0.3.3, updated 2026-11-02):** `capture_screenshots.gd` emits the scene
|
||||||
to The Joke Shop at elapsed 620 s (EVENING has routine spawns; LATE has none), retry the wand
|
gallery; states 7–10 switch to The Joke Shop at elapsed 620 s, retry the wand until it alerts,
|
||||||
until it alerts, then jump to 760 s after staging for night lighting. The timeline needs
|
then jump to 760 s after staging for night lighting. LATE now has its own routine pool.
|
||||||
`recorder.close_all_open()`, because `to_dict()` only lists closed incidents. The escalation
|
Shot 12 closes any stale wand/inspection modal before the venue beauty shot (the wand fallback
|
||||||
HUD mockup is third-person now; `judge` still classes it `review` (no diff).
|
can leave `hud.show_wand` open without `wand_open`). The timeline needs
|
||||||
|
`recorder.close_all_open()`, because `to_dict()` only lists closed incidents.
|
||||||
|
`capture_ui_states.gd` adds 14–21; crowd panic stages a group 70 frames into the flee and
|
||||||
|
responder arrival parks the responder with the door locked. `check_screenshots.sh` writes all
|
||||||
|
captures to `docs/screenshots/` before `compare`; judge is 21/21 match.
|
||||||
- **Prop collision (v0.4.0):** `_add_prop_model()` fits a `StaticBody3D` from the model bounds
|
- **Prop collision (v0.4.0):** `_add_prop_model()` fits a `StaticBody3D` from the model bounds
|
||||||
(cylinder for bollard/bin/hydrant, box otherwise) and adds a `NavigationObstacle3D`; NPC agents
|
(cylinder for bollard/bin/hydrant, box otherwise) and adds a `NavigationObstacle3D`; NPC agents
|
||||||
enable avoidance and move with the safe velocity from `velocity_computed`. The navmesh stays a
|
enable avoidance and move with the safe velocity from `velocity_computed`. The navmesh stays a
|
||||||
flat plane, so avoidance (not a baked mesh) routes guests around props. Placements live in
|
flat plane, so avoidance (not a baked mesh) routes guests around props. Placements live in
|
||||||
`PROP_PLACEMENTS` with `placement_problems()` validation; variants come from `variant_for(index)`.
|
`PROP_PLACEMENTS` with `placement_problems()` validation; variants come from `variant_for(index)`.
|
||||||
`smoke_props.gd` must be windowed because the guard reads captured-mouse input.
|
`smoke_props.gd` must be windowed because the guard reads captured-mouse input.
|
||||||
|
- **Realism pass (2026-11-01, completed + adopted):** `tools/scene_concepts.py`
|
||||||
|
(`list`/`generate`/`process`/`promote`/`audit`/`realism`) never overwrites an image
|
||||||
|
(`next_free_path` adds `-vN`; `process` skips existing unless `--new`; `promote` keeps an
|
||||||
|
existing pick). Raw AI output: `assets/textures/ai/v2/raw/` (gitignored). Candidate pool:
|
||||||
|
`assets/textures/ai/game_ready/v2/` (gitignored) and the **tracked runtime assets** are
|
||||||
|
`.../v2/picks/{skyline_day,skyline_dusk,skyline_night,brick_facade,sidewalk_pavers,asphalt,
|
||||||
|
asphalt_wet,awning_canvas}.png` (+ `_normal`). Concepts `docs/screens/concepts/` (committed,
|
||||||
|
`.gdignore`, targets in its README). Runs `docs/screens/realism/<run>/` (PNG captures
|
||||||
|
gitignored; `report.{json,md}` + `sheet.jpg` committed).
|
||||||
|
`src/test/capture_realism.gd` runs five stages (day 0 s / evening 620 s / late 760 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
|
||||||
|
`_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.7
|
||||||
|
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
|
||||||
|
`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
|
||||||
|
repeat, near the 2:1 panorama aspect). Legacy `assets/textures/skyline.png` is no longer
|
||||||
|
loaded but stays on disk for the `test_world` asset check.
|
||||||
|
**Phase look:** day sun 0.62 / exposure 0.6 / ambient 0.22; evening sun 0.12 / exposure
|
||||||
|
0.72 / dark violet sky; late exposure 0.95 / ambient 0.10 with the wet asphalt street and a
|
||||||
|
bright skyline tint (1.5) so the night windows read. Stripes: `stripe_period()` (detrended
|
||||||
|
autocorrelation) + `align_stripes()` (resample to whole periods) replace the edge crossfade
|
||||||
|
for `awning_canvas`; `audit_striped_tile()` compares the wrap step with the harshest interior
|
||||||
|
step.
|
||||||
|
**Judge:** the default `google/gemini-2.5-flash-lite` mostly works but intermittently answers
|
||||||
|
HTTP 400 "API key not valid" (one shot of ten on 2026-11-01); re-run or pass
|
||||||
|
`--model google/gemini-2.5-flash` when it does. Scores are noisy (±1–2), so
|
||||||
|
`realism --repeats 3` averages and `summarize()` reports a like-for-like mean over the shots
|
||||||
|
every set captured. Final: overall 0.8→1.0, backdrop 0.6→1.6, metric gap 0.444→0.348.
|
||||||
|
`screen_designs.py judge` gained one retry for the same transient 400.
|
||||||
|
**Character portrait capture (2026-11-01):** `capture_realism.gd` has a `portrait` stage
|
||||||
|
(`npc_portrait` -> concept `npc_portrait_day`) because crowd shots cannot judge avatars. It
|
||||||
|
freezes one NPC, parks the rest of the crowd 140 m away (a passer-by otherwise blocks the
|
||||||
|
frame), moves the subject to an open sidewalk patch, turns it into the camera and stands the
|
||||||
|
guard on the sunlit side. Needed because the NPC FSM re-writes `rotation.y` every physics tick
|
||||||
|
(so the yaw must be set after `set_physics_process(false)`), the venue's morning sun leaves a
|
||||||
|
face in shadow from most angles, and `visible = false` does not keep the crowd out of frame.
|
||||||
|
`--portrait-type=N` forces a role; hooded roles (trespasser/violent/crisis) are skipped.
|
||||||
|
**Flashlight (2026-11-01, final):** a *tight* `SpotLight3D` on `Head`: `spot_range` 20,
|
||||||
|
`spot_angle` 14, `light_energy` 4.2, `spot_attenuation` 0.9, forward `rotation_degrees = 0`,
|
||||||
|
starts invisible. A fake additive light shaft was tried twice (cylinder with a UV ramp, then a
|
||||||
|
vertical-fade `ShaderMaterial`) and **rejected both times**: on GL Compatibility a first-person
|
||||||
|
camera inside the cone renders it as a filled disc and the far ring shows, so
|
||||||
|
`Materials.light_beam()` and the beam mesh are gone. Regression guard:
|
||||||
|
`test_flashlight_aims_a_tight_forward_spot` in `src/test/tests/test_door_and_flashlight.gd`
|
||||||
|
(lamp on the head, aims straight, cone ≤ 20°, starts off). Night captures are staged in LATE
|
||||||
|
(`elapsed_s` 760), not dusk.
|
||||||
|
**NPC detail pass (2026-11-01):** `_face()` now builds sclera + iris + upper lid per eye, brow
|
||||||
|
ridge, cheekbones, nose bridge/tip, ears with lobes and split upper/lower lips; the new
|
||||||
|
`eye_white` material is a *fixed-colour* slot, so `_apply_outfit_materials()` leaves it white.
|
||||||
|
`_hands_and_shoes()` has four fingers plus a thumb and `_clothing()` adds `Cuff` tori.
|
||||||
|
Budget work at the time: `CHAR_MAX_VERTS` 5000 (the library cap is now 8000; see the
|
||||||
|
character-mesh-cap decision), body decimation 0.26, upper lids are
|
||||||
|
boxes rather than spheres, and knuckle spheres/nostrils were cut to stay inside it.
|
||||||
|
**Orientation debugging:** to check a GLB's front axis, compare the mean Z of the `eye_white`
|
||||||
|
surface (face) and of the `rubber` sole verts (toes) — all 8 avatars are +Z, so any
|
||||||
|
"they walk backwards" symptom is a yaw bug, not an export flip.
|
||||||
|
- **Blender asset library (v0.6.0, integrated 2026-11-01):**
|
||||||
|
`tools/blender_assets.py` (`build`/`render` in Blender; `audit`/`sheet`/`list` stdlib) writes
|
||||||
|
`assets/models/blender/{npc,npc_gear,props}/*.glb`, `manifest.json` (integration source of
|
||||||
|
truth), sources in `assets/models/blender_src/` (`.gdignore`d), and review sheets
|
||||||
|
`docs/blender_previews/sheet_*.jpg` (per-asset PNG renders are gitignored). 8 characters, 18
|
||||||
|
gear, 20 props; notes in `docs/blender-assets.md`. Characters are drop-in for `npc_base`
|
||||||
|
(same mesh node name, bones at the same rest positions, five tint slots); the `npc_base`
|
||||||
|
fallback stayed under its frozen 6000/4000 budget because of body decimation (0.26) +
|
||||||
|
`smart_project` at 80°: glTF vertex
|
||||||
|
count includes UV-seam splits, so extra beveled detail quickly breaks the limit. The 2026-11-01
|
||||||
|
face/hand pass raised `CHAR_MAX_VERTS` to 5000 (tris 3,974–5,026) after measuring 16 avatars at
|
||||||
|
~6.9 ms of a 50 ms frame; on 2026-11-02 the library cap became 8000/8000 while
|
||||||
|
`npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) stayed frozen at 4000/6000.
|
||||||
|
**Gotchas:** `bisect_plane` and thin bevels leave zero-area triangles (Godot warns "non-finite
|
||||||
|
normal in LOD generation"); `_clean()` + a weld after bisect fix it, and the audit rejects them.
|
||||||
|
Fixed-colour detail materials carry a 4×4 texture because `_apply_outfit_materials()` sets
|
||||||
|
`albedo_color = WHITE` on unknown slots. Cycles CPU render ≈ 3 s/asset; Godot import of the
|
||||||
|
library is clean.
|
||||||
|
**Integration:** `NpcAvatar.character_model_for()` selects a variant by role/seed; only the
|
||||||
|
five contract slots are tinted (detail materials untouched; `npc_vest` keeps its fixed hivis
|
||||||
|
vest, firefighter/guard get dark uniform tints). Gear is attached at head/back/chest/hand and
|
||||||
|
falls back to primitives; `npc_hoodie` skips the extra hood gear. `WorldBuilder` prefers
|
||||||
|
`assets/models/blender/props/` for the six replacements and the new street dressing, fits the
|
||||||
|
same colliders/obstacles, and collects library emissives for `set_night_mode()`.
|
||||||
|
`LIBRARY_TRIANGLE_BUDGET` = 60k (current ~27,986). Library props are excluded from
|
||||||
|
`PROP_PLACEMENTS` only when they need dedicated slots (door/marquee/sedan/handrail/lantern).
|
||||||
|
**Gear fit (v0.6.1):** `fit` measures head width (0.315 m), skirt/hip radius and gear bounds;
|
||||||
|
sunglasses are 0.202 m, the bag's body inner face is 0.262 m (coat 0.225, dress 0.260), and the
|
||||||
|
helmet is lifted 2 cm above the brow. `test_npc_character` guards head/back gear in Godot.
|
||||||
|
Blender's GLB export is byte-nondeterministic for unchanged assets (padding/index order), so do
|
||||||
|
not commit a full no-op rebuild; rebuild only the assets whose geometry changed.
|
||||||
|
- **Venue geometry (v0.6.1+, Joke Shop updated 2026-11-02):** `WorldBuilder.VENUE_SPECS` is the per-venue table; `WorldBuilder.new(root, id)` / `set_venue()` select it, unknown ids fall back to `hollywood_building`. Dimensions, window/pilaster rows, stairs, street, nav bounds, guard spawn, feature flags and prop placements are read from the spec. `GameManager.world_root` holds only the world; `_rebuild_world_for_venue()` frees/recreates it on venue selection/cycling so guard/UI survive. Joke Shop now uses `architecture: "comedy_store"` with `_build_comedy_store_building()`, `SunsetHillside`, `SunsetNeighbours` and `SunsetAcrossStreet`; the old `_build_alley_dressing()` is gated off. TV Studio keeps the stone facade, bulb canopy, car paint and barrier placements. Gallery shot 12 now maps to `joke_shop_entrance_night`; shot 13 stays `studio_stage_door_night`.
|
||||||
|
- **Screen-design judge (2026-11-01):** `screen_designs.py judge` could not run because `OPENROUTER_API_KEY` returned HTTP 400 "API key not valid". `check_screenshots.sh` still passed 13/13; the judge retry is a TODO follow-up.
|
||||||
|
- **Portrait capture:** `capture_realism.gd` faces the **Rig** toward the camera (using the
|
||||||
|
inverse look direction) and hides the blue `FocusCircle`; the old code used the wrong yaw and
|
||||||
|
left the focus disc over the face. An explicit `--portrait-type=N` now overrides the hooded
|
||||||
|
skip, but the day roster spawns none of types 5-7, so a hooded close-up is deferred.
|
||||||
|
- **v0.6.0 environment pass:** `tools/bake_ao.py` bakes 256² AO maps per library asset
|
||||||
|
(`<name>_ao.png`, red channel) and `Materials.apply_ao()`/`SurfaceMaterials` wire them in;
|
||||||
|
`tools/make_normal_maps.py` derives tangent normals for the 1024² brick/concrete/asphalt
|
||||||
|
textures. Forward+ boots on desktop but is rejected for v0.6.0 (project-wide renderer, Web
|
||||||
|
must stay GL Compatibility). Headless 222/222, Python 69/69.
|
||||||
- **Prop pipeline (done):** audit enforces 400 tris / 600 verts, ground contact, UV range, no
|
- **Prop pipeline (done):** audit enforces 400 tris / 600 verts, ground contact, UV range, no
|
||||||
degenerate tris, one material. `capture_prop_gallery.gd` writes `10-prop-gallery.png` (3x2 studio
|
degenerate tris, one material. `capture_prop_gallery.gd` writes `10-prop-gallery.png` (3x2 studio
|
||||||
line-up, back row on a platform) and the `prop_gallery` catalogue entry compares it.
|
line-up, back row on a platform) and the `prop_gallery` catalogue entry compares it.
|
||||||
@@ -76,9 +555,19 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
adopted (custom runner covers it without an editor plugin).
|
adopted (custom runner covers it without an editor plugin).
|
||||||
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
|
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
|
||||||
|
|
||||||
|
## UI / Presentation Decisions
|
||||||
|
|
||||||
|
- Runtime UI/scene art is loaded through `src/game/ui/art.gd` (`assets/images/ui/` then `scenes/`); missing files return null so panels keep procedural fallbacks.
|
||||||
|
- Screen mockups with baked-in controls are used as backdrops plus an opaque `ArtPanel` cover, not as clickable full-screen skins.
|
||||||
|
- Radio, wand, inspection, and body-camera timeline panels use their reference art as backdrops; forms sit on transparent, padded panels over the covered mockup controls.
|
||||||
|
- HUD target names use a boxed chip under the crosshair; escalation has a five-segment bar below the text label. The body-camera REC/clock block starts at y=92 on the right so it clears the shift/rep/crowd text.
|
||||||
|
- Staged captures in `docs/screenshots/` are committed and were last regenerated after the realism and NPC passes; re-run `tools/check_screenshots.sh` (not a partial capture) before replacing them.
|
||||||
|
- `tools/check_screenshots.sh` is the repeatable capture+compare smoke; both capture scripts accept `--out=res://docs/screenshots`. Judge verdicts on the staged set were 7 match / 4 review / 0 diff.
|
||||||
|
- Venue selection used to leave `guard.input_locked` true and the mouse visible; `_start_shift()` must call `_refresh_freeze()` after starting the clock.
|
||||||
|
|
||||||
## Current State
|
## Current State
|
||||||
|
|
||||||
- **v0.3.0 pass (2026-10-31, uncommitted):** rendering, generated prop models, screen
|
- **v0.3.0 pass (2026-10-31, historical; shipped):** rendering, generated prop models, screen
|
||||||
catalogue, aim-free selection. See ADR-0011 (selection) and ADR-0012 (materials/props).
|
catalogue, aim-free selection. See ADR-0011 (selection) and ADR-0012 (materials/props).
|
||||||
- `src/game/materials.gd` (`SurfaceMaterials`) is now the single source of surface
|
- `src/game/materials.gd` (`SurfaceMaterials`) is now the single source of surface
|
||||||
recipes + `configure_environment()`. `GameManager.PHASE_LIGHTING` gained
|
recipes + `configure_environment()`. `GameManager.PHASE_LIGHTING` gained
|
||||||
@@ -128,7 +617,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`carried_items` per spawn (seeded). Tests in `src/test/tests/test_access_loadout.gd`.
|
`carried_items` per spawn (seeded). Tests in `src/test/tests/test_access_loadout.gd`.
|
||||||
- Wand shortcut is **`C`**, not `W` (`W` is walk). `radio_emergency` input map no longer includes W.
|
- Wand shortcut is **`C`**, not `W` (`W` is walk). `radio_emergency` input map no longer includes W.
|
||||||
`hud.controls` / `hud.screen_first` updated.
|
`hud.controls` / `hud.screen_first` updated.
|
||||||
- Control pass (in tree, uncommitted, smoke-tested): cone focus via `src/game/npc_focus.gd`,
|
- Control pass (historical; smoke-tested): cone focus via `src/game/npc_focus.gd`,
|
||||||
accel/decel, gravity only airborne, `input_locked` freeze, Esc no longer on the guard.
|
accel/decel, gravity only airborne, `input_locked` freeze, Esc no longer on the guard.
|
||||||
`NpcAvatar` in group `npc`; neck/hair/eyes/shoes; blue focus circle + `Label3D` name; `set_focus_visual`.
|
`NpcAvatar` in group `npc`; neck/hair/eyes/shoes; blue focus circle + `Label3D` name; `set_focus_visual`.
|
||||||
`src/game/ui/action_radial.gd` doughnut (LMB/Space open, A/D/arrows, Space/click confirm, Esc/RMB
|
`src/game/ui/action_radial.gd` doughnut (LMB/Space open, A/D/arrows, Space/click confirm, Esc/RMB
|
||||||
@@ -140,7 +629,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
awning, and marquee are visible; step treads rise toward the door; `ShiftCoordinator` pulls the
|
awning, and marquee are visible; step treads rise toward the door; `ShiftCoordinator` pulls the
|
||||||
event scheduler once per simulated second (was every physics frame → >1200 NPCs in seconds);
|
event scheduler once per simulated second (was every physics frame → >1200 NPCs in seconds);
|
||||||
`GameManager.MAX_LIVE_NPCS = 16` caps live avatars.
|
`GameManager.MAX_LIVE_NPCS = 16` caps live avatars.
|
||||||
- **Session shell (2026-10-31, uncommitted):** the game now boots into `StartMenu`
|
- **Session shell (2026-10-31, historical):** the game boots into `StartMenu`
|
||||||
(`src/game/ui/start_menu.gd`, layer 20) instead of a live shift. `GameManager._on_venue_selected()`
|
(`src/game/ui/start_menu.gd`, layer 20) instead of a live shift. `GameManager._on_venue_selected()`
|
||||||
builds the scenario and calls `_start_shift()`; `_shift_running` gates input and `_refresh_freeze()`.
|
builds the scenario and calls `_start_shift()`; `_shift_running` gates input and `_refresh_freeze()`.
|
||||||
Esc with nothing open now pauses (`PauseOverlay`, layer 18) → resume / restart / settings /
|
Esc with nothing open now pauses (`PauseOverlay`, layer 18) → resume / restart / settings /
|
||||||
@@ -155,7 +644,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`StaticBody3D` with per-tread `BoxShape3D` colliders; marquee `font_size` 160 / outline 24; focus
|
`StaticBody3D` with per-tread `BoxShape3D` colliders; marquee `font_size` 160 / outline 24; focus
|
||||||
circle (blue disc in front of the face) + name tag 48px; `NpcAvatar.ephemeral`/`lifetime_s` despawns routine traffic
|
circle (blue disc in front of the face) + name tag 48px; `NpcAvatar.ephemeral`/`lifetime_s` despawns routine traffic
|
||||||
(authored events stay). Guard spawn height verified on the landing (guard_y=0.84).
|
(authored events stay). Guard spawn height verified on the landing (guard_y=0.84).
|
||||||
- **PLAN verbs (2026-10-31, uncommitted):** the radial now has 12 slices
|
- **PLAN verbs (2026-10-31, historical):** the radial has 12 slices
|
||||||
(`Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio`).
|
(`Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio`).
|
||||||
`eye_contact` reuses the Level 1 reaction table via `_apply_interaction`. Recognition is a player
|
`eye_contact` reuses the Level 1 reaction table via `_apply_interaction`. Recognition is a player
|
||||||
decision: `NPCController.player_recognized` + `IncidentRecorder.add_access_evidence`, and
|
decision: `NPCController.player_recognized` + `IncidentRecorder.add_access_evidence`, and
|
||||||
@@ -163,7 +652,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
it. The body camera is a real flag (`GameManager.body_camera_on`, `Hud.set_body_camera`), off by
|
it. The body camera is a real flag (`GameManager.body_camera_on`, `Hud.set_body_camera`), off by
|
||||||
default, `B` toggles it, and a formal warning arms it and writes a `body_camera` incident event.
|
default, `B` toggles it, and a formal warning arms it and writes a `body_camera` incident event.
|
||||||
Blocking also calls `_station_between()` to physically place the guard 0.9 m from the NPC toward
|
Blocking also calls `_station_between()` to physically place the guard 0.9 m from the NPC toward
|
||||||
the entrance. `_request_reason()` logs the NPC's seeded `dialogue_lines` pick.
|
the entrance. `_request_reason()` uses the authored `reason` context (falling back to seeded `dialogue_lines`) and stores the pick for the timeline.
|
||||||
- **NPC navigation was dead (fixed 2026-10-31):** avatars never moved in the live game, for three
|
- **NPC navigation was dead (fixed 2026-10-31):** avatars never moved in the live game, for three
|
||||||
stacked reasons. (1) `agent.target_position` was re-assigned every physics frame, which
|
stacked reasons. (1) `agent.target_position` was re-assigned every physics frame, which
|
||||||
invalidates the path so `get_next_path_position()` keeps returning the current point — only set
|
invalidates the path so `get_next_path_position()` keeps returning the current point — only set
|
||||||
@@ -202,6 +691,9 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
`unknown`. `--dry-run`, `--json`, `--only` supported. The prompt explicitly ignores art style,
|
`unknown`. `--dry-run`, `--json`, `--only` supported. The prompt explicitly ignores art style,
|
||||||
because the references are stylised mockups; the live run gave 3 match, 3 review, 0 diff.
|
because the references are stylised mockups; the live run gave 3 match, 3 review, 0 diff.
|
||||||
Python tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs`.
|
Python tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs`.
|
||||||
|
- **String newlines (2026-11-02):** `content/strings.en.json` needs one escaped
|
||||||
|
newline (`\n`), not two. Two backslashes reached the HUD as literal `\n` in
|
||||||
|
the shift status and wand panel; `test_strings_format` now guards this.
|
||||||
- **String formatting safety (2026-10-31):** `Strings.placeholder_count()` counts `%` specs
|
- **String formatting safety (2026-10-31):** `Strings.placeholder_count()` counts `%` specs
|
||||||
(ignoring `%%`), `fmt()` warns and returns the template when the arg count does not match
|
(ignoring `%%`), `fmt()` warns and returns the template when the arg count does not match
|
||||||
(instead of raising an engine error), and `validate()` lints the table for trailing `%`,
|
(instead of raising an engine error), and `validate()` lints the table for trailing `%`,
|
||||||
@@ -295,7 +787,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
and published — installers/AppImage are on the releases page. Releasing = bump version → tag → push.
|
and published — installers/AppImage are on the releases page. Releasing = bump version → tag → push.
|
||||||
- NSIS gotchas (validated in a local ubuntu:24.04 docker repro): makensis uses `-D` defines
|
- NSIS gotchas (validated in a local ubuntu:24.04 docker repro): makensis uses `-D` defines
|
||||||
(never `/D`), resolves relative `-DICON`/`-DARTIFACT` against the **script directory** so CI
|
(never `/D`), resolves relative `-DICON`/`-DARTIFACT` against the **script directory** so CI
|
||||||
passes `$PWD`-absolute paths; installed exe must be space-free (`step-line.exe`); ICO must be
|
passes `$PWD`-absolute paths; installed exe must be space-free (`gig-line.exe`); ICO must be
|
||||||
classic BMP entries (ImageMagick `icon:auto-resize=48,32,16`; PIL emits PNG-compressed ICOs NSIS
|
classic BMP entries (ImageMagick `icon:auto-resize=48,32,16`; PIL emits PNG-compressed ICOs NSIS
|
||||||
cannot load).
|
cannot load).
|
||||||
- appimagetool runs system `appstreamcli` if present (strict, exit 3 on warnings) — project
|
- appimagetool runs system `appstreamcli` if present (strict, exit 3 on warnings) — project
|
||||||
@@ -340,9 +832,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
removed so hosts scanning both paths do not double-run.
|
removed so hosts scanning both paths do not double-run.
|
||||||
- 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.
|
(wristband, ID/ticket, wand-check, refusal, prohibited-item). Hollywood uses a wristband line,
|
||||||
- CI cache: `.gitea/workflows/build.yml` no longer uses `actions/cache` (the runner can't reach
|
the Joke Shop uses ID/ticket/wand lines, and the Studio uses ticket/credential/guest-list lines.
|
||||||
the GitHub cache service; import is fast). `GODOT_SILENCE_ROOT_WARNING=1` set on jobs.
|
- CI cache evaluation: Gitea Actions cache was tested for the Godot binary and
|
||||||
|
trimmed 4.7.2 templates. Restores were inconsistent and saves timed out in
|
||||||
|
`CreateCacheEntry` or were rejected as reserved by another job. The cache steps
|
||||||
|
are disabled until the host cache service is healthy; keep direct downloads.
|
||||||
|
`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/
|
||||||
@@ -402,10 +898,10 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
- Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
|
- Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
|
||||||
- Persistence tests write into the real `user://shift_results.json` (harmless local pollution of the demo history).
|
- Persistence tests write into the real `user://shift_results.json` (harmless local pollution of the demo history).
|
||||||
- macOS export required `rendering/textures/vram_compression/import_etc2_astc=true` in `project.godot` (universal build demands ETC2 ASTC enabled).
|
- macOS export required `rendering/textures/vram_compression/import_etc2_astc=true` in `project.godot` (universal build demands ETC2 ASTC enabled).
|
||||||
- Joke Shop `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
|
- Venue `door_staff_lines` are logged through `GameManager` (inspect / wand / refuse). They are not a separate dialogue UI.
|
||||||
- Access loadout is implemented in the working tree (see Current State); do not re-fix `override_access` as if it were still unread.
|
- Access loadout is implemented; do not re-fix `override_access` as if it were still unread.
|
||||||
- `Save.SETTINGS_FILE` is declared and unused; no mouse-sensitivity or pause menu yet.
|
- `Save.SETTINGS_FILE` is declared and unused; settings persistence goes through `Save.load_settings()` / `save_settings()`.
|
||||||
- Headless suite is **77/77**; the windowed focus/radial smoke passes. Remaining visual follow-ups are at the top of `TODO.md`.
|
- Headless suite is **272/272**; Python tooling is **101/101**; screenshot compare is **21 good / 0 bad** and the automatic judge is **21/21 match, 0 diff**. Remaining visual follow-ups are in `TODO.md`.
|
||||||
- Typed spawn signal extra args: handlers must accept the 4th `event: Dictionary` or Godot will not call them (`test_shift_coordinator_runs_a_shift` failed until `_on_spawn` took four args).
|
- Typed spawn signal extra args: handlers must accept the 4th `event: Dictionary` or Godot will not call them (`test_shift_coordinator_runs_a_shift` failed until `_on_spawn` took four args).
|
||||||
- GDScript inference trap that broke the main scene: a `var` typed as a base class
|
- GDScript inference trap that broke the main scene: a `var` typed as a base class
|
||||||
(`radial: CanvasLayer`) exposes script members as `Variant`, so `var x := radial.is_open` is a
|
(`radial: CanvasLayer`) exposes script members as `Variant`, so `var x := radial.is_open` is a
|
||||||
@@ -415,28 +911,30 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
- Do not snapshot right after changing a transform in the same frame: `capture_screenshots.gd`
|
- Do not snapshot right after changing a transform in the same frame: `capture_screenshots.gd`
|
||||||
needs a state/frame gap or the capture uses the old camera orientation.
|
needs a state/frame gap or the capture uses the old camera orientation.
|
||||||
- `EventScheduler` probabilities are per simulated second, not per call. Never poll it per frame.
|
- `EventScheduler` probabilities are per simulated second, not per call. Never poll it per frame.
|
||||||
- Screenshot staging lives in `src/test/capture_screenshots.gd` (guard at z≈10.5 facing the door).
|
- Screenshot staging lives in `src/test/capture_screenshots.gd` (guard at z≈10.5 facing the door)
|
||||||
`docs/screenshots/` copies are manual: copy from `user://screenshots/`.
|
and `src/test/capture_ui_states.gd` (UI states 14–21). `tools/check_screenshots.sh` renders all
|
||||||
|
captures into `docs/screenshots/`; do not regenerate them by hand.
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
- Add a vision-model (LLM) judge on top of the screen-design comparison: pixel and
|
|
||||||
perceptual metrics cannot decide whether a screenshot's composition is correct.
|
|
||||||
- Whether the responder avatar should be playable/controllable or purely scripted.
|
- Whether the responder avatar should be playable/controllable or purely scripted.
|
||||||
- Localization target languages beyond English.
|
- Localization target languages beyond English.
|
||||||
- macOS notarization approach for broad distribution.
|
- macOS notarization approach for broad distribution.
|
||||||
|
|
||||||
## Plan vs code (re-evaluated)
|
## Plan vs code
|
||||||
|
|
||||||
On local `main` (6 commits not on origin): v0.2.1 packages, ADRs 0007–0010, asset pipeline wired to
|
`PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of
|
||||||
`assets/textures/ai/game_ready/`, screenshots refreshed.
|
2026-11-03 the playable build covers the three venues, tutorials/campaign/checkpoints, the 0.9.3
|
||||||
|
UI/accessibility pass, the 0.9.4 NPC visual optimization, the 0.9.5 texture/material pass, the
|
||||||
Uncommitted: `AccessLoadout`, control pass (cone, ring, radial, NPC face, named input actions),
|
0.9.6 integration checkpoint, and the Blender + realism asset pipeline. `TODO.md` holds the remaining
|
||||||
and boot/spawn fixes. Headless 77/77; windowed smoke passes. Access-artifact and control-pass
|
0.9.6–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not
|
||||||
sections moved to `DONE.md`.
|
GitHub Actions.
|
||||||
|
|
||||||
Still in `TODO.md`: world follow-ups (guard float, step colliders, skyline asset, marquee size);
|
|
||||||
session shell; leftover PLAN verbs; crowd rubberneck; emergency aftermath; body-cam replay;
|
|
||||||
sit/photo/film poses; real crowd audio; Joke Shop/Studio extra events; PLAN.md says GUT/GitHub.
|
|
||||||
|
|
||||||
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|
||||||
|
|
||||||
|
## Uncommitted Workstreams
|
||||||
|
|
||||||
|
- **None (2026-11-03).** The 0.9.6 integration checkpoint is committed, tagged
|
||||||
|
`v0.9.6` and published with seven assets; the workspace is clean apart from
|
||||||
|
local/gitignored realism and capture output. Keep the rule from `AGENTS.md`: check `git status`
|
||||||
|
before committing, and never revert another contributor's in-flight files.
|
||||||
@@ -1,612 +1,209 @@
|
|||||||
# Game Plan: Step Line
|
# Game Plan: Gig Line
|
||||||
|
|
||||||
## Premise
|
## Premise
|
||||||
|
|
||||||
You play a private security guard stationed at the top of the steps outside a fictional building on Hollywood Boulevard. Your job is to keep the entrance and steps clear while dealing with tourists, trespassers, performers, protesters, intoxicated pedestrians, and occasional determined intruders.
|
You are a private security guard working the entrance of a stylized reconstruction of the real El Capitan Entertainment Centre on Hollywood Boulevard. You keep the steps and doors clear, check who is allowed in, and deal with tourists, performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people in mental-health crisis, and rare determined threats.
|
||||||
|
|
||||||
The game is about **judgment, communication, and escalation management**, not simply attacking anyone who approaches.
|
The game is about **judgment, communication, access verification, and proportionate escalation**, not about attacking everyone who approaches.
|
||||||
|
|
||||||
---
|
## Design Pillars
|
||||||
|
|
||||||
|
- **Lowest effective response wins.** Observation, a gesture, or a clear direction should solve most situations.
|
||||||
|
- **People are not labels.** Clothes, props, credentials, and behavior tell the player what they need; internal NPC types stay in the debug overlay.
|
||||||
|
- **Every decision has a record.** Incidents, evidence, radio reports, and outcomes feed the shift review.
|
||||||
|
- **Emergency help is a last resort.** Responders handle crises the guard cannot safely manage; calling them has costs.
|
||||||
|
- **Readability beats raw fidelity.** The GL Compatibility renderer, clear silhouettes, the focus ring, and the HUD stay legible.
|
||||||
|
|
||||||
|
## Development Priorities
|
||||||
|
|
||||||
|
The active planning order is set in [`TODO.md`](TODO.md) and in `AGENTS.md`:
|
||||||
|
|
||||||
|
1. **Character development (unversioned).** Expand the owned procedural character library with
|
||||||
|
crowd, age, build, hair and outfit variety. Keep the frozen bone/tint/gear contract; see
|
||||||
|
[ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md) and
|
||||||
|
[`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md). Quaternius is a reference;
|
||||||
|
MakeHuman is deferred to a separate local pipeline.
|
||||||
|
2. **Local map development (unversioned).** Move beyond stylized venue reconstruction with
|
||||||
|
licensed OpenStreetMap and 3D building data, downloaded reference imagery for photoreal
|
||||||
|
facades, AI-assisted composition, and a Gaussian-splatting evaluation that stays in the
|
||||||
|
development pipeline unless it proves runtime-safe.
|
||||||
|
3. **Versioned release hardening.** The 0.10.0 release candidate and later semantic versions come
|
||||||
|
after the unversioned development tracks in planning order. Versions are assigned only when a
|
||||||
|
track's scope is accepted into a release.
|
||||||
|
|
||||||
## Core Gameplay Loop
|
## Core Gameplay Loop
|
||||||
|
|
||||||
1. Watch the stairs, entrance, and sidewalk.
|
1. Watch the entrance, steps, queue, and sidewalk.
|
||||||
2. Identify why each person is approaching.
|
2. Work out why each person is approaching.
|
||||||
3. Give verbal warnings and directions.
|
3. Use a gesture or short direction before escalating.
|
||||||
4. Escalate only when necessary.
|
4. Verify authorized access when the venue requires it.
|
||||||
5. Call for assistance in rare dangerous situations.
|
5. Escalate only when the person refuses, forces entry, or presents a genuine threat.
|
||||||
6. Maintain public safety, building security, and your employer’s reputation.
|
6. Record the incident and call for help when it is justified.
|
||||||
|
7. Review the shift: safety, judgment, accuracy, crowd reaction, and reputation.
|
||||||
|
|
||||||
People should not all behave the same way. Some are confused, some are rude, some are filming, and a very small number are deliberately attempting to enter.
|
A shift lasts roughly 10–15 minutes. Most people comply when approached calmly.
|
||||||
|
|
||||||
## Authorized Access
|
## Access and Verification
|
||||||
|
|
||||||
Some people are authorized to enter the building. The security guard must verify them before granting access.
|
Some people are authorized to enter. The guard may admit them by:
|
||||||
|
|
||||||
An authorized person can be admitted if either:
|
- recognizing a person the guard already knows; or
|
||||||
|
- verifying a venue-appropriate artifact: wristband, ID, ticket, credential, or guest list.
|
||||||
|
|
||||||
- The guard already knows and recognizes them.
|
Artifacts can be valid, expired, counterfeit, mismatched, missing, or ambiguous. The player inspects the details the venue asks for instead of judging by appearance.
|
||||||
- The person presents a valid event or staff wristband, which the guard checks before opening the entrance.
|
|
||||||
|
|
||||||
The wristband check should require the player to inspect details such as its color, pattern, date, or event marking. NPCs may have valid wristbands, expired wristbands, counterfeit wristbands, or no wristband at all.
|
Decisions are admit, redirect, hold, or refuse. Incorrectly denying an authorized person hurts reputation; admitting an unauthorized person is a security failure. Recognition is a player decision and is recorded as evidence.
|
||||||
|
|
||||||
The player should avoid relying on appearance or assumptions. A familiar person may still need verification if the building’s current policy requires it, while an unfamiliar person with a valid wristband may be admitted after a successful check. Incorrectly denying an authorized person harms the building’s reputation; admitting someone without authorization creates a security failure.
|
## Escalation Model
|
||||||
|
|
||||||
---
|
| Level | Player response | Intent |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 0 | Observation | Watch harmless behavior; intervene only when needed. |
|
||||||
|
| 1 | Simple deterrence / polite direction | Raise a hand, make eye contact, point to the sidewalk or check-in area, shake the head, give a short instruction. |
|
||||||
|
| 2 | Formal warning | State the rule and ask for compliance; optionally arm the body camera. |
|
||||||
|
| 3 | Blocking and positioning | Stand between the person and the door, secure the entrance, keep distance and an escape route, ask for their reason. |
|
||||||
|
| 4 | Radio for security assistance | Request a second guard, supervisor, building management, or other support. |
|
||||||
|
| 5 | Emergency response | Hold and confirm the emergency call only for an immediate threat such as a weapon, assault, forced entry, or serious threat to occupants. |
|
||||||
|
|
||||||
## Escalation System
|
At Level 2 an NPC may leave, argue, pretend not to understand, record the guard, call someone, or move closer. At Level 3 the goal is to deny access **without starting a fight**. Physical contact creates legal, employment, and public-relations consequences.
|
||||||
|
|
||||||
## Level 0: Observation
|
At Level 4 the report matters: location, description, behavior, weapons seen, and immediate danger. Exaggerated reports damage credibility. At Level 5 the call may evacuate the building, close the street, trigger a review, cost reputation, or open an investigation if unjustified. Responders may command, restrain, evacuate, or arrest; they are not a routine stronger attack.
|
||||||
|
|
||||||
The guard watches NPC behavior and decides whether intervention is needed.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
- Someone taking a photograph from the sidewalk
|
|
||||||
- A tourist reading a map
|
|
||||||
- A person sitting briefly on the edge of the steps
|
|
||||||
- Someone approaching the entrance with a delivery package
|
|
||||||
|
|
||||||
The player should avoid interrupting harmless behavior. Unnecessary confrontations reduce the guard’s performance rating.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level 1: Simple Deterrence and Polite Direction
|
|
||||||
|
|
||||||
The player can begin with a simple, nonverbal deterrent before speaking. These actions are quick and low-pressure, making them useful when someone is only approaching the steps casually or appears unsure.
|
|
||||||
|
|
||||||
Possible actions include:
|
|
||||||
|
|
||||||
- Raise an open hand to signal “stop” or “please wait”
|
|
||||||
- Make eye contact
|
|
||||||
- Point toward the public sidewalk
|
|
||||||
- Gesture toward the wristband-check area
|
|
||||||
- Shake the head gently when someone approaches a restricted entrance
|
|
||||||
|
|
||||||
If the person continues, the player uses a short verbal prompt.
|
|
||||||
|
|
||||||
Example commands:
|
|
||||||
|
|
||||||
- “Please keep the stairs clear.”
|
|
||||||
- “The entrance is for authorized guests only.”
|
|
||||||
- “You can’t remain here.”
|
|
||||||
- “Please move back to the sidewalk.”
|
|
||||||
|
|
||||||
At this stage, most NPCs comply immediately.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level 2: Formal Warning
|
|
||||||
|
|
||||||
If the person remains on the steps or continues toward the entrance, the player issues a formal warning.
|
|
||||||
|
|
||||||
Possible dialogue:
|
|
||||||
|
|
||||||
> “This is private property. You have been asked to leave. Please move away from the entrance now.”
|
|
||||||
|
|
||||||
The player may activate a visible security light or body camera. This creates a record of the interaction and can discourage repeat offenders.
|
|
||||||
|
|
||||||
At this level, the NPC may:
|
|
||||||
|
|
||||||
- Leave
|
|
||||||
- Argue
|
|
||||||
- Pretend not to understand
|
|
||||||
- Start recording the guard
|
|
||||||
- Call someone else
|
|
||||||
- Move closer to the door
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level 3: Blocking and Physical Positioning
|
|
||||||
|
|
||||||
The guard moves into a defensive position between the NPC and the building.
|
|
||||||
|
|
||||||
Gameplay actions:
|
|
||||||
|
|
||||||
- Stand in front of the entrance
|
|
||||||
- Point toward the public sidewalk
|
|
||||||
- Lock or secure the door
|
|
||||||
- Request the person’s reason for entry
|
|
||||||
- Keep distance while maintaining a clear escape route
|
|
||||||
- Use a flashlight or radio warning tone at night
|
|
||||||
|
|
||||||
The player should not automatically shove or strike people. Physical contact creates legal, employment, and public-relations consequences.
|
|
||||||
|
|
||||||
This level is about **denying access without creating a fight**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level 4: Radio for Security Assistance
|
|
||||||
|
|
||||||
If the person refuses to leave, attempts to force the door, threatens staff, or repeatedly returns, the player uses the radio.
|
|
||||||
|
|
||||||
Possible assistance:
|
|
||||||
|
|
||||||
- A second security guard
|
|
||||||
- Building management
|
|
||||||
- Police dispatch
|
|
||||||
- Nearby security personnel
|
|
||||||
|
|
||||||
The radio call takes time, so the player must continue monitoring the person while waiting. The player can choose what information to report:
|
|
||||||
|
|
||||||
- Location
|
|
||||||
- Description
|
|
||||||
- Behavior
|
|
||||||
- Whether weapons have been seen
|
|
||||||
- Whether anyone is in immediate danger
|
|
||||||
|
|
||||||
Incorrect or exaggerated reports damage the guard’s credibility.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Level 5: Emergency Response
|
|
||||||
|
|
||||||
This is reserved for immediate threats, such as:
|
|
||||||
|
|
||||||
- A person displaying a weapon
|
|
||||||
- An attempted forced entry while people are inside
|
|
||||||
- An assault on the guard or another person
|
|
||||||
- A serious threat against occupants
|
|
||||||
- A violent struggle that cannot be safely disengaged
|
|
||||||
|
|
||||||
The player presses and holds a clearly marked **Emergency Radio** button. A confirmation prompt prevents accidental activation.
|
|
||||||
|
|
||||||
The call brings an off-duty law-enforcement officer or armed emergency responder to the location. This character has greater authority and can control a dangerous situation, but the call has serious consequences:
|
|
||||||
|
|
||||||
- The building may be evacuated
|
|
||||||
- The street may be closed
|
|
||||||
- The guard’s actions are reviewed
|
|
||||||
- The building loses reputation
|
|
||||||
- The player may face an investigation if the call was unjustified
|
|
||||||
- The officer may use force only when the game’s threat assessment supports it
|
|
||||||
|
|
||||||
The officer should not function as a convenient “stronger attack.” Their role is to handle a crisis the player cannot safely manage. In most scenarios, their arrival results in commands, restraint, evacuation, or arrest rather than automatic gunfire.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## NPC Behavior Types
|
## NPC Behavior Types
|
||||||
|
|
||||||
## Tourists
|
- **Tourists:** take photos, sit on steps, drift toward restricted doors; usually respond well to polite directions.
|
||||||
|
- **Street performers:** may block stairs or argue when moved; can be redirected to a permitted area.
|
||||||
- Take photos
|
- **Influencers and filmmakers:** film the guard, test boundaries, and create public-relations risk.
|
||||||
- Sit on steps
|
- **Confused visitors:** may have appointments or genuinely believe the building is public; reward patient explanation.
|
||||||
- Wander toward restricted doors
|
- **Intoxicated pedestrians:** move unpredictably, ignore instructions, and need extra distance or assistance.
|
||||||
- Usually respond well to polite directions
|
- **Trespassers:** test entrances, use distractions, and may return after being told to leave.
|
||||||
|
- **Violent threats:** rare, escalate quickly, and justify emergency response only when behavior shows immediate danger.
|
||||||
## Street Performers
|
- **People in mental-health crisis:** may loiter, behave unpredictably, and respond poorly to aggression; require patience and careful de-escalation. The setting may refer to a 51/50 hold, but the game should present the person respectfully, not as an automatic threat.
|
||||||
|
|
||||||
- May block stairs
|
|
||||||
- May become argumentative if moved
|
|
||||||
- Can be redirected to a permitted area
|
|
||||||
|
|
||||||
## Influencers and Filmmakers
|
|
||||||
|
|
||||||
- Film the guard
|
|
||||||
- Test boundaries for content
|
|
||||||
- May accuse the guard of overreacting
|
|
||||||
- Create public-relations risk
|
|
||||||
|
|
||||||
## Confused Visitors
|
|
||||||
|
|
||||||
- Have appointments or directions
|
|
||||||
- May genuinely believe the building is public
|
|
||||||
- Reward patient explanations
|
|
||||||
|
|
||||||
## Intoxicated Pedestrians
|
|
||||||
|
|
||||||
- Move unpredictably
|
|
||||||
- May ignore instructions
|
|
||||||
- Require additional distance and assistance
|
|
||||||
|
|
||||||
## Trespassers
|
|
||||||
|
|
||||||
- Repeatedly test entrances
|
|
||||||
- Use distractions
|
|
||||||
- May return after being told to leave
|
|
||||||
|
|
||||||
## Violent Threats
|
|
||||||
|
|
||||||
- Rare
|
|
||||||
- Escalate quickly
|
|
||||||
- Trigger the emergency response system only when their behavior indicates immediate danger
|
|
||||||
|
|
||||||
## 51/50s
|
|
||||||
|
|
||||||
Crazy Homeless Individuals may be referred to as "51/50s" in the context of the game, indicating a person who may be experiencing a mental health crisis and could pose a potential threat to themselves or others.
|
|
||||||
|
|
||||||
- May loiter near entrances
|
|
||||||
- Can be unpredictable in behavior
|
|
||||||
- Often respond poorly to aggressive confrontation
|
|
||||||
- Require careful de-escalation and patience
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Special Systems
|
## Special Systems
|
||||||
|
|
||||||
## Reputation Meter
|
### Reputation
|
||||||
|
|
||||||
The player is evaluated on:
|
The shift evaluates peaceful resolutions, response time, radio accuracy, unnecessary confrontations, public complaints, property damage, entrance security, and whether assistance was justified. Calling armed help too often scores poorly even when no one is hurt.
|
||||||
|
|
||||||
- Number of incidents resolved peacefully
|
### Evidence and Body Camera
|
||||||
- Response time
|
|
||||||
- Accuracy of radio reports
|
|
||||||
- Number of unnecessary confrontations
|
|
||||||
- Public complaints
|
|
||||||
- Property damage
|
|
||||||
- Whether the entrance remained secure
|
|
||||||
|
|
||||||
A player who calls armed assistance too often should score poorly, even if no one was injured.
|
Interactions are recorded automatically. The body camera is a real state the player can toggle; a formal warning also arms it. The shift review uses the recorded events and evidence to show whether the response was justified.
|
||||||
|
|
||||||
## Evidence and Body Camera
|
### Crowd Reaction
|
||||||
|
|
||||||
Interactions are automatically recorded. After each shift, the player reviews incidents and sees whether their escalation was justified.
|
Nearby pedestrians react to the guard. Calm professionalism attracts little attention; aggression draws a crowd; visible weapons or responders can cause panic. Good de-escalation keeps the boulevard moving.
|
||||||
|
|
||||||
This encourages players to think before acting.
|
### Radio Limits
|
||||||
|
|
||||||
## Public Crowd Reaction
|
The emergency radio has a cooldown, and the call requires a short report. Assistance takes time to arrive, so the guard must keep monitoring the situation.
|
||||||
|
|
||||||
Nearby pedestrians react to the guard’s behavior:
|
|
||||||
|
|
||||||
- Calm professionalism attracts little attention
|
|
||||||
- Aggressive behavior creates a crowd
|
|
||||||
- Visible weapons or emergency responders cause panic
|
|
||||||
- Good de-escalation keeps the boulevard moving normally
|
|
||||||
|
|
||||||
## Limited Radio Battery or Cooldown
|
|
||||||
|
|
||||||
The emergency radio should not be infinitely available. A call has a cooldown and may require the player to give a short report first.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Shift Structure
|
## Shift Structure
|
||||||
|
|
||||||
Each shift lasts 10–15 minutes.
|
- **Early:** harmless tourists, delivery workers, people resting on the steps.
|
||||||
|
- **Midday:** heavier crowds, more entry attempts, more filming.
|
||||||
|
- **Evening:** lower light, more intoxicated pedestrians and aggressive groups.
|
||||||
|
- **Late:** a rare serious incident may test whether the player recognizes a real threat without overreacting to ordinary behavior.
|
||||||
|
|
||||||
### Early Shift
|
## Outcomes
|
||||||
|
|
||||||
Mostly harmless tourists, delivery workers, and people sitting on the stairs.
|
A successful shift keeps the building secure, resolves most incidents without force, keeps public access clear, makes justified emergency calls, avoids bystander injuries, and follows policy.
|
||||||
|
|
||||||
### Midday
|
A poor shift involves excessive force, confronting innocent people, ignoring a real threat, false reports, allowing unauthorized entry, causing a crowd or panic, or behaving recklessly even if the door stayed locked.
|
||||||
|
|
||||||
Crowds become heavier. More people attempt to enter the building or film interactions.
|
## Venues
|
||||||
|
|
||||||
### Evening
|
### El Capitan Entertainment Centre (6840 Hollywood Blvd)
|
||||||
|
|
||||||
Lighting decreases. Intoxicated pedestrians and aggressive groups become more common.
|
The original scenario: the historic Masonic Temple / El Capitan Entertainment Centre, with six Ionic columns, eight stone steps, the Hollywood Walk of Fame sidewalk, neighbouring theatre and retail frontage, and the four-lane boulevard. Tourists, performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people in crisis, and rare violent threats approach from the street.
|
||||||
|
|
||||||
### Late Shift
|
Authorized people are recognized or present a valid wristband. Wristbands vary by color, pattern, date, and event marking, and may be valid, expired, counterfeit, or missing.
|
||||||
|
|
||||||
A rare serious incident may occur, testing whether the player recognizes a genuine threat instead of overreacting to ordinary behavior.
|
### The Joke Shop
|
||||||
|
|
||||||
---
|
A Sunset Strip comedy club inspired by The Comedy Store at 8433 Sunset Blvd: a
|
||||||
|
low black hall under a deep, signature-covered canopy, a circular blade sign,
|
||||||
|
red velvet curtains and the dry hillside rising behind it. The door person
|
||||||
|
checks IDs, tickets, reservations, guest-list status, and screens guests with a
|
||||||
|
handheld wand under venue policy.
|
||||||
|
|
||||||
## Win and Loss Conditions
|
The wand does **not** identify a weapon automatically. Keys, belts, and phones can trigger false alarms; the player must ask the guest to identify the item and apply procedure. A guest with valid credentials can still require assistance if they threaten staff or patrons.
|
||||||
|
|
||||||
## Successful Shift
|
Typical events:
|
||||||
|
|
||||||
- Building remains secure
|
- a busy weekend show creates a long line;
|
||||||
- Most incidents are resolved without physical force
|
- a performer arrives through the guest entrance;
|
||||||
- Public access remains clear
|
- a guest has a reservation but no ID;
|
||||||
- Emergency calls are justified
|
- a fake or borrowed ID appears;
|
||||||
- No bystanders are injured
|
- a wand alert comes from keys or a belt;
|
||||||
- The player follows company policy
|
- a guest refuses screening but insists on entering;
|
||||||
|
- someone tries to follow an authorized person through the door;
|
||||||
|
- a late audience member arrives during the performance.
|
||||||
|
|
||||||
## Poor Performance
|
Joke Shop escalation follows the common ladder: direction, explanation, repeat request, refusal, manager/security assistance, emergency only for immediate danger.
|
||||||
|
|
||||||
- Excessive use of force
|
### Hollywood Boulevard Late Night TV Studio
|
||||||
- Repeatedly confronting innocent people
|
|
||||||
- Ignoring a real threat
|
|
||||||
- Making false radio reports
|
|
||||||
- Allowing repeated unauthorized entry
|
|
||||||
- Causing a crowd or panic
|
|
||||||
|
|
||||||
A shift can be technically “secure” but still receive a poor rating if the guard behaves recklessly.
|
A busy studio entrance with audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, influencers, and the same range of street behavior as the building scenario.
|
||||||
|
|
||||||
---
|
Staff and guests are recognized or present a wristband, credential, ticket, guest-list confirmation, or other approved marker. The player keeps the steps clear, protects arrivals and equipment, manages filming boundaries, watches for tailgating, and calls for help only when there is immediate danger.
|
||||||
|
|
||||||
## Venues and Scenarios
|
Typical events:
|
||||||
|
|
||||||
The game should support multiple venues, each with its own access rules, crowd patterns, equipment, and escalation procedures. The core gameplay remains the same: observe, verify access, communicate clearly, and use the lowest effective level of escalation.
|
- a crowd gathers for a celebrity arrival;
|
||||||
|
- tourists block the entrance for photographs;
|
||||||
|
- a performer sets up in the audience queue;
|
||||||
|
- an influencer ignores the filming boundary;
|
||||||
|
- a confused visitor believes the studio is open;
|
||||||
|
- an intoxicated pedestrian approaches the stage door;
|
||||||
|
- a trespasser blends into an audience group;
|
||||||
|
- an authorized guest arrives without a wristband;
|
||||||
|
- someone presents a counterfeit credential;
|
||||||
|
- a violent threat appears during a crowded arrival.
|
||||||
|
|
||||||
## The Joke Shop
|
## Presentation and Controls
|
||||||
|
|
||||||
**The Joke Shop** is a comedy club scenario where the player works as a door person at the entrance. The player is responsible for checking identification, confirming that guests are attending the correct show, and screening guests for weapons with a handheld security wand.
|
The game is first-person: WASD and mouse look, a focus cone on nearby people, a billboarded focus circle, `Tab`/mouse-wheel cycling for aim-free selection, and a radial action menu opened with left click or `Space`. `Shift` is precision walk. Gamepad input is supported, and keys/buttons can be remapped in Settings.
|
||||||
|
|
||||||
### Primary Responsibilities
|
The action wheel prioritizes de-escalation: Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio. Emergency stays on `R` and is not a wheel slice. `W` is walk, never the wand; `C` is the optional wand shortcut.
|
||||||
|
|
||||||
- Check each guest’s government-issued ID where required.
|
The visual direction is readable stylized realism:
|
||||||
- Confirm that the guest meets the venue’s age requirement.
|
|
||||||
- Verify that the ID appears valid and belongs to the person presenting it.
|
|
||||||
- Check tickets, reservations, or guest-list status.
|
|
||||||
- Use the handheld wand according to venue policy.
|
|
||||||
- Direct guests through the entrance without blocking the sidewalk.
|
|
||||||
- Refuse entry when a guest has an invalid ID, no valid admission, or a prohibited item.
|
|
||||||
|
|
||||||
### Guest Outcomes
|
- **Character direction:** 8 skinned NPC variants, 18 gear pieces and 20 street/venue props, with four crowd-variety variants prototyped. The generator-first expansion is the active character track ([ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md)); Quaternius is a reference and MakeHuman is deferred to a local pipeline.
|
||||||
|
- **Realism pass:** AI-assisted per-phase skyline panoramas, v2 surface tiles with normal maps, wet asphalt at night, a warm day haze, phase-specific sun/exposure/fog, a visible flashlight beam, and denser foliage.
|
||||||
|
- **Local map direction:** the venues are currently stylized reconstructions. The local-map track evaluates licensed OpenStreetMap/3D building data, licensed reference photography, AI-assisted composition and Gaussian splatting as a development tool; online data and splat rendering are not runtime dependencies.
|
||||||
|
- **References and QA:** runtime UI art lives in `assets/images/ui/`; reference/art-direction sets live in `docs/screens/designs/` and `docs/screens/concepts/`; captures live in `docs/screenshots/`; realism runs live in `docs/screens/realism/`. `screen_designs.py compare/judge` and `tools/check_screenshots.sh` guard drift.
|
||||||
|
- **Storage convention:** see [ADR-0014](docs/adr/0014-runtime-image-root.md). Never overwrite an existing image; new outputs get a new path or `-vN` suffix.
|
||||||
|
|
||||||
A guest may have:
|
The active planning order — unversioned character and local-map development first, then the versioned 0.10.0 release-candidate hardening and later releases — is tracked in [`TODO.md`](TODO.md); this plan stays at the product/design level.
|
||||||
|
|
||||||
- A valid ID and ticket
|
Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md), [ADR-0009](docs/adr/0009-radial-action-menu.md), [ADR-0010](docs/adr/0010-procedural-npc-presentation.md), [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md), [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md), [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md), [ADR-0015](docs/adr/0015-npc-model-variety-sourcing.md).
|
||||||
- A valid ID but no ticket or reservation
|
|
||||||
- An expired, damaged, or questionable ID
|
|
||||||
- An ID that does not match the guest
|
|
||||||
- A prohibited item detected by the wand
|
|
||||||
- A harmless item that causes a false alarm
|
|
||||||
- No ID when identification is required
|
|
||||||
|
|
||||||
The player must make decisions based on the venue’s rules and observable evidence, not on a guest’s appearance or attitude. A calm guest with a valid ID should be admitted efficiently, while an aggressive guest with valid credentials may still require assistance if they threaten staff or other patrons.
|
|
||||||
|
|
||||||
### Joke Shop Escalation
|
|
||||||
|
|
||||||
1. **Nonverbal direction:** Raise a hand, point to the ID-check area, or gesture for the guest to wait.
|
|
||||||
2. **Routine explanation:** Explain the ID, ticket, or wand-check requirement.
|
|
||||||
3. **Repeat request:** Clearly state what is missing or what must happen before entry.
|
|
||||||
4. **Refusal of entry:** Keep the guest outside and direct them away from the entrance.
|
|
||||||
5. **Manager or security assistance:** Call for a supervisor or another staff member when a guest argues, refuses screening, or blocks the line.
|
|
||||||
6. **Emergency response:** Call emergency services only for an immediate threat, such as a weapon, assault, or serious attempt to force entry.
|
|
||||||
|
|
||||||
The handheld wand should not automatically identify an item as a weapon. The player must interpret the alert, ask the guest to identify the item, and follow venue procedure. The goal is to create a believable screening challenge while keeping the emphasis on communication and proportionate responses.
|
|
||||||
|
|
||||||
### Scenario Events
|
|
||||||
|
|
||||||
- A busy weekend comedy show creates a long line.
|
|
||||||
- A performer arrives through the guest entrance and must be recognized or verified.
|
|
||||||
- A guest forgets their ID but appears on the reservation list.
|
|
||||||
- A fake or borrowed ID is presented.
|
|
||||||
- A wand alert comes from keys, a belt buckle, or a phone.
|
|
||||||
- A guest refuses the screening but insists on entering.
|
|
||||||
- A disruptive guest attempts to follow another person through the door.
|
|
||||||
- A late-arriving audience member tries to enter during a performance.
|
|
||||||
|
|
||||||
## Hollywood Boulevard Late Night TV Studio
|
|
||||||
|
|
||||||
This scenario takes place outside a late-night television studio on Hollywood Boulevard. The guard manages the front steps, studio entrance, guest arrivals, deliveries, audience members, and the public crowd gathered around the building.
|
|
||||||
|
|
||||||
The studio encounters all of the NPC types described in the game plan:
|
|
||||||
|
|
||||||
- **Tourists** stopping to take photos or watch arrivals
|
|
||||||
- **Street performers** occupying the steps or performing near the entrance
|
|
||||||
- **Influencers and filmmakers** recording the guard, guests, or celebrity arrivals
|
|
||||||
- **Confused visitors** looking for the wrong entrance or trying to attend a show without understanding the access rules
|
|
||||||
- **Intoxicated pedestrians** approaching the entrance or disrupting the crowd
|
|
||||||
- **Trespassers** testing the doors, trying to follow authorized guests, or returning after being directed away
|
|
||||||
- **Violent threats**, which are rare but require careful recognition and emergency escalation
|
|
||||||
|
|
||||||
The studio also has authorized guests and staff. They must either be recognized by the guard or present a valid wristband, credential, guest-list confirmation, or other approved access marker. The player must check these credentials without holding up the audience line or allowing unauthorized people to enter.
|
|
||||||
|
|
||||||
### Studio Responsibilities
|
|
||||||
|
|
||||||
- Keep the front steps and entrance clear.
|
|
||||||
- Direct tourists and performers away from restricted areas.
|
|
||||||
- Check wristbands, credentials, tickets, or guest-list status.
|
|
||||||
- Admit authorized staff, performers, guests, and audience members.
|
|
||||||
- Manage influencers and filmmakers without unnecessarily obstructing lawful filming.
|
|
||||||
- Protect celebrity arrivals and production equipment from crowding.
|
|
||||||
- Coordinate with studio staff, production assistants, and additional security guards.
|
|
||||||
- Watch for attempts to follow authorized people through the entrance.
|
|
||||||
- Call for emergency assistance only when there is an immediate threat.
|
|
||||||
|
|
||||||
### Studio Scenario Events
|
|
||||||
|
|
||||||
- A crowd gathers to watch a celebrity arrive.
|
|
||||||
- Tourists stop on the steps and block the entrance for photographs.
|
|
||||||
- A street performer sets up in front of the audience queue.
|
|
||||||
- An influencer repeatedly ignores the restricted filming boundary.
|
|
||||||
- A confused visitor believes the studio is open to the public.
|
|
||||||
- An intoxicated pedestrian wanders toward the stage door.
|
|
||||||
- A trespasser tries to blend into an audience group.
|
|
||||||
- An authorized guest arrives without their wristband and must be verified another way.
|
|
||||||
- Someone presents a counterfeit wristband or credential.
|
|
||||||
- A violent threat appears during a crowded arrival, requiring the player to protect the entrance while calling for assistance.
|
|
||||||
|
|
||||||
The scenario should test the player’s ability to distinguish ordinary Hollywood Boulevard activity from a genuine security problem. The best solution is usually a simple gesture, clear direction, or credential check rather than immediate escalation.
|
|
||||||
|
|
||||||
Future venues can reuse this structure while changing the rules, equipment, staff roles, and types of access decisions.
|
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
## Engine: Godot 4
|
- **Engine:** Godot 4.7.2, GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
|
||||||
|
- **Language:** GDScript.
|
||||||
|
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
|
||||||
|
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
|
||||||
|
- **NPC behavior:** lightweight custom finite state machines driven by `NpcProfile` resources.
|
||||||
|
- **UI/audio:** Godot `Control` nodes, themes, procedural audio, and JSON-backed localized strings.
|
||||||
|
- **Persistence:** JSON in `user://` for settings and shift history.
|
||||||
|
- **Testing:** custom headless runner (`src/test/test_runner.gd`); GUT was evaluated and not adopted. Python tooling tests cover the asset/screenshot pipelines.
|
||||||
|
- **Source control/CI:** git on Gitea; `.gitea/workflows/build.yml` runs headless checks and builds/publishes releases on tags.
|
||||||
|
- **Targets:** Windows, Linux, macOS, and Web. Release artifacts include portables, an NSIS installer, an AppImage, a Web zip, and an optional Desktop HQ zip (Forward+ volumetric lighting; Vulkan required).
|
||||||
|
|
||||||
The game is built with the Godot Engine 4.x editor. Godot was chosen for its free and open-source license, built-in 3D rendering, navigation, animation, audio, and UI systems, and its low weight for fast prototyping and iteration.
|
## Versioning and Delivery
|
||||||
|
|
||||||
## Language: GDScript
|
`config/version` in `project.godot` is the single version source (currently `0.10.0-rc.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/): every major, minor and patch increment needs a changelog entry, a local `tools/build_releases.sh` build, and artifact/checksum verification before tagging. Unversioned development tracks do not receive a version until their scope enters a release. See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
|
||||||
|
|
||||||
Gameplay logic is written in GDScript. It is tightly integrated with the engine, fast to iterate on, and avoids an external build toolchain for the prototype phase.
|
|
||||||
|
|
||||||
## Architecture Mapping
|
|
||||||
|
|
||||||
The venue-driven architecture maps onto Godot as follows:
|
|
||||||
|
|
||||||
- **Nodes and scenes:** Each major system (`ShiftCoordinator`, `NPCController`, `InteractionSystem`, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`, `ShiftReview`) is a Godot node or scene.
|
|
||||||
- **Scenarios as resources:** `VenueScenario` and content such as `NpcProfile`, `Dialogue`, `EventPool`, and `AccessPolicy` are defined as custom Godot `Resource` types so venue content is data-driven and inspectable in the editor.
|
|
||||||
- **Navigation:** `NavigationRegion3D` and `NavigationAgent3D` drive NPC and player movement.
|
|
||||||
- **NPC behavior:** Lightweight custom finite state machines built on the `NPCController` node, with behavior traits coming from `NpcProfile` resources.
|
|
||||||
- **UI:** Godot `Control` nodes and themes for prompts, access inspection, radio reports, dialogue, timers, and the shift review screen.
|
|
||||||
- **Audio:** Godot audio buses and `AudioStreamPlayer` nodes for voices, crowd noise, radio, and environment sound.
|
|
||||||
|
|
||||||
## Content and Data
|
|
||||||
|
|
||||||
- Scenario and entity configuration uses typed Godot `Resource` files (`.tres`), created either in the editor or via scripts.
|
|
||||||
- Localized dialogue and text are stored in JSON files when they need to be editable outside the editor.
|
|
||||||
- Save data and shift results use JSON in Godot's `user://` directory.
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
- Unit and scenario tests use a lightweight custom headless runner
|
|
||||||
(`src/test/test_runner.gd`). GUT was evaluated but requires the editor plugin.
|
|
||||||
- Tests run in headless mode so rules, access verification, escalation, and scoring can be verified without rendering or user input.
|
|
||||||
|
|
||||||
## Version Control and CI
|
|
||||||
|
|
||||||
- Source is tracked with git.
|
|
||||||
- Gitea Actions (`.gitea/workflows/build.yml`) runs headless Godot tests on push/PR and exports
|
|
||||||
Linux/Windows/macOS desktop builds plus the NSIS installer and AppImage on tags.
|
|
||||||
|
|
||||||
## Planned Commands
|
|
||||||
|
|
||||||
The following commands apply once the Godot project is scaffolded:
|
|
||||||
|
|
||||||
- Open the editor: `godot --editor --path .`
|
|
||||||
- Run the game: `godot --path .`
|
|
||||||
- Run tests headlessly: `godot --headless --path . res://src/test/test_runner.tscn`
|
|
||||||
|
|
||||||
## Export Targets
|
|
||||||
|
|
||||||
Desktop is the first target: Windows, Linux, and macOS. A Web export now ships as well
|
|
||||||
(non-threaded, static hosting); it is published with each release as a zip.
|
|
||||||
|
|
||||||
## Player Control, Focus, and Action Menu (next pass)
|
|
||||||
|
|
||||||
The prototype already walks and looks in first person, but the control scheme fights itself and targeting is a hairline. This pass replaces that with three things that belong together: solid locomotion, a visible focus on a person, and a round action menu for what to do with them.
|
|
||||||
|
|
||||||
Decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md) locomotion and input layers, [ADR-0008](docs/adr/0008-cone-focus-and-head-ring.md) cone focus and focus circle, [ADR-0009](docs/adr/0009-radial-action-menu.md) radial action menu, [ADR-0010](docs/adr/0010-procedural-npc-presentation.md) procedural NPC presentation.
|
|
||||||
|
|
||||||
### What is wrong today
|
|
||||||
|
|
||||||
- `W` is walk-forward in the input map and wand-screening in `GameManager._handle_key`. Walking at someone with a wand venue fires the wand.
|
|
||||||
- `A` / `D` are strafe and also allow/deny during inspection.
|
|
||||||
- `Q` is polite direction and is also bound as `cancel`.
|
|
||||||
- Focus is an 8 m physics ray from the camera. Missing a capsule by a few pixels clears the target. There is no mark in the world that you have someone.
|
|
||||||
- NPC bodies are colored capsules with props. They read as markers, not people.
|
|
||||||
- Actions live on number keys `1`–`6` plus `Q` / `E` / `W` / `R`. That is a cheat-sheet, not a verb you pick while looking at a person.
|
|
||||||
- `Esc` only toggles mouse capture. There is no "I changed my mind" for an action in progress.
|
|
||||||
|
|
||||||
### Movement and look
|
|
||||||
|
|
||||||
Keep first-person WASD + mouse look. Fix the feel and stop stealing those keys.
|
|
||||||
|
|
||||||
- Body yaw from mouse X, head pitch from mouse Y, pitch clamped (already `-80` to `80`).
|
|
||||||
- Move relative to body yaw only (already). Add short acceleration / deceleration so starts and stops are not instant.
|
|
||||||
- Gravity only when `not is_on_floor()`; `floor_snap_length` so the steps work.
|
|
||||||
- Mouse look runs only while `MOUSE_MODE_CAPTURED` and no modal UI is open (radial, inspection, wand, radio, shift review).
|
|
||||||
- Walk speed stays around 3.2 m/s. No sprint, no crouch in this pass.
|
|
||||||
- While the radial is open: freeze look and WASD so `A` / `D` can cycle the menu. Recapture the mouse when the menu closes.
|
|
||||||
- `Esc` with a modal open closes that modal and does nothing else. `Esc` with nothing open keeps the current capture/release toggle.
|
|
||||||
|
|
||||||
Equipment stays on its own keys because it is not about a person: `G` flashlight, `L` door lock, `Tab` cycle nearby people, `V` venue (debug), `F` debug overlay. `R` stays the dedicated emergency radio (hold-to-confirm on the existing panel). Those do not go on the wheel.
|
|
||||||
|
|
||||||
Wand leaves `W`. It is a slice on the wheel (greyed when the venue has no wand) and an optional extra key that is not WASD, suggested `C`.
|
|
||||||
|
|
||||||
### Focus area
|
|
||||||
|
|
||||||
Replace the hairline ray as the primary picker.
|
|
||||||
|
|
||||||
- A **focus cone** in front of the camera: people within about 10 m whose head projects inside a screen-space circle around the crosshair (about 90 px / 10 degrees).
|
|
||||||
- If several heads sit in the circle, pick the one closest to the center, then the nearer one if tied.
|
|
||||||
- The person must be in front (dot with camera forward > 0) and not fully occluded by the building. A short ray to the head is enough for occlusion.
|
|
||||||
- `Tab` still cycles people inside 12 m as the aim-free path. Cycling sets the same focused person the cone would.
|
|
||||||
- Clearing: look away until the head leaves the circle for a few frames (small grace so a bob does not drop them), or they walk out of range.
|
|
||||||
|
|
||||||
### Focus circle
|
|
||||||
|
|
||||||
When a person is in focus, draw a blue, semi-transparent circle in front of their face.
|
|
||||||
|
|
||||||
- Attach to the avatar `Head` node, just in front of the face, billboarded to the camera so it stays a circle on screen.
|
|
||||||
- Slow spin is fine; no ping-pong scale spam.
|
|
||||||
- Idle focus: blue, semi-transparent, modest size. Radial open on that person: brighter, slightly larger.
|
|
||||||
- Optional small name under the circle (`display_name` only, not the archetype cheat `Violent Threat` in the world). The existing HUD target line can keep the archetype for the prototype.
|
|
||||||
- One circle at a time. Everyone else has none.
|
|
||||||
|
|
||||||
Implementation sketch: a thin unshaded `MeshInstance3D` circle (flat disc) in front of the face on the avatar, toggled from `GuardController` / `GameManager` when focus changes. Screen-space fallback (unproject head, draw a `Control` circle) is acceptable if the 3D circle z-fights on hats.
|
|
||||||
|
|
||||||
### Round action HUD
|
|
||||||
|
|
||||||
A doughnut / pie menu centered on the screen, opened on the focused person.
|
|
||||||
|
|
||||||
**Open**
|
|
||||||
|
|
||||||
- Left mouse button, or `Space`, while someone is in focus and no other modal is open.
|
|
||||||
- If nobody is in focus, log the existing "aim first" line and do not open.
|
|
||||||
- The click that opens the menu must not also pick a slice.
|
|
||||||
|
|
||||||
**While open**
|
|
||||||
|
|
||||||
- Mouse becomes visible. Look and walk freeze.
|
|
||||||
- Center of the doughnut shows the focused person's `display_name`.
|
|
||||||
- Slices, clockwise from the top, de-escalation first:
|
|
||||||
1. Raise hand (stop / wait)
|
|
||||||
2. Point away
|
|
||||||
3. Head shake
|
|
||||||
4. Polite direction (old `Q`)
|
|
||||||
5. Inspect access (old `E`)
|
|
||||||
6. Wand (grey if the venue has no wand)
|
|
||||||
7. Formal warning
|
|
||||||
8. Block
|
|
||||||
9. Radio assist
|
|
||||||
- Emergency is **not** on the wheel (`R` only).
|
|
||||||
- Highlight follows the mouse angle when the cursor is over the ring. `Left` / `Right` or `A` / `D` step the highlight. Wrap around.
|
|
||||||
|
|
||||||
**Confirm**
|
|
||||||
|
|
||||||
- Click a slice: that action runs, menu closes, mouse recaptured.
|
|
||||||
- `Space` while a slice is highlighted: same.
|
|
||||||
- Inspect or wand: close the wheel, then open the existing inspect / wand panel. Allow / deny on that panel stay `A` / `D` (walk is frozen only while the wheel is up; once the inspect panel is open, WASD can move again, so allow/deny on `A` / `D` remains a press handler and must ignore repeats / echo, which it already does). Safer: keep walk frozen for inspect/wand too, until the panel closes. Prefer freeze until the whole interaction ends.
|
|
||||||
- Radio assist: close the wheel, open the existing radio panel.
|
|
||||||
|
|
||||||
**Cancel**
|
|
||||||
|
|
||||||
- `Esc` or right mouse button: hide the menu, no action, no recorder event, recapture mouse.
|
|
||||||
- Focus and the focus circle stay as they were.
|
|
||||||
|
|
||||||
Number keys `1`–`6` may remain as shortcuts that skip the wheel so a smoke-test script still works. They must not fire while the wheel is open (the wheel owns `A` / `D` / `Space`). Document both in the README.
|
|
||||||
|
|
||||||
### NPC display
|
|
||||||
|
|
||||||
Stay on the procedural capsule rig (no Mixamo / GLB dependency this pass). Make them read as people at conversation distance.
|
|
||||||
|
|
||||||
- Neck between torso and head; shoes; simple hair cap (color from seed); two dark eye spheres on the face so a head has a front.
|
|
||||||
- Keep archetype props (camera, box, hat, sign, bag). Keep height / brightness variation from the visual seed.
|
|
||||||
- Collision capsule matches the scaled height so the focus ray / cone hits the body you see.
|
|
||||||
- `Head` stays a named node other systems can find (`get_node("Rig/Head")`) for the ring and the cone.
|
|
||||||
- Walk bob and the "look at the guard when noticed" cue stay.
|
|
||||||
- Do not put the internal type name (`Trespasser`, `Violent Threat`) on the body. The player should judge from clothes, props, and behavior. The debug overlay (`F`) can still print the type.
|
|
||||||
|
|
||||||
AI textures in `assets/textures/ai/` stay out of this pass unless a specific map (shirt, hair) is already the right size.
|
|
||||||
|
|
||||||
### Input map (target)
|
|
||||||
|
|
||||||
| Action | Bind |
|
|
||||||
| --- | --- |
|
|
||||||
| Walk | WASD / arrows (arrows **do not** walk while the wheel is open; they step the highlight) |
|
|
||||||
| Look | Mouse, captured |
|
|
||||||
| Open / confirm action menu | LMB, `Space` |
|
|
||||||
| Cancel menu | RMB, `Esc` |
|
|
||||||
| Step highlight | `A` / `D`, left / right arrows |
|
|
||||||
| Emergency radio | `R` |
|
|
||||||
| Flashlight | `G` |
|
|
||||||
| Door lock | `L` |
|
|
||||||
| Cycle nearby people | `Tab` |
|
|
||||||
| Wand shortcut | `C` (not `W`) |
|
|
||||||
| Inspect shortcut | `E` still allowed when the wheel is closed |
|
|
||||||
|
|
||||||
### Files this pass is expected to touch
|
|
||||||
|
|
||||||
- `src/game/guard_controller.gd` — cone focus, no look while modal, accel, floor snap.
|
|
||||||
- `src/game/npc_avatar.gd` — face / hair / neck, head marker, ring toggle.
|
|
||||||
- `src/game/ui/action_radial.gd` — new Control, `_draw` doughnut, slice pick.
|
|
||||||
- `src/game/ui/hud.gd` — host the radial; stop teaching number-key verbs as the only path.
|
|
||||||
- `src/game/game_manager.gd` — input routing, freeze flags, open/confirm/cancel.
|
|
||||||
- `project.godot` — input map.
|
|
||||||
- `src/core/strings.gd` — controls line, aim-first, no new tone-of-voice.
|
|
||||||
- `src/test/tests/test_focus_and_radial.gd` — cone pick, wrap, cancel emits nothing, `W` is not wand.
|
|
||||||
- README controls table and smoke checklist.
|
|
||||||
|
|
||||||
## Rendering, Models, and Selection (v0.3.0 pass)
|
|
||||||
|
|
||||||
Decisions: [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md) aim-free selection and precision walk, [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md) surface materials and generated props.
|
|
||||||
|
|
||||||
The blockout look and the aim-first selection model were the two biggest gaps left by the control pass. This pass closes them without changing the game's rules.
|
|
||||||
|
|
||||||
**Look.** Surfaces get real profiles instead of stock materials: brick is rough and finely tiled, concrete is rougher still, asphalt is smoother and damp-looking, glass is smooth and slightly metallic. The environment gains ACES tonemapping, soft glow, aerial fog and a mild grade, all driven by the same per-phase configuration that already moves the sun and sky. The facade gains framed windows that light up after dark, a stone base course, door trim and handles. Street furniture becomes real geometry: bollards, benches, bins, planters, newspaper boxes and a hydrant, built as `.glb` props by `tools/model_pipeline.py` with a procedural fallback. NPCs get per-role clothing palettes, small role accessories (cap, hood, backpack, sunglasses, lanyard), hands, shoes, and an arm/leg walk swing. The rule stays: the player judges people from clothes, props and behaviour, never from an archetype label.
|
|
||||||
|
|
||||||
**Models.** Prop meshes are deterministic primitives, so the build works offline. An image model can supply the per-prop colour palette from a concept sheet; that is the only AI influence on geometry, and it is optional. Colours are converted from sRGB to linear before they reach glTF, because glTF factors are linear.
|
|
||||||
|
|
||||||
**Selection.** The focus cone ranks heads by angle from the crosshair then distance. `Tab` and the mouse wheel cycle nearby people nearest-first and pin the choice, so aim-free play works. Right click clears focus and briefly suppresses re-acquisition. Holding `Shift` walks at half speed for close work at the door. Escape keeps its single meaning (close the top panel, otherwise pause).
|
|
||||||
|
|
||||||
## Design Direction
|
## Design Direction
|
||||||
|
|
||||||
The game should feel like a tense workplace simulation with occasional crisis moments. The most satisfying outcome is not overpowering an NPC; it is recognizing the situation early and resolving it calmly.
|
The game should feel like a tense workplace simulation with occasional crisis moments. The most satisfying outcome is not overpowering an NPC; it is recognizing the situation early and resolving it calmly.
|
||||||
|
|
||||||
A useful guiding rule:
|
|
||||||
|
|
||||||
> **The player wins by choosing the lowest level of escalation that keeps everyone safe.**
|
> **The player wins by choosing the lowest level of escalation that keeps everyone safe.**
|
||||||
|
|
||||||
|
## Future Ideas
|
||||||
|
|
||||||
|
- A rare Bob Dobbs cameo (Easter-egg appearance; placement note in `MEMORY.md`).
|
||||||
|
- Specific unusual NPC behaviors, such as slapping their own face, using hands as scissors, or interacting with props unexpectedly.
|
||||||
|
- Live 3D body-camera replay; additional venues or seasonal events; real voice/dialogue audio; an image-to-mesh prop pipeline.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Privacy Note
|
||||||
|
|
||||||
|
Gig Line runs locally. The game itself does not include telemetry, analytics,
|
||||||
|
accounts, advertising, cloud saves or network requests. It does not access the
|
||||||
|
camera, microphone, contacts or location, and the body-camera feature is a
|
||||||
|
simulated overlay, not a real recording device.
|
||||||
|
|
||||||
|
Player data is written only to Godot's local `user://` directory:
|
||||||
|
|
||||||
|
- `settings.json`
|
||||||
|
- `campaign.json`
|
||||||
|
- `shift_results.json`
|
||||||
|
- `shift_state.json`
|
||||||
|
|
||||||
|
Those files stay on the player's machine unless the player copies them. Deleting
|
||||||
|
the files (or the `Gig Line` user directory) resets the profile. See
|
||||||
|
[`docs/getting-started.md`](docs/getting-started.md#save-data-and-migration) for
|
||||||
|
locations, migration and rollback instructions.
|
||||||
|
|
||||||
|
The repository's development tools can call OpenRouter when a developer supplies
|
||||||
|
`OPENROUTER_API_KEY`; those calls generate or judge development assets and are
|
||||||
|
not part of the shipped game. The key and generated review artifacts remain
|
||||||
|
local/gitignored.
|
||||||
|
|
||||||
|
Questions about a storefront release should be checked against the final package
|
||||||
|
and the provider terms recorded in [`CREDITS.md`](CREDITS.md); external legal and
|
||||||
|
storefront approval is still pending for 0.10.0.
|
||||||
@@ -1,472 +1,173 @@
|
|||||||
# Step Line
|
# Gig Line
|
||||||
|
|
||||||
Step Line is a workplace security simulation about observation, communication, access verification, and proportionate escalation. The player works security at public-facing venues around Hollywood Boulevard, managing stairs, entrances, crowds, guests, staff, and occasional serious threats.
|
Gig Line is a workplace security simulation about observation, communication, access verification, and proportionate escalation. The player works security at public-facing venues around Hollywood Boulevard, managing stairs, entrances, crowds, guests, staff, and occasional serious threats.
|
||||||
|
|
||||||
The central design goal is simple:
|
The central design goal is simple:
|
||||||
|
|
||||||
> The player wins by choosing the lowest level of escalation that keeps everyone safe.
|
> The player wins by choosing the lowest level of escalation that keeps everyone safe.
|
||||||
|
|
||||||
|
## Development Priorities
|
||||||
|
|
||||||
|
The active planning order lives in [`TODO.md`](TODO.md) and [`AGENTS.md`](AGENTS.md):
|
||||||
|
|
||||||
|
1. **Character development** — crowd, age, build, hair and outfit variety on the owned procedural library, keeping the frozen NPC contract. Source evaluation and the licence decision are in [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md).
|
||||||
|
2. **Local map development** — licensed OpenStreetMap/3D data, reference-derived photoreal facades, AI-assisted composition and a Gaussian-splatting development evaluation.
|
||||||
|
3. **Versioned release hardening** — the 0.10.0 release candidate and later semantic versions follow the unversioned development tracks.
|
||||||
|
|
||||||
|
Versions are assigned only when a track's scope is accepted into a release. Every major, minor and patch version requires a changelog entry, a local release build and artifact verification before tagging.
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  | |
|
|  |  |
|
||||||
|
|  | |
|
||||||
|
|
||||||
*Screenshots are generated by [`src/test/capture_screenshots.gd`](src/test/capture_screenshots.gd) and [`src/test/capture_prop_gallery.gd`](src/test/capture_prop_gallery.gd) from the current build — day, late-night, wand screening, escalation, shift-review timeline, precision walk, and the prop lineup.*
|
*Screenshots are generated by [`src/test/capture_screenshots.gd`](src/test/capture_screenshots.gd) and [`src/test/capture_prop_gallery.gd`](src/test/capture_prop_gallery.gd) from the current build — day, late-night, wand screening, escalation, shift-review timeline,
|
||||||
|
precision walk, the Joke Shop's Sunset Strip frontage, the TV Studio arrival, and the prop lineup.*
|
||||||
|
|
||||||
## ⬇️ Downloads
|
## ⬇️ Downloads
|
||||||
|
|
||||||
| Platform | Package |
|
| Platform | Package |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| **Windows — installer** | [`step-line-setup-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · contains all game data, shortcuts + uninstaller |
|
| **Windows — installer** | [`gig-line-setup-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · contains all game data, shortcuts + uninstaller |
|
||||||
| **Windows — portable** | [`step-line-windows-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, no install needed |
|
| **Windows — portable** | [`gig-line-windows-<ver>.exe`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, no install needed |
|
||||||
| **Linux — AppImage** | [`step-line-<ver>-x86_64.AppImage`](https://git.allucanget.biz/zwitschi/security-game/releases) · single file, `chmod +x` and run |
|
| **Linux — AppImage** | [`gig-line-<ver>-x86_64.AppImage`](https://git.allucanget.biz/zwitschi/security-game/releases) · single file, `chmod +x` and run |
|
||||||
| **Linux — portable** | [`step-line-linux-<ver>.x86_64`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, `chmod +x` and run |
|
| **Linux — portable** | [`gig-line-linux-<ver>.x86_64`](https://git.allucanget.biz/zwitschi/security-game/releases) · 64-bit, `chmod +x` and run |
|
||||||
| **macOS** | [`step-line-macos-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unsigned build, quarantine note below |
|
| **macOS** | [`gig-line-macos-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unsigned build, quarantine note below |
|
||||||
| **Web (browser)** | [`step-line-web-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unzip and serve the folder from any static host (no special headers) |
|
| **Web (browser)** | [`gig-line-web-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · unzip and serve the folder from any static host (no special headers) |
|
||||||
|
| **Desktop HQ** | [`gig-line-desktop-hq-<ver>.zip`](https://git.allucanget.biz/zwitschi/security-game/releases) · optional Forward+ build with volumetric fog/SDFGI/flashlight; requires a Vulkan-capable GPU/driver |
|
||||||
|
|
||||||
**All releases:** <https://git.allucanget.biz/zwitschi/security-game/releases>
|
**All releases:** <https://git.allucanget.biz/zwitschi/security-game/releases>
|
||||||
|
|
||||||
> 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.5.0** — articulated NPC characters with LOD and idle behaviour, plus movement feel, gamepad support, and key remapping.
|
> **Latest published: v0.9.6** — the integration checkpoint: the 0.9.5 texture
|
||||||
|
> and material refinement (256² NPC maps, a four-times fabric weave without baked
|
||||||
|
> AO blotches, repaired Walk of Fame/awning surfaces and per-phase skyline haze)
|
||||||
|
> is packaged with the v0.9.4 NPC visual optimization, the Hollywood/Joke Shop
|
||||||
|
> maps and the v0.9.3 UI/accessibility polish, with the full gallery, smoke matrix
|
||||||
|
> and Web/Desktop HQ build re-verified.
|
||||||
|
>
|
||||||
|
> **Current source: v0.10.0-rc.1** — the release-candidate source; the final tag is pending external playtest and legal review.
|
||||||
> 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
|
||||||
> (NSIS + appimagetool) and uploads with the portable binaries.
|
> (NSIS + appimagetool) and uploads with the portable binaries.
|
||||||
>
|
>
|
||||||
> Note: on this host, downloading release files currently requires sign-in;
|
|
||||||
> the page and tag URLs are public.
|
|
||||||
>
|
|
||||||
> macOS builds are unsigned: right-click → Open, or clear the quarantine with
|
> macOS builds are unsigned: right-click → Open, or clear the quarantine with
|
||||||
> `xattr -dr com.apple.quarantine step-line-macos.zip`. Build instructions and
|
> `xattr -dr com.apple.quarantine gig-line-macos.zip`. Build instructions and
|
||||||
> the release pipeline live in [`docs/RELEASING.md`](docs/RELEASING.md).
|
> the release pipeline live in [`docs/RELEASING.md`](docs/RELEASING.md).
|
||||||
|
|
||||||
If you are here to develop or test locally instead of downloading, jump to
|
If you are here to develop or test locally instead of downloading, jump to
|
||||||
[Run and Test](#run-and-test) below.
|
[Setup and Run](#setup-and-run) below.
|
||||||
|
|
||||||
The project is under active development. The design and architecture are documented, and a playable prototype vertical slice exists (Godot 4.3 + GDScript): a procedural Hollywood Boulevard entrance, a first-person guard, simulated NPCs with intents and reactions, the six-level escalation model, access inspection and admission decisions, radio calls with credibility checks, reputation, crowd mood, and an end-of-shift review.
|
The project is under active development. The design and architecture are documented, and a playable prototype vertical slice exists (Godot 4 + GDScript): a stylized El Capitan Entertainment Centre block, a first-person guard, simulated NPCs with intents and reactions, the six-level escalation model, access inspection and admission decisions, radio calls with credibility checks, reputation, crowd mood, and an end-of-shift review.
|
||||||
|
|
||||||
## Game Overview
|
## Game Overview
|
||||||
|
|
||||||
A typical shift lasts 10–15 minutes. The player:
|
A typical shift lasts 10–15 minutes: watch the entrance and sidewalk, judge why
|
||||||
|
each person is approaching, verify access with recognition, wristbands, IDs,
|
||||||
1. Watches the entrance, steps, queue, and surrounding sidewalk.
|
tickets or credentials, and escalate only when necessary. The game rewards calm
|
||||||
2. Determines why each person is approaching.
|
resolution over force. The venue menu splits Hollywood Boulevard into Day and
|
||||||
3. Uses simple gestures or polite directions first.
|
Night rows; the full mechanics — the three venues, the six-level
|
||||||
4. Verifies authorized access using recognition, wristbands, credentials, tickets, or guest lists.
|
escalation model, and the core systems — are in
|
||||||
5. Escalates only when a person refuses directions, attempts unauthorized entry, or presents a genuine threat.
|
[`docs/gameplay.md`](docs/gameplay.md); the design rationale lives in
|
||||||
6. Records the incident through body-camera and radio systems.
|
[`PLAN.md`](PLAN.md).
|
||||||
7. Finishes the shift with a performance review based on safety, judgment, and professionalism.
|
|
||||||
|
|
||||||
The game rewards calm resolutions rather than aggressive behavior. Emergency assistance and armed responders are rare last-resort systems with meaningful consequences.
|
|
||||||
|
|
||||||
## Planned Venues
|
|
||||||
|
|
||||||
### Hollywood Boulevard Building
|
|
||||||
|
|
||||||
The original scenario places the guard at the top of the steps outside a fictional building. Tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats may approach the entrance.
|
|
||||||
|
|
||||||
Authorized people must either be recognized by the guard or present a valid wristband. Wristbands can have different colors, patterns, dates, or event markings. They may be valid, expired, counterfeit, or missing.
|
|
||||||
|
|
||||||
### The Joke Shop
|
|
||||||
|
|
||||||
The Joke Shop is a comedy-club scenario. The door person checks IDs, tickets, reservations, and guest-list status, then uses a handheld security wand according to venue policy. The player must interpret wand alerts rather than treating every alert as proof of a weapon; keys, belts, phones, and other harmless objects can trigger false alarms.
|
|
||||||
|
|
||||||
### Hollywood Boulevard Late Night TV Studio
|
|
||||||
|
|
||||||
This scenario combines the previously defined NPC types with a busy television-studio entrance. The player manages audience members, production staff, performers, guests, deliveries, celebrity arrivals, tourists, street performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people experiencing a mental-health crisis, and rare violent threats.
|
|
||||||
|
|
||||||
The studio uses wristbands, credentials, tickets, guest-list confirmation, and personal recognition to authorize entry. Crowd control, filming boundaries, following authorized guests through the door, and counterfeit credentials are key events.
|
|
||||||
|
|
||||||
## Escalation Model
|
|
||||||
|
|
||||||
The common escalation model has six levels:
|
|
||||||
|
|
||||||
0. **Observation** — Decide whether intervention is necessary.
|
|
||||||
1. **Simple deterrence and polite direction** — Raise an open hand, make eye contact, point toward the sidewalk or check-in area, shake the head, or give a short instruction.
|
|
||||||
2. **Formal warning** — Clearly explain the rule and request compliance.
|
|
||||||
3. **Blocking and physical positioning** — Secure the entrance, maintain distance, preserve an escape route, and deny access without starting a fight.
|
|
||||||
4. **Radio for security assistance** — Request a supervisor, second guard, building management, or other appropriate support.
|
|
||||||
5. **Emergency response** — Hold the emergency-radio button and confirm only when there is an immediate threat, such as a weapon, assault, forced entry, or serious threat to occupants.
|
|
||||||
|
|
||||||
An off-duty law-enforcement officer or armed emergency responder may arrive during a valid emergency. This character is not intended to be a routine stronger attack. Their role is crisis control, evacuation, restraint, arrest, or other appropriate intervention, with force governed by the situation and meaningful consequences for unjustified calls.
|
|
||||||
|
|
||||||
## Core Systems
|
|
||||||
|
|
||||||
- **NPC behavior:** NPCs have different motivations, temperaments, compliance levels, and reactions to the player’s approach.
|
|
||||||
- **Access verification:** Recognition, wristbands, IDs, tickets, credentials, and guest lists determine who may enter.
|
|
||||||
- **Nonverbal deterrence:** Small actions such as raising a hand can resolve low-risk situations without dialogue or force.
|
|
||||||
- **Dialogue:** Polite directions and warnings affect outcomes; simple gestures can resolve low-risk situations without dialogue.
|
|
||||||
- **Escalation:** The player chooses the lowest effective response.
|
|
||||||
- **Radio assistance:** Calls require useful information and may take time to arrive.
|
|
||||||
- **Evidence:** Body-camera records support shift review and accountability.
|
|
||||||
- **Crowd reaction:** Aggressive behavior, visible weapons, and emergency response can create panic or attract a crowd.
|
|
||||||
- **Reputation:** Peaceful resolutions, accurate reports, low property damage, and justified calls improve performance; unnecessary confrontations and false reports reduce it.
|
|
||||||
- **Shift review:** The player receives feedback on access decisions, escalation choices, public complaints, injuries, and security outcomes.
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
The planned solution uses a venue-driven simulation architecture. Venue configuration supplies rules, access types, NPC pools, equipment, events, and escalation policies. Shared simulation systems provide movement, perception, interactions, dialogue, access verification, escalation, radio calls, crowds, reputation, evidence, and shift review.
|
|
||||||
|
|
||||||
```text
|
|
||||||
Venue Scenario / Rules
|
|
||||||
|
|
|
||||||
v
|
|
||||||
Shift Coordinator -----> Event Scheduler
|
|
||||||
| |
|
|
||||||
v v
|
|
||||||
NPC Simulation <---------- Interaction System
|
|
||||||
| |
|
|
||||||
v v
|
|
||||||
Access Verification ----> Escalation / Response
|
|
||||||
| |
|
|
||||||
+-------------> Reputation / Evidence
|
|
||||||
|
|
|
||||||
v
|
|
||||||
Shift Review
|
|
||||||
```
|
|
||||||
|
|
||||||
The architecture maps onto Godot 4 nodes, scenes, and custom resources as described in [Tech Stack](#tech-stack). See the full arc42-style outline in [`docs/architecture.md`](docs/architecture.md) and the decisions in [`docs/adr/`](docs/adr/).
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
- **Engine:** Godot Engine 4.x
|
|
||||||
- **Language:** GDScript
|
|
||||||
- **Architecture:** Venue-driven simulation using nodes, scenes, and custom `Resource`-based scenario data
|
|
||||||
- **Navigation:** `NavigationRegion3D` and `NavigationAgent3D`
|
|
||||||
- **NPC behavior:** Custom lightweight finite state machines driven by `NpcProfile` resources
|
|
||||||
- **UI and audio:** Godot `Control` nodes, themes, audio buses, and `AudioStreamPlayer` nodes
|
|
||||||
- **Art assets:** authored PNGs and the in-game generated set in `assets/textures/ai/game_ready/`; street-furniture models in `assets/models/generated/` build from `tools/model_pipeline.py`; structural geometry stays procedural (`WorldBuilder`). The legacy `tools/generate_textures.py --ai` batch remains available.
|
|
||||||
- **Asset tooling:** `tools/asset_pipeline.py` generates role-aware assets through OpenRouter and provides crop, resize, seamless-tile, and image-audit commands, including gameplay screenshot checks. `tools/model_pipeline.py` builds and audits the prop `.glb` models.
|
|
||||||
- **Testing:** GUT (Godot Unit Test) in headless mode
|
|
||||||
- **Source control:** git on a Gitea host with Gitea Actions (`.gitea/workflows/build.yml`) for headless tests and desktop release builds
|
|
||||||
- **Targets:** Windows, Linux, and macOS desktop first; web later
|
|
||||||
|
|
||||||
### Image Asset Tools
|
|
||||||
|
|
||||||
Install the Pillow dependency used by the existing texture generator and the asset tools:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 -m pip install -r requirements-tools.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Generate a role-sized image (generation requires `OPENROUTER_API_KEY`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 tools/asset_pipeline.py generate --prompt "weathered red brick" --role tile --output assets/textures/brick_extra.png
|
|
||||||
```
|
|
||||||
|
|
||||||
Generated images are resized to the selected role profile. Non-square requests use
|
|
||||||
the validated `openai/gpt-5-image-mini` source ratio and crop to the final role dimensions.
|
|
||||||
Transparent glyphs can be recolored while preserving their alpha mask with
|
|
||||||
`--foreground '#ffffff'`.
|
|
||||||
|
|
||||||
Crop uses the image center by default; `--x` and `--y` select an explicit crop origin. Resize defaults to aspect-preserving `contain`; use `--fit cover` to crop or `--fit stretch` to distort to the exact dimensions.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 tools/asset_pipeline.py crop assets/textures/source.png assets/textures/crop.png --width 256 --height 128
|
|
||||||
python3 tools/asset_pipeline.py resize assets/textures/source.png assets/images/backgrounds/scene.png --width 1920 --height 1080 --fit cover
|
|
||||||
python3 tools/asset_pipeline.py seamless assets/textures/rough_tile.png assets/textures/tile.png
|
|
||||||
```
|
|
||||||
|
|
||||||
Audit accepts image files or directories. `--role auto` infers common roles from paths and filenames; explicit roles include `tile`, `texture`, `icon`, `card`, `banner`, `backdrop`, `background`, `overlay`, `app_icon`, and `screenshot`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 tools/asset_pipeline.py audit assets/textures
|
|
||||||
python3 tools/asset_pipeline.py audit assets/images/backgrounds --role background --json
|
|
||||||
python3 -m unittest discover -s tools -p 'test_*.py'
|
|
||||||
```
|
|
||||||
|
|
||||||
The audit classifies measurable fit issues as `good` or `bad` based on role-specific dimensions, aspect ratio, alpha requirements, and tile-edge continuity. It lists perspective/projection as a visual review item because image semantics cannot be judged reliably by these deterministic checks.
|
|
||||||
|
|
||||||
### Prop models
|
|
||||||
|
|
||||||
Street furniture (bollards, benches, bins, planters, newspaper boxes, a hydrant)
|
|
||||||
is real 3D geometry generated by `tools/model_pipeline.py` and written to
|
|
||||||
`assets/models/generated/*.glb`. Godot imports each file as a `PackedScene`, and
|
|
||||||
`WorldBuilder` instantiates it with a procedural fallback when the model or its
|
|
||||||
import is missing, so the world still builds on a fresh checkout.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Print the catalogue (parts, triangle count, whether a model/concept exists)
|
|
||||||
python3 tools/model_pipeline.py list
|
|
||||||
|
|
||||||
# Rebuild the models (deterministic, offline) and validate them
|
|
||||||
python3 tools/model_pipeline.py build
|
|
||||||
python3 tools/model_pipeline.py audit
|
|
||||||
|
|
||||||
# Optional: an image model supplies the colour palette per prop
|
|
||||||
# (requires OPENROUTER_API_KEY; the repo .env is read automatically)
|
|
||||||
python3 tools/model_pipeline.py concept
|
|
||||||
python3 tools/model_pipeline.py concept --only bench --force
|
|
||||||
```
|
|
||||||
|
|
||||||
Each prop is a small list of boxes and cylinders, so `build` needs no network and
|
|
||||||
the output is byte-identical between runs. `concept` asks an image model for a
|
|
||||||
studio-style reference; `dominant_colors` and `assign_roles` then map that image's
|
|
||||||
colours onto material roles (darkest → metal, warm saturated → wood, light grey →
|
|
||||||
stone, green → foliage). glTF stores colours in linear space, so the tool converts
|
|
||||||
the sRGB palettes before writing them. Re-run `build` and `godot --headless
|
|
||||||
--path . --import` after changing a prop. See
|
|
||||||
[ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md).
|
|
||||||
|
|
||||||
Surface materials share one definition in `src/game/materials.gd`: named
|
|
||||||
roughness/metallic profiles per surface, plus the environment tune-up (ACES
|
|
||||||
tonemapping, glow, fog, colour grading) that the phase lighting applies.
|
|
||||||
|
|
||||||
### Screen design references
|
|
||||||
|
|
||||||
Screen mockups and screenshot comparison use `tools/screen_designs.py`. It turns the
|
|
||||||
screen descriptions in `docs/` (README captions, ADRs 0007–0010, `PLAN.md`, and
|
|
||||||
`architecture.md`) into reference images under `docs/screens/designs/`, then uses
|
|
||||||
those images as the expected state to check the game's captures.
|
|
||||||
|
|
||||||
Each screen is tagged `scene` (a realistic first-person 3D world view) or `ui`
|
|
||||||
(an in-game panel overlaid on a softened scene), and the generator appends a
|
|
||||||
shared art-direction suffix so the frames read as one coherent game. Requests use
|
|
||||||
a 3:2 landscape source and crop to the 16:9 capture dimensions.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Export the built-in scenarios to editor-authorable .tres resources
|
|
||||||
godot --headless --path . --script res://tools/export_venues.gd
|
|
||||||
|
|
||||||
# List the catalogue (name, kind, whether a reference design exists)
|
|
||||||
python3 tools/screen_designs.py list
|
|
||||||
|
|
||||||
# Deterministic wireframes (offline, no API key); existing designs are kept
|
|
||||||
# unless --force is passed, so an offline run never replaces an AI mockup
|
|
||||||
python3 tools/screen_designs.py generate --draft
|
|
||||||
python3 tools/screen_designs.py generate --draft --only wand --force
|
|
||||||
|
|
||||||
# Realistic 3D scenes and in-game screen designs via OpenRouter
|
|
||||||
# (requires OPENROUTER_API_KEY)
|
|
||||||
python3 tools/screen_designs.py generate
|
|
||||||
|
|
||||||
# Prop gallery (studio line-up) for close-range prop checks
|
|
||||||
godot --path . --script res://src/test/capture_prop_gallery.gd
|
|
||||||
|
|
||||||
# Compare docs/screenshots/*.png against the designs
|
|
||||||
python3 tools/screen_designs.py compare
|
|
||||||
python3 tools/screen_designs.py compare --json
|
|
||||||
|
|
||||||
# Ask a vision model whether each capture realises its design's screen and layout
|
|
||||||
# (requires OPENROUTER_API_KEY; the repo .env is read automatically)
|
|
||||||
python3 tools/screen_designs.py judge
|
|
||||||
python3 tools/screen_designs.py judge --model openai/gpt-4o-mini --json
|
|
||||||
python3 tools/screen_designs.py judge --only 03- # one capture
|
|
||||||
python3 tools/screen_designs.py judge --dry-run # build requests, no network
|
|
||||||
```
|
|
||||||
|
|
||||||
The catalogue covers 21 screens: the eleven README captures plus the start menu,
|
|
||||||
pause overlay, settings, shift review, radial menu, emergency radio, wand
|
|
||||||
screening, Joke Shop queue, TV Studio arrival, crowd panic, responder arrival,
|
|
||||||
body-camera timeline, and the escalation HUD. All 19 have an AI reference in
|
|
||||||
`docs/screens/designs/`; the eleven screens with staged captures are also compared
|
|
||||||
or judged against the running game.
|
|
||||||
|
|
||||||
`compare` flags gross drift: wrong aspect ratio, undersized frame, near-blank
|
|
||||||
frame, and large layout/palette/detail distance. It is a regression gate, not a
|
|
||||||
semantic judge — pixel and perceptual metrics cannot decide whether a frame's
|
|
||||||
composition is *right*.
|
|
||||||
|
|
||||||
`judge` covers that gap: it sends each capture together with its concept mockup to
|
|
||||||
a vision model and asks whether the capture realises the same screen and layout
|
|
||||||
intent. Art style, fidelity, fonts, and placeholder text are explicitly ignored.
|
|
||||||
Verdicts are classed as `match`, `review` (a mismatch below `--fail-confidence`,
|
|
||||||
default 0.6 — expected when a concept mockup is more stylised than the game), or
|
|
||||||
`diff` (a confident mismatch, which exits non-zero). Regenerate the designs after changing screen layout, then re-run
|
|
||||||
`compare` after regenerating the game screenshots with
|
|
||||||
`src/test/capture_screenshots.gd`.
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
1. Download the Godot 4.3 editor (official build) and put `godot` on your PATH.
|
|
||||||
2. Open or run the project from this directory.
|
|
||||||
|
|
||||||
### Run and Test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Open in the editor
|
|
||||||
godot --editor --path .
|
|
||||||
|
|
||||||
# Run the game
|
|
||||||
godot --path .
|
|
||||||
|
|
||||||
# Headless smoke boot (120 frames then exit)
|
|
||||||
godot --headless --path . --quit-after 120
|
|
||||||
|
|
||||||
# Run all unit tests headlessly (exit code 0 = pass)
|
|
||||||
godot --headless --path . --script res://src/test/test_runner.gd
|
|
||||||
|
|
||||||
# Save a screenshot to user:// (windowed)
|
|
||||||
godot --path . --script res://src/test/take_screenshot.gd
|
|
||||||
|
|
||||||
# Windowed control smoke: focus circle, action wheel, wheel cycling + right-click clear; saves PNGs, exits 1 on failure
|
|
||||||
godot --path . --script res://src/test/smoke_focus_radial.gd
|
|
||||||
|
|
||||||
# Session-shell smoke: menu → shift → pause → settings → menu (headless or windowed)
|
|
||||||
godot --headless --path . --script res://src/test/smoke_session_shell.gd
|
|
||||||
|
|
||||||
# PLAN-verb smoke: recognize, request reason, body camera, warning, blocking
|
|
||||||
godot --headless --path . --script res://src/test/smoke_plan_verbs.gd
|
|
||||||
|
|
||||||
# Prop-collision smoke (windowed): guard stops at a bench, guest routes around it
|
|
||||||
godot --path . --script res://src/test/smoke_props.gd
|
|
||||||
|
|
||||||
# NPC budget smoke: 16 full-rig avatars against the documented frame budget
|
|
||||||
godot --headless --path . --script res://src/test/smoke_npc_budget.gd
|
|
||||||
|
|
||||||
# Movement smoke (windowed): steps, precision walk, footsteps and landing
|
|
||||||
godot --path . --script res://src/test/smoke_movement.gd
|
|
||||||
|
|
||||||
# Crowd smoke: rubbernecking on aggression, panic clearing the entrance
|
|
||||||
godot --headless --path . --script res://src/test/smoke_crowd.gd
|
|
||||||
|
|
||||||
# Emergency smoke: unjustified call, investigation note, evacuation aftermath
|
|
||||||
godot --headless --path . --script res://src/test/smoke_emergency.gd
|
|
||||||
|
|
||||||
# Body-camera timeline smoke: review → timeline → step through → back to review
|
|
||||||
godot --headless --path . --script res://src/test/smoke_timeline.gd
|
|
||||||
|
|
||||||
# Audio smoke: crowd bed follows mood, radio open/close crackle
|
|
||||||
godot --headless --path . --script res://src/test/smoke_audio.gd
|
|
||||||
|
|
||||||
# Scenario-content smoke: wand refusal, celebrity crowd spike
|
|
||||||
godot --headless --path . --script res://src/test/smoke_scenario_content.gd
|
|
||||||
```
|
|
||||||
|
|
||||||
The unit test runner is the project's own lightweight harness (no editor plugin required) so CI can run it without the editor.
|
|
||||||
|
|
||||||
### Controls
|
|
||||||
|
|
||||||
Keyboard and mouse are the default; a gamepad works without configuration (left stick moves,
|
|
||||||
right stick looks, A opens/confirms the wheel, B cancels, X inspects, Y calls the radio, LB walks
|
|
||||||
slowly, RB uses the wand). Keys and pad buttons can be rebound in Settings, and the remaps persist
|
|
||||||
in `user://settings.json`. The HUD legend switches to gamepad hints when a pad event arrives.
|
|
||||||
|
|
||||||
| Input | Action |
|
|
||||||
| --- | --- |
|
|
||||||
| W/A/S/D + mouse | Move and look |
|
|
||||||
| Space / left click | Action wheel for the focused person (Stop, Look, Point, No, Ask, Inspect, Wand, Warn, Block, Reason, Recognize, Radio) |
|
|
||||||
| A / D or ←/→ | Step through the action wheel (while it is open) |
|
|
||||||
| Space / left click | Confirm the highlighted action (while the wheel is open) |
|
|
||||||
| Esc / right click | Close the top panel; Esc with nothing open pauses the shift (Esc again resumes) |
|
|
||||||
| ← / → or ↑ / ↓ | Navigate the venue menu and the pause / settings panels |
|
|
||||||
| Enter | Start the highlighted venue from the menu, or confirm in a panel |
|
|
||||||
| 1 / 2 / 3 | Quick gestures without the wheel: raise hand, point, head shake (Level 1) |
|
|
||||||
| Q | Polite direction (Level 1) |
|
|
||||||
| 4 | Formal warning (Level 2) |
|
|
||||||
| 5 | Blocking and positioning (Level 3) |
|
|
||||||
| 6 | Security assistance radio (Level 4) |
|
|
||||||
| R | Emergency radio, hold on-screen button ~1.6s (Level 5) |
|
|
||||||
| E | Inspect access artifacts / close inspection |
|
|
||||||
| C | Handheld wand screening (wand venues only) |
|
|
||||||
| A / D | Allow / deny entry during inspection or wand check |
|
|
||||||
| V | Cycle venue (debug shortcut; restart via V restarts the current shift) |
|
|
||||||
| Tab / mouse wheel ↓ / ↑ | Cycle the target among nearby NPCs, nearest first (aim-free; the target stays selected) |
|
|
||||||
| Right click (nothing open) | Clear the focused person and return to aim-based focus |
|
|
||||||
| Shift (hold) | Precision walk at roughly half speed for close work at the door |
|
|
||||||
| G | Toggle flashlight (widens NPC perception at night) |
|
|
||||||
| B | Toggle the body camera; a formal warning switches it on automatically |
|
|
||||||
| L | Lock / unlock the restricted door (thwarts forced entry) |
|
|
||||||
| F | Toggle debug overlay |
|
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
The full arc42-style architecture documentation lives in [`docs/architecture.md`](docs/architecture.md). It covers goals, constraints, context, solution strategy, building blocks, runtime views, deployment, cross-cutting concepts, quality requirements, risks, a glossary, the CI/CD build pipeline, semantic versioning, and release management.
|
A venue-driven simulation: shared systems (movement, perception, interaction,
|
||||||
|
access verification, escalation, radio, crowd, reputation, evidence, shift
|
||||||
|
review) driven by per-venue scenario data, on Godot 4 + GDScript. The full
|
||||||
|
arc42-style document is [`docs/architecture.md`](docs/architecture.md);
|
||||||
|
decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
- **Engine:** Godot 4.7.2 · **Language:** GDScript
|
||||||
|
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
|
||||||
|
- **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/`
|
||||||
|
- **Asset tooling:** `asset_pipeline.py`, `model_pipeline.py`, `npc_pipeline.py`, `blender_assets.py`, `scene_concepts.py`, `screen_designs.py`, `check_screenshots.sh`
|
||||||
|
- **Testing:** custom headless runner (`src/test/test_runner.gd`)
|
||||||
|
- **Targets:** Windows, Linux, macOS, Web
|
||||||
|
|
||||||
|
The asset pipelines, model tools, and screenshot gates are documented in
|
||||||
|
[`docs/asset-tooling.md`](docs/asset-tooling.md).
|
||||||
|
|
||||||
|
## Setup and Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m pip install -r requirements-tools.txt
|
||||||
|
|
||||||
|
godot --editor --path . # open in the editor
|
||||||
|
godot --path . # run the game
|
||||||
|
godot --headless --path . --script res://src/test/test_runner.gd # run all tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Full setup, every run/test/smoke command, and the controls table are in
|
||||||
|
[`docs/getting-started.md`](docs/getting-started.md).
|
||||||
|
|
||||||
## Project Documentation
|
## Project Documentation
|
||||||
|
|
||||||
- [`PLAN.md`](PLAN.md) — Game design plan and scenario details.
|
- [`PLAN.md`](PLAN.md) — Game design plan, development priorities and scenario details.
|
||||||
- [`AGENTS.md`](AGENTS.md) — Development and collaboration workflow.
|
- [`TODO.md`](TODO.md) — Priority-ordered tasks: character and local-map development, release milestones, and future work.
|
||||||
- [`TODO.md`](TODO.md) — Active checkbox task list.
|
- [`docs/README.md`](docs/README.md) — Documentation index, current priorities and visual previews.
|
||||||
|
- [`docs/npc-model-sourcing.md`](docs/npc-model-sourcing.md) — Character-source evaluation, licence rules and the character-development plan.
|
||||||
|
- [`AGENTS.md`](AGENTS.md) — Development, commit, build and collaboration workflow.
|
||||||
- [`DONE.md`](DONE.md) — Completed task sections.
|
- [`DONE.md`](DONE.md) — Completed task sections.
|
||||||
- [`MEMORY.md`](MEMORY.md) — Persistent session notes.
|
- [`MEMORY.md`](MEMORY.md) — Persistent session notes.
|
||||||
|
- [`CHANGELOG.md`](CHANGELOG.md) — User-facing changes by version.
|
||||||
- [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation.
|
- [`docs/architecture.md`](docs/architecture.md) — arc42-style architecture documentation.
|
||||||
|
- [`docs/gameplay.md`](docs/gameplay.md) — Gameplay systems, venues, and the escalation model.
|
||||||
|
- [`docs/hollywood-boulevard-map.md`](docs/hollywood-boulevard-map.md) — Real-site references, game mapping and limitations for the Hollywood venue.
|
||||||
|
- [`docs/joke-shop-map.md`](docs/joke-shop-map.md) — Real-site references, game mapping and limitations for the Joke Shop / Sunset Strip venue.
|
||||||
|
- [`docs/tutorial.md`](docs/tutorial.md) — First-shift tutorial beats and rules.
|
||||||
|
- [`docs/asset-tooling.md`](docs/asset-tooling.md) — Asset pipelines, model tools, and screenshot gates.
|
||||||
|
- [`docs/getting-started.md`](docs/getting-started.md) — Setup, run/test commands, and controls.
|
||||||
|
- [`docs/development-status.md`](docs/development-status.md) — Implemented features and what's next.
|
||||||
|
- [`docs/accessibility.md`](docs/accessibility.md) — Accessibility features, known gaps and statement.
|
||||||
|
- [`docs/known-limitations.md`](docs/known-limitations.md) — Release-candidate blockers and accepted limitations.
|
||||||
|
- [`docs/smoke-checklist.md`](docs/smoke-checklist.md) — Manual smoke-test checklist.
|
||||||
|
- [`CREDITS.md`](CREDITS.md) — Credits, AI/reference provenance and licensing notes.
|
||||||
|
- [`PRIVACY.md`](PRIVACY.md) — Local-only data, save files and development API use.
|
||||||
|
- [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points.
|
||||||
|
- [`docs/npc-visual-review.md`](docs/npc-visual-review.md) — 0.9.4 NPC baseline, acceptance criteria and ranked visual gaps; 0.9.5 texture comparison is in [`docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`](docs/blender_previews/sheet_texture_refinement_0.9.5.jpg).
|
||||||
|
- [`docs/npc-proportion-audit.md`](docs/npc-proportion-audit.md) — NPC proportion measurements against the shared stylized guide.
|
||||||
- [`docs/adr/`](docs/adr/) — Architecture Decision Records.
|
- [`docs/adr/`](docs/adr/) — Architecture Decision Records.
|
||||||
|
|
||||||
## Development Status
|
## Development Status
|
||||||
|
|
||||||
Implemented so far:
|
v0.10.0-rc.1 is the current release-candidate source: the 0.9.6 integration
|
||||||
|
checkpoint plus save-migration hardening and release tooling, on top of the 0.9.5
|
||||||
|
texture refinement (256² NPC maps, a 4× fabric weave with baked-AO removal, repaired
|
||||||
|
Walk of Fame/awning surfaces and per-phase skyline haze), on top of the v0.9.4
|
||||||
|
NPC visual optimization and the v0.9.3 UI/accessibility polish pass. It builds on
|
||||||
|
v0.9.2's Hollywood/Joke Shop map rebuilds, v0.9.1's Godot 4.7.2 baseline,
|
||||||
|
v0.9.0's production-quality pass, v0.8's
|
||||||
|
tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. The active
|
||||||
|
planning priorities are the unversioned character and local-map development tracks;
|
||||||
|
the 0.10.0 release candidate is the next versioned release. See
|
||||||
|
[`docs/development-status.md`](docs/development-status.md) for the implemented list
|
||||||
|
and [`TODO.md`](TODO.md) for the priority-ordered roadmap. Manual verification uses
|
||||||
|
the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
|
||||||
|
|
||||||
- Godot 4.3 project scaffold, input map, procedural world builder
|
## Credits, Privacy and Accessibility
|
||||||
- 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
|
|
||||||
- Headless unit tests: **208 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
|
|
||||||
- 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`)
|
|
||||||
- Session shell: venue start menu (keyboard + mouse), Esc pause overlay (resume / restart / settings / quit to menu), settings panel with mouse-look sensitivity and HUD font scale persisted to `user://settings.json`, and "Run another shift" returning to the venue menu
|
|
||||||
- World presentation: skyline backdrop rendered with an alpha material, walkable step and landing colliders, larger marquee text, and larger focus circle / name tag
|
|
||||||
- Routine traffic despawns after a while at its waypoint so the crowd cap no longer fills with idle standers
|
|
||||||
- PLAN verbs: eye contact (distinct Level 1 cue), recognizing a person as a player decision recorded as access evidence, a body-camera flag that a formal warning arms (and `B` toggles), blocking that physically stations the guard between the person and the door, and a Level 3 request-reason ask answered from the NPC's `dialogue_lines`
|
|
||||||
- Incidents are now actually opened on focus and closed at shift end, so player actions, access evidence, escalation levels, and unresolved interactions reach the review (previously every recorded event was dropped)
|
|
||||||
- Crowd presentation: aggressive behavior and responder arrivals make idle bystanders stop and face the incident; panic sends people away from the door (and they leave the scene). A busy 16-NPC entrance measured ~1.2 ms/frame, so no LOD/culling was needed at the current cap
|
|
||||||
- Distant skyline ring: four alpha-scissored planes at 200 m read as a hazy city on the horizon (the baked backdrop used to show as a black slab), with a larger ground plane so the buildings meet the street
|
|
||||||
- Flashlight aims straight ahead and lights the person/door being checked instead of the ground in front of the guard
|
|
||||||
- Emergency aftermath: the `evacuation` outcome locks the door and clears the entrance, an emergency call that the situation did not justify opens an investigation and applies the false-report hit, and the shift review names the responder outcome and any investigations
|
|
||||||
- Body-camera timeline: the shift review opens a text timeline of every recorded incident event (time, person, action/outcome) that you step through with the arrow keys or buttons. No live 3D replay yet
|
|
||||||
- NPC theater: seated guests sit on the steps with bent legs, influencers and tourists raise a camera prop while photographing, performers sway their sign, and filming visitors pan slowly — all once they reach their intent's waypoint
|
|
||||||
- Audio: a looping procedural crowd bed (filtered murmur) whose volume follows `CrowdSystem.mood`, plus radio open/close crackle. All generated at runtime, no audio assets, and safe with a dummy audio server
|
|
||||||
- Accessibility: the escalation cue shows a shape meter plus the numeric level (`Escalation: Blocking [###--] L3/5`) so it reads in grayscale, and the HUD font scale from settings is applied at boot by resizing fonts (not Control.scale, which broke the right-aligned layout)
|
|
||||||
- Editor-ready venues: `tools/export_venues.gd` writes `content/venues/<id>.tres` from `ScenarioFactory`, and the `.tres` files load back with events, profiles, policy, phases, door lines, and locations intact (the factory stays the source of truth)
|
|
||||||
- Localization safety: `Strings.fmt` validates the placeholder count before formatting and fails safe (warns, returns the template) instead of raising an engine error, `Strings.placeholder_count` ignores `%%`, and `Strings.validate()` lints the table for trailing `%`, unsupported conversions, and mixed positional/sequential placeholders
|
|
||||||
- Authored scenario content: Joke Shop reservation-without-ID, borrowed/mismatched ID, a guest who refuses the wand screen, and a late arrival during a performance; Studio filming-boundary repeats and a celebrity arrival that draws a small crowd; Building events that point the player at the body camera and request-reason verbs
|
|
||||||
- Visual polish pass (v0.2.0): phase-based lighting (sun/sky/ambient per shift phase), street lamps with night-mode bulbs and omni lights, glowing marquee signage, crosswalk, planters and low-poly street trees, NPC height/brightness variety, denser routine traffic — day and late-night screenshot sets
|
|
||||||
- Assets pass: authored textures in `assets/textures/` (brick facade, concrete, asphalt, awning, skyline, vignette, HUD icons, access-card art) generated by `tools/generate_textures.py`, soft sun shadows, humanoid NPC rigs with archetype props + procedural walk bob and attention head-turn, inspection artifact cards, escalation vignette, mode icons, and a body-camera overlay (REC + shift clock)
|
|
||||||
- Rendering pass (v0.3.0 work, [ADR-0012](docs/adr/0012-surface-materials-and-generated-props.md)): one material module with roughness/metallic profiles per surface, ACES tonemapping, glow, aerial fog and colour grading driven by the shift phase, correctly scaled brick, framed facade windows that light up at night, door trim and handles, a curb and lane dashes, and the glowing marquee/lamp bulbs. NPCs gained per-role clothing palettes, caps/hoods/backpacks/sunglasses/lanyards, hands and shoes, and an arm/leg walk swing
|
|
||||||
- NPC characters (v0.5.0): articulated limb rigs, layered outfits, hand items, face/hair variety, idle behaviour (phone, clipboard, crossed arms, look-around), escalation gestures, readable reaction symbols, door-queue offsets, and three LOD tiers with a billboard impostor
|
|
||||||
- Player movement (v0.5.0): separate acceleration/braking, step-up assist, head bob and landing dip (toggleable), precision-walk FOV/chip/tick, surface-aware footsteps, gamepad support, and persistent key/button remapping in settings
|
|
||||||
- Prop collision and placement (v0.4.0): every prop fits a static collider from its mesh bounds and publishes a navigation obstacle, so the guard and guests cannot walk through benches, bins, or bollards; placements are grouped into zones with a validator, and deterministic variants add rotation, scale, and small clutter
|
|
||||||
- Prop atlas (v0.3.1): `tools/model_pipeline.py` packs each prop's palette into one power-of-two colour atlas plus a metallic/roughness atlas and emits a single material with per-vertex UVs, so a prop is one draw material rather than one per part; `audit` enforces the contract
|
|
||||||
- Generated prop models (v0.3.0 work): `tools/model_pipeline.py` builds bollards, benches, bins, planters, newspaper boxes and a hydrant as `.glb` props with per-part materials, loaded by `WorldBuilder` with a procedural fallback; the optional AI concept step (`model_pipeline.py concept`) supplies per-prop colour palettes
|
|
||||||
- Web build: `build/step-line-web-<version>.zip` (Godot's non-threaded web template, no COOP/COEP headers needed) built by `tools/build_releases.sh` and published with the desktop artifacts; serve the unzipped folder from any static host
|
|
||||||
- Aim-free selection pass (v0.3.0 work, [ADR-0011](docs/adr/0011-aim-free-selection-and-precision-walk.md)): the focus cone ranks candidates by angle then distance, `Tab` and the mouse wheel cycle nearby people nearest-first and pin the selection, right click clears focus with a short re-acquire grace, the HUD reports how many people are in the ring, and holding `Shift` walks at half speed for close work
|
|
||||||
|
|
||||||
Not yet implemented: live 3D body-camera replay, editor-based GUT integration, and crowd performance profiling/LOD (see `TODO.md`).
|
Gig Line is a local-only single-player game: there is no runtime telemetry or
|
||||||
|
network service, and saves stay in Godot's local `user://` folder. The
|
||||||
### Smoke Test Checklist
|
body-camera overlay is simulated. Asset provenance, AI-assisted image usage and
|
||||||
|
credits are recorded in [`CREDITS.md`](CREDITS.md); the local-data policy is in
|
||||||
1. `godot --path .` starts the game on the venue menu without script errors.
|
[`PRIVACY.md`](PRIVACY.md); accessibility features and gaps are in
|
||||||
2. Choosing a venue (click or ↑/↓ + Enter) starts that venue's shift and hides the menu.
|
[`docs/accessibility.md`](docs/accessibility.md); and release-candidate blockers
|
||||||
3. The guard moves and looks around; the building, steps, and sidewalk are visible.
|
are listed in [`docs/known-limitations.md`](docs/known-limitations.md).
|
||||||
4. The guard's camera sits at eye height and the guard stands on the landing, not inside the building.
|
|
||||||
5. Walking into the steps carries the guard up onto the landing (steps have colliders).
|
|
||||||
6. The skyline backdrop shows silhouettes against the sky, not an opaque black slab.
|
|
||||||
7. The `STEP LINE` marquee is readable from the sidewalk.
|
|
||||||
8. NPCs spawn and approach the entrance during the first minutes.
|
|
||||||
9. Looking at an NPC inside the focus cone shows a blue focus circle in front of the face, the person's name, and the HUD target line.
|
|
||||||
10. `Space` or left click opens the action wheel; `A`/`D` highlight a slice, `Space` confirms it, `Esc`/right click cancels without a log entry.
|
|
||||||
11. `E`/`C` open the inspection/wand panels from the wheel and freeze movement until they close; walking never fires the wand.
|
|
||||||
12. Pressing `Q` produces a reaction log entry and reputation feedback.
|
|
||||||
13. `E` opens access inspection showing venue-correct artifacts and policy result; `A`/`D` record a decision.
|
|
||||||
14. `6` opens the assistance form; submitting shows dispatch feedback.
|
|
||||||
15. `R` opens the emergency form; the button must be held ~1.6s or the call cancels.
|
|
||||||
16. `G` toggles the flashlight (indicator appears in the HUD); `L` toggles the door lock (indicator turns red when locked).
|
|
||||||
17. `F` toggles the debug overlay with NPC states and shift stats.
|
|
||||||
18. The wheel's `Look` slice is eye contact (Level 1) and logs as its own action.
|
|
||||||
19. `Reason` asks why the person is there and logs their `dialogue_lines` reply.
|
|
||||||
20. `Recognize` records the guard's recognition as access evidence; pressing it twice says so.
|
|
||||||
21. `Warn` turns the body camera on (REC overlay appears); `B` toggles it manually.
|
|
||||||
22. `Block` moves the guard between the person and the door.
|
|
||||||
23. The shift review reports the incident count, including interactions left unresolved.
|
|
||||||
24. Escalating on someone (or a responder arriving) makes idle bystanders stop and face the incident.
|
|
||||||
25. Repeated alarms panic the crowd and nearby people clear away from the door instead of standing around.
|
|
||||||
26. `Esc` with nothing open pauses the shift; resume / restart / settings / quit-to-menu all work, and settings changes persist across a restart.
|
|
||||||
27. NPCs route around the building using the navigation mesh (no stuck-at-wall behavior during a smoke run).
|
|
||||||
28. An unjustified emergency call (calm person, no weapon) logs an investigation and costs reputation.
|
|
||||||
29. After an evacuation outcome the door is locked and NPCs are leaving the entrance.
|
|
||||||
30. The shift review's "Body camera timeline" button steps through the recorded events (Left/Right or the buttons) and Esc returns to the review.
|
|
||||||
31. The escalation label shows a `[###--] L3/5` shape meter as well as the level name, and stays readable in grayscale.
|
|
||||||
32. Changing "HUD font scale" in Settings resizes the HUD text and persists across a restart.
|
|
||||||
33. When the shift timer reaches 0, the shift review screen shows grade, incident summary, responder outcomes, investigations, and persisted shift history; "Run another shift" returns to the venue menu.
|
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,479 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
Godot 4.3 prototype. Latest release **v0.5.0** (NPC characters and player movement). Headless
|
Work is grouped by theme. Each item should be small enough to complete and verify on its own;
|
||||||
suite **208/208** plus **56** Python tooling tests; the session, PLAN-verb, crowd, emergency,
|
see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these plans.
|
||||||
timeline, audio, scenario-content, props, NPC-budget, movement, and windowed focus/radial smokes
|
|
||||||
pass. Anonymous downloads are enabled on the host.
|
|
||||||
|
|
||||||
The scheduled presentation pass is complete (see `DONE.md`). Only optional future ideas remain.
|
**Priority order:** Character development → Local map development → versioned release milestones →
|
||||||
|
future/deferred work. See `AGENTS.md` §Priority and Versioning.
|
||||||
|
|
||||||
|
## Character development
|
||||||
|
|
||||||
|
Goal: break the eight-character clone effect with four licence-cleared crowd-variety looks while
|
||||||
|
keeping the frozen `npc_base` bone, tint-slot and gear-attach contract. The procedural generator is
|
||||||
|
the primary path; Quaternius is a reviewed reference and MakeHuman is deferred to a separate local
|
||||||
|
development pipeline. This is the current development priority; keep it out of the frozen
|
||||||
|
0.10.0 release candidate and assign a release version only when its scope is accepted.
|
||||||
|
|
||||||
|
### Source review and decision
|
||||||
|
|
||||||
|
- [x] Research free/open-source character sources and evaluate at least three downloads against
|
||||||
|
the existing Blender contract. (Measured Quaternius CC0, Kenney CC0, Khronos
|
||||||
|
CesiumMan/RiggedFigure CC-BY and the MakeHuman CC0 base mesh; none is a drop-in.
|
||||||
|
Results, local preview sheet and SHA-256 provenance are in
|
||||||
|
`docs/npc-model-sourcing.md`.)
|
||||||
|
- [x] Review the sourcing research with the project owner and choose Option A (procedural),
|
||||||
|
Option B (Quaternius CC0 intake) or Option C (MakeHuman/MPFB body pipeline); record the
|
||||||
|
decision in an ADR and in `MEMORY.md`. (2026-11-03: extend the procedural generator as the
|
||||||
|
primary path, keep Quaternius as a reviewed prototype/reference, defer MakeHuman to a
|
||||||
|
separate local pipeline. Recorded in ADR-0015 and `MEMORY.md`.)
|
||||||
|
- [x] Add a source licence allow-list and provenance rule: CC0 preferred, CC-BY only with
|
||||||
|
attribution in `CREDITS.md`, and no service assets whose terms restrict redistribution.
|
||||||
|
(ADR-0015; the CC-BY research previews are attributed in `CREDITS.md`.)
|
||||||
|
- [x] Decide whether the external preview sheet stays local under `tmp/` or is committed with
|
||||||
|
the required CC-BY attribution. (Committed as
|
||||||
|
`docs/blender_previews/sheet_npc_sources_research.jpg` with Cesium CC-BY attribution;
|
||||||
|
the project-owned crowd prototype sheet is also committed.)
|
||||||
|
|
||||||
|
### Intake and validation
|
||||||
|
|
||||||
|
- [ ] Add a Blender `inspect` path that imports a GLB, applies node transforms, reports
|
||||||
|
tris/verts, bounds, bones, materials, UVs and skinning, and lists contract failures.
|
||||||
|
- [ ] Add an `adapt` path for future external assets: scale/ground, weld seams, decimate, map the
|
||||||
|
five tint slots, and either rebuild the contract armature or record an explicit second-rig
|
||||||
|
contract. The Quaternius prototype showed that a contract rebuild needs a proportion warp,
|
||||||
|
so this is not on the character-development critical path.
|
||||||
|
- [ ] Keep `tools/blender_assets.py audit` as the single final gate; add a regression test for the
|
||||||
|
intake report/adaptation using a deterministic synthetic or licence-cleared fixture.
|
||||||
|
- [ ] Document the adapter commands and the go/no-go checks in `docs/asset-tooling.md`.
|
||||||
|
|
||||||
|
### Quaternius prototype
|
||||||
|
|
||||||
|
- [x] Prototype one Quaternius CC0 variant: weld/decimate to budget and capture Idle/Walk
|
||||||
|
renders. (12,518 imported verts -> 3,199 after weld -> 2,423 / 4,654 tris after a 0.75
|
||||||
|
decimate; Idle/Walk quality is good. Preview in
|
||||||
|
`docs/blender_previews/sheet_npc_sources_research.jpg`.)
|
||||||
|
- [x] Measure the prototype against the `npc_casual` controls: silhouette, rest pose, body
|
||||||
|
proportions and gear fit. (No-go for a contract rebuild: T-pose 62-bone realistic rig,
|
||||||
|
~0.96 m hip, ~1.68 m arm span and ~0.153 m shoulder joint do not match the arm-down
|
||||||
|
13-bone contract. Keep as reference; a second rig/animation path needs its own ADR.)
|
||||||
|
- [x] Make a go/no-go decision on Option B. (No-go for the current pass; proceed with the procedural
|
||||||
|
generator and keep Quaternius as a visual/style reference.)
|
||||||
|
|
||||||
|
### Roster and runtime
|
||||||
|
|
||||||
|
- [x] Approve four crowd-variety looks (build, head silhouette, hair/beard, outer layer and
|
||||||
|
accessory; no clothing that labels the NPC's behaviour). (`npc_crowd_a` bun/slim/sunglasses,
|
||||||
|
`npc_crowd_b` bald/broad/beard/shoulder bag, `npc_crowd_c` coat/umbrella, `npc_crowd_d`
|
||||||
|
hood/cup; prototype sheet committed.)
|
||||||
|
- [ ] Add the four approved specs to `CHARACTERS`, build and commit their GLBs/AO maps, and
|
||||||
|
update the manifest with roles and tint data. (Prototype assets are local under `tmp/`;
|
||||||
|
do not add them to the current release candidate.)
|
||||||
|
- [ ] Replace the fixed `character_model_for()` mapping with deterministic per-role pools and add
|
||||||
|
tests for repeatability and duplicate avoidance.
|
||||||
|
- [ ] Rebuild and verify gear fit for every new variant (`blender_assets.py fit` plus the runtime
|
||||||
|
gear checks).
|
||||||
|
|
||||||
|
### QA and release
|
||||||
|
|
||||||
|
- [ ] Run the 24-NPC budget smoke, portrait baseline, gear fit, headless suite and a release build
|
||||||
|
with the expanded library.
|
||||||
|
- [ ] Update `CREDITS.md`, `docs/development-status.md`, `docs/npc-visual-review.md` and
|
||||||
|
`CHANGELOG.md`; record any accepted visual limits.
|
||||||
|
- [ ] Exit: a reviewed 12-character library passes contract audit, portrait/gear acceptance,
|
||||||
|
the 24-NPC budget and licence/provenance review without changing the runtime contract.
|
||||||
|
|
||||||
|
### Deferred MakeHuman local pipeline
|
||||||
|
|
||||||
|
- [x] Evaluate the MakeHuman CC0 base mesh for a later separate local development pipeline.
|
||||||
|
(19,158 verts / 36,972 tris; scaled to 1.82 m; decimate 0.35 -> 3,780 verts / 6,468 tris;
|
||||||
|
UVs present, no normals/material groups/rig. Feasible only with retopology, a custom rig and
|
||||||
|
project-owned clothing; keep out of CI/build.)
|
||||||
|
- [ ] Decide whether body-shape diversity still matters after the 12-character library lands; if
|
||||||
|
yes, prototype the local MPFB/MakeHuman pipeline outside the repo and commit only the final
|
||||||
|
CC0-derived assets with provenance.
|
||||||
|
|
||||||
|
## Local map development
|
||||||
|
|
||||||
|
Goal: build a local, data-backed map pipeline that can replace or supplement the stylized venue
|
||||||
|
geometry with licensed OpenStreetMap footprints, 3D building massing, reference-derived photoreal
|
||||||
|
facades and AI-assisted composition. This is an unversioned development track, not a release gate.
|
||||||
|
|
||||||
|
### Data, licensing and scope
|
||||||
|
|
||||||
|
- [ ] Define the first target block and whether the result replaces, supplements or only informs
|
||||||
|
the current stylized venue specs (`docs/hollywood-boulevard-map.md`,
|
||||||
|
`docs/joke-shop-map.md`).
|
||||||
|
- [ ] Audit OpenStreetMap's ODbL attribution/share-alike obligations and decide whether derived
|
||||||
|
geometry ships, stays development-only, or needs a separate data layer.
|
||||||
|
- [ ] Choose an offline OSM extract workflow (Overpass/Geofabrik) and pin the extract date and
|
||||||
|
query so the map build is reproducible.
|
||||||
|
- [ ] Evaluate licence-compatible 3D building datasets (OSM Buildings, Overture, CityGML/LOD1–2
|
||||||
|
or local authority data); record coverage, accuracy, format and redistribution terms.
|
||||||
|
- [ ] Add a provenance sidecar for every map source and derived asset, including source URL,
|
||||||
|
licence, capture/extract date and attribution text.
|
||||||
|
|
||||||
|
### Reference imagery
|
||||||
|
|
||||||
|
- [ ] Write a reference shot list per block: facade materials, windows, signage, rooflines,
|
||||||
|
street furniture, curb cuts and lighting.
|
||||||
|
- [ ] Download and catalogue reference images from Wikimedia Commons, local/own photography or
|
||||||
|
other clearly licensed sources; record author, licence and attribution. Do not use
|
||||||
|
unlicensed Street View or scraped commercial imagery.
|
||||||
|
- [ ] Separate development-only references from shipped textures; commit only images with clear
|
||||||
|
redistribution rights and keep the rest under `tmp/` or the ignored reference folders.
|
||||||
|
- [ ] Define the photoreal target and a material-derivation workflow (albedo/normal/roughness,
|
||||||
|
AO, weathering) that matches the existing Compatibility renderer.
|
||||||
|
|
||||||
|
### Geometry and AI-assisted composing
|
||||||
|
|
||||||
|
- [ ] Prototype OSM footprint import into Blender at game scale and orientation, then compare it
|
||||||
|
against the current venue footprint/collider layout.
|
||||||
|
- [ ] Import 3D building massing for the target block, clean the topology and assign LOD bands;
|
||||||
|
do not import unbounded city-scale meshes into the runtime.
|
||||||
|
- [ ] Build a reusable photoreal facade kit (window bays, cornices, storefronts, awnings, signage)
|
||||||
|
so buildings share materials and stay inside the venue triangle/material budgets.
|
||||||
|
- [ ] Add an AI-assisted composition step for palette, facade rhythm and reference boards; record
|
||||||
|
the model, prompt and output, and keep human review as the acceptance gate. AI output must
|
||||||
|
not be treated as licensed map data or shipped without provenance.
|
||||||
|
- [ ] Integrate the result behind `WorldBuilder.VENUE_SPECS` with colliders, navigation obstacles,
|
||||||
|
occlusion and the existing day/night materials.
|
||||||
|
|
||||||
|
### Gaussian splatting evaluation: photo intake and provenance
|
||||||
|
|
||||||
|
Gaussian splatting is evaluated as a photo-driven pipeline: licensed or permissioned photos
|
||||||
|
become a reference, texture source, mesh proxy or distant backdrop. It is an unversioned local
|
||||||
|
track with no runtime dependency or release gate until the ADR closes it, and it extends the
|
||||||
|
reference-image licence and privacy gates above rather than replacing them.
|
||||||
|
|
||||||
|
- [ ] Define the accepted photo channels: project/team captures, volunteer or user-supplied
|
||||||
|
photos with written permission, and downloaded images from clearly licensed archives
|
||||||
|
(Wikimedia Commons, Openverse, Mapillary and similar). Record which channel produced
|
||||||
|
each reconstruction.
|
||||||
|
- [ ] Write a one-page capture brief for user-supplied photos: overlapping arc or orbit around
|
||||||
|
the facade, 60–80% view overlap, 12 MP+ originals, fixed exposure/white balance, HDR and
|
||||||
|
filters off, no motion blur, no people or plates in frame where avoidable, overcast or
|
||||||
|
even light, and the facade height/doors/steps included in several frames.
|
||||||
|
- [ ] Build an intake checklist and provenance sidecar per photo set: contributor, consent or
|
||||||
|
property permission, licence and attribution text, source URL, capture date, camera/lens,
|
||||||
|
location, faces/plates/interiors present, redactions applied, file hashes and whether the
|
||||||
|
set is shipped or development-only.
|
||||||
|
- [ ] Set the licence gate: own photos need an explicit contributor licence; CC0/CC BY are
|
||||||
|
preferred; CC BY-SA triggers a share-alike review for derived textures and meshes; reject
|
||||||
|
Street View, social-media scrapes, unlicensed commercial imagery and AI-upscaled copies of
|
||||||
|
unknown originals. Attribution must be feasible in `CREDITS.md` before use.
|
||||||
|
- [ ] Set the privacy gate: blur or remove faces, minors, licence plates, screens, private
|
||||||
|
interiors and anything behind a closed door; obtain property permission where required;
|
||||||
|
keep a redacted copy as the reconstruction input and never commit the originals.
|
||||||
|
- [ ] Treat downloaded photo sets as sparse and of unknown intrinsics. Use them for reference,
|
||||||
|
palette and texture study, or as extra training views; do not expect a usable splat from
|
||||||
|
10–30 casual web photos of a facade.
|
||||||
|
- [ ] Keep photos, masks, COLMAP databases, checkpoints and splats outside git; commit only
|
||||||
|
derived, licensed, provenance-stamped assets that pass the review gate.
|
||||||
|
|
||||||
|
### Gaussian splatting: reconstruction and alignment
|
||||||
|
|
||||||
|
- [ ] Pin a reproducible offline toolchain (for example COLMAP or GLOMAP for camera poses plus
|
||||||
|
gsplat, OpenSplat, Nerfstudio or Brush for training), with exact versions, GPU/VRAM/disk
|
||||||
|
needs and known failure modes recorded in the sidecar.
|
||||||
|
- [ ] Reconstruct two quality tiers: a dense 100–400-photo arc/orbit capture and a sparse
|
||||||
|
10–30-photo downloaded set. Record camera-registration rate, training time, splat count,
|
||||||
|
file size and held-out PSNR/SSIM/LPIPS for both.
|
||||||
|
- [ ] Mask sky, people, vehicles and moving foliage before training; verify the masks do not
|
||||||
|
erase facade edges, signage or window detail, and keep the redacted input variant.
|
||||||
|
- [ ] Align the splat to game coordinates from the OSM footprint plus surveyed points (door
|
||||||
|
width, column spacing, step rise, storefront height) and record alignment residuals in a
|
||||||
|
Blender scene containing both the splat and the current venue geometry.
|
||||||
|
- [ ] Judge quality from held-out views and a render from the game’s day/night camera poses,
|
||||||
|
not from training views alone; reject splats that only look correct from the capture path.
|
||||||
|
- [ ] Maintain a coverage map per block: which facades, corners and rooflines have usable views,
|
||||||
|
and which areas must fall back to the facade kit or stylized geometry.
|
||||||
|
|
||||||
|
### Gaussian splatting: map enhancement paths
|
||||||
|
|
||||||
|
- [ ] **Path A — Reference and QA (lowest risk):** render the splat from game camera poses and
|
||||||
|
compare it with the realism captures; derive dimensions, signage placement, facade rhythm
|
||||||
|
and material colours. No splat data reaches the runtime.
|
||||||
|
- [ ] **Path B — Texture derivation:** project splat renders onto the facade kit to produce
|
||||||
|
albedo, normal, roughness and AO candidates; de-light and bake them, then verify UV scale,
|
||||||
|
tiling and readability under the Compatibility renderer.
|
||||||
|
- [ ] **Path C — Mesh proxy:** extract a mesh from the splat or dense reconstruction, retopo and
|
||||||
|
dress it in Blender, assign LODs, and keep it inside the venue triangle/material budgets
|
||||||
|
with mesh-based colliders and navigation.
|
||||||
|
- [ ] **Path D — Distant backdrop:** test a baked panorama, impostor or billboard generated from
|
||||||
|
the splat for skyline and opposite-street depth where the player cannot walk; measure file
|
||||||
|
size, loading and visible pop at the venue boundary.
|
||||||
|
- [ ] **Path E — User-photo supplement:** let a small supplied photo set improve one facade or
|
||||||
|
landmark (a signage patch, colour reference or hero detail) without rebuilding the venue;
|
||||||
|
define the minimum evidence and the same licence/privacy/review gate as a full capture.
|
||||||
|
- [ ] For every path record quality gain versus effort, licence compatibility of the derived
|
||||||
|
output, and whether the result may ship or stays development-only. Prefer the cheapest
|
||||||
|
path that closes the visible gap.
|
||||||
|
|
||||||
|
### Gaussian splatting: runtime evaluation and decision
|
||||||
|
|
||||||
|
- [ ] Probe Godot 4.7.2 Compatibility and Web support for splat rendering in a throwaway scene:
|
||||||
|
addon or importer availability, shader/sort cost, memory, load time and fallback behaviour.
|
||||||
|
Do not add a splat dependency to the release project during evaluation.
|
||||||
|
- [ ] Set hard limits before any runtime experiment: maximum per-splat file size and total
|
||||||
|
memory, allowed frame-time delta on the 24-NPC budget scene, acceptable Web load time, and
|
||||||
|
no compute-shader requirement for the Compatibility/Web path.
|
||||||
|
- [ ] Keep collision and navigation mesh-based even if a splat is displayed; a splat must never
|
||||||
|
become the playable floor or the access/occlusion authority.
|
||||||
|
- [ ] Write the ADR with a per-path go/no-go, the accepted licence/provenance rules, whether each
|
||||||
|
result ships or stays development-only, rejected alternatives and the evidence bundle.
|
||||||
|
- [ ] Exit: one licensed photo capture measurably improves a venue through a documented path and
|
||||||
|
passes visual, performance and provenance review; or the approach is rejected with
|
||||||
|
reproducible findings and removed from the release path.
|
||||||
|
|
||||||
|
### QA and exit
|
||||||
|
|
||||||
|
- [ ] Compare the data-backed block against the existing screenshots and map documentation; keep
|
||||||
|
the stylized fallback available.
|
||||||
|
- [ ] Run the venue triangle/mesh budget, navigation and collider checks, plus day/night capture
|
||||||
|
comparisons.
|
||||||
|
- [ ] Update `docs/architecture.md`, the venue map documents, `docs/asset-tooling.md`,
|
||||||
|
`docs/development-status.md` and `CHANGELOG.md` when the pipeline ships or a source is
|
||||||
|
rejected.
|
||||||
|
- [ ] Exit: one local block is reconstructed from licensed data with reference-derived photoreal
|
||||||
|
facades, passes performance/navigation/visual QA and has complete provenance; or the
|
||||||
|
pipeline is rejected with the findings recorded.
|
||||||
|
|
||||||
|
## Milestone 0.10.0 — Release candidate
|
||||||
|
|
||||||
|
Goal: freeze the feature set, prove it with external players, clear release/legal blockers and
|
||||||
|
verify every distribution path. This remains the next versioned release after the 0.9.x patch
|
||||||
|
line, but follows the unversioned character and local-map tracks in planning order.
|
||||||
|
|
||||||
|
### Content lock and external playtest
|
||||||
|
|
||||||
|
- [x] Declare a content/feature freeze for 0.10.0; only release-blocking fixes and balance changes
|
||||||
|
may land after the freeze. (Frozen 2026-11-03 after the 0.9.6 integration
|
||||||
|
checkpoint; this pass is limited to release reliability, accessibility,
|
||||||
|
balance evidence and packaging.)
|
||||||
|
- [x] Produce a release-candidate build with the tutorial, campaign, all three venues, Help,
|
||||||
|
accessibility settings and checkpoint/resume enabled. (Clean worktree
|
||||||
|
`a9658ec` built `0.10.0-rc.1`: Linux 161.5 MB, Windows 197.2 MB, macOS
|
||||||
|
148.0 MB, Web 97.8 MB and HQ 241.6 MB. The Web/HQ archives include the
|
||||||
|
credits, privacy, accessibility and known-limitations pages; SHA-256
|
||||||
|
manifests were written; the Linux and HQ binaries launched headless and the
|
||||||
|
Web index/wasm/pck/docs returned HTTP 200. Not published because external
|
||||||
|
playtest and legal approval remain open.)
|
||||||
|
- [ ] Run at least five first-time-player sessions covering the tutorial and one full venue shift;
|
||||||
|
record where players get stuck, misunderstand evidence or choose disproportionate escalation.
|
||||||
|
- [ ] Triage findings by severity (P0/P1/P2) and fix every P0/P1 onboarding/accessibility issue;
|
||||||
|
keep the rest as explicit known limitations or post-0.10 items.
|
||||||
|
- [ ] Re-run the affected tutorial/campaign smokes after each fix and capture a fresh first-hour
|
||||||
|
walkthrough for the release notes.
|
||||||
|
|
||||||
|
### Balance and fairness pass
|
||||||
|
|
||||||
|
- [x] Define measurable targets for routine compliance, access-decision accuracy, peaceful
|
||||||
|
resolution, justified emergency calls and false-positive/false-negative rates.
|
||||||
|
(`docs/balance-acceptance.md` defines cohorts, denominators, 36 matrix cells,
|
||||||
|
seeds, thresholds and matched emergency-first comparisons. Documentation verified;
|
||||||
|
targets are not measured results.)
|
||||||
|
- [ ] 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. Include the
|
||||||
|
type-derived `_read_npc_truth()` mismatch with observed threats/forced entry;
|
||||||
|
use independently labelled behavior evidence, not the helper as its own oracle.
|
||||||
|
- [ ] 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
|
||||||
|
|
||||||
|
- [x] 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. (Committed
|
||||||
|
fixtures under `src/test/fixtures/saves/`; 9 migration/failure tests cover
|
||||||
|
old settings/campaign/history, the 0.9.0 checkpoint, all three venue
|
||||||
|
checkpoint round-trips, clean install, corrupt JSON and a blocked atomic
|
||||||
|
replace. Suite is now 272 tests.)
|
||||||
|
- [x] Test fresh install → tutorial → campaign → pause → quit → resume → review → next venue on
|
||||||
|
an isolated user-data directory. (Tutorial and campaign smokes shared one
|
||||||
|
isolated `XDG_DATA_HOME`; tutorial completion/replay/skip then campaign
|
||||||
|
resume/review-continue/help both passed. Pause/menu behavior is covered by
|
||||||
|
`smoke_session_shell.gd`.)
|
||||||
|
- [x] Test corrupt JSON, partial temp files, missing optional fields and a failed atomic rename;
|
||||||
|
confirm fallback behavior never destroys a valid save. (Corrupt/partial files
|
||||||
|
fall back to defaults; a blocked temp path reports an error and leaves the
|
||||||
|
prior valid settings intact. `_load_json` now uses the non-logging JSON
|
||||||
|
instance parser.)
|
||||||
|
- [x] Verify checkpoint resume after all three venues, after an incident, with NPCs at the door and
|
||||||
|
with flashlight/body-camera/door state set. (The migration suite round-trips a
|
||||||
|
checkpoint for Hollywood, the Joke Shop and the TV Studio with an open
|
||||||
|
incident, one NPC row, flashlight/body-camera/door flags; the campaign smoke
|
||||||
|
resumes a live checkpoint through the real `GameManager`.)
|
||||||
|
- [x] Document save locations, schema versions, reset behavior and rollback/export instructions in
|
||||||
|
`docs/getting-started.md` and the release notes. (`getting-started.md` now
|
||||||
|
documents the four files, version-1 checkpoint, atomic write/fallback,
|
||||||
|
clean install, reset and backup/rollback.)
|
||||||
|
|
||||||
|
### Release engineering and distribution
|
||||||
|
|
||||||
|
- [x] Run `tools/build_releases.sh` from a clean checkout and verify Linux/Windows/macOS/Web/HQ
|
||||||
|
artifact names, sizes and checksums. (Clean worktree `a9658ec` built the
|
||||||
|
five artifacts listed above; `PUBLISH_DRY_RUN=1` produced and printed
|
||||||
|
`build/SHA256SUMS-0.10.0-rc.1.txt` without touching the API.)
|
||||||
|
- [ ] Smoke-test fresh Linux portable/AppImage, Windows portable/installer, macOS unzip/launch,
|
||||||
|
Web static hosting and Desktop HQ Vulkan fallback on the target matrix.
|
||||||
|
(Linux portable and Desktop HQ launched headless; Web files served over a
|
||||||
|
local static server with HTTP 200. AppImage/installer were not built locally
|
||||||
|
and Windows/macOS launch testing still needs the target matrix.)
|
||||||
|
- [x] Add a disk-space preflight and retention policy to the release/publish scripts so a full
|
||||||
|
Gitea host cannot leave a partially uploaded release. (`publish_release.sh`
|
||||||
|
checks artifact size/free space, writes SHA-256 checksums, supports
|
||||||
|
`PUBLISH_DRY_RUN`, rolls back uploaded assets/new releases on failure, and
|
||||||
|
offers opt-in `RETAIN_RELEASES` pruning; dry-run verified.)
|
||||||
|
- [x] 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.
|
||||||
|
(Source/version and tag are both 0.9.6; all seven published releases carry
|
||||||
|
5–7 assets, including the retained v0.8.0/v0.8.1/v0.9.0/v0.9.1 line.
|
||||||
|
`publish_release.sh` documents opt-in `RETAIN_RELEASES` pruning and
|
||||||
|
`RELEASING.md` describes the seven-release policy.)
|
||||||
|
- [x] Decide and document whether macOS signing/notarization is required for 0.10.0 or explicitly
|
||||||
|
remains a future release blocker; record the quarantine instructions either way.
|
||||||
|
(0.10.0 ships unsigned with quarantine instructions; signing/notarization
|
||||||
|
remains an explicit public-release blocker in `RELEASING.md` and
|
||||||
|
`known-limitations.md`.)
|
||||||
|
|
||||||
|
### Legal, credits and platform policy
|
||||||
|
|
||||||
|
- [x] Audit AI-assisted asset provenance and licenses; record source/model usage and any
|
||||||
|
redistribution constraints for textures, characters, props and UI art.
|
||||||
|
(`CREDITS.md` records the Blender/OpenRouter toolchain, default model slugs,
|
||||||
|
missing per-file generation metadata and the commercial-rights review as an
|
||||||
|
explicit release blocker.)
|
||||||
|
- [x] Audit audio/SFX/music licensing (or confirm everything is procedural) and add a credits file.
|
||||||
|
(All runtime audio is procedural; no external music/SFX files are bundled.
|
||||||
|
`CREDITS.md` records this.)
|
||||||
|
- [x] Review body-camera/privacy language, mental-health-crisis representation, age/content rating
|
||||||
|
and storefront requirements; fix any release-blocking copy or content.
|
||||||
|
(`PRIVACY.md` clarifies the simulated body camera/local-only data; the
|
||||||
|
accessibility and known-limitations pages record the remaining
|
||||||
|
mental-health/rating/storefront review as a release blocker rather than
|
||||||
|
claiming approval.)
|
||||||
|
- [x] Add the player-facing credits, known limitations, accessibility statement and privacy note to
|
||||||
|
the release package/README. (`README.md` links `CREDITS.md`, `PRIVACY.md`,
|
||||||
|
`docs/accessibility.md` and `docs/known-limitations.md`; the Web and Desktop
|
||||||
|
HQ package builders copy those documents into the shipped archives.)
|
||||||
|
- [ ] Mark external legal/storefront approval as complete or explicitly block the 0.10.0 release 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.
|
||||||
|
- [x] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
|
||||||
|
- [x] Document the character development toolchain in `docs/architecture.md`: base vs library
|
||||||
|
sources, tool/artifact/gate table, runtime attach/animation contracts and rebuild discipline.
|
||||||
|
(Added §5 "Character development tooling" plus risk and ownership-map updates;
|
||||||
|
documentation check passed.)
|
||||||
|
|
||||||
|
### 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-0.10 work.
|
||||||
|
- [ ] Create the `v0.10.0` 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 0.10.0 release candidate.
|
||||||
|
|
||||||
|
## Gap Analysis and 0.x Roadmap
|
||||||
|
|
||||||
|
Baseline: **v0.9.6** (2026-11-03). Three playable venues, tutorial/campaign/checkpoint resume,
|
||||||
|
difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
|
||||||
|
escalation/access/radio loop, shift review, the Blender asset library, 272 headless + 101 Python
|
||||||
|
tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is the
|
||||||
|
baseline; 0.10.0-rc.1 is the current candidate source, with release approvals still open.
|
||||||
|
|
||||||
|
### Documentation audit (completed 2026-11-01)
|
||||||
|
|
||||||
|
- [x] Make `docs/architecture.md` the single architecture source: asset/content pipeline
|
||||||
|
contracts, runtime venue-switch/fallback flows, deployment/version constraints, quality
|
||||||
|
requirements, risk register and documentation ownership map.
|
||||||
|
- [x] Keep command-heavy operational pages separate but subordinate: `docs/asset-tooling.md`,
|
||||||
|
`docs/blender-assets.md`, `docs/getting-started.md`, `docs/RELEASING.md` and
|
||||||
|
`docs/smoke-checklist.md` link to architecture rather than acting as parallel sources.
|
||||||
|
- [x] Remove the obsolete `docs/plan-graphics-v0.6.md` and its links; completed graphics work is
|
||||||
|
represented by ADR-0013, the asset pipeline section and the changelog.
|
||||||
|
- [x] Resolve stale claims: README release version/download row, development status
|
||||||
|
"Forward+ not implemented", and Blender props "not AO-baked".
|
||||||
|
- [x] Record the documentation ownership rule in `docs/architecture.md` §12: design intent
|
||||||
|
(`PLAN.md`), mechanics (`gameplay.md`), system architecture/contracts (`architecture.md`),
|
||||||
|
decisions (ADRs), status (`development-status.md`), roadmap (`TODO.md`), operations
|
||||||
|
(tooling/release docs).
|
||||||
|
|
||||||
|
### Gap register (remaining roadmap)
|
||||||
|
|
||||||
|
| Area | Current baseline | Remaining gap | Risk | Milestone |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| Character development | 8-variant library; source/licence review and Quaternius/MakeHuman evaluation complete | Four crowd variants, role pools, gear fit and runtime integration | Repetition remains or external assets break the contract | Unversioned |
|
||||||
|
| Local map development | Stylized venue geometry and reference maps | OSM/3D data, photoreal references, AI-assisted composition and splat evaluation | Licensing/provenance or performance failure | Unversioned |
|
||||||
|
| 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 the release candidate | 0.10.0 |
|
||||||
|
| Dialog/UI | Audited terminology, copy, button states, focus/navigation, modal close, long strings and all 21 screen captures | Keep the capture/compare/judge gate current as content changes | Low; the remaining risk is drift after new UI is added | Complete (0.9.3) |
|
||||||
|
| Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping, 8,000/8,000 NPC cap | Thorough NPC silhouette/face/gear/pose/LOD optimization before visual QA | Close-up jank reduces perceived quality | Complete (0.9.4) |
|
||||||
|
| 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 release cannot claim accessible play | 0.10.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.10.0 |
|
||||||
|
| Performance/platform | 24-NPC headless budget (6.94 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.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.10.0 |
|
||||||
|
| QA/CI | Headless suite, smokes, screenshot compare, 21/21 judge | Release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.6 / 0.10.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.10.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.6 / 0.10.0 |
|
||||||
|
| Future 0.x | Stable 0.x feature set | Live replay, more venues, VO/music, image-to-mesh props and seasonal content | Scope creep before release | Unscheduled |
|
||||||
|
|
||||||
|
**Current priority:** the unversioned **Character development** and **Local map development**
|
||||||
|
tracks are the active planning order. The **0.10.0 release candidate** follows them in this list
|
||||||
|
as the next versioned release; content lock, external playtest, balance, save migration and
|
||||||
|
release/legal sign-off remain tracked there. The source version is 0.10.0-rc.1; the v0.9.6
|
||||||
|
release is published. Earlier map/NPC/UI/texture/integration passes are complete and in
|
||||||
|
`DONE.md`.
|
||||||
|
|
||||||
|
## Future 0.x / non-blocking candidates
|
||||||
|
|
||||||
|
- [ ] Live 3D body-camera replay.
|
||||||
|
- [ ] Additional venues or seasonal events.
|
||||||
|
- [ ] Real voice/dialogue audio.
|
||||||
|
- [ ] Image-to-mesh prop pipeline.
|
||||||
|
- [ ] Rare easter eggs/cameos (e.g. Bob Dobbs) only after core content and QA are stable.
|
||||||
|
|
||||||
|
## Roadmap dependencies and risks
|
||||||
|
|
||||||
|
- Content volume is the largest schedule risk; tutorial and campaign work must not outrun the
|
||||||
|
event/dialogue matrix.
|
||||||
|
- The vision judge is a dev-time aid with an external key/budget; CI must never make it a hard gate.
|
||||||
|
- Godot version changes can alter lighting/imports; do not combine an engine baseline move with a
|
||||||
|
content/feature milestone.
|
||||||
|
- Signed macOS builds and legal/AI provenance are release blockers, not polish.
|
||||||
|
- Photo-derived map assets add a second provenance risk: downloaded or user-supplied photos can
|
||||||
|
carry unclear licences, identifiable people, plates and property restrictions. No photo or
|
||||||
|
splat-derived asset ships without a completed sidecar, consent/licence review and redaction.
|
||||||
|
- Gaussian-splat training is GPU/disk-heavy and the toolchain churns quickly; keep it offline,
|
||||||
|
version-pinned and outside CI, and never make a runtime splat renderer a release dependency.
|
||||||
|
- Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
|
||||||
|
difficulty and feedback.
|
||||||
|
|
||||||
|
## Realism follow-ups (deferred)
|
||||||
|
|
||||||
|
- [x] Re-run the screen-design judge for `12-joke-shop`, `13-studio-arrival` and the
|
||||||
|
Forward+ A/B with the valid key: **13/13 match, 0 diff**; the HQ A/B is in the report.
|
||||||
|
- [ ] Capture a hooded/winter NPC close-up once a scenario spawns types 5-7 (the explicit
|
||||||
|
`--portrait-type` override is already in `capture_realism.gd`).
|
||||||
|
- [ ] Human-authored tree/hedge silhouettes: the whole scene now reads well except the foliage,
|
||||||
|
which is still flat-shaded clumps (`_shrub()`/`_tree()` in `tools/blender_assets.py`).
|
||||||
|
Only worth doing if a higher-poly organic builder is added to the library.
|
||||||
|
- [ ] Camera height: the concept frames are shot at ~1.55 m with a slightly wider lens; the game
|
||||||
|
camera sits at 1.7 m. Decide whether the first-person height should match the art direction
|
||||||
|
or stay at the current gameplay value.
|
||||||
|
|
||||||
## Future ideas (optional, not scheduled)
|
## Future ideas (optional, not scheduled)
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1007 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1004 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1000 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 954 KiB |
|
After Width: | Height: | Size: 910 KiB |
|
After Width: | Height: | Size: 971 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1021 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 13 KiB |