diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f5f9c..5afd4d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable user-facing changes to Gig Line. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions use Semantic Versioning. -## [Unreleased] +## [0.9.5] — 2026-11-02 ### Changed diff --git a/MEMORY.md b/MEMORY.md index d601156..b28e45c 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -63,14 +63,20 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o `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 + flashlight wash were accepted or deferred. The 24-NPC budget is 6.94 ms, the gallery is 13 good / 0 bad, the screen-design judge is 13/13 and a clean portrait measured a 0.732 vision gap against the photoreal concept. No release build, version bump or tag was created at this gate. - **NPC texture resolution (0.9.5, 2026-11-02):** `tools/npc_pipeline.py` now generates 256² albedo/normal/ORM maps instead of 128² (AI shirt/trousers are resized to 256). The base and all eight library GLBs plus AO maps were rebuilt; texture files total ~0.5 MB, eight GLBs ~5.75 MB, - and the 24-NPC smoke remains 6.90 ms. + and the 24-NPC smoke is 6.94 ms. +- **0.9.5 texture/UI audit (2026-11-02):** all 21 screen-art textures are + 1280×720 and referenced by their screens; access cards are 256×128 and HUD + icons 64×64, with no oversized or unused runtime texture. The 24-NPC smoke now + reports **168 meshes / 131,616 triangles / 6.94 ms** (50 ms budget). Compressed + payloads are picks **24.55 MB**, UI art **22.67 MB**, NPC maps **0.48 MB**. + Legacy root textures remain only for `generate_textures.py` and the asset test. - **Environment surface audit (0.9.5, 2026-11-02):** `capture_realism.gd` gained `surfaces` (Hollywood pavers/asphalt/limestone/facade) and `surfaces_joke` (neighbour awning, canopy, pavers) stages with the HUD hidden. The Walk of Fame @@ -168,16 +174,15 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o 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** + polish milestone, **0.9.4** after the NPC pass, now **0.9.5** after the texture + and material pass. Next work is **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 + major-version scope is defined yet. The `v0.9.5` 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. + 0.9.3 UI polish, 0.9.4 NPC visual optimization and 0.9.5 texture/material pass + are complete and in `DONE.md`. 0.9.6 integration and 0.10.0 release work are + next. The current source version is 0.9.5. - **Release v0.9.4 (2026-11-02):** commit `a57b86c` tagged `v0.9.4`; Gitea Actions run 916 passed checks and the full build and published seven assets (Linux, Windows, macOS, NSIS setup, AppImage, Web, Desktop HQ). Release page: @@ -205,7 +210,7 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o `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. + detail stays with the 0.9.5 texture pass rather than the map milestone. - **Docs validation (2026-11-02):** `python3 tools/check_docs.py` requires a README only in directories containing tracked files, verifies local links and requires every tracked image in a folder to be linked from its README. Gitignored @@ -843,8 +848,8 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o `PLAN.md` describes intended design; `README.md` and `DONE.md` describe what shipped. As of 2026-11-02 the playable build covers the three venues, tutorials/campaign/checkpoints, the 0.9.3 -UI/accessibility pass, the 0.9.4 NPC visual optimization, and the Blender + realism asset pipeline. `TODO.md` holds the remaining -0.9.4–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not +UI/accessibility pass, the 0.9.4 NPC visual optimization, the 0.9.5 texture/material pass, and the Blender + realism asset pipeline. `TODO.md` holds the remaining +0.9.6–0.10.0 work. The project uses a custom headless runner, not GUT, and Gitea Actions, not GitHub Actions. diff --git a/PLAN.md b/PLAN.md index 9a6988e..8fc7b77 100644 --- a/PLAN.md +++ b/PLAN.md @@ -176,7 +176,7 @@ Primary decisions: [ADR-0007](docs/adr/0007-locomotion-and-input-layers.md), [AD ## Versioning and Delivery -`config/version` in `project.godot` is the single version source (currently `0.9.4`). Releases are tagged `v`; the CI pipeline builds and publishes the standard artifacts plus the optional Desktop HQ zip. Version bumps follow [Semantic Versioning](https://semver.org/). See [`docs/RELEASING.md`](docs/RELEASING.md) and [`README.md`](README.md) for commands. +`config/version` in `project.godot` is the single version source (currently `0.9.5`). Releases are tagged `v`; 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 diff --git a/README.md b/README.md index e75270c..526bc4f 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,13 @@ precision walk, the Joke Shop's Sunset Strip frontage, the TV Studio arrival, an > Downloads are public (no sign-in required) since the host's instance-wide > `REQUIRE_SIGNIN_VIEW` was disabled on 2026-10-31. > -> **Latest published: v0.9.4** — the NPC visual optimization pass: face/head -> depth, hands and gear placement, shoes and boots, headgear clearance, and the -> 8,000/8,000 character mesh budget on top of the Hollywood/Joke Shop maps and +> **Latest published: v0.9.5** — the texture and material refinement pass: +> 256² NPC maps, a four-times fabric weave without baked AO blotches, repair of +> the Walk of Fame terrazzo band and awning stripe, and per-phase skyline haze, +> on top of the v0.9.4 NPC visual optimization, 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. +> **Current source: v0.9.5** — tagged and built from the same commit. > Releases are built automatically when a `vX.Y.Z` tag is pushed > (see [`docs/RELEASING.md`](docs/RELEASING.md)); manual builds use > `./tools/build_releases.sh`. Installer/AppImage packaging runs in the same pipeline @@ -121,18 +122,19 @@ Full setup, every run/test/smoke command, and the controls table are in - [`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/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-visual-review.md`](docs/npc-visual-review.md) — 0.9.4 NPC baseline, acceptance criteria and ranked visual gaps; 0.9.5 texture comparison is in `docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`. - [`docs/npc-proportion-audit.md`](docs/npc-proportion-audit.md) — NPC proportion measurements against the shared stylized guide. - [`docs/adr/`](docs/adr/) — Architecture Decision Records. - [`TODO.md`](TODO.md) — Active tasks plus the 0.x gap analysis and milestone roadmap. ## Development Status -v0.9.4 is the current source version: the completed NPC visual optimization -(face/head depth, hands and gear placement, shoes/boots, headgear clearance and -the 8,000/8,000 mesh budget), on top of the v0.9.3 UI/accessibility polish -pass and v0.9.2's Hollywood/Joke Shop map rebuilds. It builds on -v0.9.1's Godot 4.7.2 baseline, v0.9.0's production-quality pass, v0.8's +v0.9.5 is the current source version: the completed texture and material +refinement (256² NPC maps, a 4× fabric weave with baked-AO removal, repaired +Walk of Fame/awning surfaces and per-phase skyline haze), on top of the v0.9.4 +NPC visual optimization and the v0.9.3 UI/accessibility polish pass. It builds on +v0.9.2's Hollywood/Joke Shop map rebuilds, v0.9.1's Godot 4.7.2 baseline, +v0.9.0's production-quality pass, v0.8's tutorial/campaign/resume work and the v0.7.x venue/gear/judge work. 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). diff --git a/TODO.md b/TODO.md index 97070fa..b59fbd7 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,7 @@ see `AGENTS.md` for the workflow and `MEMORY.md` for the decisions behind these ## Gap Analysis and 0.x Roadmap -Baseline: **v0.9.4** (2026-11-02). Three playable venues, tutorial/campaign/checkpoint resume, +Baseline: **v0.9.5** (2026-11-02). Three playable venues, tutorial/campaign/checkpoint resume, difficulty/help, audio/accessibility settings, a 24-NPC budget baseline, a complete escalation/access/radio loop, shift review, the Blender asset library, 263 headless + 101 Python tests, a 21/21 clean screen-design judge and an optional Forward+ Desktop HQ build. This is a strong @@ -37,7 +37,7 @@ release-candidate foundation, not yet a 0.10.0 release candidate. | Animation/presentation | Procedural pose layers, portrait captures, reduced hem clipping, 8,000/8,000 NPC cap | Thorough NPC silhouette/face/gear/pose/LOD optimization before visual QA | Close-up jank reduces perceived quality | Complete (0.9.4) | | Audio/accessibility | Procedural ambience/SFX, volume controls, captions/reduce-motion settings, searchable Help | Full accessibility/localization acceptance review, audio caption coverage and P0/P1 fixes | Public release cannot claim accessible play | 0.10.0 | | Localization | English JSON table, validation and input-generated Help | Pseudo-locale/layout audit and translator workflow sign-off | Text expansion/clipping at release | 0.10.0 | -| Performance/platform | 24-NPC headless budget (6.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 | +| Performance/platform | 24-NPC headless budget (6.94 ms), Compatibility/Web/HQ paths | Target hardware matrix, Web/HQ manual profiling, frame-time/memory evidence | Platform-specific drops or startup failures | 0.9.6 / 0.10.0 | | Save lifecycle | Settings/campaign/history/checkpoint files, atomic writes | Migration fixtures from 0.8/0.9, fresh-install/upgrade verification, rollback instructions | Player progress loss on upgrade | 0.10.0 | | QA/CI | Headless suite, smokes, screenshot compare, 21/21 judge | Release-candidate smoke matrix, final gallery and release dry run | Regressions escape the release gate | 0.9.6 / 0.10.0 | | Release/legal | Unsigned desktop/macOS builds, Web/HQ packages | Signing/notarization decision, checksums, AI-asset provenance, credits, privacy/body-camera and rating review | Public release blocked by trust/policy | 0.10.0 | @@ -45,12 +45,12 @@ release-candidate foundation, not yet a 0.10.0 release candidate. | 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+ | **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. +**0.9.3 UI polish**, **0.9.4 NPC visual optimization** and **0.9.5 texture +refinement** passes are complete (all moved to `DONE.md` on 2026-11-02). +0.9.6 integration and the 0.10.0 release candidate are queued. The source +version is now 0.9.5. -## Postponed — Patch 0.9.5 — Texture and material refinement +## 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. @@ -82,20 +82,36 @@ Compatibility/Web parity, deterministic assets and offline CI. skin/hair/gear keep AO. Comparison `sheet_npc_baseline_compare-texuv.jpg`.) - [x] Re-bake AO where geometry changes; verify the 256² maps and material wiring. (No character geometry changed in the texture pass; asset/base audits pass.) -- [ ] 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. +- [x] Audit library props and UI/card/icon textures at their actual screen sizes; + remove blurry/oversized or unused textures where safe. (All 21 screen-art + textures are 1280×720 and referenced; access cards are 256×128, HUD icons + 64×64; no oversized or unused runtime texture found. Legacy root textures + remain only as the `generate_textures.py`/asset-test fallback.) +- [x] Run texture audits, import, and the full asset test suite; record texture memory + and triangle/draw-call impact. (Godot 263/263, Python 101/101; asset and base + audits pass; 24 NPCs = 168 meshes / 131,616 triangles / 6.94 ms. Compressed + payloads: picks 24.55 MB, UI art 22.67 MB, NPC maps 0.48 MB.) ### 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. +- [x] Run `python3 tools/scene_concepts.py realism` for the affected stages with the + judge enabled; record metric gaps and model/spend. (Run + `docs/screens/realism/2026-11-02-tex` with `z-ai/glm-5.3-flash`, one pass per + shot; mean `after` overall 1.8, lighting 2.3, materials 1.8, texture 1.2, + backdrop 2.0, characters 1.2, Pillow gap 0.306. The judge is optional and not + a CI gate; the report stays local.) +- [x] Re-run `tools/check_screenshots.sh` and the screen-design judge; clear all + `diff` verdicts. (21 good / 0 bad; `screen_designs.py judge` = 21/21 match, + 0 review, 0 diff.) +- [x] Capture before/after close-ups for brick, pavement, asphalt, character cloth + and skyline; document accepted trade-offs. (Committed + `docs/blender_previews/sheet_texture_refinement_0.9.5.jpg`: Walk of Fame + pavers, asphalt aggregate, limestone facade, day skyline haze and NPC cloth; + asphalt/limestone picks intentionally held, no replacement.) +- [x] Update asset docs and the changelog/status with the promoted texture versions. + (README/PLAN/architecture/status/MEMORY and the 0.9.5 changelog entry now + carry the texture results; the 0.9.5 section moved to `DONE.md` after the + release build.) ## Postponed — Patch 0.9.6 — Integration, performance and judge gate diff --git a/docs/architecture.md b/docs/architecture.md index af9f456..92e59cd 100644 --- a/docs/architecture.md +++ b/docs/architecture.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. - **PATCH** — bug fixes and small polish that do not change behavior. -The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.4`). Each release is tagged in git as `v` (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). +The single source of truth for the version is `config/version` in `project.godot` (currently `0.9.5`). Each release is tagged in git as `v` (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 diff --git a/docs/asset-tooling.md b/docs/asset-tooling.md index 3915098..94c7a3c 100644 --- a/docs/asset-tooling.md +++ b/docs/asset-tooling.md @@ -235,12 +235,13 @@ godot --path . --script res://src/test/capture_npc_baseline.gd -- \ python3 tools/npc_baseline.py sheet --dir tmp/npc-baseline ``` -`capture_realism.gd` runs nine stages (day, Hollywood surface close-ups, Joke Shop surface close-ups, 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). For the 0.9.5 texture audit, run the surface -stages directly; the HUD is hidden for them: +`capture_realism.gd` runs nine stages in this order: day, Hollywood surface close-ups, +portrait, evening, late, Joke Shop day, Joke Shop surface close-ups, 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). For the 0.9.5 texture audit, run +the surface stages directly; the HUD is hidden for them: ```bash godot --path . --script res://src/test/capture_realism.gd \ @@ -249,11 +250,24 @@ godot --path . --script res://src/test/capture_realism.gd \ 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. +resulting decisions/docs, not the run folders. The 0.9.5 texture/UI audit checked actual screen sizes: all screen art is +1280×720, access cards are 256×128 and HUD icons are 64×64; no runtime texture +was oversized or unused. The 24-NPC smoke now reports 168 meshes / 131,616 +triangles / 6.94 ms. Compressed payloads are 24.55 MB of surface picks, 22.67 MB +of screen art and 0.48 MB of NPC maps. + +The 0.9.5 realism judge ran once per shot with `z-ai/glm-5.3-flash` +(`python3 tools/scene_concepts.py realism --run docs/screens/realism/2026-11-02-tex +--judge`). Its mean `after` scores were overall 1.8, lighting 2.3, materials 1.8, +texture detail 1.2, backdrop 2.0 and characters 1.2; the Pillow metric gap was +0.306. The judge still ranks the painted concept targets above the stylized build, +particularly lit night facades and dense backdrop detail. That is expected: the +pass validated close-range surfaces and promoted the texture repairs, not a +photoreal renderer. The 0.9.5 before/after close-up sheet is +[`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg); +the texture-adoption run itself was the earlier 0.8-style candidate comparison, +and its report remains local/gitignored. + 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 diff --git a/docs/blender_previews/README.md b/docs/blender_previews/README.md index f096a7a..ce283b4 100644 --- a/docs/blender_previews/README.md +++ b/docs/blender_previews/README.md @@ -54,6 +54,7 @@ Committed contact sheets and local Blender renders for the character, gear and p | sheet_npc_baseline_compare-shoes.jpg | [`sheet_npc_baseline_compare-shoes.jpg`](sheet_npc_baseline_compare-shoes.jpg) | | sheet_npc_baseline_compare-tex256.jpg | [`sheet_npc_baseline_compare-tex256.jpg`](sheet_npc_baseline_compare-tex256.jpg) | | sheet_npc_baseline_compare-texuv.jpg | [`sheet_npc_baseline_compare-texuv.jpg`](sheet_npc_baseline_compare-texuv.jpg) | +| sheet_texture_refinement_0.9.5.jpg | [`sheet_texture_refinement_0.9.5.jpg`](sheet_texture_refinement_0.9.5.jpg) | | sheet_npc_gear.jpg | [`sheet_npc_gear.jpg`](sheet_npc_gear.jpg) | | sheet_props.jpg | [`sheet_props.jpg`](sheet_props.jpg) | | shoulder_bag.png | [`shoulder_bag.png`](shoulder_bag.png) | diff --git a/docs/blender_previews/sheet_texture_refinement_0.9.5.jpg b/docs/blender_previews/sheet_texture_refinement_0.9.5.jpg new file mode 100644 index 0000000..ed8763f Binary files /dev/null and b/docs/blender_previews/sheet_texture_refinement_0.9.5.jpg differ diff --git a/docs/development-status.md b/docs/development-status.md index eb2aa1d..832b5aa 100644 --- a/docs/development-status.md +++ b/docs/development-status.md @@ -44,7 +44,9 @@ Implemented so far: - 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`. - Release v0.9.4 (2026-11-02): the tagged commit `a57b86c` passed the Gitea checks and full build and published seven artifacts (Linux, Windows, macOS, NSIS setup, AppImage, Web and Desktop HQ). Release page: . - Environment texture pass (0.9.5 work): `capture_realism.gd` now has hidden-HUD `surfaces`/`surfaces_joke` close-up stages. The Walk of Fame band uses the paver texture as dark terrazzo, the neighbour awning keeps its cream stripe, and the skyline shader blends its lower 42 m toward a per-phase haze colour. Brick, asphalt, limestone and paver UV scales/profiles passed without replacement. +- Texture/prop audit (0.9.5 work): all 21 screen-art textures are 1280×720 and referenced; access cards are 256×128 and HUD icons 64×64. No oversized or unused runtime texture was found; the legacy root textures remain only as the texture-generator/asset-test fallback. The 24-NPC smoke now reports 168 meshes, 131,616 triangles and 6.94 ms (50 ms budget); compressed payload is 24.55 MB of surface picks, 22.67 MB of screen art and 0.48 MB of NPC maps. - NPC texture pass (0.9.5 work): the NPC base and all eight library characters now use 256² albedo/normal/ORM maps instead of 128². Cloth and pants use `NPC_FABRIC_UV_SCALE` (4× weave) and skip the baked per-character AO, removing the large blotchy patches in portraits; skin, hair and gear keep baked AO. The base and eight GLBs plus AO maps were rebuilt; the 24-NPC smoke remains green. +- Texture visual verification (0.9.5 work): the nine-stage realism run used `z-ai/glm-5.3-flash` once per shot; mean `after` scores were overall 1.8, lighting 2.3, materials 1.8, texture detail 1.2, backdrop 2.0 and characters 1.2, with a Pillow metric gap of 0.306. The judge remains an optional review aid, not a CI gate. The committed before/after close-up sheet is [`blender_previews/sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg); it records that the paver/Walk of Fame and NPC fabric repairs are visible, while asphalt, limestone and skyline picks held without a replacement. `tools/check_screenshots.sh` passed 21 good / 0 bad and the screen-design judge passed 21/21 match with 0 review. - 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. @@ -74,6 +76,6 @@ Implemented so far: - 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. +- 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.94 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. 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). diff --git a/docs/npc-visual-review.md b/docs/npc-visual-review.md index f273b4e..3d11a7d 100644 --- a/docs/npc-visual-review.md +++ b/docs/npc-visual-review.md @@ -93,7 +93,7 @@ pass every applicable item before a library rebuild is accepted. 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 + within the existing 6.94 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 @@ -224,11 +224,14 @@ The face-detail pass is [`sheet_npc_baseline_compare-face-detail.jpg`](blender_p 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. +The 0.9.5 texture pass adds +[`sheet_texture_refinement_0.9.5.jpg`](blender_previews/sheet_texture_refinement_0.9.5.jpg), +which pairs the close-range surface and cloth comparisons. 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.9.4 and the 0.9.5 texture pass are closed. The next visual work belongs to the 0.10.0 acceptance review; keep the NPC baseline/final-context commands as the regression gate for any future character edit. diff --git a/docs/screenshots/01-venue-overview.png b/docs/screenshots/01-venue-overview.png index eaf5cde..35a9ba9 100644 Binary files a/docs/screenshots/01-venue-overview.png and b/docs/screenshots/01-venue-overview.png differ diff --git a/docs/screenshots/02-targeting-npc.png b/docs/screenshots/02-targeting-npc.png index dfb1b51..feb5fba 100644 Binary files a/docs/screenshots/02-targeting-npc.png and b/docs/screenshots/02-targeting-npc.png differ diff --git a/docs/screenshots/05-late-night-avenue.png b/docs/screenshots/05-late-night-avenue.png index 0b36010..4a313f6 100644 Binary files a/docs/screenshots/05-late-night-avenue.png and b/docs/screenshots/05-late-night-avenue.png differ diff --git a/docs/screenshots/06-night-flashlight.png b/docs/screenshots/06-night-flashlight.png index 712234a..eb7fadc 100644 Binary files a/docs/screenshots/06-night-flashlight.png and b/docs/screenshots/06-night-flashlight.png differ diff --git a/docs/screenshots/08-escalation-hud.png b/docs/screenshots/08-escalation-hud.png index f0ff234..28d44f1 100644 Binary files a/docs/screenshots/08-escalation-hud.png and b/docs/screenshots/08-escalation-hud.png differ diff --git a/docs/screenshots/09-body-camera-timeline.png b/docs/screenshots/09-body-camera-timeline.png index aa0ef88..612ad92 100644 Binary files a/docs/screenshots/09-body-camera-timeline.png and b/docs/screenshots/09-body-camera-timeline.png differ diff --git a/docs/screenshots/10-prop-gallery.png b/docs/screenshots/10-prop-gallery.png index ebf6120..eb00db6 100644 Binary files a/docs/screenshots/10-prop-gallery.png and b/docs/screenshots/10-prop-gallery.png differ diff --git a/docs/screenshots/11-precision-walk.png b/docs/screenshots/11-precision-walk.png index 555f8cb..2053381 100644 Binary files a/docs/screenshots/11-precision-walk.png and b/docs/screenshots/11-precision-walk.png differ diff --git a/docs/screenshots/12-joke-shop.png b/docs/screenshots/12-joke-shop.png index 6ca7219..f28caea 100644 Binary files a/docs/screenshots/12-joke-shop.png and b/docs/screenshots/12-joke-shop.png differ diff --git a/docs/screenshots/13-studio-arrival.png b/docs/screenshots/13-studio-arrival.png index e677a6d..45fcc0f 100644 Binary files a/docs/screenshots/13-studio-arrival.png and b/docs/screenshots/13-studio-arrival.png differ diff --git a/docs/screenshots/17-shift-review.png b/docs/screenshots/17-shift-review.png index d5b8436..28520ef 100644 Binary files a/docs/screenshots/17-shift-review.png and b/docs/screenshots/17-shift-review.png differ diff --git a/docs/screenshots/19-radial-menu.png b/docs/screenshots/19-radial-menu.png index a297407..1f154d9 100644 Binary files a/docs/screenshots/19-radial-menu.png and b/docs/screenshots/19-radial-menu.png differ diff --git a/docs/screenshots/20-crowd-panic.png b/docs/screenshots/20-crowd-panic.png index f5400e9..dc8cce0 100644 Binary files a/docs/screenshots/20-crowd-panic.png and b/docs/screenshots/20-crowd-panic.png differ diff --git a/docs/screenshots/21-responder-arrival.png b/docs/screenshots/21-responder-arrival.png index 7908cbe..ce8684d 100644 Binary files a/docs/screenshots/21-responder-arrival.png and b/docs/screenshots/21-responder-arrival.png differ diff --git a/project.godot b/project.godot index 3d4d3d5..2038fc1 100644 --- a/project.godot +++ b/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="Gig Line" config/description="Workplace security simulation about observation, access verification, and proportionate escalation." -config/version="0.9.4" +config/version="0.9.5" run/main_scene="res://scenes/main.tscn" config/features=PackedStringArray("4.7", "GL Compatibility") diff --git a/src/test/capture_realism.gd b/src/test/capture_realism.gd index aff9bb2..41f92ce 100644 --- a/src/test/capture_realism.gd +++ b/src/test/capture_realism.gd @@ -81,15 +81,16 @@ const SHOTS_PORTRAIT := [ ] ## Stage list: shift time selects the phase, `venue` switches the scenario first. const STAGES := [ - {"name": "day", "elapsed": 0.0, "venue": "", "shots": SHOTS_DAY, "night": false}, - {"name": "surfaces", "elapsed": 0.0, "venue": "", "shots": SHOTS_SURFACES, "night": false}, - {"name": "surfaces_joke", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_SURFACES_JOKE, "night": false}, - # Portrait next, while the day crowd is still on the street. - {"name": "portrait", "elapsed": 0.0, "venue": "", "shots": SHOTS_PORTRAIT, + {"name": "day", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_DAY, "night": false}, + {"name": "surfaces", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_SURFACES, "night": false}, + # Portrait before the venue switch: re-staging a close-up after a rebuild is + # not reliable, and this keeps the day crowd on Hollywood. + {"name": "portrait", "elapsed": 0.0, "venue": "hollywood_building", "shots": SHOTS_PORTRAIT, "night": false}, - {"name": "evening", "elapsed": 620.0, "venue": "", "shots": SHOTS_EVENING, "night": true}, - {"name": "late", "elapsed": 760.0, "venue": "", "shots": SHOTS_LATE, "night": true}, + {"name": "evening", "elapsed": 620.0, "venue": "hollywood_building", "shots": SHOTS_EVENING, "night": true}, + {"name": "late", "elapsed": 760.0, "venue": "hollywood_building", "shots": SHOTS_LATE, "night": true}, {"name": "joke_shop_day", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_JOKE_DAY, "night": false}, + {"name": "surfaces_joke", "elapsed": 0.0, "venue": "joke_shop", "shots": SHOTS_SURFACES_JOKE, "night": false}, {"name": "joke_shop", "elapsed": 700.0, "venue": "joke_shop", "shots": SHOTS_JOKE, "night": true}, {"name": "studio", "elapsed": 700.0, "venue": "tv_studio", "shots": SHOTS_STUDIO, "night": true}, ] @@ -180,6 +181,7 @@ func _process(delta: float) -> bool: return false func _begin_stage() -> void: + _clear_capture_pause() _stage += 1 while _stage < STAGES.size() and not _only_stages.is_empty() \ and not _only_stages.has(str(STAGES[_stage]["name"])): @@ -209,6 +211,7 @@ func _begin_stage() -> void: print("capture_realism: stage %s at %d ms" % [stage["name"], Time.get_ticks_msec()]) func _run_queue(delta: float) -> void: + _clear_capture_pause() if _queue.is_empty(): _phase = "stage" return @@ -241,9 +244,18 @@ func _run_queue(delta: float) -> void: _queue.pop_front() _shot_frames = 0 +## Capture staging must not inherit a pause overlay from the previous stage or a +## window-focus change; a paused frame hides the very surfaces the pass audits. +func _clear_capture_pause() -> void: + if gm == null: + return + var pause = gm.get("pause_overlay") + if pause != null and pause.visible: + gm.call("_close_pause") + ## Frame a nearby NPC from the front, with the sun behind the camera so the face -## is lit. The subject's own yaw is re-written every frame by its FSM, so the -## portrait turns the visual `Rig` child instead and stands on the sunlit side. +## is lit. The subject's FSM and idle head-turn are frozen so the still keeps the +## face toward the lens; photo/film poses are skipped because their props cover it. func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: var guard_pos: Vector3 = gm.guard.global_position var light := _sun_direction() @@ -254,7 +266,17 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: var npc := node as Node3D if npc == null or _faces_covered(npc): continue - if _portrait_type >= 0 and int(_profile_of(npc).get("npc_type")) != _portrait_type: + var profile = _profile_of(npc) + if profile == null: + continue + if _portrait_type >= 0 and int(profile.get("npc_type")) != _portrait_type: + continue + # A film/photo pose holds a camera or phone in front of the face; keep the + # default portrait on an idle person so the texture pass sees skin. + var pose := "" + if npc.has_method("theater_pose"): + pose = str(npc.call("theater_pose")) + if _portrait_type < 0 and pose in ["photo", "film", "perform"]: continue var distance: float = npc.global_position.distance_to(guard_pos) if distance > 25.0: @@ -280,9 +302,10 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: continue other.set_physics_process(false) other.global_position += Vector3(0.0, 0.0, 140.0) - # Freeze the subject: its FSM re-writes the yaw every physics tick, which - # would turn it away from the camera again. + # Freeze the subject: its FSM re-writes the yaw every physics tick, and the + # idle head-turn would still look away after the body is aimed at the camera. best.set_physics_process(false) + best.set_process(false) # Clear standing spot on the sidewalk, away from the queue: the close-up is a # character still, not a slice of the scene, and the crowd would block it. var spot := Vector3(0.0, 0.0, 0.0) @@ -290,6 +313,11 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: spot = gm.guard.get("spawn_position") best.global_position = spot + _portrait_spot best.rotation.y = 0.0 + var subject_head := best.get_node_or_null("Rig/Head") as Node3D + if subject_head == null: + subject_head = best.find_child("Head", true, false) as Node3D + if subject_head != null: + subject_head.rotation.y = 0.0 # Stand between the subject and the sun, so the face is front-lit. var to_light := -light to_light = to_light.rotated(Vector3.UP, deg_to_rad(angle_deg)) @@ -305,10 +333,12 @@ func _stage_portrait(delta: float, angle_deg: float = 0.0) -> bool: # Face the camera: from the subject, the guard lies in the -look direction. # Use the drawn rig so an FSM yaw on the root cannot fight the pose. var rig := best.find_child("Rig", true, false) as Node3D + # NPC art faces +Z; yaw the root toward the guard so the face, not the + # back, is under the camera. + var face := atan2(-look.x, -look.z) + best.rotation.y = face if rig != null: - rig.rotation.y = atan2(-look.x, -look.z) - else: - best.rotation.y = atan2(-look.x, -look.z) + rig.rotation.y = 0.0 return true diff --git a/src/test/smoke_npc_budget.gd b/src/test/smoke_npc_budget.gd index 92f5f83..22b1f07 100644 --- a/src/test/smoke_npc_budget.gd +++ b/src/test/smoke_npc_budget.gd @@ -42,10 +42,19 @@ func _process(delta: float) -> bool: if frame >= WARMUP_FRAMES + SAMPLE_FRAMES: var average := sample_ms / SAMPLE_FRAMES var meshes := 0 + var triangles := 0 for avatar in avatars: - meshes += avatar.find_children("*", "MeshInstance3D", true, false).size() - print("NPC budget: %d avatars, %d meshes, avg frame %.2f ms (budget %.0f ms)" % [ - COUNT, meshes, average, BUDGET_MS]) + for node in avatar.find_children("*", "MeshInstance3D", true, false): + var mi := node as MeshInstance3D + if mi == null or mi.mesh == null: + continue + meshes += 1 + for surface in mi.mesh.get_surface_count(): + var arrays := mi.mesh.surface_get_arrays(surface) + var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX] + triangles += indices.size() / 3 + print("NPC budget: %d avatars, %d meshes, %d triangles, avg frame %.2f ms (budget %.0f ms)" % [ + COUNT, meshes, triangles, average, BUDGET_MS]) if average > BUDGET_MS: printerr("SMOKE FAIL: frame time %.1f ms exceeds the %.0f ms budget" % [ average, BUDGET_MS])