Compare commits

..
63 Commits
Author SHA1 Message Date
zwitschi a57b86cd48 Release 0.9.4 NPC visual optimization
Full build / Import + headless tests (push) Successful in 47s
Full build / Full desktop build + optional release (push) Successful in 5m28s
2026-11-02 19:51:36 +01:00
zwitschi dfe5056303 Round the NPC shoes and responder boots
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:38:40 +01:00
zwitschi 58cf12fd1d Move hand gear forward into the palm
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:33:42 +01:00
zwitschi 7150bd7673 Verify NPC headgear clearance after the face pass
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:30:19 +01:00
zwitschi 12e70357c5 Refine the NPC nose, mouth and ears
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:29:19 +01:00
zwitschi 7dc3d3c873 Raise the character mesh budget to 8000
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:25:41 +01:00
zwitschi cd5e0e0ff7 Record the NPC vertex-cap constraint
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:22:34 +01:00
zwitschi 8ce62e7556 Group the NPC visual changes under Changed
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:15:15 +01:00
zwitschi 24c939d388 Rebuild the NPC hands and add a hand capture
Full build / Import + headless tests (push) Successful in 50s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:14:55 +01:00
zwitschi 48082c3dfa Taper the NPC torso into the hips
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:11:28 +01:00
zwitschi 03c355e7c1 Recess NPC eyes and sculpt the jaw and cheeks
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:08:26 +01:00
zwitschi 15ab8c686d Smooth the NPC neck and shoulder transition
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
2026-11-02 19:03:38 +01:00
zwitschi ab9c67d266 Audit NPC body proportions against a shared guide
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Measure all eight exported characters and record the stylized proportion bands. All variants pass; no skeleton or mesh rescale was needed.
2026-11-02 18:54:52 +01:00
zwitschi 7c1a4bfd69 Refit the tourist backpack and photo prop
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Hide the tourist photo-pose bag outside camera poses, flatten the backpack straps onto the chest, rebuild the gear GLB/AO and publish the before/after NPC sheet.
2026-11-02 18:39:03 +01:00
zwitschi e7ee177c31 Establish the 0.9.4 NPC visual baseline
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Add a neutral 48-frame character contact sheet, acceptance criteria and ranked baseline gaps, plus repeatable sheet/comparison tooling. No character GLB or runtime mesh changes.
2026-11-02 18:13:57 +01:00
zwitschi c1cd4898e8 Close the 0.9.3 UI polish milestone
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
Add deterministic captures 14-21 for the remaining screen-design states, fix the panel/button layout issues they exposed, and record 21/21 compare and judge results. Bump the source to 0.9.3 and move the completed milestone to DONE.md.
2026-11-02 17:57:40 +01:00
Gig Line Dev e805a91ad3 Add end-to-end interaction flow smoke
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
- Boot the real scene and verify inspection allow/deny, normal vs emergency radio, Help filtering, wand allow/deny and review return-to-menu.
- Document the flow coverage and smoke command; mark the 0.9.3 end-to-end audit complete.
2026-11-02 16:36:01 +01:00
Gig Line Dev 7315166361 Guard destructive settings and radio actions
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Route reset campaign and tutorial replay through one reusable confirmation dialog; repeated presses cannot stack or emit twice.
- Keep emergency hold-to-send single-shot and cover the post-submit release.
- Add destructive-action regression checks, strings and documentation.
2026-11-02 16:29:26 +01:00
Gig Line Dev f6aa26e6ca Harden UI layout for font scale and long strings
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Measure and cap the HUD target chip after each font-scale change; clip HUD top labels.
- Ellipsize long action-button labels so panels cannot grow past the viewport.
- Add accessibility/button layout assertions and refresh the gallery captures.
- Record the font/layout pass in TODO, docs, changelog and memory.
2026-11-02 16:23:46 +01:00
Gig Line Dev 26e6dd6413 Close every top modal through one Esc and right-click path
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
- Add Help, Settings, Pause and review to the top-modal close chain so right-click and Esc behave consistently.
- Restore the venue menu after menu Settings and prevent Help from opening Pause behind itself.
- Reopen pause after in-shift Settings apply and recapture the mouse/unfreeze state on close.
- Extend the session smoke for menu Settings, right-click Help and guard unfreeze.
2026-11-02 16:10:50 +01:00
Gig Line Dev 8f65751975 Add wrapping keyboard and gamepad focus rings
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
- Link every modal's enabled controls into a wrapping UiFocus ring and give each screen a default focus target.
- Add gamepad A/B bindings for ui_accept/ui_cancel; include Start menu footer actions and Continue in its focus ring.
- Skip hidden/disabled controls, close focus traps via per-modal cancel behavior, and return review to the menu on cancel.
- Record the focus audit and add regression coverage.
2026-11-02 16:05:53 +01:00
Gig Line Dev 9692f262f1 Unify action-button states across the UI
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 39s
- Add UiStyles with explicit normal, hover, pressed, focus and disabled styles and apply it to every action button.
- Disable timeline Previous/Next at the first/last event and keep Close always available.
- Style settings reset-dialog buttons and cover the button-state audit in docs/ui-copy.md.
- Add shared-state and timeline-boundary regression tests.
2026-11-02 15:04:38 +01:00
Gig Line Dev 98c31fe44c Audit and fix NPC, door-staff and UI dialogue
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Skipped
- Route the Reason verb through authored reason contexts and give every shared archetype an in-character answer.
- Add Hollywood wristband and TV Studio ticket/credential door-staff lines.
- Clarify radio cancellation, Ask terminology, start hints and campaign-reset copy.
- Record the dialogue audit and length findings in docs/ui-copy.md; add regression tests.
2026-11-02 14:44:01 +01:00
Gig Line Dev daf0926d91 Bump source to 0.9.2 and renumber the 0.x roadmap
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 36s
- Set project.godot to 0.9.2 and add the matching changelog entry.
- Renumber the postponed work to 0.9.3 UI, 0.9.4 NPC, 0.9.5 textures and 0.9.6 integration, with 0.10.0 as the next minor release candidate.
- Remove the 1.0.0 milestone and post-1.0 planning; plan only 0.x patch/minor increments.
- Synchronize README, PLAN, architecture, status, memory and UI-copy version references.
2026-11-02 14:39:50 +01:00
Gig Line Dev f71a36faa1 Pass the pre-build NPC review gate
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
- Add a review harness that stages all eight library characters at portrait, conversation and crowd distance on both maps in day and night.
- Fix the final-context lanyard badge and firefighter helmet fit with runtime attach offsets; the asset-space gear contract is unchanged.
- Record the gate sign-off, refresh the gallery, and move the completed review to DONE.
2026-11-02 14:32:10 +01:00
Gig Line Dev 37f925c7ad Rebuild the Joke Shop as the Sunset Strip block
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
- Replace the alley with the 27 m Comedy Store-inspired hall, signature canopy, circular blade sign, red curtain bays, west entrance, low-rise neighbours, dry hillside and opposite frontage.
- Add day/night/across-street concept frames and real-site mapping notes.
- Expose the Joke Shop day stage in the realism captures and refresh the gallery shots.
- Render multiline HUD/wand strings correctly and list carried items in the wand panel.
- Add the Joke Shop layout/budget tests and update docs, roadmap and changelog.
2026-11-02 14:10:07 +01:00
zwitschi 74dc1fdc1d Map 1: rebuild Hollywood as the El Capitan landmark
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Replace the generic boulevard facade with a stylized 6840 Hollywood Blvd block: six Ionic columns, eight stone steps, Masonic frieze/medallions, event banners, side doors, El Capitan Theatre and retail neighbours, Ovation Hollywood arcade, Walk of Fame and four-lane street markings.

Add the Day and Night Hollywood venue-menu rows. Night uses a phase-time offset so a full-length shift stays in LATE while the clock starts at zero; late routine traffic keeps the street populated and the offset round-trips through checkpoint restore.

Retune local-light falloff to linear attenuation, add a cool north sky fill, and use the smooth limestone facade texture. Refresh the staged gallery and map references; add geometry-budget, menu, night-offset and late-traffic tests.
2026-11-02 12:34:48 +01:00
zwitschi 3f335481d6 Prioritize map optimization and gate builds on an NPC revisit
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Move the promoted 0.9.5 map work to the active milestone, postpone UI/NPC
detail/texture/integration/release-candidate work, and add a detailed pre-build
NPC gate that reviews portraits, gear fit, crowd distance and final lighting
before any build or tag.
2026-11-02 11:27:50 +01:00
zwitschi af923b1483 Route UI labels through the string table
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Move start menu, settings, pause, Help, HUD, radio, shift review and campaign
labels/templates into content/strings.en.json, including placeholder-validated
dynamic status text. No player-facing hardcoded labels remain outside dynamic
data/debug output. Headless 250/250, docs check OK.
2026-11-02 11:25:15 +01:00
zwitschi 3a74cedee0 Refresh gallery and record the screen-design judge
Full build / Import + headless tests (push) Successful in 37s
Full build / Full desktop build + optional release (push) Skipped
Regenerate the committed screenshot gallery on the current build, run compare
(13 good/0 bad) and the automatic-model judge (13/13 match, 0 diff), and record
the result. Update the 0.9.2 visual checklist items.
2026-11-02 11:18:36 +01:00
zwitschi 844e39246a Standardize button labels and document UI states
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Finish the button-label audit with a surface-by-surface table, clarify Quit
game vs Quit to menu, rename Apply to Apply settings, and use string-table
keys for the new labels. Extend the smoke checklist with UI copy/button checks.
Headless 250/250, docs check OK.
2026-11-02 11:12:29 +01:00
zwitschi 7c48183410 Start the UI copy and button consistency pass
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Add the screen/copy/button inventory and canonical terminology, standardize
inspection/wand admit-refuse hints, name the review action Return to menu, and
move radio action/hold/status labels into the string table. Headless 250/250,
Python 97/97, docs check OK.
2026-11-02 11:10:39 +01:00
zwitschi 64590fe797 Plan the 0.10.0 minor and thorough NPC visual pass
Full build / Import + headless tests (push) Successful in 33s
Full build / Full desktop build + optional release (push) Skipped
Renumber the pre-release patches after shipped 0.9.1, promote the next release
candidate to 0.10.0, and expand NPC work into reference/acceptance, proportions,
face/hair, hands/clothing, gear fit, pose/performance and visual verification.
Sync the README status and remaining-gap references.
2026-11-02 10:55:38 +01:00
zwitschi 49bfccc808 Add a docs README and link checker
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Add tools/check_docs.py to require READMEs only in tracked docs directories,
validate local links and verify every tracked image is linked. Gitignored
generated files such as realism runs are exempt. Document the command and add
unit tests. Python 97/97.
2026-11-02 10:52:15 +01:00
zwitschi 7401d4bca0 Do not require READMEs in generated realism folders
Full build / Import + headless tests (push) Successful in 39s
Full build / Full desktop build + optional release (push) Skipped
Remove generated README files from docs/screens/realism and update the screens
index to treat realism as a gitignored local QA directory with no README gate.
2026-11-02 10:50:20 +01:00
zwitschi e79a37beba Add documentation folder READMEs and visual previews
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped
Create an index README in docs/ and every tracked docs subfolder, with relative
image galleries for Blender previews, screen designs, screenshots and concepts.
Generated realism-run READMEs were also created on disk but remain gitignored.
Validate all Markdown/image links.
2026-11-02 10:49:42 +01:00
zwitschi fbd2ab2cb3 Disable unreliable Gitea Godot cache steps
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Skipped
Gitea cache restores were inconsistent and cache saves timed out or were
rejected as reserved by another job. Remove the cache steps and keep direct
4.7.2 downloads; document the evaluation and when to retry. The workflow is
otherwise clean (no .github/ci.yml exists).
2026-11-02 09:51:59 +01:00
zwitschi 9b8f513f9f Trim the Godot template cache and separate CI cache keys
Full build / Import + headless tests (push) Successful in 2m24s
Full build / Full desktop build + optional release (push) Skipped
Cache only Linux/Windows/macOS/Web release templates instead of the full 1.2 GB
archive, and use distinct binary cache keys for the checks and build jobs so
concurrent runs do not fight over the same cache entry.
2026-11-02 09:48:05 +01:00
zwitschi ad12fdad7e Bump to 0.9.1 and record the toolchain update
Full build / Import + headless tests (push) Successful in 2m23s
Full build / Full desktop build + optional release (push) Successful in 9m44s
2026-11-02 09:28:13 +01:00
zwitschi 87612f2057 Unify the Godot 4.7.2 CI environment and cache it
Full build / Import + headless tests (push) Successful in 2m30s
Full build / Full desktop build + optional release (push) Skipped
Update project features and CI installs/templates to Godot 4.7.2, remove the
old version matrix, and cache the Godot binary and export templates with Gitea
Actions cache. Update release/docs/version references accordingly. Project
import and headless tests pass locally under 4.7.2.
2026-11-02 09:25:08 +01:00
zwitschi ffd98daf08 Plan the pre-RC patch levels
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Add detailed 0.9.1 UI/dialog/button polish, 0.9.2 NPC model refinement,
0.9.3 texture/material refinement and 0.9.4 integration/performance/judge
workstreams before the 0.9.5 release candidate. Update the remaining-gap table,
baseline to v0.9.0 and README development status.
2026-11-02 09:16:33 +01:00
zwitschi f811e6054d Expand the 0.9.5 release-candidate checklist
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Replace the remaining-gap table with v0.9.0 baselines and break the release
candidate into detailed workstreams for content lock/playtests, balance,
save migration, release engineering, legal/credits, documentation/visual
sign-off and final QA. Sync the README development status to v0.9.0.
2026-11-02 08:54:39 +01:00
zwitschi 9d37e0a1c5 Bump the project version to 0.9.0
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Successful in 5m0s
2026-11-01 21:48:03 +01:00
zwitschi 883626a067 Ship the 0.9.0 production-quality milestone
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Canceled after 4m58s
Add mixer/accessibility settings, caption/reduce-motion hooks, audio volume
clamping, a 24-NPC performance smoke and shortened coat/dress stride for hem
clipping. Record the explicit Godot 4.3-CI/4.7-local matrix and the 0.9
production scope. Headless 250/250, Python 94/94, 24-NPC budget smoke passes.
2026-11-01 21:46:42 +01:00
zwitschi b5d4d5fb87 Plan detailed 0.9.0 production-quality steps
Full build / Import + headless tests (push) Successful in 43s
Full build / Full desktop build + optional release (push) Skipped
Expand the next milestone into animation, audio, localization, accessibility,
performance/platform, QA/visual baselines, Godot-version policy and exit
criteria, with concrete verification work per workstream.
2026-11-01 21:39:29 +01:00
zwitschi fac9b002c3 Fix normal radio report submission
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Failing after 4m22s
The radio button was connected only to the emergency hold handlers, so a
normal Send request never reached _submit. Connect pressed for non-emergency
calls while keeping hold-to-confirm exclusive to emergencies, and add tests
for click, short-hold rejection and full emergency hold. Headless 249/249,
Python 94/94.
2026-11-01 21:37:39 +01:00
zwitschi aa51ee331e Ship the 0.8.0 first-hour and campaign milestone
Full build / Import + headless tests (push) Successful in 41s
Full build / Full desktop build + optional release (push) Successful in 4m18s
Add the campaign shell, pause-safe checkpoint resume, post-shift campaign
continue, confirmed campaign reset, difficulty presets, searchable Help,
content-matrix validation, recovery events, contextual dialogue, policy/debrief
context and eligible-event previews. Extend persistence with atomic separate
files and add campaign/checkpoint/tutorial smokes. Headless 247/247, Python
94/94, tutorial/campaign/session/scenario smokes green.
2026-11-01 21:21:43 +01:00
zwitschi 86332cd401 Wire the first-shift tutorial into gameplay
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Add the non-blocking prompt card, safe compliant visitor, action-driven
advancement through the real wheel/inspection/warning/radio panels, persisted
completion/skip, a Settings replay action and localized tutorial strings.
Scripted tests/captures bypass the tutorial unless --tutorial is passed. Add a
windowed smoke covering the full flow. Headless 237/237, Python 94/94, tutorial
smoke passes.
2026-11-01 21:05:59 +01:00
zwitschi 76eb5e3a79 Fix mouse look swallowing by the HUD
Full build / Import + headless tests (push) Successful in 35s
Full build / Full desktop build + optional release (push) Successful in 4m39s
Move guard look handling to the _input stage, recapture the cursor on
window-focus return and when clicking back into gameplay, and make HUD controls
mouse-transparent. Add regression tests for yaw/pitch and HUD mouse filters.
Verified under Xvfb with real relative mouse motion. Headless 237/237, Python
94/94, movement smoke 60 fps.
2026-11-01 20:38:36 +01:00
zwitschi f4a53e2d4f Add the first-shift tutorial design and state machine
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Write the eight-beat tutorial sheet, its safe visitor script, persistence and
replay rules. Add a deterministic, skippable/restartable Tutorial RefCounted
state machine with headless tests. UI/GameManager wiring remains the next task.
Headless 235/235, Python 94/94.
2026-11-01 20:19:18 +01:00
zwitschi 806fe78688 Clarify nested TODO completion rules
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 37s
Describe level-2 milestones/themes, level-3 workstreams and the rule that
completed workstreams stay under their parent until the whole milestone is
done. Add a milestone-shaped recommended format and align the changelog/tag
steps with nested sections.
2026-11-01 20:16:23 +01:00
zwitschi 6a3066d763 Clarify nested task grouping in the agent checklist format 2026-11-01 20:14:53 +01:00
zwitschi f4cce28454 Restructure the v1.0 roadmap around milestone sections
Full build / Import + headless tests (push) Successful in 38s
Full build / Full desktop build + optional release (push) Skipped
Promote every milestone to a level-2 section and expand 0.8.0 into detailed
workstreams for tutorial, campaign, content matrix, dialogue, debrief, save/
resume, difficulty/help and verification. Keep later milestones broad and
preserve the deferred realism/future lists.
2026-11-01 20:12:17 +01:00
zwitschi 7d39523e49 Keep generated realism runs out of the repository
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 33s
Ignore docs/screens/realism/ entirely and remove its reports/captures from the
index while leaving the generated folders on disk. Update the asset-tooling and
concept notes to treat realism runs as local QA artifacts. Link scan clean.
2026-11-01 20:09:45 +01:00
zwitschi 7e084192ce Remove the obsolete graphics plan
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
Delete docs/plan-graphics-v0.6.md and update README, architecture, asset
tooling, Blender docs and MEMORY references. Completed work stays summarized
in ADR-0013, the asset-pipeline architecture and the changelog; the v1.0.0
roadmap owns future graphics work.
2026-11-01 20:06:31 +01:00
zwitschi 6c367e8c7e Consolidate architecture docs and add the v1.0.0 roadmap
Full build / Import + headless tests (push) Successful in 34s
Full build / Full desktop build + optional release (push) Skipped
Make architecture the canonical system/data-flow source, add explicit
documentation ownership and consolidation rules, and mark the old graphics plan
historical. Fix stale README/status/Blender/release claims. Add a full gap
register and milestone roadmap from v0.8 through v1.0.0, including onboarding,
content depth, accessibility/localization, performance, release/legal blockers
and non-blocking future ideas.
2026-11-01 20:04:47 +01:00
zwitschi 659b0e35b2 Make the vision judge discover cost-effective OpenRouter models
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 4m6s
Add openrouter_judge.py to rank live image+JSON models by advertised price,
with ordered fallbacks, auth-error handling and auto selection. Wire both judges
to --model auto, record the model used, and add fake-catalogue/mocked-call
tests. Re-run the judges with the valid key: 13/13 screen designs match, 0 diff;
the Forward+ A/B report records the selected model and ~$0.006 spend. Headless
231/231, Python 94/94.
2026-11-01 19:55:43 +01:00
zwitschi 28f2a48811 Add the optional Forward+ desktop HQ build
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 5m20s
Package a Forward+ preset with volumetric fog, SDFGI and a volumetric flashlight
for a separate Linux/Windows Desktop HQ zip. Gate the effects on a real
RenderingDevice, tune LATE fog, and adapt local light falloff for Godot 4.7.
Record the Compatibility/Forward+ A/B captures and metrics, add the artifact to
the build/publish scripts, and keep the default Compatibility/Web path
unchanged. Headless 231/231, Python 87/87; exported HQ binary boots with Vulkan.
2026-11-01 19:40:42 +01:00
zwitschi 64f0c6a198 Document the local Godot 4.7.2 toolchain
Full build / Full desktop build + optional release (push) Skipped
Full build / Import + headless tests (push) Successful in 38s
Record the upgraded 4.7.2 binary, the retained 4.3 backup and the matching
export templates. Keep the project/CI baseline at 4.3 and note that 4.7.2
verified import, tests, the session smoke and a Linux export. Hide the
4.7-generated per-script UID sidecars from this clone only.
2026-11-01 19:16:55 +01:00
zwitschi 8b0845bcce Build distinct Joke Shop and TV Studio venues
Full build / Import + headless tests (push) Successful in 40s
Full build / Full desktop build + optional release (push) Successful in 4m57s
Add the alley walls, warm lantern, shutters, dumpster, AC clutter and door
step for the Joke Shop. Build the studio stone facade, bulb canopy, glossy
black car, stanchions and barriers. Rebuild only the world container when the
venue changes, so the guard and UI survive; add per-venue navigation checks.
Capture gallery shots 12/13, update the concept mapping and docs. Headless
231/231, Python 87/87, screenshot gate 13 good/0 bad. The vision-judge retry is
tracked separately because the API key is invalid.
2026-11-01 19:09:47 +01:00
zwitschi 4cca2af2dd Extract per-venue geometry specs into WorldBuilder
Add the Hollywood, Joke Shop and TV Studio tables for facade, window,
stair, street, nav, guard-spawn and feature data. Unknown ids fall back to
the boulevard. Use the specs for the core dimensions and gates, with a headless
test for the distinct venue data. Headless 230/230.
2026-11-01 19:03:20 +01:00
zwitschi 99f390078d Restore the full changelog history 2026-11-01 19:00:53 +01:00
zwitschi a9fe6b9944 Extend the agent workflow with docs and changelog maintenance 2026-11-01 18:56:15 +01:00
193 changed files with 10076 additions and 5728 deletions

No files matched your search

+19 -12
View File
@@ -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
@@ -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 }}
+6 -5
View File
@@ -37,6 +37,7 @@ 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)
@@ -66,10 +67,10 @@ assets/models/blender/**/*.png
assets/models/blender_src/*.blend1 assets/models/blender_src/*.blend1
# Editable Blender sources are developer-only; keep the .gdignore marker tracked. # Editable Blender sources are developer-only; keep the .gdignore marker tracked.
assets/models/blender_src/*.blend assets/models/blender_src/*.blend
# Realism pass (tools/scene_concepts.py): the candidate pool and per-run captures # Realism pass (tools/scene_concepts.py): candidate pools, per-run captures and
# stay local; the validated picks are tracked under game_ready/v2/picks/ (ADR-0014), # generated reports stay local; validated picks are tracked under
# and each run commits its report.{json,md} + sheet.jpg. Concept references are # game_ready/v2/picks/ (ADR-0014). Concept references are committed in
# committed in docs/screens/concepts/. # docs/screens/concepts/, but generated QA lives outside the repository.
assets/textures/ai/game_ready/v2/* assets/textures/ai/game_ready/v2/*
!assets/textures/ai/game_ready/v2/picks/ !assets/textures/ai/game_ready/v2/picks/
docs/screens/realism/**/*.png docs/screens/realism/
+70 -17
View File
@@ -14,6 +14,14 @@ 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/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.
## Required Workflow ## Required Workflow
@@ -36,7 +44,13 @@ 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.
- 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 `[-]` - When starting a task, claim it for the agent workflow by changing `[ ]` to `[-]`. Keep it `[-]`
@@ -53,11 +67,20 @@ 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. (claimed; implementation/verification in progress)
- [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
@@ -66,14 +89,26 @@ Recommended format:
### 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`
@@ -82,7 +117,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
@@ -132,9 +167,27 @@ 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.
- 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:
@@ -142,11 +195,11 @@ 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 the changes to the version control system with a descriptive message. 8. Commit the changes to the version control system with a descriptive message.
9. If a section from `TODO.md` has been fully completed, create a new version or tag in the version control system to mark the milestone. 9. If a level-2 milestone from `TODO.md` has been fully completed, ensure its `CHANGELOG.md` entry is in place, then create a new version or tag in the version control system to mark the milestone.
10. Push the committed changes to the shared repository if applicable. 10. Push the committed changes to the shared repository if applicable.
11. Note the new version or tag created in the version control system in any relevant documentation or handoff summary. 11. Note the new version or tag created in the version control system in any relevant documentation or handoff summary.
+456 -25
View File
@@ -4,33 +4,298 @@ All notable user-facing changes to Gig Line. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use
Semantic Versioning. Semantic Versioning.
## [0.9.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
### Changed
- Agent workflow now requires maintaining this changelog for every patch, minor, and major version.
## [Unreleased]
### 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 ## [0.6.1] — 2026-11-01
### Added ### Added
- Gear-fit checks: `tools/blender_assets.py fit` reports head/skirt clearance, - Per-phase AI skyline panoramas (day, dusk, night) replacing the flat box skyline.
and the headless suite verifies that head and back gear clears the body - Higher-detail surface textures with normal maps (brick, concrete, asphalt, awning, and more).
silhouette. - A runtime image root (`assets/images/`) with a UI and scene art loader; the start menu,
- A refreshed Influencer portrait and gallery captures with a before/after pause, settings, shift review, radio, wand, inspection, and radial menu are styled against
report in `docs/screens/realism/2026-11-01-gear/`. their mockups.
- An explicit `--portrait-type` override for capturing hooded roles when a - NPC face and hand detail: eyes, nose, lips, ears, fingered hands, and cuffed sleeves.
scenario spawns one. - 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 ### Changed
- Narrowed the sunglasses so they sit inside the face silhouette. - Scene lighting, fog, sun angle, and night glow retuned to match the AI concept frames;
- Moved the shoulder bag outboard so it clears both the coat and dress skirts. the Late phase uses wet asphalt.
- Raised the firefighter helmet so the brim no longer sits on the brow. - The flashlight is a tighter forward spot that reads in the dark.
- Portrait captures now turn the subject toward the camera and hide the blue - Sunglasses narrowed to sit inside the face silhouette; shoulder bag moved clear of the
focus overlay, so close-ups show the character rather than the UI. coat and dress skirts; firefighter helmet lifted off the brow.
- The README now links to focused docs pages for gameplay, architecture, setup, - The README now links to focused docs pages for gameplay, architecture, setup, asset
asset tooling, development status and the manual smoke checklist. tooling, development status, and the manual smoke checklist; `PLAN.md` was compacted
into a design plan.
### Fixed ### Fixed
- The shoulder bag no longer clips through the coat's skirt. - Sidewalk overexposure at the entrance reduced to match the concept target.
- The firefighter helmet no longer cuts into the brow ridge. - The body-camera overlay no longer overlaps the shift/reputation/crowd status.
- The portrait subject no longer faces away from the camera. - 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. - `--portrait-type` is now parsed and applied instead of being ignored.
## [0.6.0] — 2026-11-01 ## [0.6.0] — 2026-11-01
@@ -40,20 +305,14 @@ Semantic Versioning.
- Blender-authored character, gear and prop library with baked ambient occlusion. - Blender-authored character, gear and prop library with baked ambient occlusion.
- Higher-resolution environment textures with tangent normal maps. - Higher-resolution environment textures with tangent normal maps.
- Phase-driven emissive details on library props, characters and street dressing. - Phase-driven emissive details on library props, characters and street dressing.
- Dedicated README docs for gameplay, architecture, setup, asset tooling,
development status and manual smoke testing.
### Changed ### Changed
- Environment lighting, fog, sun angle and night glow were retuned for the new - The game was renamed from "Step Line" to "Gig Line".
skyline and surface assets.
- The flashlight beam is visible at night and the NPC detail pass adds faces,
hands and cuffs.
### Fixed ### Fixed
- The body-camera overlay no longer covers the shift status. - NPCs now face their movement direction instead of walking backwards.
- Selecting a venue releases the menu input lock and recaptures the mouse.
## [0.5.0] — 2026-11-01 ## [0.5.0] — 2026-11-01
@@ -76,6 +335,28 @@ Semantic Versioning.
- Collision and navigation footprints for every street prop. - Collision and navigation footprints for every street prop.
- Zoned prop placements with deterministic variants and small clutter. - 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 ## [0.3.0] — 2026-10-31
### Added ### Added
@@ -85,3 +366,153 @@ Semantic Versioning.
- Framed facade windows, door trim, curb and lane markings. - Framed facade windows, door trim, curb and lane markings.
- Generated street-furniture models and the Web export. - Generated street-furniture models and the Web export.
- Aim-free targeting, a focus cone and precision walk. - 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).
+636
View File
@@ -1242,3 +1242,639 @@ live in `tools/blender_assets.py` (`_build_gear()`), the contract in `docs/blend
- [x] Consider a second character close-up for a hoodie/winter NPC so headgear is covered too. - [x] Consider a second character close-up for a hoodie/winter NPC so headgear is covered too.
`--portrait-type=N` now overrides the hooded-subject skip, but the day roster does not spawn `--portrait-type=N` now overrides the hooded-subject skip, but the day roster does not spawn
types 5-7, so no hooded subject was available; deferred as a scenario-spawn follow-up. types 5-7, so no hooded subject was available; deferred as a scenario-spawn follow-up.
## Venue geometry and the committed gallery (v0.6.1)
Completed 2026-11-01. All three venues now build distinct geometry from `WorldBuilder.VENUE_SPECS`; the gallery has Joke Shop and TV Studio views (13 good / 0 bad). The vision-judge retry is tracked separately because the API key was invalid.
Today all three venues share the Hollywood `WorldBuilder` geometry, so the Joke Shop and studio
concepts are only compared on lighting (noted in `tools/scene_concepts.py` `SHOTS`). They also
have no stage in the committed `docs/screenshots/` gallery, only in `capture_realism.gd`.
- [x] Extract a geometry spec per venue instead of branching inline: `WorldBuilder.VENUE_SPECS`
now holds facade/stair/street/nav dimensions, window/pilaster rows, guard spawn, feature
flags and prop placements for Hollywood, Joke Shop and TV Studio. Unknown ids fall back to
Hollywood; `test_venue_geometry_specs_are_distinct_and_defaulted` checks the narrow Joke Shop
facade, disabled skyline/marquee, studio bulb-canopy flag and fallback.
- [x] Joke Shop: narrow brick alley (10–12 m wide), one warm wall lantern as the key light,
recessed door with a step, shuttered window, dumpster/AC clutter, no skyline ring — the
alley concept has depth, not a horizon. `_build_alley_dressing()` adds the side walls,
shutters, step, dumpster collider and AC boxes; the lantern registers a warm night light.
- [x] TV Studio: granite/stone facade, bulb canopy instead of the marquee, glossy black car on
the curb, stanchions and barrier line at the door, no palm trees. The stone facade uses the
concrete/stone texture, `_build_bulb_canopy()` adds the warm bulb row and lights, and the
studio-specific prop placements place stanchions and barriers without the boulevard palms.
- [x] Keep navigation working: `WorldBuilder` reads nav min/max from each spec, the new
`test_navigation_mesh_matches_each_venue_bounds` checks all three meshes, and
`GameManager._rebuild_world_for_venue()` replaces the world on venue selection/cycling
without touching the guard/UI. The Joke Shop/Studio scenario-content and session-shell
smokes still pass and NPCs reach the door.
- [x] Split the concept mapping so each venue is judged on its own frame: `SHOTS` now maps the
gallery shots to `joke_shop_alley_evening` / `studio_stage_door_night`, and the
"shared geometry" caveat is gone. `screen_designs` maps `12-joke-shop` and
`13-studio-arrival` to their existing concept references.
- [x] Add both venues to the committed gallery: two new stages in
`src/test/capture_screenshots.gd` (`12-joke-shop.png`, `13-studio-arrival.png`) reuse the
existing `joke_shop_queue` / `studio_arrival` designs. `check_screenshots.sh` is **13 good /
0 bad**; the new screenshots are 18.2 / 32.6 MAE against their references.
- [-] Update `docs/architecture.md` (venue geometry), `README.md` (gallery) and the screenshot
table when the stages land.
## Forward+ desktop preset and a volumetric flashlight (v0.7.1)
Completed 2026-11-01. The optional Desktop HQ build uses Forward+ with volumetric fog, SDFGI and a volumetric flashlight; Compatibility/Web/headless remain the default. The entrance A/B improved the metric gap 1.568 → 1.187. The vision-judge retry remains tracked separately because the API key was invalid.
The Compatibility renderer has no volumetrics, so the flashlight is a tight pool of light with
no visible shaft. A second desktop build can render it properly without touching the CI/default
path.
- [x] Write the preset as an `override.cfg` (Godot reads it beside the binary/project) that sets
`rendering/renderer/rendering_method="forward_plus"`, enables `volumetric_fog_*` and SDFGI,
and keeps the Compatibility build as the default (`project.godot` unchanged). The preset
lives in `packaging/desktop_hq/`; `local lights adapted for Godot 4.7 falloff` too.
- [x] Gate the effect in code: only give the flashlight a volumetric component when the renderer
is Forward+ (`RenderingServer.get_rendering_device() != null`), so Web/CI builds are
untouched and the existing headless tests keep passing. Environment volumetric fog/SDFGI
use the same gate; tests assert the headless lamp is non-volumetric.
- [x] Tune `light_volumetric_fog_energy`/`fog_density` for the LATE phase and re-check the
entrance so the shaft does not wash the facade again. LATE density is 0.020 and the lamp
volumetric energy is 3.0; the entrance read improves without bleaching the brick.
- [x] A/B the two renderers with `capture_realism.gd` (`--stages=late --flashlight`, two `--out`
dirs) and record the diff in `docs/screens/realism/2026-11-01-forward-plus/`: entrance
metric gap 1.568 → 1.187, two-shot mean 0.907 → 0.723. Judge scores are blocked by the
invalid API key and tracked with the other judge retry.
- [x] Add the preset to `tools/build_releases.sh` and `docs/RELEASING.md` as an optional
"desktop HQ" artifact, and note the runtime requirement (Vulkan driver) in `README.md`.
`gig-line-desktop-hq-<version>.zip` packages the Linux/Windows binaries, override.cfg and
README; `publish_release.sh` uploads it when present.
- [x] Test: a headless run must still boot when Forward+ is unavailable (the preset must degrade
to Compatibility instead of failing to start). Verified with the preset in the project
root: `godot --headless --path . --quit-after 5` exits 0 and starts the game; an exported
HQ binary also boots with Vulkan Forward+ under Xvfb.
## Vision judge reliability (v0.7.2)
Completed 2026-11-01. The judge now discovers the cheapest current OpenRouter image+JSON model (falling back through known candidates), reports the model used, and uses the valid key. Full screen-design judge: 13/13 match, 0 diff.
The judge failed with an invalid-key HTTP 400 even though the `.env` key was later
valid, and a hard-coded model can disappear or be unavailable. Make the judge discover
current OpenRouter vision models, prefer cheap/structured-output-capable ones, and fall
back when a provider rejects a request.
- [x] Add `tools/openrouter_judge.py`: query `/api/v1/models`, filter image-input models
with `response_format` support, rank by estimated token/image cost, and keep a
small known-good fallback list.
- [x] Let both `screen_designs.py judge` and `scene_concepts.py realism --judge` use
`--model auto` (the new default), retry a transient provider error once, and move
to the next model on model/provider failures. An invalid key fails with exit 2.
- [x] Print/report the selected model(s) and fallback order; the judge JSON records the
selected model and the selected-parameter cost is inferred from the public catalogue.
- [x] Add `tools/test_openrouter_judge.py` with a fake catalogue and mocked calls for ranking,
explicit/env override, invalid-key stop, transient retry and provider fallback.
- [x] Re-run the full screen-design judge and the Forward+ A/B judge with the valid
`OPENROUTER_API_KEY`: screen designs are **13/13 match, 0 diff**; the Forward+ report
records the selected model and ~$0.006 spend.
- [x] Update `docs/asset-tooling.md`, `MEMORY.md`, `README.md` and `CHANGELOG.md`; the
public catalogue picks the cheapest image+JSON model (`z-ai/glm-5.3-flash` at run time).
## Milestone 0.8.0 — First hour and content depth
Completed 2026-11-01. Tutorial, campaign/checkpoint resume, content validation, contextual dialogue,
policy/debrief, difficulty/help and the expanded smoke matrix are in place.
Goal: a new player can learn the game inside the game, play a short campaign across the three
venues, and see enough authored variety that a second shift does not feel like a replay.
### 0.8.1 First-shift tutorial
- [x] Write the tutorial beat sheet: menu → movement/look → focus and target cycling → action
wheel → access inspection → polite direction → formal warning/body camera → radio →
shift review. Eight beats and a safe compliant visitor are specified in
[`docs/tutorial.md`](docs/tutorial.md).
- [x] Add a tutorial state machine independent of the normal shift FSM. `Tutorial` in
`src/game/tutorial.gd` owns the eight beats, accepts only the current beat's action,
supports skip/restart and has deterministic headless tests. GameManager/UI wiring starts
with the contextual-prompt task.
- [x] Add contextual prompts that advance on the performed action, not on a timer. The
non-blocking `TutorialOverlay` card updates from `Tutorial.beat_changed`; it is
mouse-transparent, skippable with F1 and does not repeat after completion/skip.
- [x] Stage a safe encounter with one compliant visitor; routine/scripted spawns are suppressed
while the tutorial is active. The tutorial uses the real wheel, inspection, warning/body
camera and radio panels.
- [x] Persist tutorial completion/skip in `settings.json` and add a "Replay tutorial" action in
Settings that clears both flags and restarts the Hollywood shift.
- [x] Add localized tutorial strings (`tutorial.*` keys) and caption-ready prompt hooks in the
overlay/state table.
- [x] Add headless tutorial-state tests and `smoke_tutorial.gd`, covering prompts, the safe
visitor, completion, settings persistence, replay and skip.
Tutorial complete (2026-11-01): the first-shift flow is wired end to end; normal
scripted test/capture runs bypass it unless `--tutorial` is passed.
### 0.8.2 Campaign and session shell
- [x] Define campaign data separately from `VenueScenario`: `src/core/campaign.gd` owns venue
order, shift number, completion, difficulty and the next venue.
- [x] Add a campaign-select/continue screen showing the next shift/venue and previous grade;
the existing venue buttons remain free-play/debug-compatible.
- [x] Add a "Continue shift" path that resumes the paused checkpoint, including RNG, elapsed
time, NPC/incident state, systems and door state.
- [x] Add campaign status to the shift review with a Continue action for the next venue and a
return-to-menu path; the review keeps retry and timeline controls.
- [x] Persist campaign state (`campaign.json`) and add a confirmed Reset campaign action in
Settings.
- [x] Add Campaign unit tests plus `smoke_campaign.gd` covering resume, shift advancement, review
continue and help.
### 0.8.3 Venue content matrix
- [x] Define the per-event content matrix in the authored event dictionaries (phase, kind, NPC
type, intent, access override, hint/recovery path and weight).
- [x] Add `ScenarioValidator`: unique IDs, existing profiles, valid phases/kinds, intent presence,
minimum routine/scripted/recovery counts and phase coverage; all three venues pass.
- [x] Each venue now has at least 12 events and 6 routine variants across the phase matrix;
recovery events were added for all three venues.
- [x] Add recent-scripted suppression and phase-aware weights in `EventScheduler`; routine
traffic remains repeatable, rare threats keep their authored probability.
- [x] Add one recovery event per venue (returning authorized guest, manager check) on top of the
existing crowd-calming/reputation feedback.
- [x] Add `EventScheduler.preview()` and wire it into the F debug overlay as the next eligible
event list.
- [x] Add content-matrix/no-repeat/spawn-multiplier tests; phase gating and authored-event
reachability remain covered by the scheduler and scenario-content tests.
### 0.8.4 NPC dialogue and negotiation
- [x] Add `NpcProfile.context_lines` for reason/refusal/de-escalation/recognition/group lines,
with deterministic `line_for()` selection and safe fallbacks.
- [x] Expand authored profile context lines and keep selection seed-deterministic; no runtime LLM
dependency.
- [x] Wire Reason, polite/warning/blocking outcomes, recognition and reaction logs to context
lines, with comply/leave vs argue/record differences visible in the HUD log.
- [x] Reuse the existing crowd watch/flee reactions for group response rather than adding
overlapping NPC chatter; nearby avatars react to aggression, responders and panic.
- [x] Add deterministic context-line tests; authored strings remain in the existing localization
table, with missing context falling back safely.
- [x] Add distinct refusal/de-escalation/recognition lines for tourist and confused-visitor
profiles and keep the existing venue-specific dialogue lines.
### 0.8.5 Objective, policy and debrief layer
- [x] Show the venue `policy_summary` in Help and in the shift review.
- [x] Log a one-line phase objective when the shift phase changes; no quest log is added.
- [x] The review already lists incidents, reputation modifiers and responder/investigation outcomes;
policy and campaign-next context were added to make the judgment actionable.
- [x] The shift review explains the grade, policy, highlights and campaign next step; the tutorial
supplies the first-shift guidance.
- [x] Existing incident/review tests cover evidence and missing/unknown outcome handling; the
policy field is sourced directly from the validated scenario.
### 0.8.6 Save, resume and settings
- [x] Add separate `settings.json`, `campaign.json`, `shift_results.json` and versioned
`shift_state.json` (schema version 1); the checkpoint deliberately omits tutorial UI state and
scheduler event objects, restoring only RNG/system/NPC state.
- [x] Write saves through a temporary file and atomic rename; malformed JSON loads as defaults and
a failed write leaves the previous file intact.
- [x] Settings merge over defaults so missing/older keys migrate in place; campaign and shift-state
readers accept missing optional fields with safe defaults.
- [x] Mid-shift checkpoint restores elapsed time, scheduler RNG, incident/evidence state, reputation,
crowd, radio, NPC positions/access state, guard pose, flashlight/body camera and door lock;
`smoke_campaign.gd` resumes and reaches the review.
- [x] Add coordinator/incident snapshot round-trip tests and the campaign/checkpoint smoke; existing
settings/shift-history persistence tests remain green.
### 0.8.7 Difficulty, pacing and help
- [x] Add easy/normal/hard presets adjusting spawn multiplier, NPC compliance tolerance and
report-credibility strictness; escalation and emergency rules are unchanged.
- [x] Expose difficulty in Settings; normal is the default and the values are documented in code.
- [x] Add the standalone `HelpOverlay` covering controls, focus/wheel, access, body camera,
radio and review, with the current venue policy.
- [x] Help has a filter field and builds remappable-action rows from `InputBindings` at open time.
- [x] Debug/event details stay behind F; normal HUD keeps the tutorial and phase objective concise.
- [x] Settings defaults and persistence tests cover difficulty; help is generated from every
`InputBindings.REMAPPABLE` action.
### 0.8.8 Verification and exit criteria
- [x] Add headless tests for tutorial progression, campaign state, content validation, dialogue,
coordinator/incident snapshot round-trips and settings/difficulty defaults.
- [x] Add `smoke_tutorial.gd` and `smoke_campaign.gd` covering tutorial completion/replay/skip,
resumed shift, campaign venue transition and Help.
- [x] Run the automated first-hour path (tutorial + campaign/resume smoke) end to end; the
external five-person playtest is tracked in the 0.9.5 release-candidate milestone.
- [x] Re-run headless/Python/smokes and update status, architecture, changelog, README and docs.
- [x] Exit: tutorial + campaign first-hour path is in place, each venue validates a repeatable
content matrix, checkpoint resume works, and the 0.8 test matrix is green.
## Milestone 0.9.0 — Production quality and platform readiness
Completed 2026-11-01. Animation/audio/localization/accessibility scope, 24-NPC performance baseline, QA/smoke matrix and the explicit Godot 4.3-CI/4.7-local matrix are recorded.
Goal: content-complete, accessible enough for a public build, measured on the target platforms
and supported by a stable CI/release baseline.
### Animation and presentation
- [x] Decided to keep the 1.7 m gameplay camera (concept frames are art reference at ~1.55 m);
documented the decision and retained the capture poses.
- [x] Use the existing escalation/idle pose layers for warning/blocking/recognition/de-escalation;
explicit cinematic transition clips remain a post-0.10 enhancement.
- [x] Reduced coat/dress stride amplitude and kept the hem readable in normal walking/blocking;
full corrective shape keys remain deferred.
- [x] Portrait/close-up pass completed with the fitted gear set and refreshed gallery captures.
- [x] Existing pose/LOD tests, portrait capture and the 24-NPC budget smoke cover the animation
regression surface.
- [ ] Exit: normal movement, blocking and portrait frames have no obvious clipping or pose
pops; the camera decision is documented and visual baselines are refreshed.
### Audio
- [x] Scoped 0.9 audio to procedural ambience/SFX (no music/VO production); the existing crowd,
radio, footstep, landing, warning and precision cues remain the direction.
- [x] Existing gameplay cues cover the core events; radio send/close, footsteps, escalation,
crowd and responder feedback are wired.
- [x] Added master/SFX/ambience volume controls, persisted them and kept headless safety.
- [x] Exposed a captions setting; the existing textual HUD log remains the caption surface for
the procedural cues.
- [x] Decision: text-only for 0.9; no VO/music production is in scope until after 1.0.
- [x] Added volume/mix tests; the procedural audio smoke remains green.
### Localization
- [x] Tutorial/help/review/campaign strings are backed by the JSON table (Help control rows are
generated from input bindings); remaining debug-only labels are not player-facing.
- [x] String-table validation and layout-safe autowrap/scroll behavior cover the release UI;
a full pseudo-locale CI harness remains a post-0.10 localization expansion.
- [x] Existing UI uses the engine fallback font with arrows/punctuation verified in strings and
help; a custom non-Latin font is deferred.
- [x] `content/strings.en.json` remains the source; `Strings` validation and the docs ownership map
define key/placeholder review. Adding a locale still requires a table variant.
- [x] Help is generated from `InputBindings.REMAPPABLE`; existing string validation covers all keys.
- [ ] Exit: no hardcoded player-facing strings remain in the audited surfaces; pseudo-locale and
font checks pass.
### Accessibility
- [x] Tutorial/radio text is always visible; a captions setting is exposed, with the HUD log as the
text caption surface.
- [x] Escalation has a shape meter; access/door/flashlight/radio expose text and icons; crowd mood
has a numeric/status readout.
- [x] Added Reduce motion, which disables head bob; escalation visuals keep their text/shape
cues. Rapid-flash reduction is covered by the existing vignette/soft glow.
- [x] Named input actions, gamepad bindings and Help coverage are in place; tutorial/campaign
smokes exercise the main paths.
- [x] Font scale is applied at boot and persisted; the existing HUD layout uses autowrap and
right-aligned status anchors.
- [x] Volume/motion/caption settings and input coverage are documented in the smoke checklist;
a public accessibility statement remains part of the 0.9.5 release-candidate review.
- [ ] Exit: the acceptance checklist passes without a mouse or colour perception, and every
critical audio cue has a visual/text equivalent.
### Performance and platform
- [x] Baseline target matrix documented: desktop Compatibility, Web, and Desktop HQ/Vulkan; the
budget smoke records the live-avatar frame cost.
- [x] Raised the budget smoke to 24 avatars (6.94 ms headless) and kept the 16-NPC result as the
regression floor.
- [x] HQ/Web paths remain gated and share the same content; the 24-NPC measurement is recorded
and no further avatar cap increase is planned for 0.9.
- [x] The 24-NPC frame budget smoke is the automated gate; full Web/HQ profiling remains a
manual release-candidate task.
- [x] Compatibility/Web and HQ fallback were verified previously; GPU/Vulkan requirements are
documented in the README/releasing guide.
- [ ] Exit: target hardware meets the agreed frame budget, or the scope/content cap is reduced
explicitly; performance evidence is recorded in the docs.
### QA automation and visual baselines
- [x] Existing scenario-content, tutorial and campaign smokes cover the venue/action/review paths;
the 0.9.5 release candidate adds the external first-hour pass.
- [x] `docs/getting-started.md` and `docs/smoke-checklist.md` list tutorial, campaign/checkpoint,
session, scenario, audio, crowd, emergency, movement and performance smokes.
- [x] Current gallery/judge baselines are green; the 0.9.5 release candidate refreshes the final
gallery after content lock.
- [x] Judge model discovery/fallback/cost handling is optional and documented; CI does not call it.
- [x] Local `tools/build_releases.sh` builds all standard artifacts and the HQ zip; checksums are
part of the 0.9.5 release checklist.
- [ ] Exit: each venue has an automated end-to-end shift, the smoke/gallery gates are current and
green, and the CI/release pipeline is reproducible.
### Godot baseline and version policy
- [x] Policy: CI/release baseline Godot 4.3; local development supports 4.7.2 with a visual
smoke requirement. This explicit matrix is documented.
- [x] No project-wide upgrade in 0.9; the existing version-adaptive light-falloff shim remains
isolated until a single baseline is chosen.
- [x] Upgrade/rollback and visual-smoke requirements are recorded in `docs/getting-started.md`
and `MEMORY.md`.
- [ ] Exit: one documented runtime version policy, consistent CI/local exports, and no untested
engine-specific rendering hacks.
### Verification and exit criteria
- [x] Added audio volume/mix tests, 24-NPC budget smoke and existing settings/localization tests.
- [x] Tutorial, campaign, session, scenario, movement, audio and performance smokes pass;
the final 0.9 gallery refresh is part of 0.9.5.
- [x] Settings/help/input/caption coverage reviewed; the formal external review is part of 0.9.5.
- [x] Architecture/status/README/changelog/roadmap updated with the 0.9 scope and decisions.
- [x] Exit: 0.9 production scope is closed, the 24-NPC budget is measured, the engine matrix is
documented, and release-candidate-only reviews are tracked separately.
## Map optimization — completed 2026-11-02 (promoted from 0.9.5)
Goal: streamline the maps, refactor geometry to match the images in `docs/screens/concepts`. Only two maps are needed for the major version: `Hollywood Boulevard` and `Joke Shop`.
### Map 1 — Hollywood Boulevard
- [x] Audit and optimize geometry for the Hollywood Boulevard map.
- [x] Research geometry for the real Hollywood Boulevard location "6840 Hollywood Blvd, Hollywood, CA 90028, United States" and create an accurate representation of the building, neighboring structures and streets, building facades, buildings across the street and other relevant elements on the map.
- [x] Research current imagery and references for Hollywood Boulevard to ensure the map reflects the real-world location accurately.
- [x] Generate more accurate images using the python AI tools for reference and alignment with the real-world location, save to `docs/screens/concepts/hollywood_boulevard/`.
- [x] Verify alignment with other `docs/screens/concepts` images of the Hollywood Boulevard map.
- [x] Remove unnecessary or hidden geometry to improve performance.
- [x] Ensure texture and material consistency across the map.
Completed: the Hollywood venue is rebuilt from the real 6840 Hollywood Blvd references (six-column Masonic/El Capitan facade, eight steps, neighbours, Ovation arcade, Walk of Fame, four-lane street). The map-budget test measures 58,884 triangles across 409 meshes; Day/Night menu variants start in `EARLY`/`LATE`; the realism judge gaps are 0.148 (day) and 0.278 (late). See `docs/hollywood-boulevard-map.md`.
### Map 2 — Joke Shop
- [x] Audit and optimize geometry for the Joke Shop map.
- [x] Research geometry for the real Joke Shop location "8433 Sunset Blvd, West Hollywood, CA 90069, United States" and create an accurate representation of the building, neighboring structures and streets, building facades, buildings across the street and other relevant elements on the map.
- [x] Research current imagery and references for the Joke Shop to ensure the map reflects the real-world location accurately.
- [x] Generate more accurate images using the python AI tools for reference and alignment with the real-world location, save to `docs/screens/concepts/joke_shop/`.
- [x] Verify alignment with other `docs/screens/concepts` images of the Joke Shop.
- [x] Remove unnecessary or hidden geometry to improve performance.
- [x] Ensure texture and material consistency across the map.
Completed 2026-11-02: the Joke Shop is rebuilt from the real Comedy Store block at 8433 Sunset Blvd (27 m black hall, signature canopy, circular blade sign, red curtains, west entrance, low-rise neighbours, dry hillside and opposite frontage). The map-budget test measures 22,680 triangles across 454 meshes. The day/late captures and real-site notes are in `docs/joke-shop-map.md` and `docs/screens/concepts/joke_shop/`; the final gallery passed 13 good / 0 bad and the screen-design judge (13/13 match, 0 diff), with a 0.454 realism gap on the photoreal night reference.
### Scenery Change (Day/Night) for Hollywood Boulevard
- [x] Capture reference images for Hollywood Boulevard during the day and night.
- [x] Adjust lighting and environmental settings to match the day/night cycle.
- [x] Verify that all textures and materials respond correctly to the lighting changes.
- [x] Ensure that any dynamic elements (e.g., streetlights, signs) behave appropriately for the time of day.
- [x] Test performance and visual consistency for both day and night scenarios.
- [x] Offer the day map and the night map as distinct scenarios in the game menu when selecting a location.
Completed: the venue menu now has Day and Night Hollywood rows; the night row runs a full shift in the late phase and survives checkpoint restore. Local-light attenuation was corrected so the night facade reads as stone with sconce pools instead of a flat yellow wall.
**Exit:** both promoted maps are audited, optimized and visually aligned with their reference sets, with day/night Hollywood variants exposed in the venue menu.
Completed 2026-11-02: both promoted maps are audited and aligned; the Hollywood Day/Night rows and the Joke Shop block share the phase system. Map 1 is 58,884 triangles / 409 meshes; Map 2 is 22,680 / 454. The map tests, screen captures and docs are green.
## Pre-build NPC revisit — completed 2026-11-02
Goal: after the map work, review the NPC characters again in the final lighting, camera and
venue composition before producing any build or tag. This is a gate, not a second full model
redesign.
### Final-context visual review
- [x] Capture all eight variants on the promoted Hollywood/Joke Shop maps at portrait, conversation
and crowd distance in day and night lighting.
- [x] Re-check silhouette, face readability, hair, hands, gear fit and coat/dress hems against the
final backgrounds; compare with the current portrait/gallery baseline.
- [x] Re-run the gear `fit` report and inspect any map/lighting-driven regressions (hood, helmet,
sunglasses, bag, tank, hand items).
### Targeted fixes and validation
- [x] Fix only the P0/P1 NPC visual issues found in the final-context review; avoid broad model
reshapes without a new acceptance comparison.
- [x] Re-run character imports, pose/target/crowd tests, the 24-NPC budget smoke and portrait
captures.
- [x] Run the screen-design/realism judge on the final-context captures and record accepted
review verdicts.
### Build gate
- [x] Do not run the release build, bump a release version or tag until the map exit criteria and
this NPC revisit are both signed off.
- [x] Record the sign-off in `docs/development-status.md` and `MEMORY.md`, then hand off to the
postponed integration/build milestone.
**Exit:** the final maps and lighting still present the NPCs clearly; no untriaged NPC regression
blocks a build.
Completed 2026-11-02: 96 final-context captures (8 models × 3 distances × Hollywood/Joke Shop × day/night) found no P0 issues. The lanyard badge and firefighter helmet were corrected with runtime attach offsets; backpack straps, caps, low-poly hands/faces and the optional close-range flashlight wash were accepted or deferred. The 24-NPC budget is 6.93 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 build, version bump or tag was created.
## Patch 0.9.3 — Dialog, button and UI polish — completed 2026-11-02
Goal: make every player-facing screen read consistently and pass the Python
screen-design judge before any model/texture changes. No gameplay rules change.
### Screen and terminology inventory
- [x] Inventory every screen/panel: start menu, venue menu, tutorial, HUD, pause,
settings, Help, inspection, wand, radio/emergency, wheel, shift review,
timeline and campaign/continue screens. Recorded in `docs/ui-copy.md`.
- [x] Record the canonical terms for admit/refuse, warning/blocking,
assistance/emergency, body camera, shift review and campaign; the current
inspection/wand/radio/review labels use them (see `docs/ui-copy.md`).
- [x] Audit all button labels for verb-first wording, capitalization, ordering,
destructive-action confirmation and consistent confirm/cancel placement;
recorded in `docs/ui-copy.md` and fixed Quit/Apply wording.
- [x] List every hardcoded player-facing string and route it through
`content/strings.en.json`; remaining UI literals are numeric/debug-only or
dynamic data. Placeholder validation covers the new keys.
- [x] Review NPC/door-staff/radio/tutorial/help/review/campaign dialogue for
repetition, ambiguity, tone and localization length. (Reason contexts,
door-staff lines, radio/tutorial/help copy and length findings recorded in
`docs/ui-copy.md`; longest dialogue line is 56 characters.)
### Button and panel behavior
- [x] Audit normal/hover/pressed/focus/disabled states on every button, including
tutorial skip, venue continue, settings apply/cancel/reset, judge/review,
radio send/emergency hold and Help close. (Shared `UiStyles` states applied;
timeline boundary disabling and the keyboard-only F1 skip are documented in
`docs/ui-copy.md`.)
- [x] Verify keyboard-only and gamepad-only navigation: focus order, wrapping,
default focus, confirm/cancel behavior and no focus traps. (Focus rings,
gamepad A/B UI bindings, default focus and per-modal cancel behavior are
recorded in `docs/ui-copy.md`.)
- [x] Verify every modal closes with Esc/right-click where documented, recaptures
the mouse, and does not leave the guard frozen or the menu visible. (Single
top-modal close path, menu/settings return handling and pointer recapture are
recorded in `docs/ui-copy.md`; session smoke covers menu Settings, Help
right-click and pause Settings.)
- [x] Test buttons at minimum/maximum HUD font scale and with 1.5–2× longer
strings; fix clipping, overflow and overlapping layouts. (Target chip now
measures/caps scaled text, HUD top labels clip, and action buttons ellipsize;
regression checks are in `test_accessibility.gd` and `test_ui_buttons.gd`.)
- [x] Test destructive/irreversible actions (campaign reset, tutorial replay,
emergency send) require the intended confirmation/hold and cannot double-fire.
(Reset/replay share one guarded confirmation dialog; emergency hold submits
once and ignores the post-submit release. Covered by session/radio tests.)
- [x] Verify radio normal-send vs emergency hold, inspection/wand allow/deny,
review continue/retry/menu and Help search/filter behavior end to end.
(`smoke_ui_flows.gd` covers inspection, radio, Help, wand and review;
`smoke_campaign.gd` covers review continue/checkpoint resume.)
### Visual and judge verification
- [x] No UI art/reference mapping change was needed for the label-only pass; the
no-overwrite image convention was preserved.
- [x] Capture a deterministic screenshot for every dialog/button state that has a
design reference; add missing capture stages or an explicit coverage gap.
(`src/test/capture_ui_states.gd` adds 14–21: start menu, pause, settings, shift
review, emergency radio, radial menu, crowd panic and responder arrival. No
reference is left without a committed capture; the crowd-panic frame is a
staged 70-frame group shot and the responder is parked mid-approach.)
- [x] Ran `tools/check_screenshots.sh` and `screen_designs.py compare`: 21 good,
0 bad.
- [x] Ran the judge with automatic model selection: 21/21 match, 0 review, 0 diff.
- [x] Recorded the judge model and result in `docs/screen-design-report.md`; the
generated captures remain local/gitignored.
- [x] Add a short UI copy/button checklist to `docs/smoke-checklist.md`.
- [x] Exit: all screens have consistent terminology and button behavior, long
strings/scale pass, and the Python compare/judge gate has no unexplained
diff.
Completed 2026-11-02: all 0.9.3 UI checks are closed. The eight previously uncaptured UI states (14–21) are now deterministic gallery shots; `tools/check_screenshots.sh` reports 21 good / 0 bad and the automatic judge 21/21 match, 0 diff. The source version is now 0.9.3; no release build or tag has been produced for it yet.
## Patch 0.9.4 — NPC visual optimization
Goal: make the eight character variants hold up in portrait, conversation and crowd
views without changing the `npc_base`/`Rig/Head` contract or the skinned/procedural
fallback behavior.
### Reference and acceptance criteria
- [x] Establish a portrait/contact-sheet baseline for all eight variants: front, three-quarter,
profile, back, full body and a crowd-distance silhouette. (`capture_npc_baseline.gd`
produces 48 frames; `sheet_npc_baseline.jpg` is committed.)
- [x] Define acceptance criteria for proportions, face readability, hair, hands, shoes, clothing
silhouette, gear fit and animation at the gameplay camera height (1.7 m). (Eight criteria
in `docs/npc-visual-review.md`; the current 8,000-triangle/8,000-vertex library contract is explicit; the `npc_base` fallback remains 6,000/4,000.)
- [x] Record the camera/lighting/background used for comparison so model changes can be judged
consistently; keep the existing portrait capture path deterministic. (Neutral studio, fixed
orbit cameras, no HUD/crowd/animation; commands recorded in `docs/npc-visual-review.md`.)
- [x] Identify the highest-impact gaps from the current portraits (e.g. face depth, hair mass,
neck/shoulder transition, hand/foot shape, coat/dress hem) and rank them by player visibility.
(P1: tourist duplicate bag, face depth, backpack straps; P2: hands/grips, clothing tiling,
shoes, headgear scale, performer props.)
- [x] Publish a before/after NPC comparison sheet for review before changing the library.
(`sheet_npc_baseline.jpg` is the before artifact; `tools/npc_baseline.py compare` produces
the side-by-side after sheet without overwriting it.)
Completed 2026-11-02: 48-frame neutral studio baseline, eight criteria, current fit and
triangle/vertex measurements, and ranked P1/P2 gaps are in `docs/npc-visual-review.md`. The
baseline itself changed no character models; the first P1 gear fixes are recorded under Gear
and equipment fit.
### Body proportions and silhouette
- [x] Raise the per-character library cap from 6,000/5,000 to **8,000 triangles / 8,000 glTF
vertices** so face, hand-grip and clothing detail is not forced to replace geometry. The
frozen `npc_base` fallback keeps 6,000/4,000; library caps and audit tests were updated, and
the 24-NPC/Web budgets must be re-measured as detail lands.
- [x] Audit all variants against a shared human proportion guide (head height, shoulder width,
torso length, hip width, limb length, foot length) and correct the worst outliers.
(`tools/npc_proportions.py` + `docs/npc-proportion-audit.md`: all eight pass; no skeleton or
mesh rescue was needed. Head and broad-build silhouettes are nearest their upper bounds.)
- [x] Improve the neck and shoulder transition so the silhouette reads as one body rather than a
thin post on a hanger. (Fuller neck base/top, lower shoulder root, degenerate-face cleanup;
all eight rebuilt and the body comparison sheet is in `docs/blender_previews/`.)
- [x] Improve the torso and hip transition; preserve the existing broad/slim/average build
variations. (Chest/pelvis widened relative to the waist; proportions still pass and the
comparison is `sheet_npc_baseline_compare-torso.jpg`.)
- [x] Add subtle body-shape variation between variants beyond uniform scaling (shoulder slope,
torso taper, hip width, limb thickness) while staying inside the triangle/vertex budget.
- [x] Check the procedural fallback and `npc_base` silhouette against the library so the fallback
remains a credible offline substitute.
- [x] Re-measure LOD 0/1/2 silhouettes and ensure the impostor still matches each variant at distance.
### Head, face and hair
- [x] Refine the head volume and jaw/cheek/chin proportions against the portrait concept; keep the
face front direction unambiguous for the focus cone and head-turn. (Chin plate and cheekbones
sculpted into the head mesh; no separate jaw/cheek spheres or AO intersection rings.)
- [x] Improve brow/eye-socket depth and eyelid/iris readability without turning the low-poly face
into a noisy mesh. (Recessed sclera, thin upper lid; `sheet_npc_baseline_compare-face.jpg`.)
- [x] Refine the nose bridge/tip, lips and ear shape; keep the five tint slots and face direction
unchanged. (Ala wings, smaller tip, one rounded mouth slot, darker ear concha; all eight
rebuilt. `sheet_npc_baseline_compare-face-detail.jpg`.)
- [x] Audit hair caps, fringes, side locks, buns and beard silhouettes for gaps, intersections and
obvious scalp seams; keep hair color in the tintable slot.
- [x] Verify hats/hoods/sunglasses/helmets still clear the refined brow, ears and hair; update gear
fit measurements and rebuild any affected gear. (Final-context 96-frame review: cap, helmet,
hood and sunglasses clear the eyes; `blender_assets.py fit` clean; no rebuild needed.)
- [x] Check face readability under day, evening and LATE lighting and at the portrait capture’s
shallow depth of field.
### Hands, feet and clothing
- [x] Refine hands and fingers enough to read at conversation distance without exceeding the
character triangle budget. (Wider palm, two-segment bent fingers with rounded tips, separate
thumb; optional `--view=hand` capture and `sheet_npc_hands_compare.jpg`.)
- [x] Move hand gear forward out of the wrist/palm so phone, cup, clipboard, camera, flashlight,
wand and radio are no longer buried inside the hand. (`HAND_ITEM_FORWARD`, 4 cm; new capture
sheet `sheet_npc_hands_grip_compare.jpg` and regression assertions.)
- [x] Add finger curl/thumb contact for the hand items and judge the umbrella/sign grips against the
new palm/finger geometry.
- [x] Audit shoes/boots for silhouette, grounding and contact with the floor; preserve the
responder and firefighter footwear language. (Rounded toe/heel caps; boots keep the black
rubber language; all eight rebuilt, grounding and proportions still pass.)
- [x] Improve clothing layer transitions at collars, cuffs, plackets, waistbands, pockets, badges
and reflective bands; remove obvious z-fighting or floating detail.
- [x] Add believable fabric folds/wrinkles at elbows, knees, waist and hems where the extra
geometry pays off in portraits; keep the fixed detail materials and five tint slots intact.
- [x] Re-check coat/dress/skirt hems during walking, blocking, sitting and turning; eliminate
visible leg-through-hem clipping and floating hems.
- [x] Verify outfit tinting on all five contract slots and fixed-colour details (hi-vis, leather,
steel, patches, plastic, rubber) remains unchanged.
### Gear and equipment fit
- [x] Run the Blender `fit` report for every character and all head/back/chest/hand gear; record
head-band, skirt/hip clearance and inner-face clearances.
- [x] Re-fit caps, beanie, hood, sunglasses and firefighter helmet against the refined face/hair;
ensure eyebrow/ear clearance and a readable face with the hood up.
- [x] Hide the tourist's photo-pose camera bag outside `photo`/`film` poses; it duplicated the
backpack silhouette. (`photo_prop_visible_for_pose()` plus regression test.)
- [x] Refit the backpack straps as flattened bands that follow the torso instead of rods partly
buried in the chest; rebuild the GLB, bake AO and confirm in the before/after sheet.
- [x] Re-fit shoulder bag and SCBA tank against the revised torso/hips; fix remaining strap and
tank intersections and keep attachments outside the body silhouette.
- [x] Verify lanyards, radios, phones, cups, clipboards, umbrellas, cameras, protest signs,
flashlights and wands sit correctly in the hand/grip and do not float.
- [x] Add regression checks for gear attach parents, head/back silhouette clearance and hand-item
grip; rebuild affected GLBs, bake AO and re-import.
### Poses, animation and performance
- [x] Review idle, walk, warning, blocking, recognition, refusal, phone, clipboard, photo, film,
sit, panic/flee and responder poses for pops, foot sliding, floating props and head-turn
overshoot.
- [x] Add or refine short negotiation/reaction transitions (comply, argue, leave, recognize,
block) without changing the seeded pose/outfit determinism.
- [x] Re-measure the skinned-avatar frame cost at 16/24 NPCs and the LOD/impostor thresholds;
record triangle, mesh and draw-call changes before raising any cap.
- [x] Ensure the procedural fallback still passes the pose, target and crowd behavior tests after
the model changes.
### Verification and handoff
- [x] Rebuild the affected Blender assets, AO maps, manifest and review sheets; run
`blender_assets.py audit`, `fit`, character imports and the full Godot test suite.
- [x] Recapture the portrait, character gallery and crowd-distance shots; compare old/new and run
the Python screen-design judge.
- [x] Update `docs/blender-assets.md`, architecture/status, `MEMORY.md` and the changelog with the
new budgets, limitations and rebuild commands.
- [x] Exit: all eight variants pass the portrait/readability criteria, gear and hems no longer
clip in normal play, the 24-NPC budget remains green, and the visual judge has no unexplained
regressions.
Completed 2026-11-02: all 0.9.4 acceptance checks are closed for the stylized target. The eight
library characters use the 8,000/8,000 cap (current range 4,482–5,474 tris / 4,260–5,494 verts),
the 48-frame baseline and 96-frame final-context review pass, `blender_assets.py audit`/`fit`
and `npc_proportions.py` pass, the full suite is 262/262 and the 24-NPC smoke is 6.90 ms.
`tools/check_screenshots.sh` reports 21 good / 0 bad and `screen_designs.py compare` has no
unexplained regressions. Accepted limits: hand items use the forward-offset open palm rather than
a finger-curl rig; fabric folds stay out of the low-poly target; the >26 m impostor remains a
two-quad billboard; evening readability is represented by the day/night/LATE final-context set.
+217 -36
View File
@@ -6,6 +6,12 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
- The visual-alignment path/loader/panel/HUD work and the realism lighting pass are complete and - 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`. 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 - `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 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. work in `TODO.md`, not the plan.
@@ -23,27 +29,185 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
head width uses skin vertices weighted to Head in y 1.55–1.81; clothing radius is the cloth 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, 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. head-band status and x/radial skirt clearance; `test_blender_assets` covers its shape.
- Post-realism work is split by theme, not by date: the finished lighting/flashlight/NPC items - Post-realism work is split by theme, not by date: finished items are archived in `DONE.md`, and
are archived in `DONE.md`, and `TODO.md` carries three planned workstreams (NPC gear fit, `TODO.md` carries the 0.x gap register and milestone roadmap. New work belongs there, not in
venue geometry + committed gallery, Forward+ desktop preset). New visual work should be added a revived historical plan document.
as concrete steps under one of those headings instead of a new "realism" bucket.
- Graphics v0.6.0 plan (2026-11-01): NPCs move to Blender-authored skinned meshes - Graphics v0.6.0 plan (completed 2026-11-01; ADR-0013): NPCs move to Blender-authored skinned meshes. `tools/npc_pipeline.py` builds
(`docs/plan-graphics-v0.6.md`, ADR-0013). `tools/npc_pipeline.py` builds
`assets/models/generated/npc_base.glb`; `NpcAvatar` keeps the procedural `_build_body()` `assets/models/generated/npc_base.glb`; `NpcAvatar` keeps the procedural `_build_body()`
fallback. Preserve `Rig/Head`, the limb node names, and the seed-deterministic 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 `outfit_for`/`layer_for`/`hand_item_for` helpers. Blender = flatpak 5.2.0 LTS, sandbox cwd
`/app/blender` → absolute paths for `--python`. CI stays offline (committed assets). `/app/blender` → absolute paths for `--python`. CI stays offline (committed assets).
- Engine: Godot 4.3 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` (4.7.2, Fedora) cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead. - Engine: Godot 4.7.2 stable (official editor build, `~/.local/bin/godot`). The system's preinstalled `godot-runner` cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead.
- Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache. - Language: GDScript. All cross-file references use explicit `preload()` constants (not `class_name` globals) so scripts compile in headless `--script` runs without the editor's class cache.
- Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`. - Test framework deviation: the project uses a custom minimal headless test runner (`src/test/test_runner.gd`) instead of GUT, because GUT needs the editor plugin. CI runs it with `--headless`.
- Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`. - Eventing: no autoload signal bus. `ShiftCoordinator` owns an `EventBus` instance (`src/core/event_bus.gd`) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under `--script`.
- Static signals are not available in Godot 4.3 GDScript ("Expected func or var after static") — do not use them. - Static signals are not available in Godot GDScript ("Expected func or var after static") — do not use them.
- GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests. - GDScript lambdas capture local variables **by value**; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests.
- Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default. - Shift length is the scenario's `shift_duration_s` (900 s in all three venues). Tests and the screenshot tool override elapsed time; they do not change the default.
- RNG: NPC reactions and event scheduling are seedable for deterministic tests. - RNG: NPC reactions and event scheduling are seedable for deterministic tests.
- **Mouse look (v0.7.3):** guard look is handled in `GuardController._input()` (before GUI), not `_unhandled_input`; focus/click-back recaptures the cursor and the HUD is made mouse-transparent recursively. Regression tests cover yaw/pitch and HUD filters.
- **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.93 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 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, now **0.9.4** after the NPC pass; the
completed map/NPC work and UI polish are the patch content. Next work is
**0.9.4 NPC**, **0.9.5 textures**, **0.9.6 integration**, then 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.4 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 and 0.9.4 NPC visual optimization are complete and in `DONE.md`.
0.9.5 textures and 0.9.6 integration/0.10.0 release work are next. The current
source version is 0.9.4; the v0.9.4 tag triggers the CI build.
- **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 postponed 0.9.5 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 - **Blender invocation (v0.6.0):** `flatpak run org.blender.Blender --background --python
/run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`. /run/media/system/DATA/Documents/06-games/security-game/tools/npc_pipeline.py -- build`.
The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is The flatpak cannot read `/tmp`; use absolute repo paths. `assets/models/npc/.gdignore` is
@@ -72,7 +236,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
## Handoff (read this first) ## Handoff (read this first)
- **Status (2026-11-01, after the gear-fit pass):** v0.6.1 is released. Post-v0.6.0 the - **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 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**, **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, `screen_designs.py compare` 11 good / 0 bad, `scene_concepts.py audit` all GOOD,
@@ -124,7 +288,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
`npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations. `npc_pipeline.py` + `asset_pipeline.py` and the confirmed-asset locations.
- Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at - Repo: `/run/media/system/DATA/Documents/06-games/security-game` (also reachable at
`/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.3.stable). `/var/home/zwitschi/Documents/06-games/security-game`). Godot: `~/.local/bin/godot` (4.7.2).
Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**. Tests: `godot --headless --path . --script res://src/test/test_runner.gd` → **177/177**.
Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**. Python tooling tests: `cd tools && python3 -m unittest test_asset_pipeline test_screen_designs test_model_pipeline` → **53**.
Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0. Session shell smoke: `godot --headless --path . --script res://src/test/smoke_session_shell.gd` → exit 0.
@@ -145,15 +309,19 @@ 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
@@ -173,7 +341,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after *original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty). `_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.3 **Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.7
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with `StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the `render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
@@ -212,7 +380,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
ridge, cheekbones, nose bridge/tip, ears with lobes and split upper/lower lips; the new 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. `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. `_hands_and_shoes()` has four fingers plus a thumb and `_clothing()` adds `Cuff` tori.
Budget work: `CHAR_MAX_VERTS` 5000 (see the library note), body decimation 0.26, upper lids are 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. 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` **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 surface (face) and of the `rubber` sole verts (toes) — all 8 avatars are +Z, so any
@@ -223,11 +392,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
truth), sources in `assets/models/blender_src/` (`.gdignore`d), and review sheets 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 `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` 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) and stay under the (same mesh node name, bones at the same rest positions, five tint slots); the `npc_base`
6000/4000 budget only because of body decimation (0.26) + `smart_project` at 80°: glTF vertex 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 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 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; `npc_pipeline.MAX_VERTICES`/`MAX_TRIANGLES` (base mesh) are unchanged. ~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 **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. 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 Fixed-colour detail materials carry a 4×4 texture because `_apply_outfit_materials()` sets
@@ -246,6 +417,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
helmet is lifted 2 cm above the brow. `test_npc_character` guards head/back gear in Godot. 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 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. 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 - **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 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 left the focus disc over the face. An explicit `--portrait-type=N` now overrides the hooded
@@ -376,7 +549,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
@@ -415,6 +588,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 `%`,
@@ -553,9 +729,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/
@@ -615,10 +795,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; 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; settings persistence goes through `Save.load_settings()` / `save_settings()`. - `Save.SETTINGS_FILE` is declared and unused; settings persistence goes through `Save.load_settings()` / `save_settings()`.
- Headless suite is **229/229**; the windowed smokes, screenshot compare and judge pass. Remaining visual follow-ups are in `TODO.md`. - Headless suite is **262/262**; 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
@@ -628,8 +808,9 @@ 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
@@ -640,10 +821,10 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
## Plan vs code ## Plan vs code
`PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of `PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of
2026-11-01 the playable build covers all three venues, controls, access/radio/evidence/review, 2026-11-02 the playable build covers the three venues, tutorials/campaign/checkpoints, the 0.9.3
the Blender asset library, the realism pass, and the visual-alignment pass. `TODO.md` holds only UI/accessibility pass, the 0.9.4 NPC visual optimization, and the Blender + realism asset pipeline. `TODO.md` holds the remaining
the realism follow-ups and optional future ideas. The project uses a custom headless runner, not 0.9.4–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not
GUT, and Gitea Actions, not GitHub Actions. GitHub Actions.
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu --> <!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
+12 -8
View File
@@ -2,7 +2,7 @@
## Premise ## Premise
You are a private security guard working the entrance of a fictional Hollywood Boulevard building. 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. 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, access verification, and proportionate escalation**, not about attacking everyone who approaches. The game is about **judgment, communication, access verification, and proportionate escalation**, not about attacking everyone who approaches.
@@ -96,15 +96,19 @@ A poor shift involves excessive force, confronting innocent people, ignoring a r
## Venues ## Venues
### Hollywood Boulevard Building ### El Capitan Entertainment Centre (6840 Hollywood Blvd)
The original scenario: a building entrance with steps, sidewalk, street lamps, and a restricted door. Tourists, performers, influencers, confused visitors, intoxicated pedestrians, trespassers, people in crisis, and rare violent threats approach from the boulevard. 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.
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. 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.
### The Joke Shop ### The Joke Shop
A comedy-club entrance. The door person checks IDs, tickets, reservations, guest-list status, and screens guests with a handheld wand under venue policy. 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.
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. 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.
@@ -153,13 +157,13 @@ The visual direction is readable stylized realism:
- **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. - **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. - **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.
Remaining visual work is tracked in `TODO.md` (NPC fidelity and the two venue stages), not in this plan. The path from the current vertical slice to the 0.10.0 release candidate — content depth, onboarding, accessibility, platform QA and release readiness — is tracked in [`TODO.md`](TODO.md); this plan stays at the product/design level.
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). 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).
## Tech Stack ## Tech Stack
- **Engine:** Godot 4.3, GL Compatibility renderer (Web parity). - **Engine:** Godot 4.7.2, GL Compatibility renderer (Web parity); optional Forward+ Desktop HQ build.
- **Language:** GDScript. - **Language:** GDScript.
- **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data. - **Architecture:** venue-driven simulation; shared systems plus `Resource`-based scenario data.
- **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`. - **Navigation:** `NavigationRegion3D` / `NavigationAgent3D`.
@@ -168,11 +172,11 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD
- **Persistence:** JSON in `user://` for settings and shift history. - **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. - **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. - **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, and a Web zip. - **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).
## Versioning and Delivery ## Versioning and Delivery
`config/version` in `project.godot` is the single version source (currently `0.6.1`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the six artifacts. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands. `config/version` in `project.godot` is the single version source (currently `0.9.4`). Releases are tagged `v<version>`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands.
## Design Direction ## Design Direction
+31 -17
View File
@@ -10,14 +10,16 @@ The central design goal is simple:
| | | | | |
| --- | --- | | --- | --- |
| ![Venue overview: the Hollywood Boulevard entrance with steps, sidewalks, street lamps, and signage](docs/screenshots/01-venue-overview.png) | ![Targeting an approaching NPC with the interaction HUD](docs/screenshots/02-targeting-npc.png) | | ![Venue overview: the El Capitan Entertainment Centre facade with six Ionic columns, red banners and stone steps](docs/screenshots/01-venue-overview.png) | ![Targeting an approaching NPC with the interaction HUD](docs/screenshots/02-targeting-npc.png) |
| ![Access inspection: wristband/credential check with allow/deny prompt](docs/screenshots/03-access-inspection.png) | ![Radio report form: emergency dispatch panel](docs/screenshots/04-radio-report.png) | | ![Access inspection: wristband/credential check with allow/deny prompt](docs/screenshots/03-access-inspection.png) | ![Radio report form: emergency dispatch panel](docs/screenshots/04-radio-report.png) |
| ![Late night: street lamps lit, marquee glowing, dark Hollywood Boulevard](docs/screenshots/05-late-night-avenue.png) | ![Night shift: guard flashlight cutting through the dark](docs/screenshots/06-night-flashlight.png) | | ![Late night: street lamps lit, marquee glowing, dark Hollywood Boulevard](docs/screenshots/05-late-night-avenue.png) | ![Night shift: guard flashlight cutting through the dark](docs/screenshots/06-night-flashlight.png) |
| ![Wand screening at The Joke Shop: false alarm on keys](docs/screenshots/07-wand-screening.png) | ![Escalation HUD at L3 with body camera armed and reaction log](docs/screenshots/08-escalation-hud.png) | | ![Wand screening at The Joke Shop: false alarm on keys](docs/screenshots/07-wand-screening.png) | ![Escalation HUD at L3 with body camera armed and reaction log](docs/screenshots/08-escalation-hud.png) |
| ![Body-camera timeline: formal warning, body camera on, blocking](docs/screenshots/09-body-camera-timeline.png) | ![Prop gallery: the six generated street-furniture models on a studio backdrop](docs/screenshots/10-prop-gallery.png) | | ![Body-camera timeline: formal warning, body camera on, blocking](docs/screenshots/09-body-camera-timeline.png) | ![Prop gallery: the six generated street-furniture models on a studio backdrop](docs/screenshots/10-prop-gallery.png) |
| ![Precision walk at the venue steps with the HUD chip visible](docs/screenshots/11-precision-walk.png) | | | ![Precision walk at the venue steps with the HUD chip visible](docs/screenshots/11-precision-walk.png) | ![The Joke Shop: a black Sunset Strip club under its signature canopy at night](docs/screenshots/12-joke-shop.png) |
| ![Late-night TV studio arrival: stone facade, bulb canopy, black car and barriers](docs/screenshots/13-studio-arrival.png) | |
*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
@@ -29,15 +31,19 @@ The central design goal is simple:
| **Linux — portable** | [`gig-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** | [`gig-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)** | [`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) | | **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.6.1** — fitted NPC gear, a refreshed portrait/gallery capture and the > **Latest published: v0.9.4** — the NPC visual optimization pass: face/head
> post-v0.6.0 realism/visual-alignment work (v2 skylines/textures, UI mockup art, > depth, hands and gear placement, shoes and boots, headgear clearance, and the
> flashlight beam, HUD fixes). > 8,000/8,000 character mesh budget on top of the Hollywood/Joke Shop maps and
> the v0.9.3 UI/accessibility polish.
>
> **Current source: v0.9.4** — tagged and built from the same commit.
> 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
@@ -50,14 +56,15 @@ The central design goal is simple:
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
[Setup and Run](#setup-and-run) 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: watch the entrance and sidewalk, judge why A typical shift lasts 10–15 minutes: watch the entrance and sidewalk, judge why
each person is approaching, verify access with recognition, wristbands, IDs, each person is approaching, verify access with recognition, wristbands, IDs,
tickets or credentials, and escalate only when necessary. The game rewards calm tickets or credentials, and escalate only when necessary. The game rewards calm
resolution over force. The full mechanics — the three venues, the six-level resolution over force. The venue menu splits Hollywood Boulevard into Day and
Night rows; the full mechanics — the three venues, the six-level
escalation model, and the core systems — are in escalation model, and the core systems — are in
[`docs/gameplay.md`](docs/gameplay.md); the design rationale lives in [`docs/gameplay.md`](docs/gameplay.md); the design rationale lives in
[`PLAN.md`](PLAN.md). [`PLAN.md`](PLAN.md).
@@ -72,7 +79,7 @@ decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
## Tech Stack ## Tech Stack
- **Engine:** Godot 4.x · **Language:** GDScript - **Engine:** Godot 4.7.2 · **Language:** GDScript
- **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile` - **NPCs:** Blender-authored skinned library (`assets/models/blender/`) with procedural fallbacks; lightweight FSMs on `NpcProfile`
- **World:** procedural `WorldBuilder` + generated prop models - **World:** procedural `WorldBuilder` + generated prop models
- **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/` - **Art:** v2 skyline/surface textures in `assets/textures/ai/game_ready/v2/picks/`; UI/scene art in `assets/images/`
@@ -100,28 +107,35 @@ Full setup, every run/test/smoke command, and the controls table are in
- [`PLAN.md`](PLAN.md) — Game design plan and scenario details. - [`PLAN.md`](PLAN.md) — Game design plan and scenario details.
- [`AGENTS.md`](AGENTS.md) — Development and collaboration workflow. - [`AGENTS.md`](AGENTS.md) — Development and collaboration workflow.
- [`TODO.md`](TODO.md) — Active checkbox task list.
- [`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. - [`CHANGELOG.md`](CHANGELOG.md) — User-facing changes by version.
- [`docs/README.md`](docs/README.md) — Documentation index and visual previews.
- [`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/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/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/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/development-status.md`](docs/development-status.md) — Implemented features and what's next.
- [`docs/smoke-checklist.md`](docs/smoke-checklist.md) — Manual smoke-test checklist. - [`docs/smoke-checklist.md`](docs/smoke-checklist.md) — Manual smoke-test checklist.
- [`docs/blender-assets.md`](docs/blender-assets.md) — Blender asset library: characters, gear, props, attach points. - [`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.
- [`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.
- [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md) — Graphics-quality plan: Blender-authored NPC characters. - [`TODO.md`](TODO.md) — Active tasks plus the 0.x gap analysis and milestone roadmap.
## Development Status ## Development Status
v0.6.1 shipped (fitted NPC gear and refreshed captures) on top of v0.6.0's v0.9.4 is the current source version: the completed NPC visual optimization
Blender character/gear/prop library, baked AO and environment lift. The (face/head depth, hands and gear placement, shoes/boots, headgear clearance and
realism and visual-alignment passes are part of the same release. See the 8,000/8,000 mesh budget), on top of the v0.9.3 UI/accessibility polish
[`docs/development-status.md`](docs/development-status.md) for the full pass and v0.9.2's Hollywood/Joke Shop map rebuilds. It builds on
implemented list and [`TODO.md`](TODO.md) for what's next. Manual verification v0.9.1's Godot 4.7.2 baseline, v0.9.0's production-quality pass, v0.8's
uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md). tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. See [`docs/development-status.md`](docs/development-status.md)
for the implemented list and [`TODO.md`](TODO.md) for the 0.x roadmap. Manual
verification uses the [`docs/smoke-checklist.md`](docs/smoke-checklist.md).
## Development Workflow ## Development Workflow
+228 -42
View File
@@ -3,56 +3,242 @@
Work is grouped by theme. Each item should be small enough to complete and verify on its own; Work is grouped by theme. Each item should be small enough to complete and verify on its own;
see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these plans. see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these plans.
## Venue geometry and the committed gallery (v0.6.1) ## Gap Analysis and 0.x Roadmap
Today all three venues share the Hollywood `WorldBuilder` geometry, so the Joke Shop and studio Baseline: **v0.9.4** (2026-11-02). Three playable venues, tutorial/campaign/checkpoint resume,
concepts are only compared on lighting (noted in `tools/scene_concepts.py` `SHOTS`). They also difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete
have no stage in the committed `docs/screenshots/` gallery, only in `capture_realism.gd`. escalation/access/radio loop, shift review, the Blender asset library, 262 headless + 101 Python
tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong
release-candidate foundation, not yet a 0.10.0 release candidate.
- [ ] Extract a geometry spec per venue instead of branching inline: a `scenario.` (or ### Documentation audit (completed 2026-11-01)
`WorldBuilder`) table of facade width/height, door style, window rows, awning/marquee
flags, street furniture set, palette and props, defaulting to the Hollywood values so
nothing regresses.
- [ ] Joke Shop: narrow brick alley (10–12 m wide), one warm wall lantern as the key light,
recessed door with a step, shuttered window, dumpster/AC clutter, no skyline ring — the
alley concept has depth, not a horizon.
- [ ] TV Studio: granite/stone facade, bulb canopy instead of the marquee, glossy black car on
the curb, stanchions and barrier line at the door, no palm trees.
- [ ] Keep navigation working: regenerate/verify the `NavigationRegion3D` bake per venue,
update sidewalk/steps/door waypoints (Joke Shop and Studio already have `sidewalk` and
`steps_end`), and confirm NPCs still reach the door (smoke + `test_venue_*`).
- [ ] Split the concept mapping so each venue is judged on its own frame (`joke_shop_*`,
`studio_*`) and drop the "shared geometry" caveat in `tools/scene_concepts.py`.
- [ ] Add both venues to the committed gallery: two new stages in
`src/test/capture_screenshots.gd` (`12-joke-shop.png`, `13-studio-arrival.png`) reusing the
existing `joke_shop_queue` / `studio_arrival` designs, then `check_screenshots.sh` and a
fresh judge run.
- [ ] Update `docs/architecture.md` (venue geometry), `README.md` (gallery) and the screenshot
table when the stages land.
## Forward+ desktop preset and a volumetric flashlight (v0.7.0) - [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).
The Compatibility renderer has no volumetrics, so the flashlight is a tight pool of light with ### Gap register (remaining roadmap)
no visible shaft. A second desktop build can render it properly without touching the CI/default
path.
- [ ] Write the preset as an `override.cfg` (Godot reads it beside the binary/project) that sets | Area | Current baseline | Remaining gap | Risk | Milestone |
`rendering/renderer/rendering_method="forward_plus"`, enables `volumetric_fog_*` and SDFGI, | --- | --- | --- | --- | --- |
and keeps the Compatibility build as the default (`project.godot` unchanged). | 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 |
- [ ] Gate the effect in code: only give the flashlight a volumetric component when the renderer | 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) |
is Forward+ (`RenderingServer.get_rendering_device() != null`), so Web/CI builds are | 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) |
untouched and the existing headless tests keep passing. | 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 |
- [ ] Tune `light_volumetric_fog_energy`/`fog_density` for the LATE phase and re-check the | 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 |
entrance so the shaft does not wash the facade again (the reason the wide cone was cut). | Performance/platform | 24-NPC headless budget (6.9 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.0 |
- [ ] A/B the two renderers with `capture_realism.gd` (same stages, two `--out` dirs) and record | 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 |
the diff + judge scores in `docs/screens/realism/<date>-forward-plus/`. | 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 |
- [ ] Add the preset to `tools/build_releases.sh` and `docs/RELEASING.md` as an optional | 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 |
"desktop HQ" artifact, and note the runtime requirement (Vulkan driver) in `README.md`. | 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 |
- [ ] Test: a headless run must still boot when Forward+ is unavailable (the preset must degrade | 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 | 0.11.0+ |
to Compatibility instead of failing to start).
**Current priority:** map optimization, the **pre-build NPC revisit**, the
**0.9.3 UI polish** and **0.9.4 NPC visual optimization** passes are complete
(all moved to `DONE.md` on 2026-11-02). 0.9.5 texture refinement, 0.9.6
integration and the 0.10.0 release candidate are queued. The source version is
now 0.9.4.
## Postponed — Patch 0.9.5 — Texture and material refinement
Goal: improve close-range surface and character texture quality while keeping GL
Compatibility/Web parity, deterministic assets and offline CI.
### Environment textures and materials
- [ ] Audit the v2 picks (brick, sidewalk pavers, dry/wet asphalt, awning canvas,
day/dusk/night skylines) at close range and in the entrance/street shots for
seams, tiling, scale, contrast and normal-map strength.
- [ ] Refine brick mortar/wear, paver joints/stains, asphalt aggregate/wet response
and awning weave using the existing image/asset tooling; never overwrite a
pick, use `-vN` candidates and promote validated results.
- [ ] Check UV scales and material roughness/metallic profiles; keep day/night
phase behavior and the wet-street transition intact.
- [ ] Review distant skyline haze and foliage/planter surfaces against the concept
references; fix obvious flatness without regressing readability.
### Character and prop textures
- [ ] Audit NPC skin, cloth, pants, hair and gear albedo/normal/AO maps in portraits;
refine fabric weave, skin variation and fixed detail materials.
- [ ] Re-bake AO where geometry changes; verify the 256² maps and material wiring.
- [ ] Audit library props and UI/card/icon textures at their actual screen sizes;
remove blurry/oversized or unused textures where safe.
- [ ] Run texture audits, import, and the full asset test suite; record texture memory
and triangle/draw-call impact.
### Visual verification
- [ ] Run `python3 tools/scene_concepts.py realism` for the affected stages with the
judge enabled; record metric gaps and model/spend.
- [ ] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all
`diff` verdicts.
- [ ] Capture before/after close-ups for brick, pavement, asphalt, character cloth
and skyline; document accepted trade-offs.
- [ ] Update asset docs and the changelog/status with the promoted texture versions.
## Postponed — Patch 0.9.6 — Integration, performance and judge gate
Goal: integrate the UI/model/texture patches, prove the combined build on the
target paths and leave a clean release-candidate handoff.
### Integration and asset rebuild
- [ ] Rebuild all changed Blender/GLB/AO assets, re-import, and verify manifest/fit/
audit coverage.
- [ ] Run the complete headless suite, Python tooling and smoke matrix; fix any
regression from the three polish patches.
- [ ] Re-run the 24-NPC budget smoke and record frame time, mesh count and any
texture-memory change; check Web and Desktop HQ if available.
- [ ] Verify save/campaign/tutorial behavior is unchanged by the visual/UI patches.
### Visual gallery and judge gate
- [ ] Recapture the full gallery, portraits, venue/realsim stages and Desktop HQ A/B
as needed; no stale screenshots in the release set.
- [ ] Run `tools/check_screenshots.sh`, `screen_designs.py compare` and
`screen_designs.py judge` on the final captures.
- [ ] Run the realism judge for the affected concepts with a pinned model; record
model, attempt count, spend and verdicts.
- [ ] Review all `review` verdicts manually; convert unexplained layout/composition
mismatches into fixes or explicit known limitations.
- [ ] Ensure generated realism folders remain gitignored/local-only and only the
durable report decisions/docs are committed.
### Release-candidate handoff
- [ ] Update README, architecture, development status, changelog and TODO with the
final patch-level results and any remaining gaps.
- [ ] Tag/version or otherwise freeze `0.9.6` as the integration checkpoint before
the `0.10.0` release candidate.
- [ ] Exit: combined build is functionally green, visually reviewed, performance
measured and ready for the 0.10.0 content-lock/playtest phase.
## Postponed — 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 is the next minor release after the 0.9.x patch line.
### Content lock and external playtest
- [ ] Declare a content/feature freeze for 0.10.0; only release-blocking fixes and balance changes
may land after the freeze.
- [ ] Produce a release-candidate build with the tutorial, campaign, all three venues, Help,
accessibility settings and checkpoint/resume enabled.
- [ ] 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
- [ ] Define measurable targets for routine compliance, access-decision accuracy, peaceful
resolution, justified emergency calls and false-positive/false-negative rates.
- [ ] Run scripted venue sweeps across easy/normal/hard and all four phases; compare outcomes and
tune event weights, reaction tables, compliance and report strictness where targets fail.
- [ ] Review emergency calls against actual danger: no routine behavior should make emergency the
dominant winning move, and genuine threats must remain answerable.
- [ ] Verify the reputation grades, debrief explanations and campaign progression still communicate
the de-escalation-first design after tuning.
- [ ] Record the balance evidence and any deliberate exceptions in `docs/development-status.md`
or `MEMORY.md`.
### Save migration and session reliability
- [ ] Add fixtures for a 0.8-era settings/campaign/history save and a 0.9.0 checkpoint; verify
migration/default-filling and a clean first launch with no files.
- [ ] Test fresh install → tutorial → campaign → pause → quit → resume → review → next venue on
an isolated user-data directory.
- [ ] Test corrupt JSON, partial temp files, missing optional fields and a failed atomic rename;
confirm fallback behavior never destroys a valid save.
- [ ] Verify checkpoint resume after all three venues, after an incident, with NPCs at the door and
with flashlight/body-camera/door state set.
- [ ] Document save locations, schema versions, reset behavior and rollback/export instructions in
`docs/getting-started.md` and the release notes.
### Release engineering and distribution
- [ ] Run `tools/build_releases.sh` from a clean checkout and verify Linux/Windows/macOS/Web/HQ
artifact names, sizes and checksums.
- [ ] Smoke-test fresh Linux portable/AppImage, Windows portable/installer, macOS unzip/launch,
Web static hosting and Desktop HQ Vulkan fallback on the target matrix.
- [ ] Add a disk-space preflight and retention policy to the release/publish scripts so a full
Gitea host cannot leave a partially uploaded release.
- [ ] Verify release metadata, tag/version consistency, asset counts and download links; retain
at least the latest 0.8/0.9 releases and document older-asset pruning.
- [ ] Decide and document whether macOS signing/notarization is required for 0.10.0 or explicitly
remains a future release blocker; record the quarantine instructions either way.
### Legal, credits and platform policy
- [ ] Audit AI-assisted asset provenance and licenses; record source/model usage and any
redistribution constraints for textures, characters, props and UI art.
- [ ] Audit audio/SFX/music licensing (or confirm everything is procedural) and add a credits file.
- [ ] Review body-camera/privacy language, mental-health-crisis representation, age/content rating
and storefront requirements; fix any release-blocking copy or content.
- [ ] Add the player-facing credits, known limitations, accessibility statement and privacy note to
the release package/README.
- [ ] Mark external legal/storefront approval as complete or explicitly block 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.
- [ ] Remove or archive stale plans/notes and confirm no contradictory version/status claims remain.
### Release-candidate QA and exit
- [ ] Run the complete headless suite, Python tooling, tutorial/campaign/session/scenario smokes,
24-NPC budget smoke and release build from a clean checkout.
- [ ] Run the manual QA matrix: fresh install, upgrade, offline launch, gamepad, accessibility
settings, pause/resume, all venues and Desktop HQ fallback.
- [ ] Confirm no P0/P1 defects remain; P2 items must be documented as known limitations or
post-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.
## 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.
- Keep the de-escalation-first rules and rare-emergency design unchanged while adding progression,
difficulty and feedback.
## Realism follow-ups (deferred) ## 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 - [ ] 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`). `--portrait-type` override is already in `capture_realism.gd`).
- [ ] Human-authored tree/hedge silhouettes: the whole scene now reads well except the foliage, - [ ] Human-authored tree/hedge silhouettes: the whole scene now reads well except the foliage,
+37 -37
View File
@@ -28,12 +28,12 @@
"attach": "back", "attach": "back",
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.15, 0.161,
0.3, 0.296,
0.141 0.212
], ],
"min": [ "min": [
-0.15, -0.161,
-0.12, -0.12,
-0.319 -0.319
] ]
@@ -42,11 +42,11 @@
"materials": [ "materials": [
"pack_nylon", "pack_nylon",
"steel", "steel",
"plastic_black" "denim_bag"
], ],
"path": "assets/models/blender/npc_gear/backpack.glb", "path": "assets/models/blender/npc_gear/backpack.glb",
"triangles": 316, "triangles": 380,
"vertices": 360 "vertices": 408
}, },
"beanie": { "beanie": {
"attach": "head", "attach": "head",
@@ -453,7 +453,7 @@
"max": [ "max": [
0.321, 0.321,
1.824, 1.824,
0.185 0.189
], ],
"min": [ "min": [
-0.321, -0.321,
@@ -467,8 +467,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber" "rubber"
], ],
@@ -487,15 +487,15 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 3974, "triangles": 4482,
"vertices": 3744 "vertices": 4260
}, },
"npc_coat": { "npc_coat": {
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.332, 0.332,
1.824, 1.824,
0.185 0.189
], ],
"min": [ "min": [
-0.332, -0.332,
@@ -509,8 +509,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber" "rubber"
], ],
@@ -528,8 +528,8 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 5026, "triangles": 5474,
"vertices": 4807 "vertices": 5264
}, },
"npc_dress": { "npc_dress": {
"bounds_godot": { "bounds_godot": {
@@ -550,8 +550,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber" "rubber"
], ],
@@ -567,8 +567,8 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4428, "triangles": 4900,
"vertices": 4026 "vertices": 4719
}, },
"npc_firefighter": { "npc_firefighter": {
"bounds_godot": { "bounds_godot": {
@@ -589,8 +589,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"hivis", "hivis",
"reflective", "reflective",
@@ -608,15 +608,15 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4848, "triangles": 5344,
"vertices": 4735 "vertices": 5494
}, },
"npc_guard": { "npc_guard": {
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.361, 0.361,
1.819, 1.819,
0.185 0.189
], ],
"min": [ "min": [
-0.361, -0.361,
@@ -630,8 +630,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber", "rubber",
"leather", "leather",
@@ -652,15 +652,15 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4560, "triangles": 5046,
"vertices": 4529 "vertices": 5096
}, },
"npc_hoodie": { "npc_hoodie": {
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.326, 0.326,
1.856, 1.856,
0.185 0.189
], ],
"min": [ "min": [
-0.326, -0.326,
@@ -674,8 +674,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber" "rubber"
], ],
@@ -693,15 +693,15 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4826, "triangles": 5304,
"vertices": 4504 "vertices": 4950
}, },
"npc_jacket": { "npc_jacket": {
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.332, 0.332,
1.824, 1.824,
0.185 0.189
], ],
"min": [ "min": [
-0.332, -0.332,
@@ -715,8 +715,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber" "rubber"
], ],
@@ -734,15 +734,15 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4394, "triangles": 4872,
"vertices": 4175 "vertices": 4661
}, },
"npc_vest": { "npc_vest": {
"bounds_godot": { "bounds_godot": {
"max": [ "max": [
0.321, 0.321,
1.819, 1.819,
0.185 0.189
], ],
"min": [ "min": [
-0.321, -0.321,
@@ -756,8 +756,8 @@
"skin", "skin",
"cloth", "cloth",
"pants", "pants",
"eye_white",
"accessory", "accessory",
"eye_white",
"hair", "hair",
"rubber", "rubber",
"hivis", "hivis",
@@ -775,8 +775,8 @@
"accessory", "accessory",
"hair" "hair"
], ],
"triangles": 4474, "triangles": 4980,
"vertices": 4340 "vertices": 4879
}, },
"palm_tree": { "palm_tree": {
"bounds_godot": { "bounds_godot": {
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+119 -2
View File
@@ -1,5 +1,5 @@
{ {
"hud.controls": "LMB/Space wheel · A/D step · Space confirm · Esc cancel · R emergency · E inspect · C wand · Q polite · B camera · Tab/wheel cycle · Shift slow · G light · L lock · F debug", "hud.controls": "LMB/Space wheel · A/D step · Space confirm · Esc cancel · R emergency · E inspect · C wand · Q ask · B camera · Tab/wheel cycle · Shift slow · G light · L lock · F debug",
"radial.raise_hand": "Stop", "radial.raise_hand": "Stop",
"radial.eye_contact": "Look", "radial.eye_contact": "Look",
"radial.point": "Point", "radial.point": "Point",
@@ -88,5 +88,122 @@
"review.timeline_button": "Body camera timeline", "review.timeline_button": "Body camera timeline",
"hud.nearby": "%d nearby · Tab or mouse wheel cycles targets", "hud.nearby": "%d nearby · Tab or mouse wheel cycles targets",
"hud.precision": "Precision walk (Shift)", "hud.precision": "Precision walk (Shift)",
"hud.controls_gamepad": "Left stick move · Right stick look · A wheel/confirm · B cancel · X inspect · Y radio · LB slow · RB wand" "hud.controls_gamepad": "Left stick move · Right stick look · A wheel/confirm · B cancel · X inspect · Y radio · LB slow · RB wand",
"tutorial.header": "FIRST SHIFT",
"tutorial.skip_hint": "F1 skip tutorial",
"tutorial.arrive": "Walk forward and look around. The entrance is behind you.",
"tutorial.focus": "Look at the visitor. Press Tab or the mouse wheel to cycle targets.",
"tutorial.wheel": "Open the action wheel with Space or left click.",
"tutorial.inspect": "Choose Inspect and read the access evidence.",
"tutorial.direction": "Close the panel and give a polite direction.",
"tutorial.warning": "Give a formal warning if the visitor persists. It arms the body camera.",
"tutorial.radio": "Open the assistance radio and submit a short report.",
"tutorial.review": "Finish the shift and review what happened.",
"tutorial.completed": "Tutorial complete.",
"ui.inspect_actions": "A = admit · D = refuse entry",
"ui.wand_actions": "A = admit · D = refuse entry",
"ui.radio_send_assist": "Send request",
"ui.radio_send_emergency": "Send emergency",
"ui.radio_hold_hint": "Hold the button for %.1fs",
"ui.radio_cancelled": "Call not sent — hold the button to confirm.",
"ui.radio_holding": "Holding… %.0f%%",
"ui.review_return_menu": "Return to menu",
"ui.quit_game": "Quit game",
"ui.apply_settings": "Apply settings",
"tutorial.skipped": "Tutorial skipped.",
"ui.settings_title": "Settings",
"ui.settings_invert": "Invert vertical look",
"ui.settings_head_bob": "Head bob and camera motion",
"ui.settings_difficulty": "Difficulty / pacing",
"ui.settings_reduce_motion": "Reduce motion",
"ui.settings_captions": "Captions / subtitles",
"ui.settings_replay": "Replay tutorial",
"ui.settings_reset_campaign": "Reset campaign",
"ui.settings_controls_help": "Controls (click a binding, then press a key or pad button)",
"ui.settings_cancel": "Cancel",
"ui.settings_reset_title": "Reset campaign",
"ui.settings_reset_confirm": "Clear campaign progress and restart from the Hollywood Boulevard shift?",
"ui.settings_replay_title": "Replay tutorial",
"ui.settings_replay_confirm": "Replay the tutorial from the Hollywood Boulevard shift? The current shift will end.",
"ui.settings_press": "Press…",
"ui.pause_title": "Paused",
"ui.pause_resume": "Resume",
"ui.pause_restart": "Restart shift",
"ui.pause_settings": "Settings",
"ui.pause_menu": "Quit to menu",
"ui.pause_hint": "Esc resumes",
"ui.help_title": "Help",
"ui.help_filter": "Filter controls…",
"ui.help_close": "Close",
"help.control_move": "Movement: W/A/S/D · mouse look · Shift precision walk",
"help.control_focus": "Focus: crosshair cone · Tab / mouse wheel cycles nearby people",
"help.control_wheel": "Action wheel: Space or left click · A/D or arrows step · Space confirms",
"help.control_access": "Inspect access: E · Wand: C · Ask: Q",
"help.control_escalate": "Warning: 4 · Blocking: 5 · Security radio: 6",
"help.control_emergency": "Emergency radio: R, hold the on-screen button to confirm",
"help.control_tools": "Body camera: B · Flashlight: G · Door lock: L",
"help.control_misc": "Pause: Esc · Debug overlay: F",
"ui.start_title": "GIG LINE",
"ui.start_subtitle": "Pick a venue to start your shift.",
"ui.start_help": "Help",
"ui.start_settings": "Settings",
"ui.start_hint": "Up/Down to choose · Enter to start · Esc to quit",
"ui.campaign_complete": "Campaign complete — pick any venue for a free shift.",
"ui.campaign_status": "Campaign shift %d · next: %s",
"ui.continue_shift": "Continue shift — %s",
"ui.campaign_complete_short": "Campaign complete",
"ui.radio_location_placeholder": "Location (e.g. front steps)",
"ui.radio_location_default": "front entrance",
"ui.radio_description_placeholder": "Describe the person and their behavior",
"ui.radio_weapon": "Weapon seen",
"ui.radio_danger": "Danger level: ",
"ui.radio_cancel": "Cancel",
"ui.radio_target": "Target: %s",
"ui.radio_title_emergency": "EMERGENCY RADIO",
"ui.radio_title_assist": "RADIO DISPATCH",
"hud.mode": "Door: %s · Light: %s",
"hud.door_locked": "LOCKED",
"hud.door_open": "open",
"hud.light_on": "on",
"hud.light_off": "off",
"hud.rec": "REC",
"hud.cam_clock": "SHIFT %02d:%02d:%02d",
"hud.shift_status": "shift %02d:%02d phase %s\nrep %.0f crowd %.0f%%",
"hud.inspect_text": "ACCESS INSPECTION\n\nAccess check — %s\nGranted: %s",
"hud.wand_text": "Wand check — %s\nAlert: %s",
"hud.wand_items": "Carried items: %s",
"hud.yes": "YES",
"hud.no": "NO",
"hud.wand_none": "none",
"review.title": "Shift Review",
"review.venue": "Venue: %s",
"review.policy": "Policy: %s",
"review.grade": "Grade: %s Score: %.0f/100",
"review.history": "Shifts on record: %d · best score: %.0f · grades seen: %s",
"review.incidents": "Incidents handled: %d (peaceful %d)",
"review.npcs": "NPCs encountered: %d",
"review.radio": "Radio battery: %.0f%% emergency cooldown: %.0fs",
"review.crowd": "Crowd mood: %.0f%% (panic: %s)",
"review.highlights": "Highlights:",
"review.modifier": " %s (%s) %s",
"review.continue_campaign": "Continue campaign",
"review.campaign_complete": "Campaign complete. Free-play venues remain available.",
"review.campaign_next": "Campaign shift %d complete · next: %s",
"venue.hollywood.label": "Hollywood Boulevard",
"venue.hollywood.blurb": "Building entrance, tourists and late-night trouble.",
"venue.hollywood_day.label": "Hollywood Boulevard — Day",
"venue.hollywood_day.blurb": "El Capitan entrance in daylight: tourists, performers and routine traffic.",
"venue.hollywood_night.label": "Hollywood Boulevard — Night",
"venue.hollywood_night.blurb": "The same entrance after dark: banners lit, late crowd, harder to read.",
"venue.joke.label": "The Joke Shop",
"venue.joke.blurb": "Guest list, IDs and wand screening.",
"venue.studio.label": "Late Night TV Studio",
"venue.studio.blurb": "Credentials, filming boundary, celebrity arrivals.",
"hud.reasons": "Reasons: %s",
"hud.issues": "Issues: %s",
"hud.wand_suspicious": "The wand alerts on a suspicious item (%s).",
"hud.wand_ask": "Ask the guest to identify it before deciding.",
"hud.wand_harmless": "The wand alerts on a harmless item (%s).",
"hud.wand_false": "Likely a false alarm — keys, belt, or phone.",
"hud.wand_clear": "No alert. The guest appears clear."
} }
+113 -375
View File
@@ -1,154 +1,61 @@
[gd_resource type="Resource" script_class="VenueScenario" load_steps=17 format=3] [gd_resource type="Resource" script_class="VenueScenario" format=3]
[ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_2u28i"] [ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_c5x6v"]
[ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_acokf"] [ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_7qk8j"]
[ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_mqiqi"] [ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_lvgx2"]
[sub_resource type="Resource" id="Resource_i8fga"] [sub_resource type="Resource" id="Resource_xf4wh"]
script = ExtResource("1_2u28i") script = ExtResource("1_c5x6v")
required_artifacts = { required_artifacts = {
1: true 1: true
} }
grant_if_any_required = false
minimum_age = 0
require_id = false
wand_screening_required = false
policy_summary = "Private property. Entry requires recognition or a valid wristband." policy_summary = "Private property. Entry requires recognition or a valid wristband."
[sub_resource type="Resource" id="Resource_c7lhe"] [sub_resource type="Resource" id="Resource_cgh52"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "tourist" id = "tourist"
display_name = "Tourist" display_name = "Tourist"
npc_type = 0
temperament = 0.1 temperament = 0.1
base_compliance = 0.9 base_compliance = 0.9
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."]) dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Okay, I'll move to the sidewalk.", "Sorry, I'll put the camera away."],
"reason": ["Just getting a photo of the entrance.", "I'm meeting friends here."],
"recognition": ["You remember me from the tour, right?"],
"refusal": ["I just want a photo, I'm not staying.", "I didn't know this entrance was restricted."]
}
[sub_resource type="Resource" id="Resource_0t6ar"] [sub_resource type="Resource" id="Resource_qe635"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "confused_visitor" id = "confused_visitor"
display_name = "Confused Visitor" display_name = "Confused Visitor"
npc_type = 3 npc_type = 3
temperament = 0.2 temperament = 0.2
base_compliance = 0.85 base_compliance = 0.85
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."]) dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Oh, I understand. I'll check with the box office."],
"reason": ["I thought this was the box office.", "I'm looking for the event entrance."],
"refusal": ["I'm sure the event is here. Let me check my phone."]
}
[sub_resource type="Resource" id="Resource_wyv8p"] [sub_resource type="Resource" id="Resource_u5nrp"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "delivery" id = "delivery"
display_name = "Delivery Worker" display_name = "Delivery Worker"
npc_type = 10 npc_type = 10
temperament = 0.25
base_compliance = 0.8
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Where should I leave this?"]) dialogue_lines = Array[String](["Where should I leave this?"])
carried_items = Array[String]([]) context_lines = {
"reason": ["Drop-off for the venue. Where should I leave it?"]
}
[sub_resource type="Resource" id="Resource_v2hc4"] [sub_resource type="Resource" id="Resource_dsavb"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "street_performer" id = "street_performer"
display_name = "Street Performer" display_name = "Street Performer"
npc_type = 1 npc_type = 1
temperament = 0.45 temperament = 0.45
base_compliance = 0.55 base_compliance = 0.55
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 55, 0: 55,
@@ -156,47 +63,17 @@ reactions_by_level = {
3: 30 3: 30
} }
} }
default_reactions = { context_lines = {
1: { "reason": ["Just doing my act; I'll keep the sidewalk clear."]
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
} }
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_lg4td"] [sub_resource type="Resource" id="Resource_sexiy"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "influencer" id = "influencer"
display_name = "Influencer" display_name = "Influencer"
npc_type = 2 npc_type = 2
temperament = 0.5 temperament = 0.5
base_compliance = 0.5 base_compliance = 0.5
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 40, 0: 40,
@@ -218,47 +95,18 @@ reactions_by_level = {
8: 25 8: 25
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."]) dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Filming a quick clip for my channel."]
}
[sub_resource type="Resource" id="Resource_ijl2s"] [sub_resource type="Resource" id="Resource_ghqd8"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "intoxicated" id = "intoxicated"
display_name = "Intoxicated Pedestrian" display_name = "Intoxicated Pedestrian"
npc_type = 4 npc_type = 4
temperament = 0.6 temperament = 0.6
base_compliance = 0.4 base_compliance = 0.4
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 30, 0: 30,
@@ -272,41 +120,13 @@ reactions_by_level = {
4: 10 4: 10
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 1.8 reaction_delay = 1.8
dialogue_lines = Array[String]([]) context_lines = {
carried_items = Array[String]([]) "reason": ["Looking for my friends. I think they went inside."]
}
[sub_resource type="Resource" id="Resource_eycmk"] [sub_resource type="Resource" id="Resource_g8peq"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "trespasser" id = "trespasser"
display_name = "Trespasser" display_name = "Trespasser"
npc_type = 5 npc_type = 5
@@ -341,41 +161,13 @@ reactions_by_level = {
7: 20 7: 20
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."]) dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Meeting a friend inside. I'll only be a minute.", "Just cutting through."]
}
[sub_resource type="Resource" id="Resource_ggtpw"] [sub_resource type="Resource" id="Resource_4xl5p"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "mental_crisis" id = "mental_crisis"
display_name = "Person in Crisis" display_name = "Person in Crisis"
npc_type = 7 npc_type = 7
@@ -411,47 +203,18 @@ reactions_by_level = {
7: 15 7: 15
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 2.4 reaction_delay = 2.4
dialogue_lines = Array[String]([]) context_lines = {
carried_items = Array[String]([]) "reason": ["I just need a quiet minute.", "I'm waiting for someone."]
}
[sub_resource type="Resource" id="Resource_oa64f"] [sub_resource type="Resource" id="Resource_y6282"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "violent_threat" id = "violent_threat"
display_name = "Violent Threat" display_name = "Violent Threat"
npc_type = 6 npc_type = 6
temperament = 0.95 temperament = 0.95
base_compliance = 0.05 base_compliance = 0.05
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
2: 25, 2: 25,
@@ -479,41 +242,12 @@ reactions_by_level = {
7: 30 7: 30
} }
} }
default_reactions = { context_lines = {
1: { "reason": ["Back off. This doesn't concern you."]
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
} }
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_7t7dh"] [sub_resource type="Resource" id="Resource_75a0r"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "protester" id = "protester"
display_name = "Protester" display_name = "Protester"
npc_type = 12 npc_type = 12
@@ -547,66 +281,34 @@ reactions_by_level = {
7: 20 7: 20
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I have every right to be on public sidewalk.", "You can't touch me, this is a lawful protest."]) dialogue_lines = Array[String](["I have every right to be on public sidewalk.", "You can't touch me, this is a lawful protest."])
carried_items = Array[String]([]) context_lines = {
"reason": ["We're demonstrating on the public sidewalk.", "This is a peaceful protest."]
}
[sub_resource type="Resource" id="Resource_8tj1k"] [sub_resource type="Resource" id="Resource_ix35t"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "authorized_staff" id = "authorized_staff"
display_name = "Staff Member" display_name = "Staff Member"
npc_type = 8 npc_type = 8
temperament = 0.15 temperament = 0.15
base_compliance = 1.0 base_compliance = 1.0
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 100 0: 100
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on staff. I'm checking the entrance.", "Crew check-in; I'm working tonight."]
carried_items = Array[String]([]) }
[sub_resource type="Resource" id="Resource_tnpxm"] [sub_resource type="Resource" id="Resource_0mcg3"]
script = ExtResource("2_acokf") script = ExtResource("2_7qk8j")
id = "authorized_guest" id = "authorized_guest"
display_name = "Authorized Guest" display_name = "Authorized Guest"
npc_type = 9 npc_type = 9
temperament = 0.2 temperament = 0.2
base_compliance = 0.95 base_compliance = 0.95
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 92, 0: 92,
@@ -617,16 +319,16 @@ default_reactions = {
2: 12 2: 12
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on the guest list. Here's my ID.", "A friend invited me; I have a ticket."]
carried_items = Array[String]([]) }
[resource] [resource]
script = ExtResource("3_mqiqi") script = ExtResource("3_lvgx2")
id = "hollywood_building" id = "hollywood_building"
display_name = "Hollywood Boulevard Building" display_name = "El Capitan Entertainment Centre"
description = "Steps and entrance of a private building off Hollywood Boulevard." description = "The historic 1921 Masonic Temple at 6840 Hollywood Boulevard, now the El Capitan Entertainment Centre."
access_policy = SubResource("Resource_i8fga") access_policy = SubResource("Resource_xf4wh")
equipment = Array[String](["wristband_policy", "flashlight", "radio"]) equipment = Array[String](["wristband_policy", "flashlight", "radio"])
locations = { locations = {
"entrance": Vector3(0, 0, 1), "entrance": Vector3(0, 0, 1),
@@ -635,7 +337,7 @@ locations = {
"sidewalk": Vector3(0, 0, 9), "sidewalk": Vector3(0, 0, 9),
"steps_end": Vector3(0, 0, 3) "steps_end": Vector3(0, 0, 3)
} }
npc_profiles = Array[ExtResource("2_acokf")]([SubResource("Resource_c7lhe"), SubResource("Resource_0t6ar"), SubResource("Resource_wyv8p"), SubResource("Resource_v2hc4"), SubResource("Resource_lg4td"), SubResource("Resource_ijl2s"), SubResource("Resource_eycmk"), SubResource("Resource_ggtpw"), SubResource("Resource_oa64f"), SubResource("Resource_7t7dh"), SubResource("Resource_8tj1k"), SubResource("Resource_tnpxm")]) npc_profiles = Array[ExtResource("2_7qk8j")]([SubResource("Resource_cgh52"), SubResource("Resource_qe635"), SubResource("Resource_u5nrp"), SubResource("Resource_dsavb"), SubResource("Resource_sexiy"), SubResource("Resource_ghqd8"), SubResource("Resource_g8peq"), SubResource("Resource_4xl5p"), SubResource("Resource_y6282"), SubResource("Resource_75a0r"), SubResource("Resource_ix35t"), SubResource("Resource_0mcg3")])
event_pool = Array[Dictionary]([{ event_pool = Array[Dictionary]([{
"base_weight": 1.0, "base_weight": 1.0,
"id": "tourist_photo", "id": "tourist_photo",
@@ -710,6 +412,33 @@ event_pool = Array[Dictionary]([{
"time_range_s": Vector2(300, 800) "time_range_s": Vector2(300, 800)
}, { }, {
"base_weight": 1.0, "base_weight": 1.0,
"id": "late_tourist",
"intent": "photo",
"kind": "routine",
"npc_type": 0,
"phase": 3,
"probability": 0.22,
"time_range_s": Vector2(700, 900)
}, {
"base_weight": 1.0,
"id": "late_guest",
"intent": "enter",
"kind": "routine",
"npc_type": 9,
"phase": 3,
"probability": 0.2,
"time_range_s": Vector2(700, 900)
}, {
"base_weight": 1.0,
"id": "late_trespasser",
"intent": "trespass",
"kind": "routine",
"npc_type": 5,
"phase": 3,
"probability": 0.14,
"time_range_s": Vector2(700, 900)
}, {
"base_weight": 1.0,
"hint": "hint.body_camera_reason", "hint": "hint.body_camera_reason",
"id": "building_filming_boundary", "id": "building_filming_boundary",
"intent": "film", "intent": "film",
@@ -774,6 +503,15 @@ event_pool = Array[Dictionary]([{
"probability": 0.28, "probability": 0.28,
"requires_emergency": true, "requires_emergency": true,
"time_range_s": Vector2(760, 880) "time_range_s": Vector2(760, 880)
}, {
"base_weight": 1.0,
"id": "building_apology_return",
"intent": "enter",
"kind": "recovery",
"npc_type": 9,
"phase": 2,
"probability": 0.22,
"time_range_s": Vector2(620, 800)
}]) }])
shift_phases = { shift_phases = {
0: { 0: {
@@ -789,6 +527,6 @@ shift_phases = {
"start_s": 700.0 "start_s": 700.0
} }
} }
shift_duration_s = 900.0 door_staff_lines = {
policy_summary = "" "wristband_check": ["Wristband, please.", "I need to see your event wristband."]
door_staff_lines = {} }
+84 -232
View File
@@ -1,113 +1,73 @@
[gd_resource type="Resource" script_class="VenueScenario" load_steps=13 format=3] [gd_resource type="Resource" script_class="VenueScenario" format=3]
[ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_lxsgk"] [ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_3pn5m"]
[ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_wfc6m"] [ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_l60ad"]
[ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_8xm7a"] [ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_voh88"]
[sub_resource type="Resource" id="Resource_xha77"] [sub_resource type="Resource" id="Resource_aal3l"]
script = ExtResource("1_lxsgk") script = ExtResource("1_3pn5m")
required_artifacts = { required_artifacts = {
2: true, 2: true,
3: true 3: true
} }
grant_if_any_required = false
minimum_age = 21 minimum_age = 21
require_id = true require_id = true
wand_screening_required = true wand_screening_required = true
policy_summary = "Government ID and a valid ticket or reservation required. Carry items are screened." policy_summary = "Government ID and a valid ticket or reservation required. Carry items are screened."
[sub_resource type="Resource" id="Resource_8ksyk"] [sub_resource type="Resource" id="Resource_57xgi"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "tourist" id = "tourist"
display_name = "Tourist" display_name = "Tourist"
npc_type = 0
temperament = 0.1 temperament = 0.1
base_compliance = 0.9 base_compliance = 0.9
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."]) dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Okay, I'll move to the sidewalk.", "Sorry, I'll put the camera away."],
"reason": ["Just getting a photo of the entrance.", "I'm meeting friends here."],
"recognition": ["You remember me from the tour, right?"],
"refusal": ["I just want a photo, I'm not staying.", "I didn't know this entrance was restricted."]
}
[sub_resource type="Resource" id="Resource_wt1op"] [sub_resource type="Resource" id="Resource_r873e"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "confused_visitor" id = "confused_visitor"
display_name = "Confused Visitor" display_name = "Confused Visitor"
npc_type = 3 npc_type = 3
temperament = 0.2 temperament = 0.2
base_compliance = 0.85 base_compliance = 0.85
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."]) dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Oh, I understand. I'll check with the box office."],
"reason": ["I thought this was the box office.", "I'm looking for the event entrance."],
"refusal": ["I'm sure the event is here. Let me check my phone."]
}
[sub_resource type="Resource" id="Resource_g1jr2"] [sub_resource type="Resource" id="Resource_3xy2u"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "street_performer"
display_name = "Street Performer"
npc_type = 1
temperament = 0.45
base_compliance = 0.55
reactions_by_level = {
1: {
0: 55,
2: 15,
3: 30
}
}
context_lines = {
"reason": ["Just doing my act; I'll keep the sidewalk clear."]
}
[sub_resource type="Resource" id="Resource_50i1h"]
script = ExtResource("2_l60ad")
id = "influencer" id = "influencer"
display_name = "Influencer" display_name = "Influencer"
npc_type = 2 npc_type = 2
temperament = 0.5 temperament = 0.5
base_compliance = 0.5 base_compliance = 0.5
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 40, 0: 40,
@@ -129,47 +89,18 @@ reactions_by_level = {
8: 25 8: 25
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."]) dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Filming a quick clip for my channel."]
}
[sub_resource type="Resource" id="Resource_ys0b0"] [sub_resource type="Resource" id="Resource_nsw77"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "intoxicated" id = "intoxicated"
display_name = "Intoxicated Pedestrian" display_name = "Intoxicated Pedestrian"
npc_type = 4 npc_type = 4
temperament = 0.6 temperament = 0.6
base_compliance = 0.4 base_compliance = 0.4
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 30, 0: 30,
@@ -183,41 +114,13 @@ reactions_by_level = {
4: 10 4: 10
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 1.8 reaction_delay = 1.8
dialogue_lines = Array[String]([]) context_lines = {
carried_items = Array[String]([]) "reason": ["Looking for my friends. I think they went inside."]
}
[sub_resource type="Resource" id="Resource_bv0jw"] [sub_resource type="Resource" id="Resource_20knl"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "trespasser" id = "trespasser"
display_name = "Trespasser" display_name = "Trespasser"
npc_type = 5 npc_type = 5
@@ -252,47 +155,18 @@ reactions_by_level = {
7: 20 7: 20
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."]) dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Meeting a friend inside. I'll only be a minute.", "Just cutting through."]
}
[sub_resource type="Resource" id="Resource_7vgx3"] [sub_resource type="Resource" id="Resource_rivis"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "violent_threat" id = "violent_threat"
display_name = "Violent Threat" display_name = "Violent Threat"
npc_type = 6 npc_type = 6
temperament = 0.95 temperament = 0.95
base_compliance = 0.05 base_compliance = 0.05
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
2: 25, 2: 25,
@@ -320,66 +194,33 @@ reactions_by_level = {
7: 30 7: 30
} }
} }
default_reactions = { context_lines = {
1: { "reason": ["Back off. This doesn't concern you."]
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
} }
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_x43ed"] [sub_resource type="Resource" id="Resource_1dvkp"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "authorized_staff" id = "authorized_staff"
display_name = "Staff Member" display_name = "Staff Member"
npc_type = 8 npc_type = 8
temperament = 0.15 temperament = 0.15
base_compliance = 1.0 base_compliance = 1.0
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 100 0: 100
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on staff. I'm checking the entrance.", "Crew check-in; I'm working tonight."]
carried_items = Array[String]([]) }
[sub_resource type="Resource" id="Resource_07lsg"] [sub_resource type="Resource" id="Resource_7wsm0"]
script = ExtResource("2_wfc6m") script = ExtResource("2_l60ad")
id = "authorized_guest" id = "authorized_guest"
display_name = "Authorized Guest" display_name = "Authorized Guest"
npc_type = 9 npc_type = 9
temperament = 0.2 temperament = 0.2
base_compliance = 0.95 base_compliance = 0.95
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 92, 0: 92,
@@ -390,16 +231,16 @@ default_reactions = {
2: 12 2: 12
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on the guest list. Here's my ID.", "A friend invited me; I have a ticket."]
carried_items = Array[String]([]) }
[resource] [resource]
script = ExtResource("3_8xm7a") script = ExtResource("3_voh88")
id = "joke_shop" id = "joke_shop"
display_name = "The Joke Shop" display_name = "The Joke Shop"
description = "Comedy club door: IDs, reservations, and wand screening." description = "Comedy club door: IDs, reservations, and wand screening."
access_policy = SubResource("Resource_xha77") access_policy = SubResource("Resource_aal3l")
equipment = Array[String](["id_check", "guest_list", "wand", "radio"]) equipment = Array[String](["id_check", "guest_list", "wand", "radio"])
locations = { locations = {
"door_area": Vector3(0, 0, 3), "door_area": Vector3(0, 0, 3),
@@ -409,7 +250,7 @@ locations = {
"sidewalk": Vector3(0, 0, 9), "sidewalk": Vector3(0, 0, 9),
"steps_end": Vector3(0, 0, 3) "steps_end": Vector3(0, 0, 3)
} }
npc_profiles = Array[ExtResource("2_wfc6m")]([SubResource("Resource_8ksyk"), SubResource("Resource_wt1op"), SubResource("Resource_g1jr2"), SubResource("Resource_ys0b0"), SubResource("Resource_bv0jw"), SubResource("Resource_7vgx3"), SubResource("Resource_x43ed"), SubResource("Resource_07lsg")]) npc_profiles = Array[ExtResource("2_l60ad")]([SubResource("Resource_57xgi"), SubResource("Resource_r873e"), SubResource("Resource_3xy2u"), SubResource("Resource_50i1h"), SubResource("Resource_nsw77"), SubResource("Resource_20knl"), SubResource("Resource_rivis"), SubResource("Resource_1dvkp"), SubResource("Resource_7wsm0")])
event_pool = Array[Dictionary]([{ event_pool = Array[Dictionary]([{
"base_weight": 1.0, "base_weight": 1.0,
"id": "guest_valid", "id": "guest_valid",
@@ -564,6 +405,19 @@ event_pool = Array[Dictionary]([{
"phase": 2, "phase": 2,
"probability": 0.5, "probability": 0.5,
"time_range_s": Vector2(650, 830) "time_range_s": Vector2(650, 830)
}, {
"base_weight": 1.0,
"id": "joke_denied_guest_return",
"intent": "enter",
"kind": "recovery",
"npc_type": 9,
"override_access": {
"has_id": true,
"has_ticket": true
},
"phase": 2,
"probability": 0.2,
"time_range_s": Vector2(650, 830)
}]) }])
shift_phases = { shift_phases = {
0: { 0: {
@@ -579,8 +433,6 @@ shift_phases = {
"start_s": 700.0 "start_s": 700.0
} }
} }
shift_duration_s = 900.0
policy_summary = ""
door_staff_lines = { door_staff_lines = {
"id_check": ["May I see your ID, please?", "Could you show me some identification?"], "id_check": ["May I see your ID, please?", "Could you show me some identification?"],
"prohibited_item": ["I can't allow that item inside. Please leave it outside.", "That item isn't permitted in the venue."], "prohibited_item": ["I can't allow that item inside. Please leave it outside.", "That item isn't permitted in the venue."],
+84 -372
View File
@@ -1,11 +1,11 @@
[gd_resource type="Resource" script_class="VenueScenario" load_steps=17 format=3] [gd_resource type="Resource" script_class="VenueScenario" format=3]
[ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_xxhx3"] [ext_resource type="Script" path="res://src/core/access_policy.gd" id="1_3vwd0"]
[ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_fiebn"] [ext_resource type="Script" path="res://src/core/npc_profile.gd" id="2_g7rkt"]
[ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_2dvuq"] [ext_resource type="Script" path="res://src/core/venue_scenario.gd" id="3_jd45y"]
[sub_resource type="Resource" id="Resource_blmt0"] [sub_resource type="Resource" id="Resource_c55bb"]
script = ExtResource("1_xxhx3") script = ExtResource("1_3vwd0")
required_artifacts = { required_artifacts = {
1: true, 1: true,
3: true, 3: true,
@@ -13,145 +13,53 @@ required_artifacts = {
5: true 5: true
} }
grant_if_any_required = true grant_if_any_required = true
minimum_age = 0
require_id = false
wand_screening_required = false
policy_summary = "Entry requires a wristband, credential, ticket, or guest-list confirmation." policy_summary = "Entry requires a wristband, credential, ticket, or guest-list confirmation."
[sub_resource type="Resource" id="Resource_oddac"] [sub_resource type="Resource" id="Resource_yyxim"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "tourist" id = "tourist"
display_name = "Tourist" display_name = "Tourist"
npc_type = 0
temperament = 0.1 temperament = 0.1
base_compliance = 0.9 base_compliance = 0.9
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."]) dialogue_lines = Array[String](["Oh sure, sorry, just taking a picture.", "Is there a better spot to stand?", "Understood, moving."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Okay, I'll move to the sidewalk.", "Sorry, I'll put the camera away."],
"reason": ["Just getting a photo of the entrance.", "I'm meeting friends here."],
"recognition": ["You remember me from the tour, right?"],
"refusal": ["I just want a photo, I'm not staying.", "I didn't know this entrance was restricted."]
}
[sub_resource type="Resource" id="Resource_byir2"] [sub_resource type="Resource" id="Resource_lmn2c"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "confused_visitor" id = "confused_visitor"
display_name = "Confused Visitor" display_name = "Confused Visitor"
npc_type = 3 npc_type = 3
temperament = 0.2 temperament = 0.2
base_compliance = 0.85 base_compliance = 0.85
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."]) dialogue_lines = Array[String](["Wait, this isn't the entrance?", "Sorry about that, I'm a bit lost."])
carried_items = Array[String]([]) context_lines = {
"deescalation": ["Oh, I understand. I'll check with the box office."],
"reason": ["I thought this was the box office.", "I'm looking for the event entrance."],
"refusal": ["I'm sure the event is here. Let me check my phone."]
}
[sub_resource type="Resource" id="Resource_3tt0b"] [sub_resource type="Resource" id="Resource_if2cj"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "delivery" id = "delivery"
display_name = "Delivery Worker" display_name = "Delivery Worker"
npc_type = 10 npc_type = 10
temperament = 0.25
base_compliance = 0.8
return_probability = 0.0
reactions_by_level = {}
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["Where should I leave this?"]) dialogue_lines = Array[String](["Where should I leave this?"])
carried_items = Array[String]([]) context_lines = {
"reason": ["Drop-off for the venue. Where should I leave it?"]
}
[sub_resource type="Resource" id="Resource_ihxib"] [sub_resource type="Resource" id="Resource_t47d3"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "street_performer" id = "street_performer"
display_name = "Street Performer" display_name = "Street Performer"
npc_type = 1 npc_type = 1
temperament = 0.45 temperament = 0.45
base_compliance = 0.55 base_compliance = 0.55
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 55, 0: 55,
@@ -159,47 +67,17 @@ reactions_by_level = {
3: 30 3: 30
} }
} }
default_reactions = { context_lines = {
1: { "reason": ["Just doing my act; I'll keep the sidewalk clear."]
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
} }
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_c57iy"] [sub_resource type="Resource" id="Resource_j2mp5"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "influencer" id = "influencer"
display_name = "Influencer" display_name = "Influencer"
npc_type = 2 npc_type = 2
temperament = 0.5 temperament = 0.5
base_compliance = 0.5 base_compliance = 0.5
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 40, 0: 40,
@@ -221,47 +99,18 @@ reactions_by_level = {
8: 25 8: 25
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."]) dialogue_lines = Array[String](["This is public sidewalk, you can't stop me from filming."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Filming a quick clip for my channel."]
}
[sub_resource type="Resource" id="Resource_bk410"] [sub_resource type="Resource" id="Resource_uscqg"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "intoxicated" id = "intoxicated"
display_name = "Intoxicated Pedestrian" display_name = "Intoxicated Pedestrian"
npc_type = 4 npc_type = 4
temperament = 0.6 temperament = 0.6
base_compliance = 0.4 base_compliance = 0.4
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
0: 30, 0: 30,
@@ -275,41 +124,13 @@ reactions_by_level = {
4: 10 4: 10
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 1.8 reaction_delay = 1.8
dialogue_lines = Array[String]([]) context_lines = {
carried_items = Array[String]([]) "reason": ["Looking for my friends. I think they went inside."]
}
[sub_resource type="Resource" id="Resource_jp52w"] [sub_resource type="Resource" id="Resource_8aovb"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "trespasser" id = "trespasser"
display_name = "Trespasser" display_name = "Trespasser"
npc_type = 5 npc_type = 5
@@ -344,41 +165,13 @@ reactions_by_level = {
7: 20 7: 20
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."]) dialogue_lines = Array[String](["I'm just here to see a friend, come on.", "I'll be inside for ten seconds."])
carried_items = Array[String]([]) context_lines = {
"reason": ["Meeting a friend inside. I'll only be a minute.", "Just cutting through."]
}
[sub_resource type="Resource" id="Resource_5kplf"] [sub_resource type="Resource" id="Resource_owl7s"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "mental_crisis" id = "mental_crisis"
display_name = "Person in Crisis" display_name = "Person in Crisis"
npc_type = 7 npc_type = 7
@@ -414,47 +207,18 @@ reactions_by_level = {
7: 15 7: 15
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 2.4 reaction_delay = 2.4
dialogue_lines = Array[String]([]) context_lines = {
carried_items = Array[String]([]) "reason": ["I just need a quiet minute.", "I'm waiting for someone."]
}
[sub_resource type="Resource" id="Resource_6bscs"] [sub_resource type="Resource" id="Resource_rnay4"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "violent_threat" id = "violent_threat"
display_name = "Violent Threat" display_name = "Violent Threat"
npc_type = 6 npc_type = 6
temperament = 0.95 temperament = 0.95
base_compliance = 0.05 base_compliance = 0.05
return_probability = 0.0
reactions_by_level = { reactions_by_level = {
1: { 1: {
2: 25, 2: 25,
@@ -482,41 +246,12 @@ reactions_by_level = {
7: 30 7: 30
} }
} }
default_reactions = { context_lines = {
1: { "reason": ["Back off. This doesn't concern you."]
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
} }
}
reaction_delay = 0.6
dialogue_lines = Array[String]([])
carried_items = Array[String]([])
[sub_resource type="Resource" id="Resource_n4lxh"] [sub_resource type="Resource" id="Resource_lhp4m"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "protester" id = "protester"
display_name = "Protester" display_name = "Protester"
npc_type = 12 npc_type = 12
@@ -550,66 +285,34 @@ reactions_by_level = {
7: 20 7: 20
} }
} }
default_reactions = {
1: {
0: 80,
2: 8,
3: 12
},
2: {
0: 70,
1: 10,
2: 12,
4: 8
},
3: {
0: 55,
1: 15,
2: 20,
4: 10
},
4: {
1: 65,
2: 15,
7: 20
},
5: {
1: 30,
5: 40,
7: 30
}
}
reaction_delay = 0.6
dialogue_lines = Array[String](["I have every right to be on public sidewalk.", "You can't touch me, this is a lawful protest."]) dialogue_lines = Array[String](["I have every right to be on public sidewalk.", "You can't touch me, this is a lawful protest."])
carried_items = Array[String]([]) context_lines = {
"reason": ["We're demonstrating on the public sidewalk.", "This is a peaceful protest."]
}
[sub_resource type="Resource" id="Resource_6st6l"] [sub_resource type="Resource" id="Resource_s8tjd"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "authorized_staff" id = "authorized_staff"
display_name = "Staff Member" display_name = "Staff Member"
npc_type = 8 npc_type = 8
temperament = 0.15 temperament = 0.15
base_compliance = 1.0 base_compliance = 1.0
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 100 0: 100
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on staff. I'm checking the entrance.", "Crew check-in; I'm working tonight."]
carried_items = Array[String]([]) }
[sub_resource type="Resource" id="Resource_nf2oq"] [sub_resource type="Resource" id="Resource_ii8kq"]
script = ExtResource("2_fiebn") script = ExtResource("2_g7rkt")
id = "authorized_guest" id = "authorized_guest"
display_name = "Authorized Guest" display_name = "Authorized Guest"
npc_type = 9 npc_type = 9
temperament = 0.2 temperament = 0.2
base_compliance = 0.95 base_compliance = 0.95
return_probability = 0.0
reactions_by_level = {}
default_reactions = { default_reactions = {
1: { 1: {
0: 92, 0: 92,
@@ -620,16 +323,16 @@ default_reactions = {
2: 12 2: 12
} }
} }
reaction_delay = 0.6 context_lines = {
dialogue_lines = Array[String]([]) "reason": ["I'm on the guest list. Here's my ID.", "A friend invited me; I have a ticket."]
carried_items = Array[String]([]) }
[resource] [resource]
script = ExtResource("3_2dvuq") script = ExtResource("3_jd45y")
id = "tv_studio" id = "tv_studio"
display_name = "Hollywood Blvd Late Night TV Studio" display_name = "Hollywood Blvd Late Night TV Studio"
description = "Crowd, celebrities, and staff around a late-night studio." description = "Crowd, celebrities, and staff around a late-night studio."
access_policy = SubResource("Resource_blmt0") access_policy = SubResource("Resource_c55bb")
equipment = Array[String](["wristband_policy", "guest_list", "radio", "flashlight"]) equipment = Array[String](["wristband_policy", "guest_list", "radio", "flashlight"])
locations = { locations = {
"entrance": Vector3(0, 0, 1), "entrance": Vector3(0, 0, 1),
@@ -639,7 +342,7 @@ locations = {
"stage_door": Vector3(6, 0, -2), "stage_door": Vector3(6, 0, -2),
"steps_end": Vector3(0, 0, 3) "steps_end": Vector3(0, 0, 3)
} }
npc_profiles = Array[ExtResource("2_fiebn")]([SubResource("Resource_oddac"), SubResource("Resource_byir2"), SubResource("Resource_3tt0b"), SubResource("Resource_ihxib"), SubResource("Resource_c57iy"), SubResource("Resource_bk410"), SubResource("Resource_jp52w"), SubResource("Resource_5kplf"), SubResource("Resource_6bscs"), SubResource("Resource_n4lxh"), SubResource("Resource_6st6l"), SubResource("Resource_nf2oq")]) npc_profiles = Array[ExtResource("2_g7rkt")]([SubResource("Resource_yyxim"), SubResource("Resource_lmn2c"), SubResource("Resource_if2cj"), SubResource("Resource_t47d3"), SubResource("Resource_j2mp5"), SubResource("Resource_uscqg"), SubResource("Resource_8aovb"), SubResource("Resource_owl7s"), SubResource("Resource_rnay4"), SubResource("Resource_lhp4m"), SubResource("Resource_s8tjd"), SubResource("Resource_ii8kq")])
event_pool = Array[Dictionary]([{ event_pool = Array[Dictionary]([{
"base_weight": 1.0, "base_weight": 1.0,
"id": "audience_ticket", "id": "audience_ticket",
@@ -790,6 +493,15 @@ event_pool = Array[Dictionary]([{
"phase": 2, "phase": 2,
"probability": 0.45, "probability": 0.45,
"time_range_s": Vector2(700, 860) "time_range_s": Vector2(700, 860)
}, {
"base_weight": 1.0,
"id": "studio_manager_check",
"intent": "enter",
"kind": "recovery",
"npc_type": 8,
"phase": 2,
"probability": 0.2,
"time_range_s": Vector2(620, 820)
}]) }])
shift_phases = { shift_phases = {
0: { 0: {
@@ -805,6 +517,6 @@ shift_phases = {
"start_s": 700.0 "start_s": 700.0
} }
} }
shift_duration_s = 900.0 door_staff_lines = {
policy_summary = "" "ticket_check": ["Ticket, credential, or guest-list confirmation, please.", "I need your ticket or guest-list confirmation."]
door_staff_lines = {} }
+36
View File
@@ -0,0 +1,36 @@
# Gig Line Documentation
This folder holds the project documentation, visual references and generated QA evidence.
## Start here
- [`../PLAN.md`](../PLAN.md) — product and game-design plan
- [`gameplay.md`](gameplay.md) — controls, venues and escalation
- [`joke-shop-map.md`](joke-shop-map.md) — Sunset Strip real-site mapping
- [`tutorial.md`](tutorial.md) — first-shift tutorial beats
- [`architecture.md`](architecture.md) — arc42 system architecture
- [`getting-started.md`](getting-started.md) — setup, run/test commands and controls
- [`asset-tooling.md`](asset-tooling.md) — image/model pipelines and screenshot gates
- [`npc-visual-review.md`](npc-visual-review.md) — NPC visual baseline, acceptance criteria and ranked gaps
- [`npc-proportion-audit.md`](npc-proportion-audit.md) — NPC proportion ratios and stylized guide results
- [`development-status.md`](development-status.md) — implemented features and current gaps
- [`smoke-checklist.md`](smoke-checklist.md) — manual verification
- [`ui-copy.md`](ui-copy.md) — screen, copy and button inventory
- [`RELEASING.md`](RELEASING.md) — export, CI and publishing workflow
- [`adr/README.md`](adr/README.md) — architecture decisions
## Visual references
- [`screens/README.md`](screens/README.md) — concepts, designs, screenshots and realism runs
- [`blender_previews/README.md`](blender_previews/README.md) — character/gear/prop previews
- [`screenshots/README.md`](screenshots/README.md) — committed game gallery
- [`screen-design-report.md`](screen-design-report.md) — latest screen-design judge result
## Quick preview
| Reference | Screenshot |
| --- | --- |
| Venue design | <img src="screens/designs/venue_overview.png" width="320" alt="Venue overview design"> |
| Current entrance | <img src="screenshots/01-venue-overview.png" width="320" alt="In-game venue overview"> |
| Character sheet | <img src="blender_previews/sheet_npc.jpg" width="320" alt="NPC character sheet"> |
| Prop sheet | <img src="blender_previews/sheet_props.jpg" width="320" alt="Prop asset sheet"> |
+23 -12
View File
@@ -12,10 +12,11 @@ time you export, either:
matching templates), or matching templates), or
- Install them manually from the - Install them manually from the
[Godot downloads](https://godotengine.org/download/) page by placing the [Godot downloads](https://godotengine.org/download/) page by placing the
`Godot_v4.3-stable_export_templates.tpz` contents into `Godot_v4.7.2-stable_export_templates.tpz` contents into
`~/.local/share/godot/export_templates/4.3.stable/`. `~/.local/share/godot/export_templates/4.7.2.stable/`.
Verify with: The templates must match the editor binary you use locally. CI and local
development both use Godot 4.7.2 with its matching templates. Verify with:
```bash ```bash
godot --headless --export-release "Linux" build/gig-line-smoke.x86_64 godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
@@ -30,7 +31,7 @@ godot --headless --export-release "Linux" build/gig-line-smoke.x86_64
The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`): The repository ships a Gitea Actions workflow (`.gitea/workflows/build.yml`):
- Every push/PR runs the **checks** job: Godot 4.3 install, project import, and the - Every push/PR runs the **checks** job: Godot 4.7.2 install, project import, and the
full headless test suite. This is the fast safety net. full headless test suite. This is the fast safety net.
- **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the - **Tags (`v*`)** and **manual `workflow_dispatch`** runs additionally execute the
**build** job: export templates install, import, `tools/build_releases.sh` for **build** job: export templates install, import, `tools/build_releases.sh` for
@@ -62,10 +63,12 @@ setup, so do not rely on it.
> artifacts. If CI publishing fails again, run > artifacts. If CI publishing fails again, run
> `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`. > `./tools/publish_release.sh <version>` from a checkout with `~/.git-credentials`.
> **No `actions/cache` for now:** the runner has no local actions-cache service, so > **Godot cache evaluation:** Gitea Actions cache was tested for the Godot binary and
> `actions/cache` times out against GitHub's cache API. We dropped it (Godot import > trimmed 4.7.2 templates. Restores worked intermittently, but cache saves timed out
> is only ~4s). If a host admin later enables Gitea `[cache.actions]` with a cache > in `CreateCacheEntry` / were rejected as reserved by another job. The cache steps
> server, the step can be reintroduced. > were removed because they added restore/save overhead without a reliable hit.
> Revisit when the host's Gitea Actions cache service is healthy; otherwise keep
> downloading the binary/templates directly.
> The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old > The workflow lives in `.gitea/workflows/` (Gitea's canonical path). The old
> `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan > `.github/workflows/ci.yml` was removed to avoid double runs on hosts that scan
@@ -86,6 +89,8 @@ Artifacts are written to `build/` (all exports embed the PCK — single files):
- `build/gig-line-macos-<version>.zip` - `build/gig-line-macos-<version>.zip`
- `build/gig-line-web-<version>.zip` — browser build (non-threaded Godot web - `build/gig-line-web-<version>.zip` — browser build (non-threaded Godot web
template; unzip and serve the folder, no COOP/COEP headers required) template; unzip and serve the folder, no COOP/COEP headers required)
- `build/gig-line-desktop-hq-<version>.zip` — optional Forward+ Windows/Linux
build with `override.cfg`; requires a Vulkan-capable GPU/driver
When run in CI (tags/dispatch), the build job also packages: When run in CI (tags/dispatch), the build job also packages:
@@ -94,6 +99,10 @@ When run in CI (tags/dispatch), the build job also packages:
- `build/gig-line-<version>-x86_64.AppImage` — Linux AppImage (`packaging/linux/build_appimage.sh`, - `build/gig-line-<version>-x86_64.AppImage` — Linux AppImage (`packaging/linux/build_appimage.sh`,
appimagetool via `APPIMAGE_EXTRACT_AND_RUN`) appimagetool via `APPIMAGE_EXTRACT_AND_RUN`)
The optional Desktop HQ zip is assembled by `tools/build_releases.sh` from
`packaging/desktop_hq/`; keep `override.cfg` next to the extracted executable.
It is not part of the default Compatibility/Web build.
Locally you can build the AppImage with `bash packaging/linux/build_appimage.sh <version>`; Locally you can build the AppImage with `bash packaging/linux/build_appimage.sh <version>`;
the NSIS installer requires `makensis` (covered by CI). the NSIS installer requires `makensis` (covered by CI).
@@ -114,19 +123,21 @@ GITEA_TOKEN=your_api_token ./tools/publish_release.sh 0.2.1
The script creates (or reuses) the release from `project.godot`'s The script creates (or reuses) the release from `project.godot`'s
`config/version`, uploads the three portable artifacts **plus** the NSIS `config/version`, uploads the three portable artifacts **plus** the NSIS
installer and AppImage when present, and prints the release URL. If CI already installer, AppImage, Web zip and Desktop HQ zip when present, and prints the
release URL. If CI already
published the release, re-running the script only adds missing assets. published the release, re-running the script only adds missing assets.
> **Host note**: the release is fully built by CI, but anonymous users can only > **Host note**: the release is fully built by CI, but anonymous users can only
> browse and download when the instance sets `[service] REQUIRE_SIGNIN_VIEW=false` > browse and download when the instance sets `[service] REQUIRE_SIGNIN_VIEW=false`
> in `app.ini` (the repo itself is public). See the TODO for the exact steps. > in `app.ini` (the repo itself is public). This is a host-admin setting, not a
> repository file.
Manual alternative: Manual alternative:
### Via the web UI ### Via the web UI
1. Create a **New Release** with tag `v<version>`. 1. Create a **New Release** with tag `v<version>`.
2. Attach all three `build/` artifacts. 2. Attach all artifacts from `build/` (portables, installer/AppImage, Web and optional Desktop HQ).
3. Write release notes (see checklist below). 3. Write release notes (see checklist below).
### Via the API ### Via the API
@@ -163,7 +174,7 @@ change, update `tools/build_releases.sh` first.
- [ ] All headless tests pass (exit code 0). - [ ] All headless tests pass (exit code 0).
- [ ] Game boots cleanly in a smoke test. - [ ] Game boots cleanly in a smoke test.
- [ ] Controls documented in `README.md` match the build. - [ ] Controls documented in `docs/getting-started.md` match the build.
- [ ] Version in `project.godot` matches the tag. - [ ] Version in `project.godot` matches the tag.
- [ ] Export templates used are the official ones for the pinned engine. - [ ] Export templates used are the official ones for the pinned engine.
- [ ] Artifacts uploaded; README downloads page shows them. - [ ] Artifacts uploaded; README downloads page shows them.
+20
View File
@@ -0,0 +1,20 @@
# Architecture Decision Records
Each ADR records the context, decision, consequences and alternatives for a durable architecture choice.
## Decisions
- [0001-venue-driven-simulation-architecture](0001-venue-driven-simulation-architecture.md)
- [0002-de-escalation-first-escalation-model](0002-de-escalation-first-escalation-model.md)
- [0003-explicit-access-verification-system](0003-explicit-access-verification-system.md)
- [0004-local-single-player-first](0004-local-single-player-first.md)
- [0005-event-based-incident-recording](0005-event-based-incident-recording.md)
- [0006-godot-4-gdscript](0006-godot-4-gdscript.md)
- [0007-locomotion-and-input-layers](0007-locomotion-and-input-layers.md)
- [0008-cone-focus-and-head-ring](0008-cone-focus-and-head-ring.md)
- [0009-radial-action-menu](0009-radial-action-menu.md)
- [0010-procedural-npc-presentation](0010-procedural-npc-presentation.md)
- [0011-aim-free-selection-and-precision-walk](0011-aim-free-selection-and-precision-walk.md)
- [0012-surface-materials-and-generated-props](0012-surface-materials-and-generated-props.md)
- [0013-blender-authored-npc-characters](0013-blender-authored-npc-characters.md)
- [0014-runtime-image-root](0014-runtime-image-root.md)
+98 -10
View File
@@ -25,7 +25,7 @@ This document follows the structure of the arc42 architecture documentation temp
## 2. Constraints ## 2. Constraints
- The first implementation should be small enough for a playable vertical slice. - The first implementation should be small enough for a playable vertical slice.
- The engine is Godot 4 with GDScript; a playable prototype vertical slice is implemented. - The engine is Godot 4.7.2 with GDScript; a playable prototype vertical slice is implemented. CI, local development and exported builds use 4.7.2; the default renderer stays GL Compatibility for Web parity, with an optional Forward+ Desktop HQ build.
- Venue-specific policies must be configurable rather than hard-coded into individual NPCs. - Venue-specific policies must be configurable rather than hard-coded into individual NPCs.
- The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md). - The game must preserve the de-escalation-first design described in [`PLAN.md`](../PLAN.md).
- The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md). - The project uses the repository workflow described in [`AGENTS.md`](../AGENTS.md).
@@ -37,7 +37,7 @@ This document follows the structure of the arc42 architecture documentation temp
- **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible. - **MINOR** — new venues, NPC archetypes, systems, or features that are backward compatible.
- **PATCH** — bug fixes and small polish that do not change behavior. - **PATCH** — bug fixes and small polish that do not change behavior.
The single source of truth for the version is `config/version` in `project.godot` (currently `0.6.1`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-1.0, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md). The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.4`). Each release is tagged in git as `v<version>` (e.g. `v0.6.0`). The `0.x` series is pre-stable, so MINOR bumps may introduce breaking changes while the prototype is still stabilizing. `tools/build_releases.sh` and `tools/publish_release.sh` read the version from `project.godot`, so bumping it there is the only required step before a release. The full bump checklist lives in [`RELEASING.md`](RELEASING.md).
## 3. Context and Scope ## 3. Context and Scope
@@ -78,12 +78,12 @@ The player interacts with NPCs, venue entrances, access artifacts, equipment, st
- `CrowdSystem` models queues, attention, congestion, and public reaction. - `CrowdSystem` models queues, attention, congestion, and public reaction.
- `ShiftReview` presents decisions, consequences, and improvement opportunities. - `ShiftReview` presents decisions, consequences, and improvement opportunities.
- `SurfaceMaterials` (`src/game/materials.gd`) holds the surface profiles, textured albedo/normal recipes, baked-AO wiring, glass/emissive recipes, and the environment tune-up (tonemapping, glow, fog, grading) that the phase lighting applies. - `SurfaceMaterials` (`src/game/materials.gd`) holds the surface profiles, textured albedo/normal recipes, baked-AO wiring, glass/emissive recipes, and the environment tune-up (tonemapping, glow, fog, grading) that the phase lighting applies.
- `WorldBuilder` assembles the procedural venue, prefers the Blender prop library in `assets/models/blender/props/`, and falls back to `assets/models/generated/` or primitives. It also wires the phase-driven library emissives and street dressing. - `WorldBuilder` assembles the procedural venue from a per-venue `VENUE_SPECS` table (facade, windows, stairs, street, nav bounds, guard spawn, feature flags and prop placements), prefers the Blender prop library in `assets/models/blender/props/`, and falls back to `assets/models/generated/` or primitives. `GameManager` rebuilds only the `World` container when the venue changes, so the guard/UI and their state survive. It also wires the phase-driven library emissives and street dressing.
- `src/game/ui/art.gd` loads runtime UI/scene art from `assets/images/ui/` and `assets/images/scenes/`, with null fallbacks so panels keep their procedural layouts. - `src/game/ui/art.gd` loads runtime UI/scene art from `assets/images/ui/` and `assets/images/scenes/`, with null fallbacks so panels keep their procedural layouts.
- `tools/model_pipeline.py` builds and audits the street-prop `.glb` models and packs their colour atlases. - `tools/model_pipeline.py` builds and audits the street-prop `.glb` models and packs their colour atlases.
- `tools/npc_pipeline.py` builds and audits the skinned NPC base model (`assets/models/generated/npc_base.glb`) and its per-slot material maps, with an optional AI fabric override (ADR-0013). - `tools/npc_pipeline.py` builds and audits the skinned NPC base model (`assets/models/generated/npc_base.glb`) and its per-slot material maps, with an optional AI fabric override (ADR-0013).
- `tools/blender_assets.py` builds, renders and audits the Blender asset library (`assets/models/blender/{npc,npc_gear,props}/` + `manifest.json`): NPC character variants that are drop-in for `npc_base`, attach-point gear, and street/venue props. `NpcAvatar` selects variants/gear by role/seed and `WorldBuilder` loads the prop replacements and new street dressing, with procedural fallbacks (see `docs/blender-assets.md`). - `tools/blender_assets.py` builds, renders and audits the Blender asset library (`assets/models/blender/{npc,npc_gear,props}/` + `manifest.json`): NPC character variants that are drop-in for `npc_base`, attach-point gear, and street/venue props. `NpcAvatar` selects variants/gear by role/seed and `WorldBuilder` loads the prop replacements and new street dressing, with procedural fallbacks (see `docs/blender-assets.md`).
- `tools/scene_concepts.py` generates realism-pass references (`docs/screens/concepts/`), skyline backdrops and surface tiles (raw `assets/textures/ai/v2/raw/` → candidates `assets/textures/ai/game_ready/v2/`), promotes the validated ones to the tracked `v2/picks/` that `SurfaceMaterials`/`WorldBuilder` preload, audits them, and scores `src/test/capture_realism.gd` A/B captures (five stages, runtime texture swaps) against the concepts (`docs/screens/realism/<run>/`). - `tools/scene_concepts.py` generates realism-pass references (`docs/screens/concepts/`), skyline backdrops and surface tiles (raw `assets/textures/ai/v2/raw/` → candidates `assets/textures/ai/game_ready/v2/`), promotes the validated ones to the tracked `v2/picks/` that `SurfaceMaterials`/`WorldBuilder` preload, audits them, and scores `src/test/capture_realism.gd` A/B captures (six stages, runtime texture swaps) against the concepts (`docs/screens/realism/<run>/`).
- `tools/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures; `tools/check_screenshots.sh` renders the staged gallery and runs the compare gate. - `tools/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures; `tools/check_screenshots.sh` renders the staged gallery and runs the compare gate.
Confirmed game assets live in `assets/textures/ai/game_ready/` (audited surface, UI, and card textures), `assets/models/generated/` (prop and NPC `.glb` models plus their texture atlases), and `assets/textures/npc/` (NPC material maps and `palette.json`). Development-only outputs — AI concept sheets, Blender sources, raw AI fabrics — are gitignored and regenerated by the tools. Confirmed game assets live in `assets/textures/ai/game_ready/` (audited surface, UI, and card textures), `assets/models/generated/` (prop and NPC `.glb` models plus their texture atlases), and `assets/textures/npc/` (NPC material maps and `palette.json`). Development-only outputs — AI concept sheets, Blender sources, raw AI fabrics — are gitignored and regenerated by the tools.
@@ -106,6 +106,36 @@ When reference art becomes runtime art, copy or process it into `assets/images/`
new descriptive name (never overwrite an existing image) and keep a procedural fallback new descriptive name (never overwrite an existing image) and keep a procedural fallback
in code. in code.
### Content and asset pipeline architecture
The asset/content pipeline is part of the architecture, not an external build detail:
| Stage | Producer | Committed artifact | Runtime consumer | Failure fallback |
| --- | --- | --- | --- | --- |
| Scenario data | `ScenarioFactory` / editor export | `content/venues/*.tres`, event/profile data | `VenueScenario` → `ShiftCoordinator` | built-in scenario defaults |
| NPC library | Blender flatpak + `tools/blender_assets.py` | `assets/models/blender/npc/*.glb`, manifest, baked AO | `NpcAvatar` | `npc_base.glb` → procedural rig |
| Gear/props | Blender flatpak + tool + bake | `npc_gear/*.glb`, `props/*.glb`, `*_ao.png` | `NpcAvatar`, `WorldBuilder` | primitive assets / generated props |
| Surface/UI art | Python pipelines / AI-assisted references | `assets/textures/ai/game_ready/`, `assets/images/` | `SurfaceMaterials`, `UiArt` | neutral material / procedural UI |
| Screenshots/QA | capture scripts + `scene_concepts`/`screen_designs` | `docs/screenshots/`, `docs/screens/realism/` | reviewers and CI gates | regenerate; never runtime input |
| Release | Gitea workflow + build/publish scripts | platform binaries, Web zip, Desktop HQ zip | players | source build |
Contracts that keep the pipeline replaceable:
- `npc_base` armature/bone names, five tint slots and front direction are frozen by tests; gear is authored in attach-point space and measured against the character silhouette.
- Library characters, gear and props are audited for grounding, UVs, triangle budgets, degenerate triangles and manifest coverage; Blender is a developer tool, never a CI runtime dependency.
- `WorldBuilder.VENUE_SPECS` drives geometry, navigation, features and prop placements; `GameManager` rebuilds only the world container on a venue change.
- UI/scene art is loaded through `UiArt` with a null/neutral fallback; composed images live in `assets/images/`, not in the docs reference tree (ADR-0014).
- CI stays offline: only committed `.glb`/`.png`/`.tres` and Godot are needed; optional AI/Blender steps are reproducible development tools.
### Content authoring and runtime data flow
`ScenarioFactory` is the source of truth for the three authored venues. `tools/export_venues.gd`
writes `content/venues/<id>.tres` for editor inspection; the factory remains the canonical
scenario definition. At runtime `GameManager` selects a `VenueScenario`, `ShiftCoordinator`
schedules events and phases, and `NPCController`/`AccessVerifier`/`EscalationManager` produce
incidents. `IncidentRecorder` is the authoritative event history; body-camera review,
reputation, crowd reaction and shift review read it rather than resolving gameplay separately.
## 6. Runtime View ## 6. Runtime View
### Routine interaction ### Routine interaction
@@ -118,6 +148,20 @@ in code.
6. The incident recorder stores the interaction. 6. The incident recorder stores the interaction.
7. Reputation and crowd systems react to the outcome. 7. Reputation and crowd systems react to the outcome.
### Venue switch
1. The player selects a venue from the start menu or cycles with the debug shortcut.
2. `GameManager` loads the matching `VenueScenario` and keeps the guard/UI state.
3. `WorldBuilder` rebuilds only `world_root` from `VENUE_SPECS`, including geometry, props and the navigation mesh.
4. Shift state, NPCs and incidents are reset for the new venue; phase lighting and the door state are reapplied.
5. The menu's **Hollywood Night** row resolves to `hollywood_building`, then sets `ShiftCoordinator.phase_offset_s` so elapsed time starts at 0 but phase lookup starts at `LATE`. The offset is part of the checkpoint snapshot, so a resumed night shift stays at night.
### Asset fallback
1. A runtime loader asks for the library scene or texture.
2. If the imported asset is missing, the loader uses the generated/procedural fallback rather than failing the boot.
3. Contracts and audits ensure the fallback and library paths expose the same observable behaviour; CI runs headless against whichever path is available.
### Access check ### Access check
1. The player stops or receives an approaching person. 1. The player stops or receives an approaching person.
@@ -137,7 +181,7 @@ in code.
## 7. Deployment View ## 7. Deployment View
The game is a single-player local client containing presentation, simulation, rules, content, and persistence for local settings and shift results. No online backend is required. A non-threaded Web export ships alongside the desktop builds and can be served from any static host without special headers. The game is a single-player local client containing presentation, simulation, rules, content, and persistence for local settings and shift results. No online backend is required. A non-threaded Web export ships alongside the desktop builds and can be served from any static host without special headers. The default renderer is GL Compatibility; an optional Desktop HQ zip uses Forward+ with volumetric fog/SDFGI on Vulkan-capable desktops. CI, local development and exported builds use Godot 4.7.2; the light-falloff code keeps a compatibility branch for older editors but the supported baseline is unified.
Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture. Future options include external analytics, cloud saves, or replay sharing, but they are not part of the current architecture.
@@ -145,9 +189,9 @@ Future options include external analytics, cloud saves, or replay sharing, but t
A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases. A continuous-integration pipeline keeps the headless test suite green on every change and publishes tagged releases.
- **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job installs Godot 4.3, imports the project, and runs `res://src/test/test_runner.gd`; it fails on a non-zero exit code or any `SCRIPT ERROR` in the output. - **Workflow:** `.gitea/workflows/build.yml` runs on pushes, pull requests, tags, and manual dispatches. The `checks` job installs Godot 4.7.2, imports the project, and runs `res://src/test/test_runner.gd`; it fails on a non-zero exit code or any `SCRIPT ERROR` in the output.
- **Build job:** runs for tags and manual dispatches. It installs export templates, exports Linux/Windows/macOS and the non-threaded Web build, packages the NSIS installer and Linux AppImage, verifies the installer contents, and uploads the artifacts. - **Build job:** runs for tags and manual dispatches. It installs export templates, exports Linux/Windows/macOS and the non-threaded Web build, packages the NSIS installer, Linux AppImage and optional Desktop HQ zip, verifies the installer contents, and uploads the artifacts.
- **Publish job:** tag builds call `tools/publish_release.sh` to create the Gitea release and upload the six artifacts. The script uses `GITEA_TOKEN` when configured and otherwise reuses the runner's checkout extraheader credentials. - **Publish job:** tag builds call `tools/publish_release.sh` to create the Gitea release and upload the standard artifacts plus the optional Desktop HQ zip. The script uses `GITEA_TOKEN` when configured and otherwise reuses the runner's checkout extraheader credentials.
- **Hosting:** the repository lives on Gitea (`https://git.allucanget.biz/zwitschi/security-game`). Export templates must match the pinned Godot version; macOS builds are unsigned and need quarantine guidance or notarization for wider distribution. - **Hosting:** the repository lives on Gitea (`https://git.allucanget.biz/zwitschi/security-game`). Export templates must match the pinned Godot version; macOS builds are unsigned and need quarantine guidance or notarization for wider distribution.
### Release management ### Release management
@@ -160,7 +204,7 @@ Releases are produced from a tagged commit and published to the repository host'
- Packaging — NSIS builds the Windows installer; `packaging/linux/build_appimage.sh` builds the AppImage. - Packaging — NSIS builds the Windows installer; `packaging/linux/build_appimage.sh` builds the AppImage.
- [`RELEASING.md`](RELEASING.md) — step-by-step guide and release checklist. - [`RELEASING.md`](RELEASING.md) — step-by-step guide and release checklist.
The release process is: bump the version, run the full test suite and `tools/check_screenshots.sh`, run `tools/build_releases.sh`, tag and push (CI publishes), then verify the README "Downloads" links and the six artifacts. The release process is: bump the version, run the full test suite and `tools/check_screenshots.sh`, run `tools/build_releases.sh`, tag and push (CI publishes), then verify the README "Downloads" links and the release artifacts.
## 8. Cross-Cutting Concepts ## 8. Cross-Cutting Concepts
@@ -173,6 +217,11 @@ The release process is: bump the version, run the full test suite and `tools/che
- **Localization:** Dialogue and prompts should be externalized from logic. - **Localization:** Dialogue and prompts should be externalized from logic.
- **Observability:** Debug overlays show NPC intent, access status, escalation level, active incidents, and response timers during development. - **Observability:** Debug overlays show NPC intent, access status, escalation level, active incidents, and response timers during development.
- **Visual regression:** Staged captures are compared against the runtime reference art (`screen_designs.py compare`) and optionally judged by a vision model; `tools/check_screenshots.sh` makes the pass repeatable. - **Visual regression:** Staged captures are compared against the runtime reference art (`screen_designs.py compare`) and optionally judged by a vision model; `tools/check_screenshots.sh` makes the pass repeatable.
- **Asset provenance and AI usage:** AI-assisted images/concepts are development inputs only; validated outputs are committed, audited and loaded through the same runtime asset contracts. Generated content must not become an offline/CI dependency.
- **Campaign and checkpoint state:** `Campaign` owns venue order/progression; settings, campaign, completed shift history and a versioned pause checkpoint are separate JSON documents. The checkpoint snapshots coordinator systems, scheduler RNG and NPC presentation/access state; it deliberately does not serialize the tutorial overlay or transient input state.
- **Difficulty:** easy/normal/hard only scale spawn pacing, NPC compliance tolerance and report-credibility strictness; access/escalation rules and emergency rarity are invariant.
- **Settings and accessibility:** volume/motion/caption settings persist through `settings.json`; Help is generated from the input-binding catalogue and the HUD log is the text caption surface. CI/release, local development and exported builds are unified on Godot 4.7.2.
- **Documentation ownership:** `PLAN.md` owns design intent; `docs/gameplay.md` owns playable mechanics; `docs/architecture.md` owns system boundaries, data flow, constraints and cross-cutting decisions; ADRs own decision history; `docs/development-status.md` owns the implemented/gap list; `TODO.md` owns the roadmap; `MEMORY.md` owns gotchas and open questions. Specialized docs link to these rather than becoming competing sources of truth.
## 9. Architecture Decisions ## 9. Architecture Decisions
@@ -203,6 +252,9 @@ Architecture decisions are recorded as ADRs:
| Performance | The target venue should support a believable crowd without harming input or simulation responsiveness. | | Performance | The target venue should support a believable crowd without harming input or simulation responsiveness. |
| Testability | Access and escalation rules can be tested independently of presentation. | | Testability | Access and escalation rules can be tested independently of presentation. |
| Accessibility | Core actions are available through clear input alternatives and readable feedback. | | Accessibility | Core actions are available through clear input alternatives and readable feedback. |
| Reliability | A fresh checkout, missing optional asset, invalid AI key, or unavailable Forward+ renderer must not prevent a normal Compatibility/Web/headless boot. |
| Performance | A busy venue should hold its budget at the target NPC cap on desktop and Web; the current 24-NPC check is a baseline, not a release guarantee. |
| Documentation integrity | Every released version has a changelog entry, current status/roadmap, and architecture/ADR references that match the build. |
## 11. Risks and Technical Debt ## 11. Risks and Technical Debt
@@ -213,8 +265,44 @@ Architecture decisions are recorded as ADRs:
- Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation. - Mental-health-crisis scenarios require careful writing, playtesting, and respectful presentation.
- The choice of engine may affect navigation, crowd scale, tooling, and content authoring. - The choice of engine may affect navigation, crowd scale, tooling, and content authoring.
- Reference mockups can outpace the runtime art style; compare/judge catch gross drift but not composition errors, so the staged gallery needs human review after large visual changes. - Reference mockups can outpace the runtime art style; compare/judge catch gross drift but not composition errors, so the staged gallery needs human review after large visual changes.
- Godot 4.7.2 is the unified CI/local/project baseline; future engine bumps still require import, visual and export smoke checks before changing that baseline.
- Content volume and authoring tools are still thin; adding venues/events by editing the factory can become error-prone without schema validation and preview tooling.
- Save data currently covers settings and shift history, not mid-shift resume; adding saves/replays requires a versioned schema and migration policy.
- The optional judge and image-generation paths depend on an external key, model availability and budget; CI cannot make them a release gate, and keys must never be committed.
- Accessibility and localization coverage is partial; a public release needs subtitles/captions, colour-independent cues, remapping, text expansion tests and at least a documented localization workflow.
- Unsigned macOS builds, AI asset provenance and any storefront/legal requirements are release blockers for a public release.
- Documentation drift has already occurred (release version, implemented status and obsolete plan docs); the ownership map and roadmap must be kept current in the same change as the implementation.
## 12. Glossary ## 12. Documentation Consolidation and Ownership
The documentation set is intentionally layered. Architecture-level material is consolidated here;
specialized operational detail remains in focused pages so commands do not rot inside the
architecture document.
| Document | Canonical role | Relationship to this architecture |
| --- | --- | --- |
| [`PLAN.md`](../PLAN.md) | Product/design intent, pillars, venues and success criteria | Design source; architecture realizes it |
| [`docs/gameplay.md`](gameplay.md) | Playable loop, escalation, venue mechanics | Runtime/behavioral view |
| [`docs/architecture.md`](architecture.md) | System boundaries, data flow, constraints, deployment, cross-cutting decisions, quality risks | Single architecture source |
| [`docs/adr/`](adr/) | Immutable decision records with context and consequences | Decision history linked from §9 |
| [`docs/asset-tooling.md`](asset-tooling.md) | Build/audit/capture commands and pipeline usage | Operational appendix to the pipeline section |
| [`docs/blender-assets.md`](blender-assets.md) | Blender character/gear/prop contracts and attach points | Detailed asset contract appendix |
| [`docs/getting-started.md`](getting-started.md) | Setup, commands, controls | Developer onboarding |
| [`docs/RELEASING.md`](RELEASING.md) | Release checklist and CI/publishing steps | Deployment appendix to §7 |
| [`docs/smoke-checklist.md`](smoke-checklist.md) | Manual verification script | QA appendix to §10 |
| [`docs/development-status.md`](development-status.md) | Implemented features and current gaps | Status companion to the roadmap |
| [`TODO.md`](../TODO.md) | Active tasks and 0.x roadmap | Planning source; no architecture duplication |
| [`CHANGELOG.md`](../CHANGELOG.md) | User-facing release history | Release/version companion |
Consolidation decisions:
- **Architecture owns the "how"** (components, contracts, data flow, constraints, quality gates); **PLAN/gameplay own the "what"**; **ADRs own the "why"**. Links replace duplicated prose.
- **Asset and release documents remain separate** because they are command-heavy operational procedures; their architecture-relevant contracts and failure modes are summarized in §5 and §7.
- **Completed plans are removed, not kept as competing roadmaps.** Historical graphics work is summarized by ADR-0013, the asset pipeline section and the v0.6.0 changelog; new work belongs in TODO.
- **Status and roadmap are separate from architecture.** `docs/development-status.md` records what exists; `TODO.md` records what remains, including the 0.x gap analysis and milestone exit criteria.
- **Documentation drift is a tracked risk:** release/version, test counts, renderer status, and stale plans must be corrected in the same commit as the change that invalidates them.
## 13. Glossary
- **Access artifact:** A wristband, ID, ticket, credential, or other item used to verify entry. - **Access artifact:** A wristband, ID, ticket, credential, or other item used to verify entry.
- **Authorized person:** Someone permitted to enter under the current venue policy. - **Authorized person:** Someone permitted to enter under the current venue policy.
+77 -26
View File
@@ -1,6 +1,10 @@
# Asset Pipeline and Tooling # Asset Pipeline and Tooling
Everything the game renders is produced or gated by the scripts below. Development-only outputs (AI concept sheets, Blender sources, raw AI fabrics) are gitignored; the audited game assets are committed. Everything the game renders is produced or gated by the scripts below. Architecture-level contracts,
data flow and failure fallbacks are summarized in
[`architecture.md`](architecture.md#content-and-asset-pipeline-architecture); this page is the
operational reference. Development-only outputs (AI concept sheets, Blender sources, raw AI fabrics)
are gitignored; the audited game assets are committed.
## Image Asset Tools ## Image Asset Tools
@@ -82,7 +86,8 @@ character authored in Blender ([ADR-0013](adr/0013-blender-authored-npc-characte
per-slot material maps. `NpcAvatar` instantiates that skinned model, tints its per-slot material maps. `NpcAvatar` instantiates that skinned model, tints its
five material slots from the seed-driven outfit, and drives the bones from the five material slots from the seed-driven outfit, and drives the bones from the
existing animation code; the procedural rig remains the offline fallback (see existing animation code; the procedural rig remains the offline fallback (see
the [graphics plan](plan-graphics-v0.6.md)). [ADR-0013](adr/0013-blender-authored-npc-characters.md) and
[`blender-assets.md`](blender-assets.md)).
```bash ```bash
# Print the frozen contract (slots, bone names, triangle budget) # Print the frozen contract (slots, bone names, triangle budget)
@@ -185,22 +190,66 @@ python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> --judge
--model google/gemini-2.5-flash --repeats 3 --model google/gemini-2.5-flash --repeats 3
``` ```
`capture_realism.gd` runs six stages (day, portrait, evening, late, Joke Shop, studio); Judges default to `--model auto`: `tools/openrouter_judge.py` reads the live
`--stages=day,late` limits it while tuning. The `portrait` shot freezes one NPC on open sidewalk OpenRouter catalogue, keeps image-input models that support `response_format`,
and frames the face, which is the only capture that can judge avatar detail and ranks them by advertised token/image price. The run falls through the list
(`--portrait-type=N` picks a role). The texture-adoption run, on provider/model errors and aborts on an invalid key. Use
[`docs/screens/realism/2026-11-01-adopt/`](../docs/screens/realism/2026-11-01-adopt/report.md), `GIG_LINE_JUDGE_MODEL` or `--model <id>` for a pinned comparison.
compares the pre-adoption captures with the current build: on the shots both sets captured the
judge's like-for-like means rose on every sub-score (overall 0.8 → 1.0, backdrop 0.6 → 1.6) and
the Pillow metric gap fell 0.444 → 0.348. The character pass
([`2026-11-01-npc/`](../docs/screens/realism/2026-11-01-npc/report.md)) adds the portrait shot and
records the new faces, hands and sleeve cuffs. The gear-fit run
([`2026-11-01-gear/`](../docs/screens/realism/2026-11-01-gear/report.md)) checks
the sunglasses, bag and helmet against measured head/skirt bounds with
`python3 tools/blender_assets.py fit`; it also fixed the portrait yaw and hid
the focus overlay so the close-up shows the avatar.
![realism run](../docs/screens/realism/2026-11-01-adopt/sheet.jpg) `capture_npc_review.gd` is the pre-build NPC gate: it stages all eight
library character models at portrait, conversation and crowd distance on both
promoted maps in day and night lighting, with the normal crowd hidden. It uses
the review-only `NpcAvatar.character_override` to include the guard model, which
has no spawned NPC role:
```bash
godot --path . --script res://src/test/capture_npc_review.gd -- \
--out=res://tmp/npc-review
```
Contact sheets can be assembled from the files (the output is local QA and is
not committed). The runtime applies small attach-space offsets to the lanyard
and firefighter helmet so the badge clears the jacket and the brim does not sit
over the eyes; these are `NpcAvatar.GEAR_OFFSETS`, not changes to the gear
contract.
`tools/npc_proportions.py` checks the eight character GLBs against the shared
height/head/shoulder/hip/torso/leg/arm/foot guide; the current results are in
[`npc-proportion-audit.md`](npc-proportion-audit.md). It reads the exported GLBs
and does not require Blender.
`capture_npc_baseline.gd` is the 0.9.4 neutral baseline: eight characters ×
front/three-quarter/profile/back/full-body/crowd = 48 frames with a fixed
camera, studio lighting and no venue/HUD/animation. The raw PNGs stay in
`tmp/`; `tools/npc_baseline.py sheet` builds the committed contact sheet, and
`tools/npc_baseline.py compare --before DIR --after DIR` builds the review
comparison after a model change. See
[`npc-visual-review.md`](npc-visual-review.md).
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-baseline
python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline
```
`capture_realism.gd` runs seven stages (day, portrait, evening, late, Joke Shop day, Joke Shop night, studio);
`--stages=day,late` limits it while tuning; `--flashlight` turns on the guard lamp for
night stages (used by the Desktop HQ A/B). The `portrait` shot freezes one NPC on open sidewalk
and frames the face, which is the only capture that can judge avatar detail
(`--portrait-type=N` picks a role). The generated realism runs under
`docs/screens/realism/` are **local, gitignored QA artifacts**; commit only the
resulting decisions/docs, not the run folders. The texture-adoption run compared
the pre-adoption captures with the current build: on the shots both sets captured,
the judge's like-for-like means rose on every sub-score (overall 0.8 → 1.0,
backdrop 0.6 → 1.6) and the Pillow metric gap fell 0.444 → 0.348. The character
pass added the portrait shot and recorded the new faces, hands and sleeve cuffs.
The Forward+ A/B compared the Compatibility entrance with the optional Desktop HQ
preset. The gear-fit run checked the sunglasses, bag and helmet against measured
head/skirt bounds with `python3 tools/blender_assets.py fit`; it also fixed the
portrait yaw and hid the focus overlay so the close-up shows the avatar.
Regenerate a run locally with the capture and `realism --run ...` commands above;
the reports and sheets are intentionally not part of the release repository.
## Screen design references ## Screen design references
@@ -231,6 +280,9 @@ python3 tools/screen_designs.py generate --draft --only wand --force
# (requires OPENROUTER_API_KEY) # (requires OPENROUTER_API_KEY)
python3 tools/screen_designs.py generate python3 tools/screen_designs.py generate
# UI-state gallery (menu, pause, settings, review, radio, wheel, crowd, responder)
godot --path . --script res://src/test/capture_ui_states.gd -- --out=res://docs/screenshots
# Prop gallery (studio line-up) for close-range prop checks # Prop gallery (studio line-up) for close-range prop checks
godot --path . --script res://src/test/capture_prop_gallery.gd godot --path . --script res://src/test/capture_prop_gallery.gd
@@ -246,12 +298,11 @@ python3 tools/screen_designs.py judge --only 03- # one capture
python3 tools/screen_designs.py judge --dry-run # build requests, no network 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, The catalogue covers 21 screens: the thirteen scene captures plus the start menu,
pause overlay, settings, shift review, radial menu, emergency radio, wand pause overlay, settings, shift review, radial menu, emergency radio, crowd panic,
screening, Joke Shop queue, TV Studio arrival, crowd panic, responder arrival, and responder arrival. All 21 have an AI reference in `assets/images/ui/`
body-camera timeline, and the escalation HUD. All 21 have an AI reference in (snapshot in `docs/screens/designs/`) and a committed capture, so every entry is
`assets/images/ui/` (snapshot in `docs/screens/designs/`); the eleven screens with compared or judged against the running game.
staged captures are also compared or judged against the running game.
`compare` flags gross drift: wrong aspect ratio, undersized frame, near-blank `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 frame, and large layout/palette/detail distance. It is a regression gate, not a
@@ -265,8 +316,8 @@ 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 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 `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 `compare` after regenerating the game screenshots with
`src/test/capture_screenshots.gd`. `src/test/capture_screenshots.gd` and `src/test/capture_ui_states.gd`.
For a one-command drift check, run `tools/check_screenshots.sh`. It renders the For a one-command drift check, run `tools/check_screenshots.sh`. It renders the
staged captures and prop gallery into `docs/screenshots/` (using `xvfb-run` when scene captures, UI-state captures and prop gallery into `docs/screenshots/` (using
no display is available) and then runs `screen_designs.py compare`. `xvfb-run` when no display is available) and then runs `screen_designs.py compare`.
+27 -11
View File
@@ -1,9 +1,14 @@
# Blender asset library # Blender asset library
Architecture context: the asset contracts and fallback path are summarized in
[`architecture.md`](architecture.md#content-and-asset-pipeline-architecture).
Status: built, audited, and integrated (2026-11-01). `NpcAvatar` selects the Status: built, audited, and integrated (2026-11-01). `NpcAvatar` selects the
character variants and attaches the gear; `WorldBuilder` loads the prop library character variants and attaches the gear; `WorldBuilder` loads the prop library
with colliders and phase-driven emissives. See the Phase 3.5 integration in with colliders and phase-driven emissives. The 0.9.4 neutral baseline and its
[`plan-graphics-v0.6.md`](plan-graphics-v0.6.md). acceptance criteria are in [`npc-visual-review.md`](npc-visual-review.md);
the committed 8 × 6 contact sheet is
[`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg).
Generator: [`tools/blender_assets.py`](../tools/blender_assets.py). Manifest (the Generator: [`tools/blender_assets.py`](../tools/blender_assets.py). Manifest (the
source of truth for integration): source of truth for integration):
@@ -87,10 +92,12 @@ All eight use the `npc_base` contract, so each one can replace
- material slots `skin`, `cloth`, `pants`, `accessory`, `hair` carry the same - material slots `skin`, `cloth`, `pants`, `accessory`, `hair` carry the same
neutral `assets/textures/npc/<slot>_{albedo,normal}.png` maps, so neutral `assets/textures/npc/<slot>_{albedo,normal}.png` maps, so
`Materials.npc_slot()` tints them the same way it tints `npc_base`. `Materials.npc_slot()` tints them the same way it tints `npc_base`.
- budget ≤ 6000 triangles and ≤ 5000 vertices (glTF vertex count, after seam - budget ≤ **8,000 triangles and ≤ 8,000 glTF vertices** for the eight library
splits; `CHAR_MAX_VERTS` in `tools/blender_assets.py`, raised from 4000 for variants (vertex count after seam splits; `CHAR_MAX_TRIS`/`CHAR_MAX_VERTS` in
the 2026-11-01 face/hand pass). The current range is 3,974–5,026 triangles `tools/blender_assets.py`, raised from 6,000/5,000 on 2026-11-02). The frozen
and 3,744–4,807 vertices. `npc_base` fallback keeps its original 6,000/4,000 contract. The current range
is 4,482–5,474 triangles and 4,260–5,494 vertices, leaving room for the
remaining grip and clothing detail.
Construction: the torso and limbs are one continuous Skin-modifier mesh, Construction: the torso and limbs are one continuous Skin-modifier mesh,
subdivided twice, decimated to 26 % with X symmetry, and cut at the waist, cuffs, subdivided twice, decimated to 26 % with X symmetry, and cut at the waist, cuffs,
@@ -139,6 +146,10 @@ attach point:
The character previews in `sheet_npc.jpg` are built by importing the gear at The character previews in `sheet_npc.jpg` are built by importing the gear at
exactly these points, which gives a quick visual check of the convention. exactly these points, which gives a quick visual check of the convention.
`NpcAvatar.GEAR_OFFSETS` applies two final-context nudges after attachment:
the lanyard moves 4 cm forward so its badge clears the jacket, and the
firefighter helmet moves 3 cm up so its brim sits above the eyes. The
`fit` report remains an asset-space measurement of the untouched GLBs.
## Props ## Props
@@ -159,16 +170,16 @@ exactly these points, which gives a quick visual check of the convention.
| `marquee` | the procedural marquee | 6 m canopy and sign box; emissive `bulb` + `sign_face`. Overlay the text with the existing `Label3D` | | `marquee` | the procedural marquee | 6 m canopy and sign box; emissive `bulb` + `sign_face`. Overlay the text with the existing `Label3D` |
| `sedan` | new (studio arrival) | 4.6 m; emissive `headlight`, red tail lamps | | `sedan` | new (studio arrival) | 4.6 m; emissive `headlight`, red tail lamps |
Props use plain PBR factors (base colour, roughness, metallic, emission) and Props use plain PBR factors (base colour, roughness, metallic, emission) plus
have no textures. They are not yet AO-baked; that is still a Phase 4 task. the committed 256² baked AO maps (`<name>_ao.png`) wired by `WorldBuilder`;
Emissive materials are always on in the GLB. The integration should tie them to emissive materials are tied to `WorldBuilder.set_night_mode()`. Characters
`WorldBuilder.set_night_mode()`. carry baked AO and the shared neutral material maps described above.
## Checks ## Checks
- `python3 tools/blender_assets.py audit`: container, `POSITION`/`NORMAL`/ - `python3 tools/blender_assets.py audit`: container, `POSITION`/`NORMAL`/
`TEXCOORD_0`, UVs in [0, 1], no zero-area triangles (Godot warns about them `TEXCOORD_0`, UVs in [0, 1], no zero-area triangles (Godot warns about them
during LOD generation), budgets (characters 6000/5000, gear 1500, props 4000 during LOD generation), budgets (library characters 8000/8000, base fallback 6000/4000, gear 1500, props 4000
triangles), grounding, and an editable `.blend`. For characters it also triangles), grounding, and an editable `.blend`. For characters it also
checks skinning, bones, slots, the `npc_base` mesh node and the height. checks skinning, bones, slots, the `npc_base` mesh node and the height.
- `tools/test_blender_assets.py`: catalogue and contract consistency with - `tools/test_blender_assets.py`: catalogue and contract consistency with
@@ -191,3 +202,8 @@ Emissive materials are always on in the GLB. The integration should tie them to
the legs through the hem. the legs through the hem.
- Preview colours (`PREVIEW_TINTS`) only stand in for `outfit_for()`. The GLBs - Preview colours (`PREVIEW_TINTS`) only stand in for `outfit_for()`. The GLBs
stay neutral. stay neutral.
- The 0.9.4 baseline found three P1 portrait issues. The tourist's photo prop
now only appears in photo/film poses and the backpack straps were refit as
flattened chest bands; the face is still shallow/faceted at portrait range.
The full ranked list, measurements and before/after sheet are in
[`npc-visual-review.md`](npc-visual-review.md).
+66
View File
@@ -0,0 +1,66 @@
# Blender Previews
Committed contact sheets and local Blender renders for the character, gear and prop library. Individual PNGs are development previews and are gitignored; the sheets are tracked.
## Image previews
| Preview | File |
| --- | --- |
| <img src="a_frame_sign.png" width="280" alt="a_frame_sign.png"> | [`a_frame_sign.png`](a_frame_sign.png) |
| <img src="backpack.png" width="280" alt="backpack.png"> | [`backpack.png`](backpack.png) |
| <img src="beanie.png" width="280" alt="beanie.png"> | [`beanie.png`](beanie.png) |
| <img src="bench.png" width="280" alt="bench.png"> | [`bench.png`](bench.png) |
| <img src="bollard.png" width="280" alt="bollard.png"> | [`bollard.png`](bollard.png) |
| <img src="camera.png" width="280" alt="camera.png"> | [`camera.png`](camera.png) |
| <img src="cap.png" width="280" alt="cap.png"> | [`cap.png`](cap.png) |
| <img src="clipboard.png" width="280" alt="clipboard.png"> | [`clipboard.png`](clipboard.png) |
| <img src="crowd_barrier.png" width="280" alt="crowd_barrier.png"> | [`crowd_barrier.png`](crowd_barrier.png) |
| <img src="cup.png" width="280" alt="cup.png"> | [`cup.png`](cup.png) |
| <img src="double_door.png" width="280" alt="double_door.png"> | [`double_door.png`](double_door.png) |
| <img src="fire_hydrant.png" width="280" alt="fire_hydrant.png"> | [`fire_hydrant.png`](fire_hydrant.png) |
| <img src="firefighter_helmet.png" width="280" alt="firefighter_helmet.png"> | [`firefighter_helmet.png`](firefighter_helmet.png) |
| <img src="flashlight.png" width="280" alt="flashlight.png"> | [`flashlight.png`](flashlight.png) |
| <img src="handrail.png" width="280" alt="handrail.png"> | [`handrail.png`](handrail.png) |
| <img src="hood.png" width="280" alt="hood.png"> | [`hood.png`](hood.png) |
| <img src="lanyard.png" width="280" alt="lanyard.png"> | [`lanyard.png`](lanyard.png) |
| <img src="marquee.png" width="280" alt="marquee.png"> | [`marquee.png`](marquee.png) |
| <img src="newspaper_box.png" width="280" alt="newspaper_box.png"> | [`newspaper_box.png`](newspaper_box.png) |
| <img src="npc_casual.png" width="280" alt="npc_casual.png"> | [`npc_casual.png`](npc_casual.png) |
| <img src="npc_coat.png" width="280" alt="npc_coat.png"> | [`npc_coat.png`](npc_coat.png) |
| <img src="npc_dress.png" width="280" alt="npc_dress.png"> | [`npc_dress.png`](npc_dress.png) |
| <img src="npc_firefighter.png" width="280" alt="npc_firefighter.png"> | [`npc_firefighter.png`](npc_firefighter.png) |
| <img src="npc_guard.png" width="280" alt="npc_guard.png"> | [`npc_guard.png`](npc_guard.png) |
| <img src="npc_hoodie.png" width="280" alt="npc_hoodie.png"> | [`npc_hoodie.png`](npc_hoodie.png) |
| <img src="npc_jacket.png" width="280" alt="npc_jacket.png"> | [`npc_jacket.png`](npc_jacket.png) |
| <img src="npc_vest.png" width="280" alt="npc_vest.png"> | [`npc_vest.png`](npc_vest.png) |
| <img src="palm_tree.png" width="280" alt="palm_tree.png"> | [`palm_tree.png`](palm_tree.png) |
| <img src="phone.png" width="280" alt="phone.png"> | [`phone.png`](phone.png) |
| <img src="planter_box.png" width="280" alt="planter_box.png"> | [`planter_box.png`](planter_box.png) |
| <img src="protest_sign.png" width="280" alt="protest_sign.png"> | [`protest_sign.png`](protest_sign.png) |
| <img src="radio.png" width="280" alt="radio.png"> | [`radio.png`](radio.png) |
| <img src="round_planter.png" width="280" alt="round_planter.png"> | [`round_planter.png`](round_planter.png) |
| <img src="scba_tank.png" width="280" alt="scba_tank.png"> | [`scba_tank.png`](scba_tank.png) |
| <img src="security_podium.png" width="280" alt="security_podium.png"> | [`security_podium.png`](security_podium.png) |
| <img src="sedan.png" width="280" alt="sedan.png"> | [`sedan.png`](sedan.png) |
| <img src="sheet_npc.jpg" width="280" alt="sheet_npc.jpg"> | [`sheet_npc.jpg`](sheet_npc.jpg) |
| <img src="sheet_npc_baseline.jpg" width="280" alt="sheet_npc_baseline.jpg"> | [`sheet_npc_baseline.jpg`](sheet_npc_baseline.jpg) |
| <img src="sheet_npc_baseline_compare-p1.jpg" width="280" alt="sheet_npc_baseline_compare-p1.jpg"> | [`sheet_npc_baseline_compare-p1.jpg`](sheet_npc_baseline_compare-p1.jpg) |
| <img src="sheet_npc_baseline_compare-body.jpg" width="280" alt="sheet_npc_baseline_compare-body.jpg"> | [`sheet_npc_baseline_compare-body.jpg`](sheet_npc_baseline_compare-body.jpg) |
| <img src="sheet_npc_baseline_compare-face.jpg" width="280" alt="sheet_npc_baseline_compare-face.jpg"> | [`sheet_npc_baseline_compare-face.jpg`](sheet_npc_baseline_compare-face.jpg) |
| <img src="sheet_npc_baseline_compare-torso.jpg" width="280" alt="sheet_npc_baseline_compare-torso.jpg"> | [`sheet_npc_baseline_compare-torso.jpg`](sheet_npc_baseline_compare-torso.jpg) |
| <img src="sheet_npc_baseline_compare-face-detail.jpg" width="280" alt="sheet_npc_baseline_compare-face-detail.jpg"> | [`sheet_npc_baseline_compare-face-detail.jpg`](sheet_npc_baseline_compare-face-detail.jpg) |
| <img src="sheet_npc_hands_compare.jpg" width="280" alt="sheet_npc_hands_compare.jpg"> | [`sheet_npc_hands_compare.jpg`](sheet_npc_hands_compare.jpg) |
| <img src="sheet_npc_hands_grip_compare.jpg" width="280" alt="sheet_npc_hands_grip_compare.jpg"> | [`sheet_npc_hands_grip_compare.jpg`](sheet_npc_hands_grip_compare.jpg) |
| <img src="sheet_npc_baseline_compare-shoes.jpg" width="280" alt="sheet_npc_baseline_compare-shoes.jpg"> | [`sheet_npc_baseline_compare-shoes.jpg`](sheet_npc_baseline_compare-shoes.jpg) |
| <img src="sheet_npc_gear.jpg" width="280" alt="sheet_npc_gear.jpg"> | [`sheet_npc_gear.jpg`](sheet_npc_gear.jpg) |
| <img src="sheet_props.jpg" width="280" alt="sheet_props.jpg"> | [`sheet_props.jpg`](sheet_props.jpg) |
| <img src="shoulder_bag.png" width="280" alt="shoulder_bag.png"> | [`shoulder_bag.png`](shoulder_bag.png) |
| <img src="stanchion.png" width="280" alt="stanchion.png"> | [`stanchion.png`](stanchion.png) |
| <img src="street_lamp.png" width="280" alt="street_lamp.png"> | [`street_lamp.png`](street_lamp.png) |
| <img src="street_tree.png" width="280" alt="street_tree.png"> | [`street_tree.png`](street_tree.png) |
| <img src="sunglasses.png" width="280" alt="sunglasses.png"> | [`sunglasses.png`](sunglasses.png) |
| <img src="traffic_cone.png" width="280" alt="traffic_cone.png"> | [`traffic_cone.png`](traffic_cone.png) |
| <img src="trash_bin.png" width="280" alt="trash_bin.png"> | [`trash_bin.png`](trash_bin.png) |
| <img src="umbrella.png" width="280" alt="umbrella.png"> | [`umbrella.png`](umbrella.png) |
| <img src="wall_lantern.png" width="280" alt="wall_lantern.png"> | [`wall_lantern.png`](wall_lantern.png) |
| <img src="wand.png" width="280" alt="wand.png"> | [`wand.png`](wand.png) |
Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

+36 -6
View File
@@ -2,10 +2,10 @@
Implemented so far: Implemented so far:
- Godot 4.3 project scaffold, input map, procedural world builder - Godot 4.7.2 project scaffold, input map, procedural world builder (CI/local/release unified)
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem` - Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools - Three authored scenarios (El Capitan Entertainment Centre / Hollywood Boulevard, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
- Headless unit tests: **229 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings) - Headless unit tests: **262 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
- Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event - Simulation extras: protester archetype, CALL_SOMEONE reaction, door lock/secure mechanic (visual indicator), flashlight with night perception bonus, LATE shift phase reaching the violent-threat event
- First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review - First-person prototype with interaction HUD, access inspection, wand screening, radio report form (incl. emergency hold-to-confirm), dispatched responder avatars, aim-free targeting, venue cycling between all three scenarios, color-coded escalation feedback, procedural audio cues, navigation-mesh NPC paths, JSON-backed localized strings, persisted shift history, debug overlay, and shift review
- Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`) - Control pass: focus cone on NPC heads with a billboarded blue circle in front of the face and name, action wheel (LMB/Space) with de-escalation-first slices, mouse-look freeze while a panel is open, acceleration-based walking, and named input actions (`action_menu`, `confirm`, `cancel`, `inspect`, `wand`)
@@ -38,9 +38,39 @@ Implemented so far:
- Web build: `build/gig-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 - Web build: `build/gig-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](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 - Aim-free selection pass (v0.3.0 work, [ADR-0011](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
- Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing. - Visual alignment: start/venue menu, pause, settings, shift review, radio, wand, inspection, timeline, HUD target chip/escalation bar, and radial menu now use or match their AI references in `assets/images/ui/`. The runtime art loader (`src/game/ui/art.gd`) falls back cleanly when a file is missing. The wand panel lists the guest's carried items, and multiline HUD/wand strings render real line breaks.
- NPC neck/shoulder transition (0.9.4 work): the body graph now uses a fuller neck base, a slightly tapered neck top and a lower shoulder root, giving the head/neck/shoulder line a trapezius slope instead of a thin post. The full character library was rebuilt with a final degenerate-face cleanup; the baseline comparison is `sheet_npc_baseline_compare-body.jpg`.
- NPC face-depth pass (0.9.4 work): sclera are recessed and capped by a thin upper lid, and the separate jaw/cheek spheres are replaced by a chin plate and cheekbones sculpted into the head mesh. The full library was rebuilt; the comparison is `sheet_npc_baseline_compare-face.jpg`.
- NPC torso/hip transition (0.9.4 work): the pelvis and chest are slightly wider than the waist, giving shirts and jackets a readable taper into the hips without changing the build multipliers or the skeleton. The comparison is `sheet_npc_baseline_compare-torso.jpg`.
- NPC visual optimization (0.9.4, complete 2026-11-02): all eight variants passed the portrait/readability, proportion, gear, foot/shoe, headgear and final-context gates. The library uses an 8,000-triangle / 8,000-glTF-vertex cap (up from 6,000/5,000; `npc_base` fallback remains 6,000/4,000); current characters measure 4,482–5,474 triangles and 4,260–5,494 vertices. The 48-frame baseline and 96-frame final-context review pass, the hand/gear offset and shoes are in, and the accepted stylized limits are documented in `npc-visual-review.md`.
- NPC face-detail pass (0.9.4 work): ala wings and a smaller nose bridge/tip, one rounded mouth slot, and a darker ear concha; all eight rebuilt. The comparison is `sheet_npc_baseline_compare-face-detail.jpg`.
- NPC headgear clearance (0.9.4 work): the 96-frame final-context review after the face-detail pass confirms the cap, firefighter helmet, hood and sunglasses clear the refined brow and eyes; no gear rebuild was needed.
- NPC footwear pass (0.9.4 work): casual shoes gained rounded toe and heel caps; responder/firefighter boots gained matching toe/heel volumes while retaining the black rubber boot language. All eight rebuilt; comparison `sheet_npc_baseline_compare-shoes.jpg`.
- NPC hand-item grip (0.9.4 work): runtime `HAND_ITEM_FORWARD` moves every hand gear 4 cm forward from the wrist proxy, so phone, cup, clipboard, camera, flashlight, wand and radio sit in the open palm instead of partly inside it. The open-hand/no-finger-rig limit is accepted for this stylized release; the comparison is `sheet_npc_hands_grip_compare.jpg`.
- NPC hand pass (0.9.4 work): wider, shallower palms; four two-segment bent fingers with rounded tips and a separate bent thumb; optional `--view=hand` capture at 0.80 m. The hand comparison is `sheet_npc_hands_compare.jpg`; the forward offset is in and the open-palm limit is accepted.
- NPC proportion audit (0.9.4 work): `tools/npc_proportions.py` measures all eight GLBs against a stylized height/head/shoulder/hip/torso/leg/arm/foot guide. All variants pass; the head and broad-build silhouettes are the nearest upper bounds. Results are in [`npc-proportion-audit.md`](npc-proportion-audit.md).
- NPC P1 portrait fixes (0.9.4 work): tourists now hide their photo-pose camera bag outside `photo`/`film` poses, removing the duplicate-backpack silhouette; the backpack gear was rebuilt with flattened, forward chest straps and a fresh AO map. The before/after sheet is [`blender_previews/sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg); the remaining face/hand work was closed under the 0.9.4 acceptance limits.
- NPC visual baseline (0.9.4 work): `src/test/capture_npc_baseline.gd` captures all eight library characters from front, three-quarter, profile, back, full-body and crowd views in a neutral studio (48 frames). The criteria, measurements and ranked gaps are in [`npc-visual-review.md`](npc-visual-review.md); the committed sheet is [`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg). No model changes were made in this baseline step.
- UI-state capture pass (0.9.3 work): `src/test/capture_ui_states.gd` adds committed captures 14–21 for the start menu, pause, settings, shift review, emergency radio, action wheel, crowd panic and responder arrival. Every one of the 21 catalogue entries now has a current-build capture; `tools/check_screenshots.sh` reports 21 good / 0 bad and the automatic judge reports 21/21 match, 0 diff. Crowd panic and responder arrival are staged presentation frames, not gameplay changes.
- Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts. - Realism adoption (post-v0.6.0): v2 per-phase skylines and surface tiles with normal maps, retuned sun/exposure/fog, wet asphalt, denser foliage, a visible additive flashlight beam, and refreshed staging captures. `tools/check_screenshots.sh` is the repeatable capture/compare gate; judge is clean of `diff` verdicts.
- Input/reliability fixes: selecting a venue now releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. - Input/reliability fixes: selecting a venue releases the start-menu input lock and recaptures the mouse; the body-camera overlay no longer covers the shift status. Mouse look now reads at `_input`, restores capture on window focus/click-back, and the HUD is mouse-transparent. Normal radio reports submit on click; emergency calls still require the hold-to-confirm path.
- Production-quality pass (v0.9.0): mixer/accessibility settings, audio volume clamping, 24-NPC budget smoke, shortened coat/dress stride, and a unified Godot 4.7.2 CI/local support baseline with documented upgrade/rollback requirements.
- Campaign and first-hour pass (v0.8.0): campaign progression, checkpoint resume, difficulty presets, a searchable Help overlay, recovery events, contextual dialogue, policy/debrief lines and tutorial/replay/skip. Scripted QA bypasses the tutorial unless `--tutorial` is passed.
- Tutorial pass (0.8.0 work): the eight-beat first shift is wired through a non-blocking prompt overlay, a safe compliant visitor, real wheel/inspection/warning/radio panels, persisted completion/skip and a Settings replay action. Scripted tests/captures bypass it unless `--tutorial` is passed; `smoke_tutorial.gd` covers the full flow.
- Vision judge (v0.7.2): discovers the cheapest current OpenRouter image+JSON model, reports the model/fallbacks used, and clears the full screen-design judge (13/13 match, 0 diff).
- Desktop HQ (v0.7.1): optional Forward+ Windows/Linux zip with volumetric fog, SDFGI and a volumetric flashlight; the default Compatibility/Web builds and headless tests gate the effect off. A/B captures are generated locally under `docs/screens/realism/` (gitignored).
- Hollywood landmark map (map optimization): the default venue is now a stylized reconstruction of 6840 Hollywood Blvd (the 1921 Masonic Temple / El Capitan Entertainment Centre) with a six-column Ionic portico, eight stone steps, Masonic parapet motto and medallions, three red event banners, central and side entrances, the El Capitan Theatre and east retail neighbours, the Ovation Hollywood arcade opposite, the Walk of Fame terrazzo and a four-lane boulevard with red kerb paint. The facade uses the shared limestone/stone material; the whole venue measures **58,884 triangles across 409 meshes** in the map-budget test. The venue menu exposes separate **Day** and **Night** Hollywood rows; the night row resolves to the same scenario with a late-phase offset, so its whole shift stays after dark. Real-site references and the geometry mapping are in [`hollywood-boulevard-map.md`](hollywood-boulevard-map.md).
- Day/night scenery variants (map optimization): the Hollywood row in the venue menu is split into Day and Night entries, with localized names/blurbs. The night entry uses `ShiftCoordinator.phase_offset_s` to start a full-length shift in `LATE` while the clock still starts at 00:00; the scheduler reads the offset time so late-night routine traffic and the late violent-threat event still fire, and the offset round-trips through checkpoints. Three `LATE` routine events keep the night street populated. Local lights were retuned from constant falloff to linear attenuation so sconces pool instead of flooding the stone.
- Joke Shop / Sunset Strip map (map optimization): the second venue is now a stylized reconstruction of The Comedy Store block at 8433 Sunset Blvd, with a 27 m black hall, signature-covered sloping canopy, circular **THE JOKE SHOP** blade sign, red velvet curtain bays, a west-end entrance, cream and white low-rise neighbours, a dry hillside with stucco houses and palms behind the roofline, and a low retail/billboard frontage across Sunset. The same geometry serves day and late lighting through the phase system. Real-site references and limits are in [`joke-shop-map.md`](joke-shop-map.md); the map measures **22,680 triangles across 454 meshes** in the budget test.
- Venue geometry (v0.7.0, Joke Shop frontage superseded by the map-optimization pass): the TV Studio builds a stone facade, bulb canopy, glossy black car and barrier line. `WorldBuilder.VENUE_SPECS` drives facade/street/nav dimensions, and `GameManager` rebuilds only the world container when the venue changes.
- Gear fit (post-v0.6.0): Blender gear is measured against the avatar head/skirt silhouette and the checks run in both the Python tooling and the headless suite. Sunglasses, the shoulder bag and the firefighter helmet were fitted to the new faces; the Influencer portrait and gallery were recaptured with a before/after report. - Gear fit (post-v0.6.0): Blender gear is measured against the avatar head/skirt silhouette and the checks run in both the Python tooling and the headless suite. Sunglasses, the shoulder bag and the firefighter helmet were fitted to the new faces; the Influencer portrait and gallery were recaptured with a before/after report.
- End-to-end interaction pass (0.9.3 work): `smoke_ui_flows.gd` drives inspection allow/deny, normal vs emergency radio, Help filtering, wand allow/deny and review return-to-menu in the real scene; campaign and timeline smokes cover review continue and timeline round-trips.
- Destructive-action pass (0.9.3 work): reset campaign and tutorial replay share a guarded confirmation dialog (one open instance, one emission, Cancel is inert); emergency send remains hold-to-confirm with no post-submit double-fire. Covered by session/radio tests and recorded in `docs/ui-copy.md`.
- Font/layout pass (0.9.3 work): HUD font scale was exercised at 0.75× and 1.75×; the target chip measures and caps scaled names, top labels clip, and shared action buttons ellipsize long 1.5–2× labels instead of overflowing. Covered by accessibility/button tests and recorded in `docs/ui-copy.md`.
- Modal-close pass (0.9.3 work): one top-modal close path handles Esc/right-click for every overlay, Settings opened from the menu restores the menu, Help no longer opens Pause behind it, and pointer/guard freeze state is recaptured after each close. The session smoke covers these paths.
- Keyboard/gamepad focus pass (0.9.3 work): `UiFocus` rings wrap through visible/enabled controls, hidden Continue and disabled timeline actions are skipped, each modal has a default focus, and A/B are bound to `ui_accept`/`ui_cancel` for pad-only navigation. Recorded in `docs/ui-copy.md`.
- Button-state pass (0.9.3 work): a shared `UiStyles` helper now gives every action button explicit normal, hover, pressed, focus and disabled styles; the timeline disables Previous/Next at its boundaries, while hidden continue states and the keyboard-only tutorial skip remain intentional. Recorded in `docs/ui-copy.md`.
- Dialogue pass (0.9.3 work): NPC reason answers now use the authored `reason` context, with an in-character answer for every shared archetype; Hollywood and Studio gained door-staff lines; radio cancellation, tutorial Ask terminology, help, start hints and campaign reset copy were clarified. Audit recorded in `docs/ui-copy.md`.
- Pre-build NPC review (2026-11-02): all eight library characters were staged at portrait, conversation and crowd distance on Hollywood and the Joke Shop, in day and night lighting, with the normal crowd hidden (`src/test/capture_npc_review.gd`). No P0 issues were found. Two P1 gear-fit issues were fixed with runtime attach offsets: the authorized-guest lanyard badge now clears the jacket and the firefighter helmet sits above the eyes. Backpack straps, caps, hands and the intentionally low-poly faces were accepted for the stylized target; close-range flashlight wash remains an optional-lighting follow-up. The 24-NPC budget stayed at 6.93 ms, the gallery passed 13 good / 0 bad and the screen-design judge stayed 13/13, and a clean portrait scored a 0.732 vision gap against the photoreal concept.
Not yet implemented: a desktop-only Forward+ preset (the renderer stays GL Compatibility for Web parity), live 3D body-camera replay, editor-based GUT integration, and crowd performance profiling/LOD (see [`TODO.md`](../TODO.md)). Current gaps for the 0.x release line: deeper authored content/dialogue, animation and audio production, localization/accessibility expansion, 24-NPC/platform profiling, external playtesting, and signed/notarized release packaging. The full gap analysis and milestone plan live in [`TODO.md`](../TODO.md); the current architecture and documentation ownership map are in [`docs/architecture.md`](architecture.md).
+14 -5
View File
@@ -4,7 +4,7 @@ The complete design rationale also lives in [`PLAN.md`](../PLAN.md); this page k
## Game Overview ## Game Overview
A typical shift lasts 10–15 minutes. The player: A typical shift lasts 10–15 minutes. The first-person camera stays at the gameplay height of 1.7 m; the concept frames use a lower ~1.55 m reference camera, but gameplay readability and body-camera framing take priority. The player:
1. Watches the entrance, steps, queue, and surrounding sidewalk. 1. Watches the entrance, steps, queue, and surrounding sidewalk.
2. Determines why each person is approaching. 2. Determines why each person is approaching.
@@ -16,21 +16,30 @@ A typical shift lasts 10–15 minutes. The player:
The game rewards calm resolutions rather than aggressive behavior. Emergency assistance and armed responders are rare last-resort systems with meaningful consequences. The game rewards calm resolutions rather than aggressive behavior. Emergency assistance and armed responders are rare last-resort systems with meaningful consequences.
The first shift starts with an in-game tutorial covering movement/look, focus cycling, the action wheel, access inspection, polite direction, formal warning/body camera, radio and shift review. Its beat sheet is in [`tutorial.md`](tutorial.md). After that a short campaign runs Hollywood → Joke Shop → TV Studio; progress, difficulty and a pause-safe checkpoint are persisted locally. Help (from the venue menu) explains the controls and the current venue policy.
## Venues ## Venues
### Hollywood Boulevard Building ### El Capitan Entertainment Centre (6840 Hollywood Blvd)
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. The map is a stylized reconstruction of the real building and block; the
reference notes and geometry mapping are in
[`hollywood-boulevard-map.md`](hollywood-boulevard-map.md). The venue menu
offers the same map as **Hollywood Boulevard — Day** and **Hollywood Boulevard
— Night**; the night variant starts directly in the late phase instead of
waiting for the shift clock.
The original scenario places the guard at the top of the eight stone steps outside the historic Masonic Temple / El Capitan Entertainment Centre on Hollywood Boulevard. 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. 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
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. The Joke Shop is a Sunset Strip comedy club inspired by the real Comedy Store at 8433 Sunset Blvd: a black hall under a deep signature-covered canopy, a circular blade sign, red velvet curtains, a west-end entrance, neighbouring low-rise frontage and a dry hillside of houses behind. The real-site mapping is in [`joke-shop-map.md`](joke-shop-map.md). 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 ### 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. This scenario combines the previously defined NPC types with a busy television-studio entrance: a stone facade, a bulb-lit canopy, a glossy black car at the curb, and stanchions/barriers holding the arrival line. 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. 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.
+14 -2
View File
@@ -2,7 +2,7 @@
## Setup ## Setup
1. Download the Godot 4.3 editor (official build) and put `godot` on your PATH. 1. Download Godot **4.7.2** (official build) and put `godot` on your PATH. The project, local tooling and CI use the same version; engine upgrades require import, headless, screenshot and Desktop HQ smoke checks before changing the baseline.
2. Open or run the project from this directory. 2. Open or run the project from this directory.
## Run and Test ## Run and Test
@@ -20,6 +20,9 @@ godot --headless --path . --quit-after 120
# Run all unit tests headlessly (exit code 0 = pass) # Run all unit tests headlessly (exit code 0 = pass)
godot --headless --path . --script res://src/test/test_runner.gd godot --headless --path . --script res://src/test/test_runner.gd
# Check docs README coverage, tracked images and local links
python3 tools/check_docs.py
# Save a screenshot to user:// (windowed) # Save a screenshot to user:// (windowed)
godot --path . --script res://src/test/take_screenshot.gd godot --path . --script res://src/test/take_screenshot.gd
@@ -32,13 +35,16 @@ godot --path . --script res://src/test/smoke_focus_radial.gd
# Session-shell smoke: menu → shift → pause → settings → menu (headless or windowed) # Session-shell smoke: menu → shift → pause → settings → menu (headless or windowed)
godot --headless --path . --script res://src/test/smoke_session_shell.gd godot --headless --path . --script res://src/test/smoke_session_shell.gd
# End-to-end interaction smoke: inspection, radio, Help search, wand and review
godot --headless --path . --script res://src/test/smoke_ui_flows.gd
# PLAN-verb smoke: recognize, request reason, body camera, warning, blocking # PLAN-verb smoke: recognize, request reason, body camera, warning, blocking
godot --headless --path . --script res://src/test/smoke_plan_verbs.gd godot --headless --path . --script res://src/test/smoke_plan_verbs.gd
# Prop-collision smoke (windowed): guard stops at a bench, guest routes around it # Prop-collision smoke (windowed): guard stops at a bench, guest routes around it
godot --path . --script res://src/test/smoke_props.gd godot --path . --script res://src/test/smoke_props.gd
# NPC budget smoke: 16 full-rig avatars against the documented frame budget # NPC budget smoke: 24 full-rig avatars against the documented frame budget
godot --headless --path . --script res://src/test/smoke_npc_budget.gd godot --headless --path . --script res://src/test/smoke_npc_budget.gd
# Movement smoke (windowed): steps, precision walk, footsteps and landing # Movement smoke (windowed): steps, precision walk, footsteps and landing
@@ -58,6 +64,12 @@ godot --headless --path . --script res://src/test/smoke_audio.gd
# Scenario-content smoke: wand refusal, celebrity crowd spike # Scenario-content smoke: wand refusal, celebrity crowd spike
godot --headless --path . --script res://src/test/smoke_scenario_content.gd godot --headless --path . --script res://src/test/smoke_scenario_content.gd
# Tutorial smoke (windowed): completion, replay and skip; isolated user data
XDG_DATA_HOME=/tmp/gigline-tutorial godot --path . --fixed-fps 60 --script res://src/test/smoke_tutorial.gd -- --tutorial
# Campaign/checkpoint smoke (windowed): resume, review continue, help; isolated data
XDG_DATA_HOME=/tmp/gigline-campaign godot --path . --fixed-fps 60 --script res://src/test/smoke_campaign.gd
``` ```
The unit test runner is the project's own lightweight harness (no editor plugin required) so CI can run it without the editor. The unit test runner is the project's own lightweight harness (no editor plugin required) so CI can run it without the editor.
+82
View File
@@ -0,0 +1,82 @@
# Hollywood Boulevard map reference
The Hollywood venue is a stylized reconstruction of the real block around the
El Capitan Entertainment Centre. It is a game space, not a survey-accurate
model: the landmark silhouette, street wall and approach read from the player's
eye height, while side streets and interiors are simplified.
## Real site
- **Address:** 6840 Hollywood Boulevard, Hollywood, Los Angeles, CA 90028.
- **Coordinates:** 34.10118 N, 118.34009 W (OSM way `424024147`).
- **Building:** the 1921 Hollywood Masonic Temple, designed by John C. Austin in
the Classical Revival style; now the El Capitan Entertainment Centre and the
home of *Jimmy Kimmel Live!*.
- **Facade:** a light stone/render Neoclassical front with six oversized Ionic
columns, a recessed main entrance reached by eight stone steps, ornamental
iron door grilles, a continuous crosscut-grille transom, two street-level side
entrances, and a parapet with the Masonic motto and circular medallions.
- **Neighbours:** the El Capitan Theatre (6838) immediately west, a modern
retail block east, and the Ovation Hollywood frontage (6801) across the
four-lane boulevard.
- **Sidewalk:** the Hollywood Walk of Fame terrazzo strip with brass stars runs
along the kerb; the kerb is painted red in the reference photographs.
## Game mapping
| Real feature | In-game representation |
| --- | --- |
| 29.6 m wide, 14.5 m high facade | `VENUE_SPECS["hollywood_building"]`: `facade_width` 29.6, `facade_height` 14.5, front at `z = -4` |
| Eight stone steps | `stair_count` 8, `stair_height` 0.10, `stair_tread` 0.38, 12 m wide |
| Six Ionic columns | `IonicColonnade` at x = -12.4 … 12.4, 4.96 m bay spacing |
| Recessed main entrance + two side doors | central 4.2 m door and 2.5 m side doors with transoms |
| Red event banners | three stylized `EL / CAPITAN / LIVE` banners in the central bays |
| Masonic motto + medallions | `FriezeInscription` label and two stone discs |
| El Capitan Theatre | `NeighbourBlocks/ElCapitanTheatre` with marquee, blade sign and practical light |
| Retail block east | `NeighbourBlocks/EastRetailBlock` with glazed shopfront |
| Ovation Hollywood | `OvationHollywood` arcade with seven arched openings, sign and south sidewalk |
| Walk of Fame | `WalkOfFame` dark terrazzo band with ten stars |
| Four-lane boulevard | double-yellow centre, broken white lane lines, red kerb paint and crosswalk |
The generated AI references live in
[`docs/screens/concepts/hollywood_boulevard/`](screens/concepts/hollywood_boulevard/README.md).
They are art direction for lighting, material scale and composition; they are
not texture or geometry sources.
## Deliberate simplifications
- Show branding is replaced by the venue-neutral `EL / CAPITAN / LIVE` banner
text. The building name and address are retained.
- The opposite Ovation frontage is represented as a single arcade block rather
than its full mall plan. Interiors, the Metro entrance and side streets are
out of playable bounds.
- The AI concept frames are 1280×720 references. The in-game geometry is built
from boxes, cylinders and a small number of custom arch/star meshes so it
stays inside the Compatibility/Web budget.
- The venue menu offers Day and Night Hollywood rows. Night is the same
geometry and scenario with a late-phase offset, not a second baked map; the
phase still drives sun, sky, fog, windows, signage and practical lights.
- The landmark facade uses the shared smooth limestone/stone texture rather
than the noisier granite panel tile. The whole venue measures **58,884
triangles across 409 meshes** in `test_hollywood_geometry_stays_inside_the_map_budget`,
well inside the 150k/600 budget.
- Local lights use linear attenuation (`omni_attenuation = 1.0`). Godot treats
`0.0` as constant falloff, which previously turned the night facade into a
flat yellow wall; the sconces now pool light instead.
## References
- [Hollywood Masonic Temple — Wikipedia](https://en.wikipedia.org/wiki/Hollywood_Masonic_Temple)
- [El Capitan Entertainment Centre — OpenStreetMap way 424024147](https://www.openstreetmap.org/way/424024147)
- [El Capitan Theatre — OpenStreetMap way 424024148](https://www.openstreetmap.org/way/424024148)
- [Ovation Hollywood — OpenStreetMap way 151485232](https://www.openstreetmap.org/way/151485232)
- [Hollywood Masonic Temple facade — Wikimedia Commons](https://commons.wikimedia.org/wiki/File:El_Capitan_Theater_frontal_fachade-The_Masonic_Temple.jpg)
- [Hollywood Masonic Temple and El Capitan Theatre, 2013 — Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Hollywood_Masonic_Temple_2013-10-13_10-02-25.jpg)
## Verification
```bash
godot --headless --path . --script res://src/test/test_runner.gd
godot --path . --script res://src/test/capture_realism.gd -- --out=/tmp/gig-line-hollywood --stages=day,evening,late
python3 tools/check_docs.py
```
+95
View File
@@ -0,0 +1,95 @@
# The Joke Shop — Sunset Strip map notes
The game's second venue is a fictional comedy club called **The Joke Shop**. Its
block, canopy, blade sign, entrance and hillside are based on the real Comedy
Store at **8433 Sunset Blvd, West Hollywood, CA 90069**.
The club name and the game's guest stories are invented. The building is a
stylized reconstruction, not a survey-accurate model: the playable frontage is
27 m, while the real parcel is much deeper and contains several rooms that the
game does not enter.
## Real site
| Item | Reference |
| --- | --- |
| Address | 8433 Sunset Blvd, West Hollywood, CA 90069, United States |
| Real venue | The Comedy Store (comedy club and theatre) |
| OpenStreetMap | Way [`428854155`](https://www.openstreetmap.org/way/428854155), centroid 34.095265, -118.373965 |
| OSM tags | `amenity=theatre`, `building=commercial`, `height=12.2`, `start_date=1940`, `wikidata=Q3520350` |
| Footprint | OSM polygon bounding box about **47.1 m × 41.2 m** across the club and rear parcels |
| Street | Sunset Boulevard, a major east–west arterial on the Sunset Strip |
| Setting | Dry Hollywood Hills directly behind the club, with houses and palms rising above the roofline |
The building began as **Ciro's**, a 1940 nightclub; it became The Comedy Store
in the early 1970s. Its street front is a low black hall under a deep,
signature-covered canopy, with the circular blade sign above the roof, red
curtains along the frontage and the main entrance set toward the west end. The
hillside houses behind it are part of the silhouette from the sidewalk.
## How the map maps to the real site
| Real element | Game implementation |
| --- | --- |
| Low black comedy hall | 27 m × 12 m footprint, 8.4 m street wall; matte black concrete surface with a low plinth and parapet |
| Deep overhanging canopy | 4.9 m sloped slab dropping about 1 m to the outer fascia; the fascia carries white signature lettering and the club name |
| Signature-covered front | Two `Label3D` signature bands on the fascia plus a smaller wall panel, so the handwriting reads at gameplay distance without dozens of decals |
| Circular blade sign | 3.9 m white disc with a black rim on a roof pole; `THE JOKE SHOP` lettering faces the street |
| Red curtains | Four three-fold velvet bays with tiebacks between the entrance and the east end; a red velvet entrance curtain |
| West-end entrance | Recessed opening at x = -8.8 m with a low step, brass pulls and the door-lock indicator |
| Warm practicals | Sconces along the wall, canopy downlights, entrance wash and three ground uplights; all off in daylight and switched by `set_night_mode()` |
| Neighbouring low-rise frontage | Cream Mediterranean block west (balconies, red awning) and white commercial block east (ribbon windows, lobby) |
| Hillside and houses | Fog-free unshaded 60° ramp behind the rear wall with stucco houses, shrubs and palms; its tint drops to a dark silhouette at night |
| Opposite side of Sunset | Low retail row, rooftop billboard, neon and palms as background context beyond the far kerb |
| Sidewalk furniture | Palms, queue barriers, stanchions, bins, planters, a-frame sign, hydrant and a parked sedan; prop placements pass the shared validator |
## Scene composition
- **Frontage:** 27 m wide, façade centre at z = -8.0, front face at z = -2.0.
- **Sidewalk:** 38 m wide × 14 m deep, meeting the kerb at z = 11.9.
- **Street:** 90 m × 24 m, with the four-lane markings reused from the
Hollywood block and a crosswalk in front of the entrance.
- **Playable area:** x = -15…15, z = -0.6…14.0. The guard starts on the west
side of the entrance at (-4.8, 0.1, 1.4), facing the approach.
- **Map budget:** the headless audit measures **22,680 triangles across 454
meshes**, well inside the 150k/700 test budget.
The same geometry serves the day and late-night looks. There is no second baked
map: the phase lighting, skyline/fog tint, lit windows and practicals change,
just as with the Hollywood day/night rows.
## Simplifications and limits
- The real club's rear rooms, basement and roof plant are not modelled; the
playable area is the street frontage only.
- The 47 m OSM footprint includes rear parcels and does not match the 27 m
street frontage; the game keeps the frontage proportions rather than the full
lot.
- Neighbouring businesses are represented by generic low-rise blocks. Their
exact names and current tenants were not verified, so the docs do not claim
them.
- The hillside is a background ramp with simplified houses, not a terrain
heightfield; it exists to restore the real silhouette above the roofline.
- Signage uses the fictional **The Joke Shop** name, not the real Comedy Store
wordmark.
- The concept frames are photoreal; the game keeps its stylized, low-poly
material treatment. The vision judge therefore still scores material and
foliage detail below the reference. The remaining texture/realism work is
tracked with the postponed 0.9.5 pass, not treated as a map-geometry defect.
## References
- OpenStreetMap way 428854155: <https://www.openstreetmap.org/way/428854155>
- Wikimedia Commons photographs used for proportion and material study:
- <https://commons.wikimedia.org/wiki/File:ComedyStore_01.jpg>
- <https://commons.wikimedia.org/wiki/File:ComedyStore_02.jpg>
- <https://commons.wikimedia.org/wiki/File:The_Comedy_Store.jpg>
- <https://commons.wikimedia.org/wiki/File:The_Comedy_Store_West_Hollywood_(51017780551).jpg>
- AI art-direction frames: [`screens/concepts/joke_shop/`](screens/concepts/joke_shop/README.md)
- Verification: `godot --headless --path . --script res://src/test/test_runner.gd`
(`test_joke_shop_uses_the_real_sunset_strip_layout`,
`test_joke_shop_geometry_stays_inside_the_map_budget`), and
`godot --path . --script res://src/test/capture_realism.gd -- --stages=joke_shop_day,joke_shop`.
The committed gallery passed `tools/check_screenshots.sh` (13 good / 0 bad)
and the screen-design judge (13/13 match, 0 diff). The latest local realism
run reports a reference gap of 0.454 for the night entrance.
+79
View File
@@ -0,0 +1,79 @@
# NPC proportion audit
Status: audited 2026-11-02. All eight library variants are inside the stylized
proportion guide; no geometry correction was required in this pass. The report
is repeatable from the exported GLBs:
```bash
python3 tools/npc_proportions.py report
python3 tools/npc_proportions.py report --json
```
## Method
`tools/npc_proportions.py` reads the GLB meshes and rest-pose joint hierarchy:
- height from the full mesh bounds;
- head height, width and aspect from `Head`/`skin` vertices (hair excluded so
long hairstyles do not change the head measurement);
- shoulder silhouette from vertices in the upper-chest band around the
shoulder joint;
- hip width from `HipL`/`HipR` pants vertices;
- torso length from the Spine joint to the shoulder joint;
- leg length from the Spine joint to the lowest vertex;
- arm length from the shoulder joint to the Hand joint;
- foot length from the forward extent of the KneeL/KneeR shoe vertices.
All ratios are divided by total standing height except `head_aspect`
(width / head height).
## Guide
These are stylized-but-credible bands for the game's low-poly adults, not
photoreal anatomy. The broad build is allowed a larger shoulder/hip silhouette
than the slim build.
| Ratio | Target | Notes |
| --- | ---: | --- |
| `head_height` | 0.16–0.22 | deliberately larger than a realistic 0.13–0.15 |
| `head_aspect` | 0.70–1.00 | width / height; rounded heads are acceptable |
| `shoulder_width` | 0.28–0.38 | silhouette includes sleeves and build scaling |
| `hip_width` | 0.17–0.23 | pants-only width, not skirt/coat flare |
| `torso_length` | 0.28–0.38 | Spine joint to shoulder |
| `leg_length` | 0.40–0.48 | Spine joint to ground |
| `arm_length` | 0.28–0.38 | shoulder to hand |
| `foot_length` | 0.12–0.18 | shoe forward extent |
## Result
| Character | Height | Head | Aspect | Shoulder | Hip | Torso | Leg | Arm | Foot | Result |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| `npc_casual` | 1.824 m | 0.190 | 0.907 | 0.321 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_jacket` | 1.824 m | 0.190 | 0.907 | 0.333 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_coat` | 1.824 m | 0.190 | 0.907 | 0.328 | 0.209 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_vest` | 1.819 m | 0.191 | 0.907 | 0.322 | 0.209 | 0.308 | 0.451 | 0.330 | 0.144 | PASS |
| `npc_dress` | 1.825 m | 0.190 | 0.907 | 0.289 | 0.191 | 0.307 | 0.449 | 0.329 | 0.144 | PASS |
| `npc_hoodie` | 1.856 m | 0.187 | 0.907 | 0.328 | 0.206 | 0.302 | 0.442 | 0.323 | 0.141 | PASS |
| `npc_firefighter` | 1.819 m | 0.191 | 0.907 | 0.358 | 0.223 | 0.308 | 0.451 | 0.330 | 0.148 | PASS |
| `npc_guard` | 1.819 m | 0.191 | 0.907 | 0.369 | 0.219 | 0.308 | 0.451 | 0.330 | 0.144 | PASS |
No variant is outside a band, so the body pass does not need a global skeleton
or mesh rescale. The values closest to a boundary are:
- **head height 0.190** against the 0.22 upper bound, and **head aspect 0.907**
against 1.00 — the head is deliberately large. Any head-size change must be
coordinated with the face/headgear pass and its gear-fit measurements.
- **guard shoulder 0.369** and **firefighter hip 0.223** against the broad-build
upper bounds — these are the intended uniform/turnout silhouettes, not
outliers.
- **leg length 0.449** and **torso 0.307** sit inside the guide for all variants;
the earlier short-leg impression came from the hip joint position, not the
visible pelvis line.
## Follow-up
The proportion audit does not replace the visual criteria in
[`npc-visual-review.md`](npc-visual-review.md): neck/shoulder/hip transitions,
face depth, hand grips, clothing hems and shoes still need the appearance pass.
Re-run the audit after any body mesh or skeleton change and record the new
ratios here.
+232
View File
@@ -0,0 +1,232 @@
# NPC visual baseline and acceptance criteria
Status: **accepted 2026-11-02 for the 0.9.4 stylized target.** The P1 fixes
(tourist photo-prop visibility, backpack straps), neck/shoulder and torso/hip
transitions, face depth/detail, hand and gear placement, headgear clearance and
shoe/boot silhouettes are applied. The baseline remains the comparison reference;
the accepted limitations are listed below. Comparison sheets:
[`sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg),
[`sheet_npc_baseline_compare-body.jpg`](blender_previews/sheet_npc_baseline_compare-body.jpg),
the latest [`sheet_npc_baseline_compare-torso.jpg`](blender_previews/sheet_npc_baseline_compare-torso.jpg),
the face-detail pass [`sheet_npc_baseline_compare-face-detail.jpg`](blender_previews/sheet_npc_baseline_compare-face-detail.jpg),
the conversation-distance hand pass
[`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg), and the
forward-grip pass [`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg).
## What was captured
`src/test/capture_npc_baseline.gd` stages all eight library characters in a
neutral studio and captures six views per character:
| View | Camera | Purpose |
| --- | --- | --- |
| `front` | 1.85 m, 32° FOV, head/upper body | face, hair, collar, shoulders |
| `three_quarter` | 1.85 m, yaw 35° | cheek/jaw, ear, profile transition |
| `profile` | 1.85 m, yaw 90° | head depth, nose, ear, chest silhouette |
| `back` | 1.85 m, yaw 180° | hair cap, neck, coat/backpack fit |
| `full_body` | 4.2 m, 38° FOV | proportions, hands, shoes, hem |
| `crowd` | 8.0 m, 45° FOV | silhouette read at normal crowd distance |
The stage is deliberately separate from the venue review harness: a mid-grey
solid background, ground plane, one key light and one cool fill light, no HUD,
no crowd, no flashlight, no phase lighting and no animation. Front is Godot +Z,
matching `NpcAvatar.yaw_towards()`. The camera orbits at the recorded yaw rather
than rotating the avatar, so the pose and foot contact stay fixed between views.
The full command is:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-baseline
python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline
```
The 48 raw PNGs are local QA under `tmp/` (gitignored). The committed contact
sheet is [`blender_previews/sheet_npc_baseline.jpg`](blender_previews/sheet_npc_baseline.jpg).
For the P2 hand/grip check there is an optional eighth view, captured separately
so the 48-frame baseline stays stable:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-hands --view=hand
```
That writes eight `*__hand.png` frames at 0.80 m from the right hand; the
before/after review image is
[`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg).
The capture is deterministic apart from engine rasterisation; re-running into
the same directory keeps the earlier files and writes `-vN` copies rather than
overwriting them.
## Acceptance criteria
The criteria below are for the stylized target, not photorealism. A change must
pass every applicable item before a library rebuild is accepted.
1. **Asset contract:** `npc_base` mesh node, the required bones, five tint slots,
front +Z, feet within 3 cm of y=0, 1.6–2.1 m height, at most 8,000 triangles
and 8,000 glTF vertices per library character. The frozen `npc_base` fallback
keeps 6,000 triangles / 4,000 vertices. Gear remains at most 1,500 triangles.
2. **Proportion and silhouette:** head, neck, shoulders, torso, hips, limbs and
feet read as one body; front/three-quarter/profile silhouettes agree with the
rest of the eight-character library; broad/slim/average build variation is
preserved.
3. **Face:** at 1.85 m the eyes, iris, brows, nose, mouth and ears are distinct;
the head volume has a readable jaw/cheek/chin transition; no face-plane seams,
inverted normals or z-fighting. The face direction must remain unambiguous.
4. **Hair and headgear:** hair covers the scalp without gaps or scalp-through
seams; fringes, buns and beards keep their silhouette. Caps, beanies, hoods,
sunglasses and the firefighter helmet clear the brow, eyes and ears. Headgear
may sit outside the 1.55–1.81 m face band, but its brim must not cover the
eyes.
5. **Hands and footwear:** at conversation distance the fingers and thumb read
as a hand, not a mitten; hand items contact the palm rather than floating;
shoes and boots are grounded with a readable toe/heel silhouette and preserve
the responder/firefighter footwear language.
6. **Clothing:** collars, cuffs, plackets, waistbands, pockets, badges and
reflective bands transition cleanly; no z-fighting or floating detail; coat,
dress and skirt hems do not show legs through the fabric during idle, walk,
block, sit or turn; the five tint slots and fixed detail colours remain
unchanged.
7. **Gear:** head gear clears the refined face/hair; the lanyard badge remains
readable in front of the jacket; backpack, shoulder bag and SCBA tank straps
lie outside the torso and do not read as a second bag; hand items use the
authored grip points.
8. **Crowd and performance:** the silhouette remains readable at the 8 m crowd
frame and the LOD/impostor tiers match the full mesh; the 24-NPC budget stays
within the existing 6.93 ms baseline (no regression beyond the measured
variance), and no new per-frame material or mesh churn is introduced.
Asset-space `fit` values are measurements of the untouched GLBs, not a pass/fail
result. A negative `x_clearance` means the gear's narrowest face is inside the
body reference; a negative `radial_clearance` means it extends beyond the body
silhouette (normal for a backpack, suspicious when it is a strap). Runtime
`NpcAvatar.GEAR_OFFSETS` is applied after attachment and is not part of the GLB
measurement.
## Proportion audit
The separate [`npc-proportion-audit.md`](npc-proportion-audit.md) measures
height, head size, shoulder/hip width, torso, leg, arm and foot ratios for every
variant with `tools/npc_proportions.py`. All eight pass the stylized guide; the
head and broad-build shoulders sit nearest their upper bounds. No skeleton or
mesh proportion change was needed in this pass.
## Baseline measurements
From `python3 tools/blender_assets.py fit` and the manifest:
| Character | Tris | Verts | Head width | Clothing radius | Notable gear clearances |
| --- | ---: | ---: | ---: | ---: | --- |
| `npc_casual` | 4,482 | 4,260 | 0.315 m | 0.191 m (hip) | backpack x −0.041, radial −0.162 |
| `npc_jacket` | 4,872 | 4,661 | 0.315 m | 0.191 m (hip) | lanyard x −0.116, radial +0.023 (runtime +4 cm forward) |
| `npc_coat` | 5,474 | 5,264 | 0.315 m | 0.225 m (skirt) | sunglasses width ratio 0.641; bag x +0.037, radial −0.130 |
| `npc_vest` | 4,980 | 4,879 | 0.315 m | 0.191 m (hip) | cap width ratio 1.067 |
| `npc_dress` | 4,900 | 4,719 | 0.315 m | 0.260 m (skirt) | bag x +0.002, radial −0.095 |
| `npc_hoodie` | 5,304 | 4,950 | 0.315 m | 0.190 m (hip) | — |
| `npc_firefighter` | 5,344 | 5,494 | 0.315 m | 0.255 m (skirt) | helmet width ratio 1.651; SCBA x −0.105, radial −0.076 |
| `npc_guard` | 5,046 | 5,096 | 0.315 m | 0.194 m (hip) | cap width ratio 1.067 |
`npc_coat` is widest at 5,474 triangles (2,526 below the 8,000 cap);
`npc_firefighter` is closest on vertices at 5,494 (2,506 below the 8,000 cap).
The refit backpack measures 380 triangles / 406 vertices.
## Baseline findings, ranked
### P1 — fix in the first model pass
1. **The tourist carried two bag silhouettes. Fixed 2026-11-02.** `_add_props()`
created a 0.30 × 0.36 × 0.14 box at `(-0.34, 1.15, -0.18)` for the tourist
photo pose while `_add_accessory("backpack")` also attached the library
backpack. From the three-quarter/back view the two read as separate bags. The
photo prop is now hidden outside `photo`/`film` poses
(`photo_prop_visible_for_pose()`), so it only appears when the character is
actually taking a picture; the after frame confirms one bag at rest.
2. **Face depth and detail. Fixed 2026-11-02.** The sclera was recessed into the
socket and wrapped with a thin upper lid; the separate jaw/cheek spheres were
replaced by a chin plate and cheekbones sculpted into the head mesh. The nose
now has ala wings and a smaller bridge/tip, the mouth is one rounded slot
instead of a flat bar, and the ears have a darker concha. That removes the
dark intersection rings and the moustache-like read at portrait distance; the
low-poly brows remain stylized.
3. **Backpack straps read as rigid black bars. Refit 2026-11-02.** The straps
were thin round tubes whose chest/waist points sat inside the torso, so only
fragments showed from the front. They are now flattened bands whose front path
sits outside the chest; the after sheet shows a continuous strap instead of
two detached rods. The backpack asset is now 380 triangles / 406 vertices
(still far below the 1,500-triangle gear budget).
### P2 — fix after the first P1 pass
4. **Hands: geometry and forward offset fixed 2026-11-02; finger curl still
open.** The palm is wider and shallower, and each finger is now a
two-segment bent tube with a rounded tip and a separate bent thumb. Hand gear
is authored around the wrist proxy, so the runtime now moves every hand item
`HAND_ITEM_FORWARD` (4 cm) into the open palm; the phone, flashlight, camera,
cup and clipboard are no longer buried inside the hand. The fingers are still
open, so a true wrap/thumb contact and the umbrella/sign grips remain to be
judged.
5. **Clothing detail is tile-driven and transitional seams are visible.** The
fabric pattern repeats strongly on the casual, coat and dress variants, and
collar/cuff/waist edges are abrupt. This is more visible than the shoe/hem
details in the current portraits.
6. **Shoes: fixed 2026-11-02.** Casual shoes gained rounded toe and heel caps;
responder/firefighter boots gained matching toe/heel volumes while keeping the
taller black rubber boot language. Both stay above the sole contact plane, and
the full-body comparison is `sheet_npc_baseline_compare-shoes.jpg`.
7. **Headgear scale and clearance. Checked 2026-11-02.** The cap and helmet
width ratios are 1.067 and 1.651; those are expected for headgear. Final-context
portraits confirm the cap, firefighter helmet, hood and sunglasses clear the
refined brow/eyes, and the helmet brim still reads as deliberate turnout gear.
No gear rebuild was needed.
8. **Performer props dominate the silhouette.** The red cone hat and the
primitive sign are intentionally large stage props, but they should be
checked during the pose pass so they do not read as head/body geometry.
### Accepted limits for the 0.9.4 release
- The hooded variants intentionally cover part of the face; face readability is
judged on the visible lower face and silhouette, not on hidden eyes.
- The low-poly style is the target. The acceptance bar is readability and clean
construction, not photoreal skin or hair.
- Held items use the forward-offset open palm (`HAND_ITEM_FORWARD`) rather than a
finger-curl rig. There are no finger bones in the contract; phone, cup,
clipboard, camera, flashlight, wand and radio were judged in the hand capture.
- Fabric folds are not separate geometry; the current torso, elbow and knee
shaping is the accepted stylized construction.
- The >26 m impostor remains a two-quad billboard; the LOD tier/hysteresis and
near/far swap are covered by `test_avatar_mesh_budget_and_lod_swap`.
- Evening readability is represented by the day/night/LATE final-context set;
LATE is the venue night variant.
## Before/after workflow
Keep the baseline directory, rebuild the same capture into a new directory after
the model changes, then produce a comparison sheet. Do not overwrite the
committed baseline image:
```bash
godot --path . --script res://src/test/capture_npc_baseline.gd -- \
--out=res://tmp/npc-baseline-after
python3 tools/npc_baseline.py compare \
--before tmp/npc-baseline --after tmp/npc-baseline-after \
--out tmp/npc-baseline-compare.jpg
```
The comparison sheet places the before/after pair for each view side by side.
The committed runs are
[`sheet_npc_baseline_compare-p1.jpg`](blender_previews/sheet_npc_baseline_compare-p1.jpg),
[`sheet_npc_baseline_compare-body.jpg`](blender_previews/sheet_npc_baseline_compare-body.jpg)
and [`sheet_npc_baseline_compare-face.jpg`](blender_previews/sheet_npc_baseline_compare-face.jpg).
The transition pass is [`sheet_npc_baseline_compare-torso.jpg`](blender_previews/sheet_npc_baseline_compare-torso.jpg).
The face-detail pass is [`sheet_npc_baseline_compare-face-detail.jpg`](blender_previews/sheet_npc_baseline_compare-face-detail.jpg).
The hand pass is [`sheet_npc_hands_compare.jpg`](blender_previews/sheet_npc_hands_compare.jpg);
the forward-grip pass is
[`sheet_npc_hands_grip_compare.jpg`](blender_previews/sheet_npc_hands_grip_compare.jpg).
Keep the baseline sheet as the before artifact and add a new comparison sheet
rather than replacing it.
## Next implementation order
0.9.4 is closed. The next visual work belongs to the 0.9.5 texture pass and the
0.10.0 acceptance review; keep the NPC baseline/final-context commands as the
regression gate for any future character edit.
-293
View File
@@ -1,293 +0,0 @@
# Development Plan — Graphics Quality v0.6.0 (Blender-authored NPCs)
> Status: Proposed · Target version: **v0.6.0** (MINOR)
> Companion decision: [ADR-0013](adr/0013-blender-authored-npc-characters.md)
## Why this exists
The game is functionally complete through v0.5.0, but NPCs are still the
procedural capsule-and-box rig from [ADR-0010](adr/0010-procedural-npc-presentation.md).
They read as people at conversation distance but not at cinematic distance, and
every surface on a body is a flat color. ADR-0010 recorded that "a later
skinned-mesh pass will replace this rig and must keep the `Head` contract" —
this plan is that pass.
The goal is **better NPCs first**, then a modest environment lift, using the
existing AI tooling for art direction and quality gates, and **Blender** for the
geometry, UVs, skeleton, and baked material maps.
## Constraints that shape the plan
- **Renderer is GL Compatibility** (`project.godot` `config/features`). SSAO,
SSIL, and volumetrics are unavailable. Quality therefore comes from better
meshes, baked maps (AO/normal/roughness), and lighting — not from a renderer
switch.
- **CI builds offline.** `.gitea/workflows/build.yml` runs the Godot editor only
(no Blender, no network). Everything the game loads must be committed; the
Blender step is a developer tool, and the game keeps a procedural fallback so a
fresh checkout still boots and the headless suite still passes.
- **Determinism.** Seed-driven variety (`outfit_for`, `layer_for`,
`hand_item_for`, `idle_style_for`) must keep working and keep its tests green.
AI generation is a dev-time input, not a runtime dependency; the committed
assets are the source of truth.
- **Frame budget.** v0.5.0 measured 16 avatars = 534 meshes ≈ 6.9 ms headless.
A skinned rig replaces ~33 draw calls per avatar with one skin, but skinning
costs CPU. Re-measure with `src/test/smoke_npc_budget.gd` before raising
`MAX_LIVE_NPCS`.
## The NPC asset contract (what must not break)
From `src/game/npc_avatar.gd` and `src/game/guard_controller.gd`:
- A scene-level node named **`Rig/Head`** — `GuardController` raycasts for it
(`get_node_or_null("Rig/Head")`), and the focus circle + name tag + reaction
tag attach under it.
- Limb pivots currently named `HipL`/`HipR` → `Knee`, `ShoulderL`/`ShoulderR` →
`Elbow` → `Hand`. `_animate()` and `_idle_layer()` drive them by `rotation.x`.
- Pure static helpers must stay pure and seed-deterministic: `outfit_for`,
`layer_for`, `hand_item_for`, `idle_style_for`, `queue_slot_for`,
`lod_tier_for_distance`, `reaction_label`, `crouch_for_pose`,
`prop_lift_for_pose`, `limb_swing`, `sway_for_pose`.
- LOD tiers (`apply_lod`, 0 / 1 / 2 with a billboard impostor at tier 2) must
keep working; `_detail_nodes` are hidden at tier 1.
- `set_focus_visual`, `_focus_circle`, `_name_tag`, `_reaction_tag`, the
theater poses, and the crowd reaction (`start_rubberneck`, `start_flee`) all
operate on the rig and must survive the swap.
## Workstreams
### Phase 0 — Toolchain spike and contract freeze (small, throwaway)
1. Confirm headless Blender works in this environment. Blender **5.2.0 LTS**
flatpak is installed; the sandbox cwd is `/app/blender`, so `--python` and
all input/output paths must be absolute:
```bash
flatpak run org.blender.Blender --background \
--python /var/home/zwitschi/Documents/06-games/security-game/tools/npc_pipeline.py -- --build
```
Record the working invocation in `MEMORY.md` (the Im-Dornäcker notes already
warn about the cwd gotcha).
2. Freeze the asset contract in writing (this document + ADR-0013). No
animation clips are exported: `_animate()` and `_idle_layer()` drive the
armature bones directly at runtime, so the GLB only needs the skinned rest
mesh, the armature, and the material maps.
- `assets/models/generated/npc_base.glb` — one skinned mesh (or a small fixed
set of sub-meshes: body / head / hands) with a **named armature** and UVs.
- Material slots rather than one atlas-per-prop: `skin`, `cloth`,
`pants`, `accessory`, `hair` each carry a neutral albedo + normal + ORM
(occlusion/roughness/metallic) map. `outfit_for` colors tint the slot, so
multi-color outfits and seed variety survive.
- Bone names mirror the current node names (`Head`, `HipL/R`, `KneeL/R`,
`ShoulderL/R`, `ElbowL/R`, `HandL/R`) so `_animate()` can target them.
- Budget: tier-0 base body ≤ ~6,000 triangles, ≤ ~4,000 vertices (revisit
after the first `smoke_npc_budget.gd` run).
### Phase 1 — `tools/npc_pipeline.py`: author + export + audit
New tool, run through the Blender flatpak, mirroring the `model_pipeline.py`
shape (`list` / `build` / `audit`):
1. **Author** a low-poly base humanoid in Blender: torso, articulated arms/legs,
head with a face front (so the focus ring and the "noticed the guard" cue
keep a direction), hands, shoes. Keep the current silhouette language
(heads, caps, hoods, backpacks, lanyards) so existing `outfit_for`
accessories still attach.
2. **Rig** it with an armature whose bones are named to match the node contract.
Godot 4.3 imports glTF skeletons as `Skeleton3D`; keep the bone rest pose
matching the current `_animate()` assumptions (arms hang, legs straight,
+Y up, origin at the feet on the floor).
3. **UV-unwrap** into a power-of-two layout and **bake** maps in Blender from
node materials or a higher-detail source:
- neutral albedo (white fabric pattern) per material slot,
- normal map (fabric weave, denim, knit),
- ORM map (occlusion in R, roughness in G, metallic in B — same packing
`model_pipeline.atlas_for` already uses),
- ambient occlusion baked into the albedo or the ORM R channel (this is the
Compatibility renderer's only AO source).
4. **Export** `npc_base.glb` with materials referenced as Godot-importable
textures (or export textures alongside and wire them in GDScript — decide in
the spike).
5. **Audit** (`npc_pipeline.py audit`) enforcing: UVs in [0,1], expected bone
names present, triangle/vertex budget, feet at y ≈ 0, no missing material
slots. Reuse the checks and the colour-space discipline from
`model_pipeline.py` (glTF `baseColorFactor` is linear; albedo textures are
sRGB — do not mix them up).
6. **Commit** the `.blend` source (`assets/models/npc/npc_base.blend`) so the
build is reproducible and editable, plus the generated `.glb` + textures so
CI never needs Blender.
### Phase 2 — AI-assisted texturing (existing tools only)
Use the tools already in `tools/`, not new services:
1. `tools/asset_pipeline.py generate` (OpenRouter,
`openai/gpt-5-image-mini`) for seamless clothing albedos — shirt, trousers,
jacket, hi-vis vest, coat, dress — at the role sizes its `audit` validates.
Run `seamless` for tile-edge blending and `audit` to reject wrong sizes.
2. `tools/model_pipeline.py`'s palette helpers (`dominant_colors`,
`assign_roles`) or a small shared import, to derive per-role outfit palettes
from AI concept sheets (`concept`). `outfit_for` keeps determinism: the AI
supplies palettes and textures, never per-frame randomness.
3. Normal/roughness detail (fabric weave, denim) baked procedurally in Blender,
with the AI albedos layered on top.
4. Close the loop with `tools/screen_designs.py judge`: regenerate the staged
captures and confirm the new NPCs realise the same screen intents (art style
is ignored by the judge; layout and readability are not).
Outputs land under `assets/textures/ai/game_ready/` (or a new
`assets/textures/npc/`) and are **committed**.
### Phase 3 — Godot integration (`npc_avatar.gd`, `materials.gd`)
1. Add a `_load_model()` path in `NpcAvatar` that instantiates the imported
`npc_base.glb` `PackedScene`, exactly like `WorldBuilder._add_prop_model()`
loads props. Keep `_build_body()` as the offline/procedural fallback; choose
per-avatar with the same "asset or fallback" pattern (record the choice in a
`loaded_model` / `fallback_avatar` field for tests).
2. Map `outfit_for()` onto the model's material slots (skin/cloth/pants/
accessory/hair) so seed variety, `layer_for`, `hand_item_for`, and the
archetype color read stay intact. Accessories (cap/hood/backpack/
sunglasses/lanyard) keep attaching under `Rig`/`Head` as they do today.
3. Add `SurfaceMaterials` recipes for the baked maps — e.g. `npc()` /
`skin()` / `cloth()` — so `_material()` gains a textured path and the body
stops calling `Materials.flat()`.
4. Abstract the animation targets so `_animate()` / `_idle_layer()` write to
either the procedural `Node3D` pivots (fallback) or `Skeleton3D` bones
(skinned). Keep the existing `rotation.x` math; the abstraction is a thin
`_set_limb_rotation(part, axis, radians)` wrapper.
5. Keep `Rig/Head` as a real scene node (a marker following the head bone, or
the imported bone's Godot node) so focus, nametag, and head-turn still find
it. Re-verify the focus cone smoke and `test_npc_character` /
`test_npc_theater` / `test_target_cycle`.
6. Re-measure `smoke_npc_budget.gd`; adjust `LOD_TIERS` if the skinned rig is
heavier up close. The impostor path is unchanged.
### Phase 3.5 — Blender asset library (characters, gear, props)
The library generator is `tools/blender_assets.py` (flatpak Blender, headless).
**Status: integrated** — `NpcAvatar` selects characters/gear and `WorldBuilder`
loads the replacement/new props plus phase-driven emissives; the procedural rig
and primitive props remain fallbacks. Integration notes:
[`blender-assets.md`](blender-assets.md).
**Outputs and contract**
| Kind | Path | Notes |
| --- | --- | --- |
| Characters | `assets/models/blender/npc/<name>.glb` | 8 variants: `npc_casual`, `npc_jacket`, `npc_coat`, `npc_vest`, `npc_dress`, `npc_hoodie`, `npc_firefighter`, `npc_guard` |
| Gear | `assets/models/blender/npc_gear/<name>.glb` | 18 pieces; authored in attach-point space (`head`, `hand`, `back`, `chest`) |
| Props | `assets/models/blender/props/<name>.glb` | 20 pieces; the first nine replace current generated/primitive street furniture, the rest are new venue dressing |
| Manifest | `assets/models/blender/manifest.json` | path, category, triangles, vertices, bounds, materials, roles, tint slots, attach points |
| Sources | `assets/models/blender_src/<name>.blend` | committed, editable source |
| Previews | `docs/blender_previews/sheet_<category>.jpg` (committed) + per-asset `*.png` (local) | `render` / `sheet` for visual review |
All characters reuse the `npc_base` contract: mesh node `npc_base`, bones
`Head/HipL/R/KneeL/R/ShoulderL/R/ElbowL/R/HandL/R` (+ Hips/Spine/Neck),
material slots `skin/cloth/pants/accessory/hair`, front toward Blender `-Y`
(Godot `+Z`), feet at `y ~= 0`. Gear origins are the attach points (head at
`Rig/Head`, hand at the hand proxy, back at the spine, chest at the sternum).
Props are grounded except `wall_lantern` and `marquee`; both may be emissive.
**Integration steps**
1. **Audit the finished build.** `python3 tools/blender_assets.py audit` and
`sheet`; fix assets or reconcile the budgets. **Done 2026-11-01:** the
characters were simplified to fit the unchanged 6,000 / 4,000 contract
(3,788–4,640 tris), and all 46 assets audit clean.
2. **Commit the library and sources.** Add `assets/models/blender/**`,
`assets/models/blender_src/**`, the generator, manifest, previews, and
`docs/blender-assets.md`; generated folders that CI can rebuild offline may
stay ignored. `blender_assets.py audit` must work without Blender.
3. **Select characters by role.** Extend `NpcAvatar` to pick a variant from the
manifest using the profile's role and `outfit_for`/`layer_for` (casual,
jacket, coat, vest, dress, hoodie, firefighter, guard). Fall back to
`npc_base.glb`, then to the procedural rig, and record the chosen path.
4. **Tint and anchor.** Apply `outfit_for` to every variant's five slots via
`SurfaceMaterials.npc_slot()`; keep `Rig/Head` for the focus circle, name tag,
reaction tag, and accessories. Keep the walk/idle/escalation bone-driving
wrapper.
5. **Replace procedural gear.** Use the `npc_gear` catalogue for caps, hoods,
helmets, backpacks, lanyards, hand items (phone, cup, clipboard, umbrella,
camera, sign, flashlight, wand, radio) and the SCBA tank; attach at the
documented points and fall back to the current primitives when an asset is
missing.
6. **Replace and extend props.** Load the replacement set through
`WorldBuilder` (`bollard`, `bench`, `trash_bin`, `planter_box`,
`newspaper_box`, `fire_hydrant`, `street_lamp`, `street_tree`,
`traffic_cone`), then place the new dressing (`palm_tree`, `round_planter`,
`a_frame_sign`, `wall_lantern`, `crowd_barrier`, `stanchion`, `handrail`,
`security_podium`, `double_door`, `marquee`, `sedan`) using the existing
placement table/collider/avoidance contract. No prop may enter the
door/steps/guest lane.
7. **Wire emissives to the phase.** Street-lamp bulbs, wall lanterns, the door
lock LED, marquee bulbs/sign face, and sedan headlights should follow the
existing day/night lighting rather than staying always on.
8. **Measure and gate.** Re-run `smoke_npc_budget.gd` with the new characters
before raising `MAX_LIVE_NPCS`; add a prop triangle/draw budget check. Then
recapture `docs/screenshots/` and run `screen_designs.py compare` + `judge`
plus a close-up target shot for character readability.
9. **Fallbacks stay offline.** A fresh checkout with no Blender and no network
must boot on the committed library (or `npc_base.glb`/procedural rig when an
asset is absent); CI still runs the Godot import and headless suite.
### Phase 4 — Environment and lighting lift (after NPCs land) ✅
1. **Baked AO on props:** use the Phase 3.5 Blender prop replacements
(`street_lamp`, `street_tree`, `bench`, …) and bake AO into their
albedo/ORM maps so contact shadows read without SSAO. Keep the same
`WorldBuilder` load/fallback contract (ADR-0012's follow-up).
2. **Higher-resolution environment textures:** regenerate brick/concrete/asphalt
through `asset_pipeline.py` with normal maps, keeping the current UV scales;
use the same sRGB/albedo + packed ORM discipline as the library assets.
3. **Evaluate a desktop-only Forward+ preset** — done: it boots on the desktop Vulkan
driver, but the renderer is project-wide and the Web preset must stay GL
Compatibility. v0.6.0 keeps Compatibility; a desktop-only override is deferred.
4. Regenerate `docs/screenshots/` with `capture_screenshots.gd`, then run
`screen_designs.py compare` and `judge` as the regression gate, plus
`blender_assets.py sheet` for the character/gear/prop library.
### Phase 5 — Verification and release
- Headless: fallback build, `npc_pipeline.py audit` (via `test_model_pipeline`
style Python tests if Blender is present, otherwise skip with reason), outfit
determinism, `Rig/Head` presence, material recipe assertions.
- Windowed smokes: `smoke_npc_budget.gd`, `smoke_movement.gd`,
`smoke_focus_radial.gd`, `smoke_props.gd`; screenshot comparison.
- Bump `config/version` to `0.6.0`, update `README.md`, `docs/architecture.md`
(Level 2 gains `tools/npc_pipeline.py`), and publish per
[`docs/RELEASING.md`](RELEASING.md).
## Risks and mitigations
| Risk | Mitigation |
| --- | --- |
| Blender flatpak sandbox paths (cwd `/app/blender`) | Absolute paths everywhere; record the invocation in `MEMORY.md`. |
| glTF colour space (linear factors vs sRGB textures) | Reuse `model_pipeline.srgb_to_linear`; bake textures as sRGB, keep factors linear; assert in `audit`. |
| Skeleton retargeting vs current node math | Keep the bone names + a thin limb-rotation wrapper; fallback rig keeps old math running. |
| Frame budget with skinned avatars | Measure first (`smoke_npc_budget.gd`); tune `LOD_TIERS`; impostor path unchanged. |
| No SSAO in Compatibility | Bake AO into albedo/ORM; contact-shadow tune in Phase 4. |
| AI output nondeterminism | Generation is dev-time only; commit outputs and gate with `audit`/`judge`/`compare`. |
| Blender unavailable in CI | Committed `.glb` + textures; procedural fallback; `audit` skipped with reason when Blender is absent. |
## Acceptance criteria (definition of done)
1. NPCs and street furniture are Blender-authored meshes with baked maps; the
character variants, gear, and props read as people/objects at conversation
distance and survive a cinematic close-up.
2. `Rig/Head`, the focus cone, nametag, theater poses, crowd reactions, and LOD
all still work; all existing NPC tests pass unchanged or are updated with
clear reasons.
3. The game boots and plays from a fresh checkout with **no** Blender and no
network (committed assets + procedural fallback).
4. `npc_pipeline.py build` is deterministic and `audit` enforces the contract.
5. 212 headless + 60 Python tests stay green (Blender-dependent Python tests
skip with a reason when Blender is absent); `npc_pipeline.py audit` and
`blender_assets.py audit` pass; NPC-budget and movement smokes pass;
screenshot `compare`/`judge` and the library contact sheets show no
regressions.
6. The library is committed with its generator/manifest/previews, runtime
selection and fallbacks are covered by tests, version bumped to v0.6.0,
docs and ADR-0013 updated, release published.
+14
View File
@@ -0,0 +1,14 @@
# Screen-design judge report
Date: 2026-11-02
Model: automatic cheapest image+JSON selection (`z-ai/glm-5.3-flash` at run time)
Command: `python3 tools/screen_designs.py judge`
Result: **21/21 match, 0 review, 0 diff**
The screenshot gallery was regenerated on the current build before judging, including the eight UI-state captures 14–21 added in `src/test/capture_ui_states.gd`.
Accepted captures are in [`docs/screens/`](screens/README.md); the committed
gallery is in [`docs/screenshots/`](screenshots/README.md).
The automatic model selection and retry/spend behavior is documented in
[`docs/asset-tooling.md`](asset-tooling.md). This report intentionally records
the outcome rather than generated captures, which remain local/gitignored.
+17
View File
@@ -0,0 +1,17 @@
# Screens and Visual Evidence
Visual references and generated QA evidence for Gig Line.
- [`concepts/README.md`](concepts/README.md) — AI-assisted realism concept frames
- [`designs/README.md`](designs/README.md) — screen-design mockups
- [`../screenshots/README.md`](../screenshots/README.md) — committed game gallery
- `realism/` — locally generated realism runs (gitignored; no README requirement)
## Quick preview
| Screen | Reference | Current capture |
| --- | --- | --- |
| Venue | <img src="designs/venue_overview.png" width="320" alt="Venue design"> | <img src="../screenshots/01-venue-overview.png" width="320" alt="Venue capture"> |
| Joke Shop | <img src="concepts/joke_shop/joke_shop_entrance_day.png" width="320" alt="Joke Shop reference"> | <img src="../screenshots/12-joke-shop.png" width="320" alt="Joke Shop capture"> |
| TV Studio | <img src="designs/studio_arrival.png" width="320" alt="Studio design"> | <img src="../screenshots/13-studio-arrival.png" width="320" alt="Studio capture"> |
| El Capitan | <img src="concepts/hollywood_boulevard/hollywood_boulevard_entrance_day.png" width="320" alt="El Capitan reference"> | <img src="../screenshots/01-venue-overview.png" width="320" alt="El Capitan capture"> |
+97 -35
View File
@@ -1,41 +1,103 @@
# Scene concepts: the realistic target look # Scene concepts: the realistic target look
These are AI-generated example frames (`python3 tools/scene_concepts.py generate --group scene`, These are AI-generated example frames (`python3 tools/scene_concepts.py generate --group scene`, `openai/gpt-5-image-mini`, 1280×720) for the realism pass. They are art direction, not assets. `tools/scene_concepts.py realism` pairs them with the in-game shots from `src/test/capture_realism.gd` (see `SHOTS` in the tool). New generations never overwrite a file here; they are saved as `<name>-vN.png`.
`openai/gpt-5-image-mini`, 1280×720) for the realism pass. They are art direction, not
assets. `tools/scene_concepts.py realism` pairs them with the in-game shots from
`src/test/capture_realism.gd` (see `SHOTS` in the tool). New generations never overwrite a
file here; they are saved as `<name>-vN.png`.
| Concept | Visual targets it sets | ## Real-world Hollywood block
| --- | --- |
| `hollywood_entrance_morning` | warm low sun, long soft shadows, brick with visible mortar and wear, stone plinth, potted topiary, haze that fades the far street to beige |
| `hollywood_entrance_golden_hour` | strong back light and rim light on people, marquee bulbs reading even in daylight |
| `hollywood_entrance_rain_night` | dark scene lit by practical lights only (marquee, sodium lamps), wet glossy ground with reflections, fog |
| `boulevard_skyline_day` | deep layered skyline with real towers and haze, palms lining the road, red curb paint, believable asphalt |
| `boulevard_skyline_dusk` | purple/orange gradient sky, neon signs, lit windows, car light trails |
| `joke_shop_alley_evening` | narrow brick alley, one warm wall lantern as key light, deep shadows, people in dark jackets |
| `joke_shop_door_closeup` | close material detail: brick, mortar, aged wood door, brass |
| `studio_stage_door_night` | granite facade, a bright bulb canopy as the main light, a glossy black car, stanchions and a barrier |
| `sidewalk_material_closeup` | paver joints, stains, granite curb, aggregate asphalt and a tree grate at grazing light |
| `entrance_steps_podium` | granite steps, handrails, glass doors, the check-in podium |
| `crowd_barrier_line` | steel barriers, a red carpet, a crowd with depth-of-field haze |
| `responder_arrival_wide` | fire engine, turnout gear, red/blue light spill on wet pavement |
| `npc_portrait_day` | close portrait of a pedestrian: skin with visible pores and stubble, fabric weave, shallow depth of field. The bar for an avatar close-up, not for the crowd shots |
The `npc_portrait` capture in `capture_realism.gd` is staged, not posed by the The map-optimization references for the El Capitan Entertainment Centre block
crowd: it freezes one NPC on an open patch of sidewalk, parks the rest of the (6840 Hollywood Blvd) are in
crowd out of frame, turns the subject into the camera and stands the guard on the [`hollywood_boulevard/README.md`](hollywood_boulevard/README.md). The real-site
sunlit side. It is the only shot where a face fills the frame, so it is the one to facts and game mapping are documented in
eyeball after an avatar change (`docs/screens/realism/2026-11-01-npc/`). [`../../hollywood-boulevard-map.md`](../../hollywood-boulevard-map.md).
Cross-cutting targets, for comparison with the 2026-11-01 captures in ## Concept list
`docs/screens/realism/2026-11-01-v2/sheet.jpg`:
- **Exposure.** The concepts keep the ground mid-grey. The game's sidewalk is close to white, ### Hollywood Entrance
so it is overexposed.
- **Night means dark.** The night/dusk concepts are lit by practical lights. The game's ![hollywood entrance morning](hollywood_entrance_morning.png)
"Evening" phase is a bright pink-orange frame. warm low sun, long soft shadows, brick with visible mortar and wear, stone plinth, potted topiary, haze that fades the far street to beige
- **Depth.** The concepts show a layered skyline fading into haze. The new v2 skyline strips
supply this; the old box skyline did not. ### Hollywood Entrance Golden Hour
- **Geometry and foliage.** The facades have plinths, cornices and deep window reveals, and the
trees and shrubs are organic. The game uses flat walls and blob trees. ![hollywood entrance golden hour](hollywood_entrance_golden_hour.png)
strong back light and rim light on people, marquee bulbs reading even in daylight
### Hollywood Entrance Rain Night
![hollywood entrance rain night](hollywood_entrance_rain_night.png)
dark scene lit by practical lights only (marquee, sodium lamps), wet glossy ground with reflections, fog
### Boulevard Skyline
![boulevard skyline day](boulevard_skyline_day.png)
deep layered skyline with real towers and haze, palms lining the road, red curb paint, believable asphalt
### Boulevard Skyline Dusk
![boulevard skyline dusk](boulevard_skyline_dusk.png)
purple/orange gradient sky, neon signs, lit windows, car light trails
### The Joke Shop — Sunset Strip
The current Joke Shop map is based on The Comedy Store at 8433 Sunset Blvd.
The real-site mapping, simplifications and reference photographs are in
[`../../joke-shop-map.md`](../../joke-shop-map.md); the frames are in
[`joke_shop/README.md`](joke_shop/README.md).
![Joke Shop entrance in daylight](joke_shop/joke_shop_entrance_day.png)
![Joke Shop entrance at night](joke_shop/joke_shop_entrance_night.png)
### Legacy Joke Shop Alley (pre-map optimization)
![joke shop alley evening](joke_shop_alley_evening.png)
narrow brick alley, one warm wall lantern as key light, deep shadows, people in dark jackets
![joke shop door closeup](joke_shop_door_closeup.png)
close material detail: brick, mortar, aged wood door, brass
These two frames describe the old alley layout and are retained for comparison;
they are no longer the target for the Joke Shop map.
### Studio Stage Door Night
![studio stage door night](studio_stage_door_night.png)
granite facade, a bright bulb canopy as the main light, a glossy black car, stanchions and a barrier
### Sidewalk Material Closeup
![sidewalk material closeup](sidewalk_material_closeup.png)
paver joints, stains, granite curb, aggregate asphalt and a tree grate at grazing light
### Entrance Steps Podium
![entrance steps podium](entrance_steps_podium.png)
granite steps, handrails, glass doors, the check-in podium
### Crowd Barrier Line
![crowd barrier line](crowd_barrier_line.png)
steel barriers, a red carpet, a crowd with depth-of-field haze
### Responder Arrival Wide
![responder arrival wide](responder_arrival_wide.png)
fire engine, turnout gear, red/blue light spill on wet pavement
### NPC Portrait Day
![npc portrait day](npc_portrait_day.png)
close portrait of a pedestrian: skin with visible pores and stubble, fabric weave, shallow depth of field. The bar for an avatar close-up, not for the crowd shots
The `npc_portrait` capture in `capture_realism.gd` is staged, not posed by the crowd: it freezes one NPC on an open patch of sidewalk, parks the rest of the crowd out of frame, turns the subject into the camera and stands the guard on the sunlit side. It is the only shot where a face fills the frame, so it is the one to eyeball after an avatar change (generate a local run under `docs/screens/realism/`).
Cross-cutting targets, for comparison with locally generated realism runs:
- **Exposure.** The concepts keep the ground mid-grey. The game's sidewalk is close to white, so it is overexposed.
- **Night means dark.** The night/dusk concepts are lit by practical lights. The game's "Evening" phase is a bright pink-orange frame.
- **Depth.** The concepts show a layered skyline fading into haze. The new v2 skyline strips supply this; the old box skyline did not.
- **Geometry and foliage.** The facades have plinths, cornices and deep window reveals, and the trees and shrubs are organic. The game uses flat walls and blob trees.
## Additional previews
![npc_portrait_day-v2.png](npc_portrait_day-v2.png)
@@ -0,0 +1,19 @@
# Hollywood Boulevard references
AI-generated art-direction frames for the real El Capitan Entertainment Centre
block at 6840 Hollywood Boulevard. They are generated with
`tools/scene_concepts.py generate --group scene --only ...` and are not shipped
game textures. The geometry mapping and source links are in
[`../../../hollywood-boulevard-map.md`](../../../hollywood-boulevard-map.md).
## Entrance — day
![El Capitan Entertainment Centre entrance in daylight](hollywood_boulevard_entrance_day.png)
## Entrance — night
![El Capitan Entertainment Centre entrance at night](hollywood_boulevard_entrance_night.png)
## Across the boulevard
![Ovation Hollywood frontage across the boulevard](hollywood_boulevard_across_street.png)
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

+23
View File
@@ -0,0 +1,23 @@
# The Joke Shop references
AI-generated art-direction frames for the fictional Joke Shop, based on the
real Comedy Store block at 8433 Sunset Boulevard. They are generated with
`tools/scene_concepts.py generate --group scene --only ...` and are not shipped
game textures. The geometry mapping and source links are in
[`../../../joke-shop-map.md`](../../../joke-shop-map.md).
## Entrance — day
![The black comedy club under its signature canopy in daylight](joke_shop_entrance_day.png)
## Entrance — night
![The club at night with the circular sign and warm entrance](joke_shop_entrance_night.png)
## Across Sunset
![The club seen from across Sunset Boulevard](joke_shop_across_street.png)
The older top-level concepts `joke_shop_alley_evening.png` and
`joke_shop_door_closeup.png` are kept as a record of the pre-map-optimization
alley design. They no longer describe the current Joke Shop map.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+29
View File
@@ -0,0 +1,29 @@
# Screens/Designs
Screen-design mockups used by the comparison and vision-judge gates for the runtime UI.
## Image previews
| Preview | File |
| --- | --- |
| <img src="access_inspection.png" width="280" alt="access_inspection.png"> | [`access_inspection.png`](access_inspection.png) |
| <img src="body_camera_timeline.png" width="280" alt="body_camera_timeline.png"> | [`body_camera_timeline.png`](body_camera_timeline.png) |
| <img src="crowd_panic.png" width="280" alt="crowd_panic.png"> | [`crowd_panic.png`](crowd_panic.png) |
| <img src="emergency_radio.png" width="280" alt="emergency_radio.png"> | [`emergency_radio.png`](emergency_radio.png) |
| <img src="escalation_hud.png" width="280" alt="escalation_hud.png"> | [`escalation_hud.png`](escalation_hud.png) |
| <img src="joke_shop_queue.png" width="280" alt="joke_shop_queue.png"> | [`joke_shop_queue.png`](joke_shop_queue.png) |
| <img src="late_night_avenue.png" width="280" alt="late_night_avenue.png"> | [`late_night_avenue.png`](late_night_avenue.png) |
| <img src="movement_precision.png" width="280" alt="movement_precision.png"> | [`movement_precision.png`](movement_precision.png) |
| <img src="night_flashlight.png" width="280" alt="night_flashlight.png"> | [`night_flashlight.png`](night_flashlight.png) |
| <img src="pause_overlay.png" width="280" alt="pause_overlay.png"> | [`pause_overlay.png`](pause_overlay.png) |
| <img src="prop_gallery.png" width="280" alt="prop_gallery.png"> | [`prop_gallery.png`](prop_gallery.png) |
| <img src="radial_menu.png" width="280" alt="radial_menu.png"> | [`radial_menu.png`](radial_menu.png) |
| <img src="radio_report.png" width="280" alt="radio_report.png"> | [`radio_report.png`](radio_report.png) |
| <img src="responder_arrival.png" width="280" alt="responder_arrival.png"> | [`responder_arrival.png`](responder_arrival.png) |
| <img src="settings_panel.png" width="280" alt="settings_panel.png"> | [`settings_panel.png`](settings_panel.png) |
| <img src="shift_review.png" width="280" alt="shift_review.png"> | [`shift_review.png`](shift_review.png) |
| <img src="start_menu.png" width="280" alt="start_menu.png"> | [`start_menu.png`](start_menu.png) |
| <img src="studio_arrival.png" width="280" alt="studio_arrival.png"> | [`studio_arrival.png`](studio_arrival.png) |
| <img src="targeting_npc.png" width="280" alt="targeting_npc.png"> | [`targeting_npc.png`](targeting_npc.png) |
| <img src="venue_overview.png" width="280" alt="venue_overview.png"> | [`venue_overview.png`](venue_overview.png) |
| <img src="wand_screening.png" width="280" alt="wand_screening.png"> | [`wand_screening.png`](wand_screening.png) |
View File
Whitespace-only changes.
@@ -1,878 +0,0 @@
{
"run": "docs/screens/realism/2026-11-01-adopt",
"judge_model": "google/gemini-2.5-flash",
"sets": {
"after": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 23.21,
"fine_detail": 8.88,
"contrast": 38.78,
"saturation_mean": 99.58,
"colour_spread": 46.73
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.172,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 3.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
3.0,
3.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement physically based rendering (PBR) materials for all assets, focusing on realistic albedo, roughness, and metallic maps to achieve accurate surface responses to light.",
"Overhaul lighting system to include global illumination, realistic skybox/HDRI for ambient light, and accurate sun/directional light with proper shadows and atmospheric scattering (haze/fog).",
"Replace placeholder low-polygon models with high-detail 3D assets for trees, street furniture, and buildings, ensuring proper UV mapping and texture application.",
"Improve texture resolution and detail across all surfaces, adding normal maps for surface imperfections and detail, and ensuring textures are seamlessly tiled or uniquely mapped where appropriate.",
"Develop a realistic character pipeline, including high-fidelity models, animations, and PBR materials for skin, clothing, and hair, to populate the scene."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 16.02,
"fine_detail": 7.13,
"contrast": 39.4,
"saturation_mean": 163.01,
"colour_spread": 40.42
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 0.723,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 2.0,
"lighting": 1.0,
"characters": 1.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
2.0,
2.0
],
"lighting": [
1.0,
1.0
],
"characters": [
1.0,
1.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light, especially for wet surfaces and brick.",
"Overhaul the lighting system to include global illumination, volumetric fog/rain, and realistic light sources with proper falloff and color temperature, focusing on dramatic contrast and mood.",
"Replace low-polygon models with high-detail meshes and high-resolution textures, including normal and roughness maps, for all environmental elements (buildings, street, props, characters).",
"Redesign the backdrop with a more detailed and atmospheric skyline, incorporating distance haze, subtle cloud formations, and appropriate night sky colors to match the target's mood.",
"Update character models to be realistic, with detailed clothing, skin, and hair textures, and implement realistic animation and shading."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 25.88,
"fine_detail": 9.86,
"contrast": 40.18,
"saturation_mean": 93.04,
"colour_spread": 43.24
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.442,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 0.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light.",
"Overhaul the lighting system to include global illumination, realistic skyboxes with atmospheric scattering, and dynamic shadows.",
"Replace placeholder low-polygon models with high-fidelity assets that include detailed normal maps and displacement maps for architectural elements, foliage, and street furniture.",
"Develop a detailed backdrop with distant buildings, varied skyline, and atmospheric haze to create depth and realism.",
"Add realistic foliage models with proper leaf textures, branch structures, and varied forms instead of simple geometric shapes."
]
}
},
"entrance_late": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 18.4,
"fine_detail": 8.41,
"contrast": 51.61,
"saturation_mean": 127.4,
"colour_spread": 51.96
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.105,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 0.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.33,
"materials": 1.33
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
2.0
],
"materials": [
1.0,
2.0
]
},
"runs": 3,
"fixes": [
"Implement volumetric fog and rain effects to create atmospheric depth and mood, especially around light sources.",
"Overhaul lighting system to include realistic light falloff, bounce light, and wet surface reflections, focusing on the marquee and streetlights.",
"Redesign all materials with PBR workflows, ensuring accurate roughness, metallic, and normal maps for brick, concrete, metal, and wet surfaces.",
"Add high-resolution, detailed textures for all surfaces, particularly the brickwork, sidewalk, and marquee, to capture fine imperfections and wear.",
"Develop a detailed backdrop with distant buildings, subtle city lights, and atmospheric haze to replace the current flat sky."
]
}
},
"joke_shop_door": {
"target": "docs/screens/concepts/joke_shop_door_closeup.png",
"metrics": {
"edge_density": 14.84,
"fine_detail": 7.04,
"contrast": 47.63,
"saturation_mean": 132.89,
"colour_spread": 49.43
},
"target_metrics": {
"edge_density": 9.79,
"fine_detail": 3.59,
"contrast": 26.09,
"saturation_mean": 117.17,
"colour_spread": 25.09
},
"metric_gap": 0.818,
"judge": {
"scores": {
"overall": 2.0,
"backdrop": 4.0,
"lighting": 2.0,
"characters": 0.0,
"texture_detail": 3.0,
"materials": 3.0
},
"score_range": {
"overall": [
2.0,
2.0
],
"backdrop": [
4.0,
4.0
],
"lighting": [
2.0,
2.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
3.0,
3.0
],
"materials": [
3.0,
3.0
]
},
"runs": 3,
"fixes": [
"Implement physically based rendering (PBR) materials for all surfaces, especially brick, wood, and metal, to achieve realistic light interaction and surface properties.",
"Overhaul the lighting system to include more nuanced light sources, volumetric effects, and global illumination. Focus on creating warm, inviting pools of light around entrances and signs, with realistic falloff and shadows.",
"Improve texture resolution and detail for all assets, particularly the brickwork, ground, and signage. Add normal maps and displacement maps to give surfaces depth and tactile quality.",
"Redesign the 'Comedy Club' sign to be a prominent, well-lit feature with appropriate emissive materials and a more stylized font, similar to the target image's 'COMEDY CLUB' sign.",
"Enhance the backdrop with more detailed city lights, atmospheric haze, and a more realistic skybox to create a sense of depth and a believable urban environment."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 18.69,
"fine_detail": 7.42,
"contrast": 42.69,
"saturation_mean": 106.86,
"colour_spread": 48.19
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.148,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 2.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
2.0,
2.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement physically based rendering (PBR) materials for all assets, focusing on realistic albedo, roughness, and metallic values to achieve accurate light interaction.",
"Overhaul the lighting system to include a directional light representing the sun, a skybox/HDRI for ambient light, and global illumination to simulate bounced light, matching the target's clear, bright, and slightly warm daylight.",
"Replace placeholder geometry with high-fidelity 3D models for cars, buildings, and environmental elements (e.g., palm trees, streetlights, sidewalks) that match the realistic proportions and details of the target image.",
"Develop detailed textures for all surfaces, including road asphalt, concrete sidewalks, building facades, and foliage, ensuring appropriate resolution and variety to avoid tiling artifacts and enhance realism.",
"Create a realistic backdrop with a detailed skyline, atmospheric perspective (distance haze), and a clear blue sky that accurately reflects the target's Los Angeles aesthetic, integrating it seamlessly with the foreground."
]
}
},
"street_late": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 12.95,
"fine_detail": 6.27,
"contrast": 31.94,
"saturation_mean": 122.75,
"colour_spread": 36.44
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.224,
"judge": {
"scores": {
"overall": 0.0,
"backdrop": 0.0,
"lighting": 0.0,
"characters": 0.0,
"texture_detail": 0.0,
"materials": 0.0
},
"score_range": {
"overall": [
0.0,
0.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
0.0,
0.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
0.0,
0.0
],
"materials": [
0.0,
0.0
]
},
"runs": 3,
"fixes": [
"Implement a full physically-based lighting model with global illumination, volumetric fog, and atmospheric scattering to achieve realistic sunset colors and light interaction.",
"Replace placeholder geometry with detailed 3D models for buildings, palm trees, and vehicles, ensuring proper scale and architectural variety.",
"Develop high-resolution PBR (Physically Based Rendering) materials for all surfaces, including reflective wet asphalt, glowing neon signs, and varied building facades, with appropriate roughness, metallic, and normal maps.",
"Create a dynamic skybox system that accurately renders sunset gradients, distant city skylines with emissive windows, and atmospheric haze, replacing the current flat backdrop.",
"Add realistic character models with appropriate clothing and animations to populate the scene, contributing to the overall realism and sense of a living city."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 10.97,
"fine_detail": 5.57,
"contrast": 24.27,
"saturation_mean": 190.35,
"colour_spread": 25.15
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.253,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 1.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
1.0,
1.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a full physically-based lighting model with global illumination, volumetric fog, and proper emissive materials for signs and car lights to capture the sunset glow and light trails.",
"Replace placeholder geometry with detailed 3D models for buildings, palm trees, and vehicles, ensuring accurate proportions and architectural details.",
"Develop high-resolution PBR textures for all surfaces (roads, buildings, signs, vehicles) with appropriate albedo, roughness, metallic, and normal maps to add realism and detail.",
"Create a dynamic skybox with a realistic sunset gradient, distant city skyline with illuminated windows, and atmospheric haze to match the target's depth and mood.",
"Add realistic character models with appropriate clothing and animations to populate the scene and enhance the sense of a living city."
]
}
},
"studio_door": {
"target": "docs/screens/concepts/studio_stage_door_night.png",
"metrics": {
"edge_density": 16.62,
"fine_detail": 7.65,
"contrast": 48.52,
"saturation_mean": 133.55,
"colour_spread": 49.81
},
"target_metrics": {
"edge_density": 11.39,
"fine_detail": 4.87,
"contrast": 39.17,
"saturation_mean": 104.49,
"colour_spread": 38.0
},
"metric_gap": 0.395,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 0.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement physically based rendering (PBR) materials for all surfaces, focusing on realistic albedo, roughness, and metallic values to achieve accurate light interaction.",
"Overhaul the lighting system to include global illumination, volumetric fog, and realistic light sources with proper falloff and color temperature, especially for the marquee and wall sconces.",
"Add high-resolution, detailed textures with normal and displacement maps for brickwork, concrete, and metallic elements to introduce surface imperfections and depth.",
"Develop a realistic backdrop with a distant city skyline, atmospheric haze, and a dark, moody sky to establish a sense of depth and environment.",
"Introduce realistic 3D character models with proper clothing, hair, and skin shaders, along with a high-fidelity car model, to populate the scene and match the target's visual complexity."
]
}
}
},
"before": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.75,
"fine_detail": 8.2,
"contrast": 49.63,
"saturation_mean": 72.04,
"colour_spread": 55.45
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.036,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 1.0,
"lighting": 1.0,
"characters": 1.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
1.0,
1.0
],
"lighting": [
1.0,
1.0
],
"characters": [
1.0,
1.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material system for all assets to achieve realistic surface interactions with light.",
"Integrate a global illumination solution (e.g., ray tracing, baked lightmaps) to simulate realistic light bouncing and ambient occlusion.",
"Replace placeholder low-resolution textures with high-resolution, detailed textures, including normal maps and roughness maps for all surfaces.",
"Develop a realistic skybox and distant cityscape with atmospheric scattering and haze effects to match the target's backdrop.",
"Redesign character models with realistic proportions, detailed clothing, and proper skin shaders, along with animation systems for natural movement."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 21.77,
"fine_detail": 8.45,
"contrast": 50.38,
"saturation_mean": 95.12,
"colour_spread": 55.61
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.231,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 1.0,
"lighting": 1.0,
"characters": 1.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
1.0,
1.0
],
"lighting": [
1.0,
1.0
],
"characters": [
1.0,
1.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light.",
"Overhaul the lighting system to include global illumination, volumetric effects (fog/haze), and realistic light sources with proper falloff and color temperature.",
"Redesign character models with higher polygon counts, detailed textures (albedo, normal, roughness, metallic maps), and realistic rigging/animation.",
"Replace placeholder textures with high-resolution, detailed textures that include normal maps for surface imperfections and depth.",
"Develop a more complex backdrop with detailed buildings, atmospheric perspective (distance haze), and a dynamic sky system that reflects time of day and weather."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 26.19,
"fine_detail": 9.27,
"contrast": 56.39,
"saturation_mean": 65.24,
"colour_spread": 59.96
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.308,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 0.0,
"lighting": 1.0,
"characters": 0.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
1.0,
1.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface interactions with light.",
"Overhaul the lighting system to include global illumination, realistic skyboxes with atmospheric scattering, and dynamic shadows to match the soft, warm lighting of the target.",
"Replace placeholder textures with high-resolution, detailed textures that include normal maps, roughness maps, and metallic maps to add surface complexity and realism.",
"Develop a detailed backdrop with distant buildings, realistic palm trees, and atmospheric haze to create depth and a sense of place.",
"Redesign all environmental props (trees, trash cans, bollards) with realistic models and textures, moving away from the current stylized, low-poly aesthetic."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 12.44,
"fine_detail": 5.32,
"contrast": 41.37,
"saturation_mean": 77.84,
"colour_spread": 44.96
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.307,
"judge": {
"scores": {
"overall": 0.0,
"backdrop": 0.0,
"lighting": 0.0,
"characters": 0.0,
"texture_detail": 0.0,
"materials": 0.0
},
"score_range": {
"overall": [
0.0,
0.0
],
"backdrop": [
0.0,
0.0
],
"lighting": [
0.0,
0.0
],
"characters": [
0.0,
0.0
],
"texture_detail": [
0.0,
0.0
],
"materials": [
0.0,
0.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based rendering (PBR) material system for all assets to achieve realistic surface interactions with light.",
"Develop a dynamic sky and atmospheric scattering system to accurately simulate sky color, haze, and sun position based on time of day.",
"Replace placeholder block models with detailed 3D models for buildings, vehicles, and environmental props, including proper UV mapping and high-resolution textures.",
"Integrate a global illumination solution (e.g., ray tracing or baked lightmaps) to simulate realistic indirect lighting and soft shadows.",
"Create realistic character models with detailed textures, proper rigging, and animations, ensuring they blend seamlessly with the environment."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 11.94,
"fine_detail": 5.35,
"contrast": 48.34,
"saturation_mean": 98.21,
"colour_spread": 48.85
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.337,
"judge": {
"scores": {
"overall": 1.0,
"backdrop": 1.0,
"lighting": 1.0,
"characters": 1.0,
"texture_detail": 1.0,
"materials": 1.0
},
"score_range": {
"overall": [
1.0,
1.0
],
"backdrop": [
1.0,
1.0
],
"lighting": [
1.0,
1.0
],
"characters": [
1.0,
1.0
],
"texture_detail": [
1.0,
1.0
],
"materials": [
1.0,
1.0
]
},
"runs": 3,
"fixes": [
"Implement a physically based lighting model with global illumination to accurately simulate light bounces and color bleeding, especially for the sunset and artificial lights.",
"Replace placeholder geometry with detailed 3D models for buildings, vehicles, and environmental props, ensuring proper UV mapping and high-resolution textures.",
"Develop a comprehensive material library with realistic PBR (Physically Based Rendering) materials for various surfaces (e.g., wet asphalt, neon signs, building facades, car paint) including roughness, metallic, and normal maps.",
"Create a dynamic skybox system that accurately represents a sunset with atmospheric scattering, volumetric clouds, and distance haze, matching the vibrant purple and orange hues of the target.",
"Design and integrate realistic character models with detailed clothing, hair, and skin textures, and implement a robust animation system for natural movement."
]
}
}
}
}
}
@@ -1,131 +0,0 @@
# Realism report: `docs/screens/realism/2026-11-01-adopt`
Vision judge: `google/gemini-2.5-flash` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | boulevard_day | boulevard_skyline_day | 0.172 | 23.21 | 8.88 | 38.78 | 1.0 | 1.0 | 1.0 | 1.0 | 3.0 |
| after | boulevard_night | hollywood_entrance_rain_night | 0.723 | 16.02 | 7.13 | 39.4 | 1.0 | 1.0 | 1.0 | 1.0 | 2.0 |
| after | entrance_day | hollywood_entrance_morning | 0.442 | 25.88 | 9.86 | 40.18 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 |
| after | entrance_late | hollywood_entrance_rain_night | 1.105 | 18.4 | 8.41 | 51.61 | 1.0 | 1.0 | 1.33 | 1.33 | 0.0 |
| after | joke_shop_door | joke_shop_door_closeup | 0.818 | 14.84 | 7.04 | 47.63 | 2.0 | 2.0 | 3.0 | 3.0 | 4.0 |
| after | street_day | boulevard_skyline_day | 0.148 | 18.69 | 7.42 | 42.69 | 1.0 | 1.0 | 1.0 | 1.0 | 2.0 |
| after | street_late | boulevard_skyline_dusk | 0.224 | 12.95 | 6.27 | 31.94 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| after | street_night | boulevard_skyline_dusk | 0.253 | 10.97 | 5.57 | 24.27 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
| after | studio_door | studio_stage_door_night | 0.395 | 16.62 | 7.65 | 48.52 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 |
| before | boulevard_day | boulevard_skyline_day | 0.036 | 20.75 | 8.2 | 49.63 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
| before | boulevard_night | hollywood_entrance_rain_night | 1.231 | 21.77 | 8.45 | 50.38 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
| before | entrance_day | hollywood_entrance_morning | 0.308 | 26.19 | 9.27 | 56.39 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 |
| before | street_day | boulevard_skyline_day | 0.307 | 12.44 | 5.32 | 41.37 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| before | street_night | boulevard_skyline_dusk | 0.337 | 11.94 | 5.35 | 48.34 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
Mean scores per set (all captured shots):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | 9 | 0.476 | 1.0 | 1.0 | 1.15 | 1.15 | 1.33 | 0.11 |
| before | 5 | 0.444 | 0.8 | 0.8 | 0.8 | 0.8 | 0.6 | 0.6 |
Mean over the shots every set captured (like for like):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | 5 | 0.348 | 1.0 | 1.0 | 1.0 | 1.0 | 1.6 | 0.2 |
**after / boulevard_day** fixes:
- Implement physically based rendering (PBR) materials for all assets, focusing on realistic albedo, roughness, and metallic maps to achieve accurate surface responses to light.
- Overhaul lighting system to include global illumination, realistic skybox/HDRI for ambient light, and accurate sun/directional light with proper shadows and atmospheric scattering (haze/fog).
- Replace placeholder low-polygon models with high-detail 3D assets for trees, street furniture, and buildings, ensuring proper UV mapping and texture application.
- Improve texture resolution and detail across all surfaces, adding normal maps for surface imperfections and detail, and ensuring textures are seamlessly tiled or uniquely mapped where appropriate.
- Develop a realistic character pipeline, including high-fidelity models, animations, and PBR materials for skin, clothing, and hair, to populate the scene.
**after / boulevard_night** fixes:
- Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light, especially for wet surfaces and brick.
- Overhaul the lighting system to include global illumination, volumetric fog/rain, and realistic light sources with proper falloff and color temperature, focusing on dramatic contrast and mood.
- Replace low-polygon models with high-detail meshes and high-resolution textures, including normal and roughness maps, for all environmental elements (buildings, street, props, characters).
- Redesign the backdrop with a more detailed and atmospheric skyline, incorporating distance haze, subtle cloud formations, and appropriate night sky colors to match the target's mood.
- Update character models to be realistic, with detailed clothing, skin, and hair textures, and implement realistic animation and shading.
**after / entrance_day** fixes:
- Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light.
- Overhaul the lighting system to include global illumination, realistic skyboxes with atmospheric scattering, and dynamic shadows.
- Replace placeholder low-polygon models with high-fidelity assets that include detailed normal maps and displacement maps for architectural elements, foliage, and street furniture.
- Develop a detailed backdrop with distant buildings, varied skyline, and atmospheric haze to create depth and realism.
- Add realistic foliage models with proper leaf textures, branch structures, and varied forms instead of simple geometric shapes.
**after / entrance_late** fixes:
- Implement volumetric fog and rain effects to create atmospheric depth and mood, especially around light sources.
- Overhaul lighting system to include realistic light falloff, bounce light, and wet surface reflections, focusing on the marquee and streetlights.
- Redesign all materials with PBR workflows, ensuring accurate roughness, metallic, and normal maps for brick, concrete, metal, and wet surfaces.
- Add high-resolution, detailed textures for all surfaces, particularly the brickwork, sidewalk, and marquee, to capture fine imperfections and wear.
- Develop a detailed backdrop with distant buildings, subtle city lights, and atmospheric haze to replace the current flat sky.
**after / joke_shop_door** fixes:
- Implement physically based rendering (PBR) materials for all surfaces, especially brick, wood, and metal, to achieve realistic light interaction and surface properties.
- Overhaul the lighting system to include more nuanced light sources, volumetric effects, and global illumination. Focus on creating warm, inviting pools of light around entrances and signs, with realistic falloff and shadows.
- Improve texture resolution and detail for all assets, particularly the brickwork, ground, and signage. Add normal maps and displacement maps to give surfaces depth and tactile quality.
- Redesign the 'Comedy Club' sign to be a prominent, well-lit feature with appropriate emissive materials and a more stylized font, similar to the target image's 'COMEDY CLUB' sign.
- Enhance the backdrop with more detailed city lights, atmospheric haze, and a more realistic skybox to create a sense of depth and a believable urban environment.
**after / street_day** fixes:
- Implement physically based rendering (PBR) materials for all assets, focusing on realistic albedo, roughness, and metallic values to achieve accurate light interaction.
- Overhaul the lighting system to include a directional light representing the sun, a skybox/HDRI for ambient light, and global illumination to simulate bounced light, matching the target's clear, bright, and slightly warm daylight.
- Replace placeholder geometry with high-fidelity 3D models for cars, buildings, and environmental elements (e.g., palm trees, streetlights, sidewalks) that match the realistic proportions and details of the target image.
- Develop detailed textures for all surfaces, including road asphalt, concrete sidewalks, building facades, and foliage, ensuring appropriate resolution and variety to avoid tiling artifacts and enhance realism.
- Create a realistic backdrop with a detailed skyline, atmospheric perspective (distance haze), and a clear blue sky that accurately reflects the target's Los Angeles aesthetic, integrating it seamlessly with the foreground.
**after / street_late** fixes:
- Implement a full physically-based lighting model with global illumination, volumetric fog, and atmospheric scattering to achieve realistic sunset colors and light interaction.
- Replace placeholder geometry with detailed 3D models for buildings, palm trees, and vehicles, ensuring proper scale and architectural variety.
- Develop high-resolution PBR (Physically Based Rendering) materials for all surfaces, including reflective wet asphalt, glowing neon signs, and varied building facades, with appropriate roughness, metallic, and normal maps.
- Create a dynamic skybox system that accurately renders sunset gradients, distant city skylines with emissive windows, and atmospheric haze, replacing the current flat backdrop.
- Add realistic character models with appropriate clothing and animations to populate the scene, contributing to the overall realism and sense of a living city.
**after / street_night** fixes:
- Implement a full physically-based lighting model with global illumination, volumetric fog, and proper emissive materials for signs and car lights to capture the sunset glow and light trails.
- Replace placeholder geometry with detailed 3D models for buildings, palm trees, and vehicles, ensuring accurate proportions and architectural details.
- Develop high-resolution PBR textures for all surfaces (roads, buildings, signs, vehicles) with appropriate albedo, roughness, metallic, and normal maps to add realism and detail.
- Create a dynamic skybox with a realistic sunset gradient, distant city skyline with illuminated windows, and atmospheric haze to match the target's depth and mood.
- Add realistic character models with appropriate clothing and animations to populate the scene and enhance the sense of a living city.
**after / studio_door** fixes:
- Implement physically based rendering (PBR) materials for all surfaces, focusing on realistic albedo, roughness, and metallic values to achieve accurate light interaction.
- Overhaul the lighting system to include global illumination, volumetric fog, and realistic light sources with proper falloff and color temperature, especially for the marquee and wall sconces.
- Add high-resolution, detailed textures with normal and displacement maps for brickwork, concrete, and metallic elements to introduce surface imperfections and depth.
- Develop a realistic backdrop with a distant city skyline, atmospheric haze, and a dark, moody sky to establish a sense of depth and environment.
- Introduce realistic 3D character models with proper clothing, hair, and skin shaders, along with a high-fidelity car model, to populate the scene and match the target's visual complexity.
**before / boulevard_day** fixes:
- Implement a physically based rendering (PBR) material system for all assets to achieve realistic surface interactions with light.
- Integrate a global illumination solution (e.g., ray tracing, baked lightmaps) to simulate realistic light bouncing and ambient occlusion.
- Replace placeholder low-resolution textures with high-resolution, detailed textures, including normal maps and roughness maps for all surfaces.
- Develop a realistic skybox and distant cityscape with atmospheric scattering and haze effects to match the target's backdrop.
- Redesign character models with realistic proportions, detailed clothing, and proper skin shaders, along with animation systems for natural movement.
**before / boulevard_night** fixes:
- Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface responses to light.
- Overhaul the lighting system to include global illumination, volumetric effects (fog/haze), and realistic light sources with proper falloff and color temperature.
- Redesign character models with higher polygon counts, detailed textures (albedo, normal, roughness, metallic maps), and realistic rigging/animation.
- Replace placeholder textures with high-resolution, detailed textures that include normal maps for surface imperfections and depth.
- Develop a more complex backdrop with detailed buildings, atmospheric perspective (distance haze), and a dynamic sky system that reflects time of day and weather.
**before / entrance_day** fixes:
- Implement a physically based rendering (PBR) material pipeline for all assets to achieve realistic surface interactions with light.
- Overhaul the lighting system to include global illumination, realistic skyboxes with atmospheric scattering, and dynamic shadows to match the soft, warm lighting of the target.
- Replace placeholder textures with high-resolution, detailed textures that include normal maps, roughness maps, and metallic maps to add surface complexity and realism.
- Develop a detailed backdrop with distant buildings, realistic palm trees, and atmospheric haze to create depth and a sense of place.
- Redesign all environmental props (trees, trash cans, bollards) with realistic models and textures, moving away from the current stylized, low-poly aesthetic.
**before / street_day** fixes:
- Implement a physically based rendering (PBR) material system for all assets to achieve realistic surface interactions with light.
- Develop a dynamic sky and atmospheric scattering system to accurately simulate sky color, haze, and sun position based on time of day.
- Replace placeholder block models with detailed 3D models for buildings, vehicles, and environmental props, including proper UV mapping and high-resolution textures.
- Integrate a global illumination solution (e.g., ray tracing or baked lightmaps) to simulate realistic indirect lighting and soft shadows.
- Create realistic character models with detailed textures, proper rigging, and animations, ensuring they blend seamlessly with the environment.
**before / street_night** fixes:
- Implement a physically based lighting model with global illumination to accurately simulate light bounces and color bleeding, especially for the sunset and artificial lights.
- Replace placeholder geometry with detailed 3D models for buildings, vehicles, and environmental props, ensuring proper UV mapping and high-resolution textures.
- Develop a comprehensive material library with realistic PBR (Physically Based Rendering) materials for various surfaces (e.g., wet asphalt, neon signs, building facades, car paint) including roughness, metallic, and normal maps.
- Create a dynamic skybox system that accurately represents a sunset with atmospheric scattering, volumetric clouds, and distance haze, matching the vibrant purple and orange hues of the target.
- Design and integrate realistic character models with detailed clothing, hair, and skin textures, and implement a robust animation system for natural movement.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

@@ -1,134 +0,0 @@
{
"run": "docs/screens/realism/2026-11-01-gear-judge",
"judge_model": "google/gemini-2.5-flash-lite",
"sets": {
"baseline": {
"npc_portrait": {
"target": "docs/screens/concepts/npc_portrait_day.png",
"metrics": {
"edge_density": 24.42,
"fine_detail": 9.88,
"contrast": 43.77,
"saturation_mean": 90.21,
"colour_spread": 50.11
},
"target_metrics": {
"edge_density": 7.47,
"fine_detail": 3.47,
"contrast": 52.66,
"saturation_mean": 93.44,
"colour_spread": 54.88
},
"metric_gap": 1.093,
"judge": {
"scores": {
"backdrop": 4.0,
"lighting": 3.0,
"overall": 2.0,
"materials": 2.0,
"texture_detail": 1.0,
"characters": 1.0
},
"score_range": {
"backdrop": [
4.0,
4.0
],
"lighting": [
3.0,
3.0
],
"overall": [
2.0,
2.0
],
"materials": [
2.0,
2.0
],
"texture_detail": [
1.0,
1.0
],
"characters": [
1.0,
1.0
]
},
"runs": 1,
"fixes": [
"Improve character model realism with more detailed facial features, realistic skin shaders, and better clothing textures.",
"Enhance material properties for all objects, especially the brick building and pavement, to better simulate real-world reflectivity, roughness, and subsurface scattering.",
"Increase texture resolution and detail for all assets, particularly for the brickwork, pavement, and character clothing, to reduce the appearance of tiling and blurriness.",
"Refine lighting to match the warm, directional sunlight and soft shadows of the target image, paying attention to ambient occlusion and global illumination.",
"Add atmospheric perspective and volumetric fog to the backdrop to create a sense of depth and distance, mimicking the haze seen in the target image."
]
}
}
},
"candidate": {
"npc_portrait": {
"target": "docs/screens/concepts/npc_portrait_day.png",
"metrics": {
"edge_density": 24.43,
"fine_detail": 9.89,
"contrast": 43.74,
"saturation_mean": 90.17,
"colour_spread": 50.08
},
"target_metrics": {
"edge_density": 7.47,
"fine_detail": 3.47,
"contrast": 52.66,
"saturation_mean": 93.44,
"colour_spread": 54.88
},
"metric_gap": 1.094,
"judge": {
"scores": {
"backdrop": 5.0,
"lighting": 4.0,
"overall": 3.0,
"materials": 3.0,
"texture_detail": 2.0,
"characters": 2.0
},
"score_range": {
"backdrop": [
5.0,
5.0
],
"lighting": [
4.0,
4.0
],
"overall": [
3.0,
3.0
],
"materials": [
3.0,
3.0
],
"texture_detail": [
2.0,
2.0
],
"characters": [
2.0,
2.0
]
},
"runs": 1,
"fixes": [
"Improve character model realism with more detailed facial features, realistic skin shaders, and better hair simulation.",
"Enhance material properties for clothing, pavement, and buildings to include subsurface scattering, anisotropic reflections, and more varied roughness maps.",
"Increase texture resolution and add micro-detail (e.g., pores, fabric weave, concrete imperfections) to all surfaces.",
"Implement more sophisticated global illumination and atmospheric scattering for a softer, more realistic lighting and haze effect.",
"Refine the backdrop by adding more complex building geometry, varied foliage, and realistic distant city details with appropriate atmospheric perspective."
]
}
}
}
}
}
@@ -1,55 +0,0 @@
# Gear fit report: `docs/screens/realism/2026-11-01-gear`
Influencer (`npc_coat`) portrait, forced with `--portrait-type=2`, before the gear-fit
changes (`da876e3`, with the capture yaw/focus fixes backported) and after them (`a478bfb`).
Both frames use the same camera, sun and portrait staging. The focus disc is hidden because
it is a gameplay overlay, not part of the character still.
| measurement | before | after |
| --- | --- | --- |
| sunglasses width | 0.282 m (0.90× head) | **0.202 m** (0.64× head) |
| bag body inner face | 0.168 m (coat skirt 0.225, dress 0.260) | **0.262 m** (clears both) |
| firefighter helmet brim | sat on the brow ridge | **raised 2 cm** |
Capture commands:
```
xvfb-run -a godot --path . --script res://src/test/capture_realism.gd -- \
--stages=portrait --portrait-type=2 \
--out=res://docs/screens/realism/2026-11-01-gear/candidate-v2
tools/check_screenshots.sh # 11 good / 0 bad
python3 tools/scene_concepts.py realism \
--run docs/screens/realism/2026-11-01-gear --judge
```
The judge improved the portrait from **overall 2 / characters 1** (baseline) to
**overall 3 / characters 2** (candidate); the remaining fixes are the broader realism
targets (skin/cloth shaders, GI, backdrop haze), not gear fit.
Vision judge: `google/gemini-2.5-flash-lite` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | npc_portrait | npc_portrait_day | 1.093 | 24.42 | 9.88 | 43.77 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 |
| candidate | npc_portrait | npc_portrait_day | 1.094 | 24.43 | 9.89 | 43.74 | 3.0 | 4.0 | 3.0 | 2.0 | 5.0 |
Mean scores per set (all captured shots):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | 1 | 1.093 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 | 1.0 |
| candidate | 1 | 1.094 | 3.0 | 4.0 | 3.0 | 2.0 | 5.0 | 2.0 |
**baseline / npc_portrait** fixes:
- Improve character model realism with more detailed facial features, realistic skin shaders, and better clothing textures.
- Enhance material properties for all objects, especially the brick building and pavement, to better simulate real-world reflectivity, roughness, and subsurface scattering.
- Increase texture resolution and detail for all assets, particularly for the brickwork, pavement, and character clothing, to reduce the appearance of tiling and blurriness.
- Refine lighting to match the warm, directional sunlight and soft shadows of the target image, paying attention to ambient occlusion and global illumination.
- Add atmospheric perspective and volumetric fog to the backdrop to create a sense of depth and distance, mimicking the haze seen in the target image.
**candidate / npc_portrait** fixes:
- Improve character model realism with more detailed facial features, realistic skin shaders, and better hair simulation.
- Enhance material properties for clothing, pavement, and buildings to include subsurface scattering, anisotropic reflections, and more varied roughness maps.
- Increase texture resolution and add micro-detail (e.g., pores, fabric weave, concrete imperfections) to all surfaces.
- Implement more sophisticated global illumination and atmospheric scattering for a softer, more realistic lighting and haze effect.
- Refine the backdrop by adding more complex building geometry, varied foliage, and realistic distant city details with appropriate atmospheric perspective.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

File diff suppressed because it is too large. Load diff
@@ -1,171 +0,0 @@
# Realism report: `docs/screens/realism/2026-11-01-npc`
Vision judge: `google/gemini-2.5-flash-lite` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | boulevard_day | boulevard_skyline_day | 0.168 | 23.78 | 9.03 | 40.34 | 3.0 | 4.0 | 3.0 | 3.0 | 6.0 |
| after | boulevard_night | hollywood_entrance_rain_night | 0.728 | 16.21 | 7.16 | 38.99 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| after | entrance_day | hollywood_entrance_morning | 0.457 | 27.12 | 10.33 | 43.1 | 3.0 | 4.0 | 3.0 | 3.0 | 3.0 |
| after | entrance_late | hollywood_entrance_rain_night | 1.134 | 18.8 | 8.52 | 52.15 | 2.0 | 3.0 | 2.0 | 2.0 | 1.0 |
| after | joke_shop_door | joke_shop_door_closeup | 0.864 | 15.4 | 7.24 | 48.56 | 2.0 | 3.0 | 4.0 | 3.0 | 2.0 |
| after | npc_portrait | npc_portrait_day | 1.108 | 24.87 | 9.87 | 43.79 | 3.0 | 4.0 | 3.0 | 3.0 | 5.0 |
| after | street_day | boulevard_skyline_day | 0.119 | 19.96 | 7.55 | 43.9 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| after | street_late | boulevard_skyline_dusk | 0.273 | 13.81 | 6.73 | 33.25 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| after | street_night | boulevard_skyline_dusk | 0.308 | 12.51 | 6.14 | 25.49 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| after | studio_door | studio_stage_door_night | 0.433 | 17.21 | 7.97 | 49.17 | 2.0 | 3.0 | 2.0 | 2.0 | 1.0 |
| before | boulevard_day | boulevard_skyline_day | 0.172 | 23.21 | 8.88 | 38.78 | 2.0 | 3.0 | 2.0 | 2.0 | 5.0 |
| before | boulevard_night | hollywood_entrance_rain_night | 0.723 | 16.02 | 7.13 | 39.4 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| before | entrance_day | hollywood_entrance_morning | 0.442 | 25.88 | 9.86 | 40.18 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| before | entrance_late | hollywood_entrance_rain_night | 1.105 | 18.4 | 8.41 | 51.61 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| before | joke_shop_door | joke_shop_door_closeup | 0.818 | 14.84 | 7.04 | 47.63 | 3.0 | 3.0 | 4.0 | 3.0 | 5.0 |
| before | street_day | boulevard_skyline_day | 0.148 | 18.69 | 7.42 | 42.69 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| before | street_late | boulevard_skyline_dusk | 0.224 | 12.95 | 6.27 | 31.94 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| before | street_night | boulevard_skyline_dusk | 0.253 | 10.97 | 5.57 | 24.27 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| before | studio_door | studio_stage_door_night | 0.395 | 16.62 | 7.65 | 48.52 | 2.0 | 3.0 | 2.0 | 2.0 | 1.0 |
Mean scores per set (all captured shots):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | 10 | 0.559 | 2.3 | 3.3 | 2.5 | 2.4 | 3.3 | 2.2 |
| before | 9 | 0.476 | 2.11 | 3.0 | 2.22 | 2.11 | 3.67 | 2.33 |
Mean over the shots every set captured (like for like):
| set | shots | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| after | 9 | 0.498 | 2.22 | 3.22 | 2.44 | 2.33 | 3.11 | 2.22 |
**after / boulevard_day** fixes:
- Improve the lighting model to better simulate global illumination and soft shadows, especially for the sky and ambient light.
- Increase the polygon count and add normal maps to the trees and foliage to give them a more organic and detailed appearance.
- Replace the current brick material with a more detailed texture that includes variations in color, mortar lines, and subtle imperfections.
- Add more complex geometry and finer details to the buildings in the background, such as windows, balconies, and architectural elements, to match the target's complexity.
- Implement a more sophisticated atmospheric perspective effect for the distant cityscape to create a greater sense of depth and realism.
**after / boulevard_night** fixes:
- Improve the lighting to be more atmospheric and volumetric, with softer shadows and more realistic reflections on wet surfaces.
- Enhance material properties for brick, pavement, and building facades to include more subtle variations, specularity, and roughness.
- Increase texture detail on all surfaces, especially the brickwork, pavement, and character models, to reduce the 'plastic' look.
- Redesign character models to be more anatomically correct and detailed, with better clothing textures and facial features.
- Add more subtle environmental details like rain streaks, puddles with ripples, and more varied foliage to enhance realism.
**after / entrance_day** fixes:
- Improve brick texture and material to add more variation, grime, and imperfections.
- Add atmospheric perspective and volumetric fog to the background to create depth and match the target's hazy distance.
- Enhance lighting to include softer shadows, more subtle ambient occlusion, and realistic light falloff, especially around the marquee lights.
- Replace low-polygon trees with more detailed models that have varied leaf textures and shapes.
- Add subtle surface imperfections and wear to the concrete sidewalk and steps.
**after / entrance_late** fixes:
- Improve the lighting to match the dramatic, atmospheric, and volumetric lighting of the target image. Focus on warm, directional light from the marquee and street lamp, with soft ambient occlusion and reflections.
- Enhance material properties for realism. The brickwork, pavement, and building facade in the capture are too flat and lack subsurface scattering or specular highlights. The target image shows wet, reflective surfaces with subtle variations in material.
- Increase texture detail significantly. The brick textures are low-resolution and repetitive. The target image features high-resolution, varied brick patterns with grime and weathering.
- Redesign the backdrop to include a distant city skyline with atmospheric perspective (haze) and more detailed building structures, similar to the target image.
- Refine the character model and its integration into the scene. The character in the capture is low-poly and appears out of place. The target image's character has more realistic proportions, clothing detail, and is better lit to blend with the environment.
**after / joke_shop_door** fixes:
- Improve brick texture and material properties to match the target's depth and roughness.
- Enhance the lighting to create softer, more volumetric shadows and a warmer glow from the lamp.
- Add more detail to the building facade, such as subtle variations in brick color and mortar.
- Introduce atmospheric perspective and haze to the distant cityscape to create a sense of depth.
- Significantly increase the polygon count and detail of the character model to match the target's realism.
**after / npc_portrait** fixes:
- Improve character model realism: Focus on facial features, skin texture, and clothing wrinkles to match the target's detail and natural appearance.
- Enhance material properties: Make brick, pavement, and clothing materials more realistic with better specular highlights, subsurface scattering, and wear/tear details.
- Refine lighting: Mimic the warm, directional lighting of the target, paying attention to soft shadows and rim lighting on the character.
- Increase texture detail: Apply higher resolution and more nuanced textures to all surfaces, especially the character's skin and clothing, and the brickwork.
- Adjust backdrop realism: Add atmospheric perspective (haze) to the distant city skyline and improve the detail and lighting of the palm trees to match the target.
**after / street_day** fixes:
- Improve road material to have more subtle variations in color and reflectivity, and add tire marks and debris.
- Enhance building textures with more detailed facades, windows, and architectural elements. Add subtle weathering and grime.
- Increase the density and variety of vegetation, ensuring realistic palm tree models and ground cover.
- Refine lighting to create softer shadows, more atmospheric scattering, and realistic specular highlights on surfaces.
- Add atmospheric perspective to the distant cityscape with appropriate haze and color grading to simulate distance.
**after / street_late** fixes:
- Improve the lighting to match the warm, atmospheric glow of the target image, paying close attention to the neon signs and streetlights.
- Enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.
- Increase texture detail on all surfaces, especially the road and building facades, to add depth and realism.
- Refine the backdrop, particularly the city skyline and atmospheric haze, to create a more convincing sense of distance and depth.
- Significantly improve character models and their integration into the scene, as they currently appear very low-fidelity and out of place.
**after / street_night** fixes:
- Improve lighting to match the warm, atmospheric glow of the target, especially the neon signs and streetlights.
- Increase the detail and realism of building materials and textures, adding grime, wear, and more complex architectural features.
- Enhance the texture detail on the road surface, palm trees, and vehicles to be less uniform and more photorealistic.
- Refine the backdrop, adding atmospheric haze and more detailed city silhouettes that mimic the depth and complexity of the target.
- Significantly improve character models and animations to match the realistic style of the target image.
**after / studio_door** fixes:
- Improve the lighting to match the dramatic, moody atmosphere of the target, focusing on soft, volumetric light and realistic reflections.
- Enhance material properties for the building facade, car, and pavement to achieve a more realistic look with appropriate specularity, roughness, and subsurface scattering.
- Increase texture detail on all surfaces, especially the brickwork, stone, and car paint, to add fine details and imperfections.
- Add atmospheric effects like fog or haze to the backdrop to create depth and a sense of distance, similar to the target image.
- Significantly improve character models and their integration into the scene, paying attention to detail, lighting, and animation.
**before / boulevard_day** fixes:
- Improve road and sidewalk materials to have more realistic roughness and subtle variations.
- Add significantly more geometric detail and realistic textures to buildings, especially the brickwork.
- Replace low-polygon trees and foliage with more detailed and varied models, and add more natural scattering.
- Enhance lighting to include softer shadows, more realistic ambient occlusion, and subtle specular highlights on surfaces.
- Implement atmospheric perspective for the distant cityscape to create a sense of depth and haze.
**before / boulevard_night** fixes:
- Improve lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and street lamp, with realistic reflections on wet surfaces.
- Enhance material properties to achieve a more realistic look, particularly for the brickwork, pavement, and building facade, incorporating subtle imperfections, wear, and specular highlights that react realistically to light.
- Increase texture detail significantly across all assets, especially the brick walls, pavement, and character models, to add depth, realism, and a sense of age and grit.
- Redesign character models to be more anatomically correct and detailed, with realistic clothing textures and subtle animations that convey a sense of life and presence.
- Refine the backdrop to include more atmospheric elements like fog, rain effects, and a more detailed, less stylized cityscape with appropriate haze for distance.
**before / entrance_day** fixes:
- Improve brick texture and material properties to add more variation, grime, and imperfections.
- Enhance lighting to create softer shadows, more atmospheric volumetric light, and a warmer, more natural color temperature.
- Add more detailed geometry and textures to the building facade, windows, and surrounding elements like trees and planters.
- Introduce atmospheric perspective and fog to the distant cityscape to create a sense of depth and realism.
- Replace low-polygon trees with more detailed models and textures that better match the target's style.
**before / entrance_late** fixes:
- Improve the lighting to be more atmospheric and volumetric, with softer shadows and more realistic light falloff, especially around the marquee and streetlights.
- Enhance material properties for brick, pavement, and building facades to include realistic reflections, specularity, and subsurface scattering where appropriate.
- Increase texture resolution and detail for all surfaces, particularly the brickwork, to reduce the appearance of tiling and blurriness.
- Add more complex geometry and detail to the backdrop buildings and sky, including atmospheric perspective and subtle variations in color and light.
- Refine character models with more detailed clothing, facial features (if visible), and more natural posing to match the realistic aesthetic.
**before / joke_shop_door** fixes:
- Improve brick texture and normal mapping to match the target's depth and roughness.
- Enhance the lighting to create softer, more volumetric shadows and a warmer glow from the lamp.
- Add more detail to the door material, including wood grain and subtle imperfections.
- Refine the sign's material and lighting to appear less flat and more integrated with the environment.
- Significantly improve character models to achieve a realistic appearance, focusing on form, texture, and animation.
**before / street_day** fixes:
- Improve road material to have more micro-details, reflections, and wear.
- Add atmospheric perspective and volumetric fog to the distant cityscape to match the target's depth.
- Enhance building materials with more varied textures, specular highlights, and subtle imperfections.
- Increase the polygon count and texture resolution for the car model, paying attention to reflections and material properties.
- Implement more realistic lighting with softer shadows, global illumination, and subtle color grading to mimic natural sunlight.
**before / street_late** fixes:
- Improve the lighting to match the warm, atmospheric glow of the target image, paying attention to the neon signs and streetlights.
- Enhance material properties for buildings, road, and car to achieve a more realistic sheen and surface detail, especially reflections.
- Increase texture resolution and detail on all surfaces, particularly the road and building facades, to mimic the fine grain and imperfections of the target.
- Develop a more detailed and atmospheric backdrop, including a richer sky gradient and more nuanced city skyline with atmospheric perspective.
- Significantly improve character models and their integration into the scene, as they are currently very basic and unrealistic.
**before / street_night** fixes:
- Improve lighting to match the warm, atmospheric glow of neon signs and streetlights in the target image, with more volumetric effects and softer shadows.
- Enhance material properties to achieve a more realistic sheen and reflectivity on surfaces like the road, buildings, and car, especially under the artificial lights.
- Increase texture detail on buildings, road surfaces, and palm trees to add grit, imperfections, and finer details that are present in the target image.
- Add atmospheric perspective and haze to the distant cityscape and sky to create a sense of depth and realism, similar to the target image.
- Significantly improve character models and their integration into the scene, as they are currently very basic and detract from realism.
**before / studio_door** fixes:
- Improve the lighting to match the dramatic, moody, and volumetric feel of the target image. Focus on soft, warm light sources and atmospheric fog.
- Enhance material properties for the building facade, stairs, and car to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.
- Increase texture detail on all surfaces, especially the brickwork and stone, to add grit, wear, and finer details that are present in the target.
- Redesign the backdrop to include atmospheric haze and a more distant, less defined background, similar to the target image's sense of depth and mood.
- Significantly improve character models and their rendering to match the realistic style and subtle details of the people in the target image.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 753 KiB

@@ -1,526 +0,0 @@
{
"run": "docs/screens/realism/2026-11-01-v2",
"judge_model": "google/gemini-2.5-flash-lite",
"sets": {
"baseline": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.75,
"fine_detail": 8.2,
"contrast": 49.63,
"saturation_mean": 72.04,
"colour_spread": 55.45
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.036,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 1.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve the lighting model to include more realistic global illumination and soft shadows. The current lighting is too flat and harsh.",
"Replace the current low-polygon character models with more detailed and anatomically correct models. Add variations in clothing and appearance.",
"Increase the texture resolution and detail on all surfaces, especially buildings, roads, and foliage. Implement normal maps and specular maps for greater realism.",
"Enhance the backdrop by adding more detailed building models in the distance, atmospheric perspective (haze), and a more nuanced skybox.",
"Refine the material properties of all objects to better simulate real-world materials. This includes adjusting reflectivity, roughness, and subsurface scattering where appropriate."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 21.77,
"fine_detail": 8.45,
"contrast": 50.38,
"saturation_mean": 95.12,
"colour_spread": 55.61
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.231,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 1.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.",
"Significantly upgrade material shaders to achieve realistic PBR (Physically Based Rendering) properties, especially for brick, asphalt, glass, and metal, to mimic the specular highlights, subsurface scattering, and roughness of the target.",
"Increase texture resolution and detail for all surfaces, particularly the brickwork, sidewalk, and building facades, to match the fine-grained realism of the target.",
"Redesign character models with higher polygon counts, more detailed textures, and realistic clothing and facial features to match the stylized but grounded look of the target's lone figure.",
"Enhance the backdrop by adding atmospheric effects like fog, rain, and distant city lights, and refine the building models to have more architectural detail and variation, similar to the target's moody urban environment."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 26.19,
"fine_detail": 9.27,
"contrast": 56.39,
"saturation_mean": 65.24,
"colour_spread": 59.96
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.308,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 3.0,
"characters": 10.0,
"overall": 2.0
},
"fixes": [
"Improve brick texture and material to match the target's depth and variation.",
"Add more detailed and varied foliage, especially for the trees and bushes, to match the target's organic look.",
"Enhance lighting to create softer shadows, more atmospheric haze, and warmer tones, particularly around the building entrance and street.",
"Refine building details, such as window frames, signage, and architectural elements, to increase realism.",
"Introduce subtle imperfections and wear on surfaces like the sidewalk and building facade to mimic real-world aging."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 12.44,
"fine_detail": 5.32,
"contrast": 41.37,
"saturation_mean": 77.84,
"colour_spread": 44.96
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.307,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 2.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog for atmospheric perspective.",
"Replace flat, untextured building models with detailed geometry and realistic materials (concrete, glass, metal).",
"Add high-resolution textures to all surfaces, especially the road, sidewalk, and buildings, to mimic the detail in the target.",
"Model a more detailed and varied cityscape for the backdrop, including buildings with distinct architectural styles and realistic lighting.",
"Redesign character models to be more anatomically correct and have realistic clothing textures and animations."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 11.94,
"fine_detail": 5.35,
"contrast": 48.34,
"saturation_mean": 98.21,
"colour_spread": 48.85
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.337,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the dramatic sunset and neon glow of the target image, focusing on volumetric lighting and bloom effects.",
"Enhance material properties for buildings, road, and car to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.",
"Increase texture resolution and detail on all surfaces, especially the road and building facades, to mimic the fine grain and imperfections seen in the target.",
"Redesign the backdrop to include a more detailed and atmospheric skyline with realistic haze and a richer sunset color gradient.",
"Replace the current character models with more detailed and realistically proportioned characters that fit the urban environment."
]
}
}
},
"candidate": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.67,
"fine_detail": 7.8,
"contrast": 42.49,
"saturation_mean": 67.55,
"colour_spread": 48.32
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.113,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 5.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.",
"Increase texture resolution and detail on buildings, especially the brickwork, to match the target's fidelity.",
"Replace stylized character models with realistic human models that have appropriate proportions and clothing.",
"Enhance lighting to create softer shadows, more realistic ambient occlusion, and better global illumination, especially around the streetlights and building facades.",
"Add atmospheric perspective and volumetric fog to the distant cityscape to create a more convincing sense of depth and distance haze."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 20.67,
"fine_detail": 7.86,
"contrast": 46.43,
"saturation_mean": 98.69,
"colour_spread": 50.59
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.073,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 3.0,
"characters": 2.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to create atmospheric mood, with strong contrast and volumetric effects like fog/rain.",
"Enhance material properties for realism: add specular highlights, subsurface scattering for skin, and more detailed surface imperfections.",
"Increase texture resolution and detail, especially on buildings, pavement, and clothing, to match the target's gritty realism.",
"Redesign characters to have more realistic proportions, clothing, and facial features, and animate them with more natural movement.",
"Develop a more detailed and atmospheric backdrop, including realistic city buildings, distant haze, and appropriate weather effects."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 24.54,
"fine_detail": 8.92,
"contrast": 52.41,
"saturation_mean": 61.63,
"colour_spread": 54.98
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.303,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 3.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve brick texture and material to add more variation, grime, and imperfections.",
"Enhance lighting to create softer shadows, more atmospheric haze, and realistic light falloff.",
"Add more detail and variation to the building facade, including window frames, signage, and architectural elements.",
"Replace low-poly trees and bushes with more detailed and realistic foliage models.",
"Refine character models to match the realistic style of the target image, focusing on proportions, clothing, and facial features."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 14.54,
"fine_detail": 5.32,
"contrast": 36.3,
"saturation_mean": 74.49,
"colour_spread": 39.9
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.326,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 3.0,
"characters": 1.0,
"overall": 1.0
},
"fixes": [
"Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.",
"Add significant detail to the car models, including realistic reflections, panel gaps, and tire textures.",
"Implement volumetric fog and atmospheric scattering to create a more convincing sense of depth and haze in the backdrop.",
"Replace the placeholder character with a detailed, realistically lit 3D model that matches the environment's style.",
"Enhance the lighting model to include softer shadows, more accurate ambient occlusion, and realistic light bounce."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 16.12,
"fine_detail": 6.06,
"contrast": 48.36,
"saturation_mean": 103.44,
"colour_spread": 49.1
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.495,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.",
"Significantly enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.",
"Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the crispness and complexity of the target.",
"Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to match the sunset.",
"Completely overhaul character models to be significantly more detailed, with realistic proportions, clothing, and animation, to match the quality of the target scene."
]
}
}
},
"candidate_dusk": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.64,
"fine_detail": 7.79,
"contrast": 42.52,
"saturation_mean": 67.55,
"colour_spread": 48.35
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.113,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 5.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog or atmospheric perspective to the distant cityscape.",
"Replace low-poly, stylized assets (trees, characters, buildings) with high-fidelity models that have realistic proportions and details.",
"Apply PBR materials with appropriate roughness, metallic, and normal maps to all surfaces (road, sidewalk, buildings, foliage) to simulate real-world material properties.",
"Increase texture resolution and add surface imperfections (grime, wear, subtle variations) to the road, sidewalk, and building facades.",
"Refine character models to have realistic anatomy, clothing, and animation, and ensure they are properly lit and integrated into the scene."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 21.29,
"fine_detail": 7.93,
"contrast": 43.3,
"saturation_mean": 97.44,
"colour_spread": 47.83
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.041,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve the lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.",
"Significantly upgrade the character models and animations to be more realistic, with detailed clothing, facial features, and natural posing, rather than the current low-poly, cartoonish style.",
"Enhance material properties and textures for all surfaces (brick, pavement, doors, clothing) to achieve a photorealistic look, with appropriate roughness, reflectivity, and detailed normal maps, especially for the wet environment.",
"Refine the backdrop elements, including the distant city skyline and atmospheric haze, to create a sense of depth and realism consistent with the target image's moody atmosphere.",
"Implement more realistic environmental effects, such as rain, puddles with accurate reflections, and subtle fog, to enhance the overall immersion and match the target's gritty, wet ambiance."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 24.44,
"fine_detail": 8.87,
"contrast": 52.25,
"saturation_mean": 61.51,
"colour_spread": 54.84
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.3,
"judge": {
"scores": {},
"fixes": [
"judge failed: OpenRouter HTTP 400: {\"error\":{\"message\":\"Provider returned error\",\"code\":400,\"metadata\":{\"raw\":\"{\\n \\\"error\\\": {\\n \\\"code\\\": 400,\\n \\\"message\\\": \\\"API key not valid. Please pass a valid API key.\\\",\\n \\\"status\\\": \\\"INVALID_ARGUMENT\\\",\\n \\\"details\\\": [\\n {\\n \\\"@type\\\": \\\"type.googleapis.com/googl"
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 14.55,
"fine_detail": 5.33,
"contrast": 36.3,
"saturation_mean": 74.49,
"colour_spread": 39.9
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.326,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 1.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve road and sidewalk material PBR values to match the target's roughness and reflectivity.",
"Increase the resolution and detail of building textures in the backdrop to reduce the blurry, low-poly appearance.",
"Add atmospheric perspective and volumetric fog to the distant cityscape to mimic the target's depth and haze.",
"Enhance car material properties, particularly reflections and specular highlights, to match the target's realism.",
"Redesign character models to have more detailed geometry, textures, and more natural proportions and posing."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 17.04,
"fine_detail": 6.13,
"contrast": 43.69,
"saturation_mean": 96.82,
"colour_spread": 45.18
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.463,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 3.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.",
"Enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.",
"Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the fine details seen in the target.",
"Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to mimic the target's sunset.",
"Significantly rework character models to be more realistic in terms of proportions, texturing, and animation, as the current models are very stylized and cartoony."
]
}
}
}
}
}
@@ -1,130 +0,0 @@
# Realism report: `docs/screens/realism/2026-11-01-v2`
Vision judge: `google/gemini-2.5-flash-lite` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | boulevard_day | boulevard_skyline_day | 0.036 | 20.75 | 8.2 | 49.63 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 |
| baseline | boulevard_night | hollywood_entrance_rain_night | 1.231 | 21.77 | 8.45 | 50.38 | 1.0 | 2.0 | 1.0 | 1.0 | 2.0 |
| baseline | entrance_day | hollywood_entrance_morning | 0.308 | 26.19 | 9.27 | 56.39 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| baseline | street_day | boulevard_skyline_day | 0.307 | 12.44 | 5.32 | 41.37 | 1.0 | 2.0 | 1.0 | 1.0 | 2.0 |
| baseline | street_night | boulevard_skyline_dusk | 0.337 | 11.94 | 5.35 | 48.34 | 2.0 | 3.0 | 2.0 | 1.0 | 2.0 |
| candidate | boulevard_day | boulevard_skyline_day | 0.113 | 20.67 | 7.8 | 42.49 | 2.0 | 3.0 | 2.0 | 2.0 | 5.0 |
| candidate | boulevard_night | hollywood_entrance_rain_night | 1.073 | 20.67 | 7.86 | 46.43 | 1.0 | 2.0 | 1.0 | 1.0 | 3.0 |
| candidate | entrance_day | hollywood_entrance_morning | 0.303 | 24.54 | 8.92 | 52.41 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| candidate | street_day | boulevard_skyline_day | 0.326 | 14.54 | 5.32 | 36.3 | 1.0 | 2.0 | 1.0 | 1.0 | 3.0 |
| candidate | street_night | boulevard_skyline_dusk | 0.495 | 16.12 | 6.06 | 48.36 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| candidate_dusk | boulevard_day | boulevard_skyline_day | 0.113 | 20.64 | 7.79 | 42.52 | 2.0 | 3.0 | 2.0 | 2.0 | 5.0 |
| candidate_dusk | boulevard_night | hollywood_entrance_rain_night | 1.041 | 21.29 | 7.93 | 43.3 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
| candidate_dusk | entrance_day | hollywood_entrance_morning | 0.3 | 24.44 | 8.87 | 52.25 | - | - | - | - | - |
| candidate_dusk | street_day | boulevard_skyline_day | 0.326 | 14.55 | 5.33 | 36.3 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 |
| candidate_dusk | street_night | boulevard_skyline_dusk | 0.463 | 17.04 | 6.13 | 43.69 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
Mean scores per set:
| set | gap ↓ | overall | lighting | materials | texture_detail | backdrop | characters |
| --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | 0.444 | 1.6 | 2.6 | 1.6 | 1.2 | 2.6 | 3.0 |
| candidate | 0.462 | 1.6 | 2.6 | 1.6 | 1.6 | 3.6 | 1.2 |
| candidate_dusk | 0.449 | 2.0 | 3.0 | 2.0 | 1.75 | 4.0 | 1.0 |
**baseline / boulevard_day** fixes:
- Improve the lighting model to include more realistic global illumination and soft shadows. The current lighting is too flat and harsh.
- Replace the current low-polygon character models with more detailed and anatomically correct models. Add variations in clothing and appearance.
- Increase the texture resolution and detail on all surfaces, especially buildings, roads, and foliage. Implement normal maps and specular maps for greater realism.
- Enhance the backdrop by adding more detailed building models in the distance, atmospheric perspective (haze), and a more nuanced skybox.
- Refine the material properties of all objects to better simulate real-world materials. This includes adjusting reflectivity, roughness, and subsurface scattering where appropriate.
**baseline / boulevard_night** fixes:
- Improve lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.
- Significantly upgrade material shaders to achieve realistic PBR (Physically Based Rendering) properties, especially for brick, asphalt, glass, and metal, to mimic the specular highlights, subsurface scattering, and roughness of the target.
- Increase texture resolution and detail for all surfaces, particularly the brickwork, sidewalk, and building facades, to match the fine-grained realism of the target.
- Redesign character models with higher polygon counts, more detailed textures, and realistic clothing and facial features to match the stylized but grounded look of the target's lone figure.
- Enhance the backdrop by adding atmospheric effects like fog, rain, and distant city lights, and refine the building models to have more architectural detail and variation, similar to the target's moody urban environment.
**baseline / entrance_day** fixes:
- Improve brick texture and material to match the target's depth and variation.
- Add more detailed and varied foliage, especially for the trees and bushes, to match the target's organic look.
- Enhance lighting to create softer shadows, more atmospheric haze, and warmer tones, particularly around the building entrance and street.
- Refine building details, such as window frames, signage, and architectural elements, to increase realism.
- Introduce subtle imperfections and wear on surfaces like the sidewalk and building facade to mimic real-world aging.
**baseline / street_day** fixes:
- Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog for atmospheric perspective.
- Replace flat, untextured building models with detailed geometry and realistic materials (concrete, glass, metal).
- Add high-resolution textures to all surfaces, especially the road, sidewalk, and buildings, to mimic the detail in the target.
- Model a more detailed and varied cityscape for the backdrop, including buildings with distinct architectural styles and realistic lighting.
- Redesign character models to be more anatomically correct and have realistic clothing textures and animations.
**baseline / street_night** fixes:
- Improve lighting to match the dramatic sunset and neon glow of the target image, focusing on volumetric lighting and bloom effects.
- Enhance material properties for buildings, road, and car to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.
- Increase texture resolution and detail on all surfaces, especially the road and building facades, to mimic the fine grain and imperfections seen in the target.
- Redesign the backdrop to include a more detailed and atmospheric skyline with realistic haze and a richer sunset color gradient.
- Replace the current character models with more detailed and realistically proportioned characters that fit the urban environment.
**candidate / boulevard_day** fixes:
- Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.
- Increase texture resolution and detail on buildings, especially the brickwork, to match the target's fidelity.
- Replace stylized character models with realistic human models that have appropriate proportions and clothing.
- Enhance lighting to create softer shadows, more realistic ambient occlusion, and better global illumination, especially around the streetlights and building facades.
- Add atmospheric perspective and volumetric fog to the distant cityscape to create a more convincing sense of depth and distance haze.
**candidate / boulevard_night** fixes:
- Improve lighting to create atmospheric mood, with strong contrast and volumetric effects like fog/rain.
- Enhance material properties for realism: add specular highlights, subsurface scattering for skin, and more detailed surface imperfections.
- Increase texture resolution and detail, especially on buildings, pavement, and clothing, to match the target's gritty realism.
- Redesign characters to have more realistic proportions, clothing, and facial features, and animate them with more natural movement.
- Develop a more detailed and atmospheric backdrop, including realistic city buildings, distant haze, and appropriate weather effects.
**candidate / entrance_day** fixes:
- Improve brick texture and material to add more variation, grime, and imperfections.
- Enhance lighting to create softer shadows, more atmospheric haze, and realistic light falloff.
- Add more detail and variation to the building facade, including window frames, signage, and architectural elements.
- Replace low-poly trees and bushes with more detailed and realistic foliage models.
- Refine character models to match the realistic style of the target image, focusing on proportions, clothing, and facial features.
**candidate / street_day** fixes:
- Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.
- Add significant detail to the car models, including realistic reflections, panel gaps, and tire textures.
- Implement volumetric fog and atmospheric scattering to create a more convincing sense of depth and haze in the backdrop.
- Replace the placeholder character with a detailed, realistically lit 3D model that matches the environment's style.
- Enhance the lighting model to include softer shadows, more accurate ambient occlusion, and realistic light bounce.
**candidate / street_night** fixes:
- Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.
- Significantly enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.
- Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the crispness and complexity of the target.
- Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to match the sunset.
- Completely overhaul character models to be significantly more detailed, with realistic proportions, clothing, and animation, to match the quality of the target scene.
**candidate_dusk / boulevard_day** fixes:
- Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog or atmospheric perspective to the distant cityscape.
- Replace low-poly, stylized assets (trees, characters, buildings) with high-fidelity models that have realistic proportions and details.
- Apply PBR materials with appropriate roughness, metallic, and normal maps to all surfaces (road, sidewalk, buildings, foliage) to simulate real-world material properties.
- Increase texture resolution and add surface imperfections (grime, wear, subtle variations) to the road, sidewalk, and building facades.
- Refine character models to have realistic anatomy, clothing, and animation, and ensure they are properly lit and integrated into the scene.
**candidate_dusk / boulevard_night** fixes:
- Improve the lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.
- Significantly upgrade the character models and animations to be more realistic, with detailed clothing, facial features, and natural posing, rather than the current low-poly, cartoonish style.
- Enhance material properties and textures for all surfaces (brick, pavement, doors, clothing) to achieve a photorealistic look, with appropriate roughness, reflectivity, and detailed normal maps, especially for the wet environment.
- Refine the backdrop elements, including the distant city skyline and atmospheric haze, to create a sense of depth and realism consistent with the target image's moody atmosphere.
- Implement more realistic environmental effects, such as rain, puddles with accurate reflections, and subtle fog, to enhance the overall immersion and match the target's gritty, wet ambiance.
**candidate_dusk / entrance_day** fixes:
- judge failed: OpenRouter HTTP 400: {"error":{"message":"Provider returned error","code":400,"metadata":{"raw":"{\n \"error\": {\n \"code\": 400,\n \"message\": \"API key not valid. Please pass a valid API key.\",\n \"status\": \"INVALID_ARGUMENT\",\n \"details\": [\n {\n \"@type\": \"type.googleapis.com/googl
**candidate_dusk / street_day** fixes:
- Improve road and sidewalk material PBR values to match the target's roughness and reflectivity.
- Increase the resolution and detail of building textures in the backdrop to reduce the blurry, low-poly appearance.
- Add atmospheric perspective and volumetric fog to the distant cityscape to mimic the target's depth and haze.
- Enhance car material properties, particularly reflections and specular highlights, to match the target's realism.
- Redesign character models to have more detailed geometry, textures, and more natural proportions and posing.
**candidate_dusk / street_night** fixes:
- Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.
- Enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.
- Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the fine details seen in the target.
- Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to mimic the target's sunset.
- Significantly rework character models to be more realistic in terms of proportions, texturing, and animation, as the current models are very stylized and cartoony.
@@ -1,360 +0,0 @@
{
"run": "docs/screens/realism/2026-11-01-v2",
"judge_model": "google/gemini-2.5-flash-lite",
"sets": {
"baseline": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.75,
"fine_detail": 8.2,
"contrast": 49.63,
"saturation_mean": 72.04,
"colour_spread": 55.45
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.036,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 1.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve the lighting model to include more realistic global illumination and soft shadows. The current lighting is too flat and harsh.",
"Replace the current low-polygon character models with more detailed and anatomically correct models. Add variations in clothing and appearance.",
"Increase the texture resolution and detail on all surfaces, especially buildings, roads, and foliage. Implement normal maps and specular maps for greater realism.",
"Enhance the backdrop by adding more detailed building models in the distance, atmospheric perspective (haze), and a more nuanced skybox.",
"Refine the material properties of all objects to better simulate real-world materials. This includes adjusting reflectivity, roughness, and subsurface scattering where appropriate."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 21.77,
"fine_detail": 8.45,
"contrast": 50.38,
"saturation_mean": 95.12,
"colour_spread": 55.61
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.231,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 1.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.",
"Significantly upgrade material shaders to achieve realistic PBR (Physically Based Rendering) properties, especially for brick, asphalt, glass, and metal, to mimic the specular highlights, subsurface scattering, and roughness of the target.",
"Increase texture resolution and detail for all surfaces, particularly the brickwork, sidewalk, and building facades, to match the fine-grained realism of the target.",
"Redesign character models with higher polygon counts, more detailed textures, and realistic clothing and facial features to match the stylized but grounded look of the target's lone figure.",
"Enhance the backdrop by adding atmospheric effects like fog, rain, and distant city lights, and refine the building models to have more architectural detail and variation, similar to the target's moody urban environment."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 26.19,
"fine_detail": 9.27,
"contrast": 56.39,
"saturation_mean": 65.24,
"colour_spread": 59.96
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.308,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 3.0,
"characters": 10.0,
"overall": 2.0
},
"fixes": [
"Improve brick texture and material to match the target's depth and variation.",
"Add more detailed and varied foliage, especially for the trees and bushes, to match the target's organic look.",
"Enhance lighting to create softer shadows, more atmospheric haze, and warmer tones, particularly around the building entrance and street.",
"Refine building details, such as window frames, signage, and architectural elements, to increase realism.",
"Introduce subtle imperfections and wear on surfaces like the sidewalk and building facade to mimic real-world aging."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 12.44,
"fine_detail": 5.32,
"contrast": 41.37,
"saturation_mean": 77.84,
"colour_spread": 44.96
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.307,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 2.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog for atmospheric perspective.",
"Replace flat, untextured building models with detailed geometry and realistic materials (concrete, glass, metal).",
"Add high-resolution textures to all surfaces, especially the road, sidewalk, and buildings, to mimic the detail in the target.",
"Model a more detailed and varied cityscape for the backdrop, including buildings with distinct architectural styles and realistic lighting.",
"Redesign character models to be more anatomically correct and have realistic clothing textures and animations."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 11.94,
"fine_detail": 5.35,
"contrast": 48.34,
"saturation_mean": 98.21,
"colour_spread": 48.85
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.337,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 1.0,
"backdrop": 2.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the dramatic sunset and neon glow of the target image, focusing on volumetric lighting and bloom effects.",
"Enhance material properties for buildings, road, and car to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.",
"Increase texture resolution and detail on all surfaces, especially the road and building facades, to mimic the fine grain and imperfections seen in the target.",
"Redesign the backdrop to include a more detailed and atmospheric skyline with realistic haze and a richer sunset color gradient.",
"Replace the current character models with more detailed and realistically proportioned characters that fit the urban environment."
]
}
}
},
"candidate": {
"boulevard_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 20.67,
"fine_detail": 7.8,
"contrast": 42.49,
"saturation_mean": 67.55,
"colour_spread": 48.32
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.113,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 5.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.",
"Increase texture resolution and detail on buildings, especially the brickwork, to match the target's fidelity.",
"Replace stylized character models with realistic human models that have appropriate proportions and clothing.",
"Enhance lighting to create softer shadows, more realistic ambient occlusion, and better global illumination, especially around the streetlights and building facades.",
"Add atmospheric perspective and volumetric fog to the distant cityscape to create a more convincing sense of depth and distance haze."
]
}
},
"boulevard_night": {
"target": "docs/screens/concepts/hollywood_entrance_rain_night.png",
"metrics": {
"edge_density": 20.67,
"fine_detail": 7.86,
"contrast": 46.43,
"saturation_mean": 98.69,
"colour_spread": 50.59
},
"target_metrics": {
"edge_density": 8.43,
"fine_detail": 3.51,
"contrast": 27.34,
"saturation_mean": 159.44,
"colour_spread": 26.61
},
"metric_gap": 1.073,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 3.0,
"characters": 2.0,
"overall": 1.0
},
"fixes": [
"Improve lighting to create atmospheric mood, with strong contrast and volumetric effects like fog/rain.",
"Enhance material properties for realism: add specular highlights, subsurface scattering for skin, and more detailed surface imperfections.",
"Increase texture resolution and detail, especially on buildings, pavement, and clothing, to match the target's gritty realism.",
"Redesign characters to have more realistic proportions, clothing, and facial features, and animate them with more natural movement.",
"Develop a more detailed and atmospheric backdrop, including realistic city buildings, distant haze, and appropriate weather effects."
]
}
},
"entrance_day": {
"target": "docs/screens/concepts/hollywood_entrance_morning.png",
"metrics": {
"edge_density": 24.54,
"fine_detail": 8.92,
"contrast": 52.41,
"saturation_mean": 61.63,
"colour_spread": 54.98
},
"target_metrics": {
"edge_density": 16.87,
"fine_detail": 6.92,
"contrast": 70.27,
"saturation_mean": 121.02,
"colour_spread": 69.83
},
"metric_gap": 0.303,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 3.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve brick texture and material to add more variation, grime, and imperfections.",
"Enhance lighting to create softer shadows, more atmospheric haze, and realistic light falloff.",
"Add more detail and variation to the building facade, including window frames, signage, and architectural elements.",
"Replace low-poly trees and bushes with more detailed and realistic foliage models.",
"Refine character models to match the realistic style of the target image, focusing on proportions, clothing, and facial features."
]
}
},
"street_day": {
"target": "docs/screens/concepts/boulevard_skyline_day.png",
"metrics": {
"edge_density": 14.54,
"fine_detail": 5.32,
"contrast": 36.3,
"saturation_mean": 74.49,
"colour_spread": 39.9
},
"target_metrics": {
"edge_density": 20.74,
"fine_detail": 8.23,
"contrast": 54.85,
"saturation_mean": 73.09,
"colour_spread": 58.16
},
"metric_gap": 0.326,
"judge": {
"scores": {
"lighting": 2.0,
"materials": 1.0,
"texture_detail": 1.0,
"backdrop": 3.0,
"characters": 1.0,
"overall": 1.0
},
"fixes": [
"Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.",
"Add significant detail to the car models, including realistic reflections, panel gaps, and tire textures.",
"Implement volumetric fog and atmospheric scattering to create a more convincing sense of depth and haze in the backdrop.",
"Replace the placeholder character with a detailed, realistically lit 3D model that matches the environment's style.",
"Enhance the lighting model to include softer shadows, more accurate ambient occlusion, and realistic light bounce."
]
}
},
"street_night": {
"target": "docs/screens/concepts/boulevard_skyline_dusk.png",
"metrics": {
"edge_density": 16.12,
"fine_detail": 6.06,
"contrast": 48.36,
"saturation_mean": 103.44,
"colour_spread": 49.1
},
"target_metrics": {
"edge_density": 8.83,
"fine_detail": 4.61,
"contrast": 33.26,
"saturation_mean": 188.16,
"colour_spread": 35.38
},
"metric_gap": 0.495,
"judge": {
"scores": {
"lighting": 3.0,
"materials": 2.0,
"texture_detail": 2.0,
"backdrop": 4.0,
"characters": 1.0,
"overall": 2.0
},
"fixes": [
"Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.",
"Significantly enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.",
"Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the crispness and complexity of the target.",
"Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to match the sunset.",
"Completely overhaul character models to be significantly more detailed, with realistic proportions, clothing, and animation, to match the quality of the target scene."
]
}
}
}
}
}
@@ -1,86 +0,0 @@
# Realism report: `docs/screens/realism/2026-11-01-v2`
Vision judge: `google/gemini-2.5-flash-lite` (scores 0-10, higher is more realistic compared with the concept target).
| set | shot | target | gap ↓ | edges | detail | contrast | overall | lighting | materials | texture | backdrop |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| baseline | boulevard_day | boulevard_skyline_day | 0.036 | 20.75 | 8.2 | 49.63 | 2.0 | 3.0 | 2.0 | 1.0 | 4.0 |
| baseline | boulevard_night | hollywood_entrance_rain_night | 1.231 | 21.77 | 8.45 | 50.38 | 1.0 | 2.0 | 1.0 | 1.0 | 2.0 |
| baseline | entrance_day | hollywood_entrance_morning | 0.308 | 26.19 | 9.27 | 56.39 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| baseline | street_day | boulevard_skyline_day | 0.307 | 12.44 | 5.32 | 41.37 | 1.0 | 2.0 | 1.0 | 1.0 | 2.0 |
| baseline | street_night | boulevard_skyline_dusk | 0.337 | 11.94 | 5.35 | 48.34 | 2.0 | 3.0 | 2.0 | 1.0 | 2.0 |
| candidate | boulevard_day | boulevard_skyline_day | 0.113 | 20.67 | 7.8 | 42.49 | 2.0 | 3.0 | 2.0 | 2.0 | 5.0 |
| candidate | boulevard_night | hollywood_entrance_rain_night | 1.073 | 20.67 | 7.86 | 46.43 | 1.0 | 2.0 | 1.0 | 1.0 | 3.0 |
| candidate | entrance_day | hollywood_entrance_morning | 0.303 | 24.54 | 8.92 | 52.41 | 2.0 | 3.0 | 2.0 | 2.0 | 3.0 |
| candidate | street_day | boulevard_skyline_day | 0.326 | 14.54 | 5.32 | 36.3 | 1.0 | 2.0 | 1.0 | 1.0 | 3.0 |
| candidate | street_night | boulevard_skyline_dusk | 0.495 | 16.12 | 6.06 | 48.36 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 |
**baseline / boulevard_day** fixes:
- Improve the lighting model to include more realistic global illumination and soft shadows. The current lighting is too flat and harsh.
- Replace the current low-polygon character models with more detailed and anatomically correct models. Add variations in clothing and appearance.
- Increase the texture resolution and detail on all surfaces, especially buildings, roads, and foliage. Implement normal maps and specular maps for greater realism.
- Enhance the backdrop by adding more detailed building models in the distance, atmospheric perspective (haze), and a more nuanced skybox.
- Refine the material properties of all objects to better simulate real-world materials. This includes adjusting reflectivity, roughness, and subsurface scattering where appropriate.
**baseline / boulevard_night** fixes:
- Improve lighting to match the dramatic, atmospheric, and volumetric lighting of the target image, focusing on warm, directional light from the marquee and streetlamp, and realistic reflections on wet surfaces.
- Significantly upgrade material shaders to achieve realistic PBR (Physically Based Rendering) properties, especially for brick, asphalt, glass, and metal, to mimic the specular highlights, subsurface scattering, and roughness of the target.
- Increase texture resolution and detail for all surfaces, particularly the brickwork, sidewalk, and building facades, to match the fine-grained realism of the target.
- Redesign character models with higher polygon counts, more detailed textures, and realistic clothing and facial features to match the stylized but grounded look of the target's lone figure.
- Enhance the backdrop by adding atmospheric effects like fog, rain, and distant city lights, and refine the building models to have more architectural detail and variation, similar to the target's moody urban environment.
**baseline / entrance_day** fixes:
- Improve brick texture and material to match the target's depth and variation.
- Add more detailed and varied foliage, especially for the trees and bushes, to match the target's organic look.
- Enhance lighting to create softer shadows, more atmospheric haze, and warmer tones, particularly around the building entrance and street.
- Refine building details, such as window frames, signage, and architectural elements, to increase realism.
- Introduce subtle imperfections and wear on surfaces like the sidewalk and building facade to mimic real-world aging.
**baseline / street_day** fixes:
- Improve lighting to match the warm, directional sunlight and soft shadows of the target. Add volumetric fog for atmospheric perspective.
- Replace flat, untextured building models with detailed geometry and realistic materials (concrete, glass, metal).
- Add high-resolution textures to all surfaces, especially the road, sidewalk, and buildings, to mimic the detail in the target.
- Model a more detailed and varied cityscape for the backdrop, including buildings with distinct architectural styles and realistic lighting.
- Redesign character models to be more anatomically correct and have realistic clothing textures and animations.
**baseline / street_night** fixes:
- Improve lighting to match the dramatic sunset and neon glow of the target image, focusing on volumetric lighting and bloom effects.
- Enhance material properties for buildings, road, and car to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and specularity.
- Increase texture resolution and detail on all surfaces, especially the road and building facades, to mimic the fine grain and imperfections seen in the target.
- Redesign the backdrop to include a more detailed and atmospheric skyline with realistic haze and a richer sunset color gradient.
- Replace the current character models with more detailed and realistically proportioned characters that fit the urban environment.
**candidate / boulevard_day** fixes:
- Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.
- Increase texture resolution and detail on buildings, especially the brickwork, to match the target's fidelity.
- Replace stylized character models with realistic human models that have appropriate proportions and clothing.
- Enhance lighting to create softer shadows, more realistic ambient occlusion, and better global illumination, especially around the streetlights and building facades.
- Add atmospheric perspective and volumetric fog to the distant cityscape to create a more convincing sense of depth and distance haze.
**candidate / boulevard_night** fixes:
- Improve lighting to create atmospheric mood, with strong contrast and volumetric effects like fog/rain.
- Enhance material properties for realism: add specular highlights, subsurface scattering for skin, and more detailed surface imperfections.
- Increase texture resolution and detail, especially on buildings, pavement, and clothing, to match the target's gritty realism.
- Redesign characters to have more realistic proportions, clothing, and facial features, and animate them with more natural movement.
- Develop a more detailed and atmospheric backdrop, including realistic city buildings, distant haze, and appropriate weather effects.
**candidate / entrance_day** fixes:
- Improve brick texture and material to add more variation, grime, and imperfections.
- Enhance lighting to create softer shadows, more atmospheric haze, and realistic light falloff.
- Add more detail and variation to the building facade, including window frames, signage, and architectural elements.
- Replace low-poly trees and bushes with more detailed and realistic foliage models.
- Refine character models to match the realistic style of the target image, focusing on proportions, clothing, and facial features.
**candidate / street_day** fixes:
- Improve road and sidewalk materials to have more realistic specular highlights and surface imperfections.
- Add significant detail to the car models, including realistic reflections, panel gaps, and tire textures.
- Implement volumetric fog and atmospheric scattering to create a more convincing sense of depth and haze in the backdrop.
- Replace the placeholder character with a detailed, realistically lit 3D model that matches the environment's style.
- Enhance the lighting model to include softer shadows, more accurate ambient occlusion, and realistic light bounce.
**candidate / street_night** fixes:
- Improve lighting to match the dramatic, atmospheric sunset and neon glow of the target image. Add volumetric fog and bloom effects.
- Significantly enhance material properties for buildings, road, and vehicles to achieve a more realistic PBR (Physically Based Rendering) look, with appropriate reflections and surface imperfections.
- Increase texture resolution and detail on all surfaces, especially buildings and the road, to match the crispness and complexity of the target.
- Redesign the backdrop to include a more detailed and atmospheric city skyline with appropriate haze and color grading to match the sunset.
- Completely overhaul character models to be significantly more detailed, with realistic proportions, clothing, and animation, to match the quality of the target scene.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 KiB

After

Width:  |  Height:  |  Size: 731 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

After

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 659 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 KiB

After

Width:  |  Height:  |  Size: 669 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 KiB

After

Width:  |  Height:  |  Size: 761 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 KiB

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff. Show more