Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7e523f63c | ||
|
|
26ecb93fd4 | ||
|
|
8997f59819 | ||
|
|
79270795a8 | ||
|
|
dc4bc6c511 | ||
|
|
c8b98fdb30 | ||
|
|
d96f53c285 | ||
|
|
b39fee6176 | ||
|
|
c2c93c28a5 | ||
|
|
3030c60ae1 | ||
|
|
cb65a5a601 | ||
|
|
06a4f5479f | ||
|
|
8032999a4d | ||
|
|
8582e496ff | ||
|
|
ae326ce970 | ||
|
|
00faf45e83 | ||
|
|
41d3511fc7 | ||
|
|
1efa5bc7d9 | ||
|
|
4745adeb13 | ||
|
|
15deb58b73 | ||
|
|
6a0bf70fdf | ||
|
|
f458551594 | ||
|
|
8f228b0c56 | ||
|
|
d307746351 |
No files matched your search
@@ -64,3 +64,12 @@ docs/blender_previews/*.png
|
|||||||
assets/models/blender/**/*.png
|
assets/models/blender/**/*.png
|
||||||
!assets/models/blender/**/*_ao.png
|
!assets/models/blender/**/*_ao.png
|
||||||
assets/models/blender_src/*.blend1
|
assets/models/blender_src/*.blend1
|
||||||
|
# Editable Blender sources are developer-only; keep the .gdignore marker tracked.
|
||||||
|
assets/models/blender_src/*.blend
|
||||||
|
# Realism pass (tools/scene_concepts.py): the candidate pool and per-run captures
|
||||||
|
# stay local; the validated picks are tracked under game_ready/v2/picks/ (ADR-0014),
|
||||||
|
# and each run commits its report.{json,md} + sheet.jpg. Concept references are
|
||||||
|
# committed in docs/screens/concepts/.
|
||||||
|
assets/textures/ai/game_ready/v2/*
|
||||||
|
!assets/textures/ai/game_ready/v2/picks/
|
||||||
|
docs/screens/realism/**/*.png
|
||||||
@@ -39,6 +39,10 @@ All planned implementation work must be represented in `TODO.md`.
|
|||||||
- Use checkbox items for each concrete task.
|
- Use checkbox items for each concrete task.
|
||||||
- Keep tasks small enough to complete and review independently.
|
- Keep tasks small enough to complete and review independently.
|
||||||
- Add new tasks when discoveries expand the scope.
|
- Add new tasks when discoveries expand the scope.
|
||||||
|
- When starting a task, claim it for the agent workflow by changing `[ ]` to `[-]`. Keep it `[-]`
|
||||||
|
while implementation or verification is in progress; only change it to `[x]` after the work and
|
||||||
|
relevant checks are finished. If work is abandoned or blocked, leave a clear note and return the
|
||||||
|
item to `[ ]` (or add a follow-up task).
|
||||||
- Mark a task complete only after the implementation and relevant verification are finished.
|
- Mark a task complete only after the implementation and relevant verification are finished.
|
||||||
- If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary.
|
- If any verification check fails, do not mark the task complete. Fix the failure, or if it cannot be fixed, add a follow-up task to `TODO.md`, record the failure in `MEMORY.md`, and report it in the handoff summary.
|
||||||
- Do not use prose status updates as a substitute for checkboxes.
|
- Do not use prose status updates as a substitute for checkboxes.
|
||||||
@@ -52,7 +56,7 @@ Recommended format:
|
|||||||
## Core Gameplay
|
## Core Gameplay
|
||||||
|
|
||||||
- [ ] Add player movement controls.
|
- [ ] Add player movement controls.
|
||||||
- [ ] Implement NPC approach behavior.
|
- [-] Implement NPC approach behavior. (claimed; implementation/verification in progress)
|
||||||
- [x] Define escalation levels.
|
- [x] Define escalation levels.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -878,3 +878,252 @@ Completed 2026-11-01 (v0.6.0). Headless **222/222**, Python **69/69**, all smoke
|
|||||||
deferred.
|
deferred.
|
||||||
- [x] Recaptured `docs/screenshots/` and ran `compare` + `judge`; no regressions.
|
- [x] Recaptured `docs/screenshots/` and ran `compare` + `judge`; no regressions.
|
||||||
- [x] Fixed the library marquee text/face alignment and added the library AO/triangle tests.
|
- [x] Fixed the library marquee text/face alignment and added the library AO/triangle tests.
|
||||||
|
|
||||||
|
## v0.6.0 Release
|
||||||
|
|
||||||
|
Completed 2026-11-01. `config/version` = `0.6.0`; ADR-0013 marked Accepted; CI published six
|
||||||
|
artifacts (Linux, Windows, macOS, NSIS installer, AppImage, Web) for tag `v0.6.0`.
|
||||||
|
|
||||||
|
- [x] Bumped the version and synchronised README/architecture/blender-assets/plan docs.
|
||||||
|
- [x] Headless **222/222**, Python **69/69**, all smokes, `compare` **11 good / 0 bad**.
|
||||||
|
- [x] Release verified: `https://git.allucanget.biz/zwitschi/security-game/releases/tag/v0.6.0`.
|
||||||
|
|
||||||
|
## Runtime Image Path Migration
|
||||||
|
|
||||||
|
Completed 2026-11-01. Historical note: the screen-design references originally lived only in
|
||||||
|
`docs/screens/designs/`; they were promoted to the runtime root `assets/images/ui/` under
|
||||||
|
ADR-0014. `docs/screens/designs/` remains a reference-only snapshot; `tools/screen_designs.py`
|
||||||
|
now reads and writes `assets/images/ui/`.
|
||||||
|
|
||||||
|
## Realistic Backgrounds, Textures and Scene References
|
||||||
|
|
||||||
|
Completed 2026-11-01 (part of the v0.6.x realism pass). The flat box skyline was replaced by
|
||||||
|
per-phase AI panoramas, the surface tiles by higher-detail v2 picks with normal maps, and the
|
||||||
|
lighting/exposure was retuned against AI concept frames. Evidence:
|
||||||
|
`docs/screens/realism/2026-11-01-adopt/` (`report.md`, `sheet.jpg`), `screen_designs.py compare`
|
||||||
|
**11 good / 0 bad**; headless **227/227**, Python **86/86**, all smokes.
|
||||||
|
|
||||||
|
### Realistic backgrounds, textures and scene references
|
||||||
|
|
||||||
|
Goal: replace the outdated flat skyline backdrop (`assets/textures/skyline.png`, black boxes
|
||||||
|
with dot windows) and the flat-looking surface tiles with AI-generated, more realistic
|
||||||
|
backgrounds and textures. Add a larger set of example 3D scene images as art direction, and
|
||||||
|
measure the in-game result against that target with the screenshot tools. Plan:
|
||||||
|
[`PLAN.md` → Visual Quality Direction → Realism pass](PLAN.md#realism-pass).
|
||||||
|
|
||||||
|
**Rule for every step: never overwrite an existing image.** New outputs get new paths. When a
|
||||||
|
path is taken, the tools pick the next free `-vN` suffix. Raw AI output stays on disk under
|
||||||
|
`assets/textures/ai/v2/raw/` (gitignored like the other raw AI folders). Processed game-ready
|
||||||
|
candidates go to `assets/textures/ai/game_ready/v2/`, a local pool where only the validated picks
|
||||||
|
are tracked (ADR-0014). Scene references go to `docs/screens/concepts/`, and trial captures and
|
||||||
|
reports to `docs/screens/realism/<run>/`.
|
||||||
|
|
||||||
|
#### Step 1 — Tooling (`tools/scene_concepts.py`)
|
||||||
|
|
||||||
|
- [x] Add a catalogue of prompts in three groups: `scene` (16:9 example 3D game frames),
|
||||||
|
`backdrop` (4:1 skyline panoramas with transparent sky), and `texture` (seamless PBR
|
||||||
|
surface tiles). Each entry has a name, prompt, role and target path.
|
||||||
|
- [x] `generate [--group] [--only] [--variants N]`: call the OpenRouter image API through
|
||||||
|
`generate_textures.generate_image` (key from the repo `.env`), save raw output, and never
|
||||||
|
overwrite (`next_free_path`). Print every file written.
|
||||||
|
- [x] `process`: turn raw backdrops into 2048×512 RGBA strips that tile horizontally (edge
|
||||||
|
crossfade, sky made fully transparent, hard alpha for the alpha-scissor material). Turn raw
|
||||||
|
textures into seamless 1024² tiles (`asset_pipeline.make_seamless`) plus a normal map
|
||||||
|
(`make_normal_maps.normal_map`). Skip outputs that already exist.
|
||||||
|
- [x] `audit`: run `asset_pipeline.audit_image` on the processed candidates (`backdrop` /
|
||||||
|
`tile` roles) and fail on any bad result.
|
||||||
|
- [x] `realism`: for each trial capture, report the Pillow detail metrics (edge density,
|
||||||
|
contrast, colour spread, saturation) next to the matching concept image. Optionally ask a
|
||||||
|
vision model (`google/gemini-2.5-flash-lite`) for 0–10 realism scores (lighting,
|
||||||
|
materials, texture detail, backdrop, overall) with concrete fixes. Write a new JSON +
|
||||||
|
Markdown report per run.
|
||||||
|
- [x] Unit tests (`tools/test_scene_concepts.py`): catalogue shape, the no-overwrite path
|
||||||
|
picker, backdrop/tile processing on synthetic images, metrics, and the judge payload/parse
|
||||||
|
(offline, no network).
|
||||||
|
|
||||||
|
#### Step 2 — Example 3D scene images
|
||||||
|
|
||||||
|
- [x] Generate 3D-game-style example frames for every venue and time of day: Hollywood entrance
|
||||||
|
(morning, golden hour, rainy night), boulevard skyline view (day, dusk), Joke Shop alley
|
||||||
|
(evening, close-up of the door), studio stage door (night arrival), sidewalk material
|
||||||
|
close-up, entrance steps and podium, crowd-control barrier line, and a responder arrival
|
||||||
|
wide shot.
|
||||||
|
- [x] Review the set and record the visual targets each frame sets (sky, haze, material detail,
|
||||||
|
backdrop depth) in the report.
|
||||||
|
|
||||||
|
#### Step 3 — Backgrounds (replace the outdated skyline)
|
||||||
|
|
||||||
|
- [x] Generate skyline panoramas for day, dusk and night (lit windows): Hollywood/Los Angeles
|
||||||
|
mid-rise blocks, palm silhouettes, the hills on the horizon, a transparent sky, and a
|
||||||
|
straight-on view, in several variants each.
|
||||||
|
- [x] Process them into `assets/textures/ai/game_ready/v2/skyline_{day,dusk,night}*.png`,
|
||||||
|
seamless horizontally for the 3× UV repeat around the backdrop ring. Strips are 2048×1024
|
||||||
|
(2:1, one UV repeat of the 400×60 m ring is about 133×60 m). 12 candidates, 11 audit
|
||||||
|
clean; `skyline_day-v3` misses the seam limit by 0.6. Variants 1–2 contain garbled
|
||||||
|
"Hollywood" lettering, so the prompt now forbids signs. Picks: `skyline_day-v4`,
|
||||||
|
`skyline_dusk-v3`, `skyline_night-v4`.
|
||||||
|
|
||||||
|
#### Step 4 — Textures
|
||||||
|
|
||||||
|
- [x] Generate higher-detail seamless tiles: red brick facade, granite/limestone facade
|
||||||
|
(studio), sidewalk concrete pavers with joints, asphalt with aggregate, wet night asphalt,
|
||||||
|
stone steps, striped awning canvas, and stucco wall.
|
||||||
|
- [x] Process them into 1024² game-ready tiles plus normal maps in
|
||||||
|
`assets/textures/ai/game_ready/v2/` and audit them (16 tiles + 16 normals, all good). The
|
||||||
|
`awning_canvas` seam crossfade smears the stripes at the tile edge; it needs a
|
||||||
|
stripe-aligned crop.
|
||||||
|
|
||||||
|
#### Step 5 — In-game trial captures (no game-code change)
|
||||||
|
|
||||||
|
- [x] Add `src/test/capture_realism.gd`. It boots the Hollywood venue, captures a fixed shot
|
||||||
|
list (entrance day, boulevard/skyline day, boulevard night), and can swap textures at
|
||||||
|
runtime from `--swap=OLD=NEW` / `--tint=` / `--normal=` user arguments (the first version used
|
||||||
|
`--skyline=`/`--brick=`/… flags; `--swap` is path-based and also covers night stages). The
|
||||||
|
swap finds materials by their original texture path, so baseline and candidate frames use
|
||||||
|
the same camera. Writes to the `--out=` directory.
|
||||||
|
- [x] Capture the baseline (current assets) and the candidate set (v2 skyline + textures), and
|
||||||
|
copy them into `docs/screens/realism/<run>/{baseline,candidate}/`.
|
||||||
|
|
||||||
|
#### Step 6 — Compare against the realistic target
|
||||||
|
|
||||||
|
- [x] Run `scene_concepts.py realism` on baseline and candidate. Record the metric deltas and the
|
||||||
|
vision scores, and note which candidate textures/backdrops win. Run
|
||||||
|
`docs/screens/realism/2026-11-01-v2/` (`report-v2.md`, `sheet.jpg`) gives these mean
|
||||||
|
judge scores: backdrop 2.6 → 3.6 (v2 day + night skyline) → **4.0** (v2 day + dusk
|
||||||
|
skyline for the Evening phase), texture detail 1.2 → 1.6–1.75, overall 1.6 → 2.0. Single
|
||||||
|
scores swing by ±1–2 between runs, so read them as trends. The `characters` score
|
||||||
|
moved from 3.0 to 1.0 with identical NPCs, which shows the noise.
|
||||||
|
- [x] Note the remaining realism gaps (sky/fog, lighting, building geometry, NPC fidelity) as
|
||||||
|
follow-up tasks below.
|
||||||
|
|
||||||
|
#### Step 6b — Follow-ups from the 2026-11-01 realism report
|
||||||
|
|
||||||
|
- [x] Fix sidewalk overexposure: lowered the day sun (0.78→0.62), exposure (0.8→0.6) and ambient
|
||||||
|
(0.42→0.22), and darkened the sidewalk/street albedo tints. The like-for-like ground
|
||||||
|
luminance in `docs/screens/realism/2026-11-01-adopt/` went from 173/162/132 to 95/92/73
|
||||||
|
(concept targets 78/100/100). The entrance shot stays ~20 % brighter than the concept: a
|
||||||
|
residual, tracked in the follow-ups below.
|
||||||
|
- [x] Make the Evening/Late phases darker and lit by practical lights (marquee, lamps,
|
||||||
|
windows), and add wet-asphalt roughness at night, as in the rain-night concept. Evening is
|
||||||
|
now dusk (`sun 0.3→0.12`, `exposure 0.95→0.72`, dark violet sky), Late is near-dark, and
|
||||||
|
`WorldBuilder.set_phase()` swaps the street to the wet asphalt map in Late.
|
||||||
|
- [x] Choose the skyline per phase (day → `skyline_day`, Evening → `skyline_dusk`, Late →
|
||||||
|
`skyline_night`) and stop the scene fog from bleaching it. The backdrop is now a
|
||||||
|
`fog_disabled` shader, because Godot 4.3 has no `fog_enabled` on `StandardMaterial3D`. The
|
||||||
|
first dusk panorama was a red floodlit skyline that clashed with the Evening sky, so a
|
||||||
|
calmer prompt produced `skyline_dusk-v5` (blue-grey towers, lit windows).
|
||||||
|
- [x] Raise the backdrop plane (60 m → 90 m) and use 2 UV repeats so the skyline is a band with
|
||||||
|
proportions near the 2:1 panorama, not a thin strip at the horizon.
|
||||||
|
- [x] Add facade depth (plinth, string courses, cornice, brick pilasters, window glazing bars)
|
||||||
|
and replace the blob trees and shrubs with denser foliage meshes: `_shrub()` now builds
|
||||||
|
many small flat-shaded clumps plus outer clumps that break the silhouette
|
||||||
|
(`street_tree` 1472→2592 tris), with fresh AO maps for `street_tree`, `planter_box` and
|
||||||
|
`round_planter`.
|
||||||
|
- [x] Re-cut `awning_canvas` so its stripes align at the tile edge: `stripe_period()` measures the
|
||||||
|
repeat and `align_stripes()` resamples to a whole number of periods (edge crossfade smeared
|
||||||
|
the stripes before). `audit_striped_tile()` checks the wrap step against the harshest
|
||||||
|
interior step instead of the flat edge-difference rule.
|
||||||
|
- [x] Capture shots from the Joke Shop and the studio too: `capture_realism.gd` now runs five
|
||||||
|
stages (day, evening, late, joke_shop, studio) with 9 shots and a `--stages=` subset. The
|
||||||
|
venues share the Hollywood geometry, so those two compare lighting, not layout.
|
||||||
|
|
||||||
|
#### Step 7 — Adopt the winners
|
||||||
|
|
||||||
|
- [x] Track the validated picks in place (ADR-0014). `.gitignore` now ignores the candidate pool
|
||||||
|
and un-ignores `game_ready/v2/picks/`, where `scene_concepts.py promote` copies the eight
|
||||||
|
validated candidates under stable names (`skyline_{day,dusk,night}`, `brick_facade`,
|
||||||
|
`sidewalk_pavers`, `asphalt`, `asphalt_wet`, `awning_canvas`) plus normal maps.
|
||||||
|
- [x] Point `WorldBuilder` at the chosen v2 skylines (separate day/dusk/night textures through
|
||||||
|
the new `set_phase()`), and retune the tints per phase.
|
||||||
|
- [x] Switch `materials.gd` / `world_builder.gd` surface preloads to the chosen v2 tiles + normal
|
||||||
|
maps, keeping the current UV scales (`Materials.asphalt()` gained a `wet` variant). Updated
|
||||||
|
`test_materials.gd` (pick paths, wet vs dry) and `test_world.gd` (shader backdrop, panorama
|
||||||
|
per phase, wet street).
|
||||||
|
- [x] Regenerate `docs/screenshots/` with `capture_screenshots.gd` (11/11), then run
|
||||||
|
`screen_designs.py compare` (**11 good / 0 bad**) and `judge` (5 match, 2 review, 4 diff —
|
||||||
|
the diffs are HUD/mockup layout gaps from the "Visual alignment" section, not realism
|
||||||
|
regressions; the default flash-lite judge model is currently failing with a provider 400, so
|
||||||
|
the run used `--model google/gemini-2.5-flash`). `scene_concepts.py realism` on
|
||||||
|
`docs/screens/realism/2026-11-01-adopt/` (3 judge repeats per shot) gives a like-for-like
|
||||||
|
improvement on every sub-score: overall 0.8→1.0, lighting 0.8→1.0, materials 0.8→1.0,
|
||||||
|
texture 0.8→1.0, backdrop 0.6→1.6, and the Pillow metric gap 0.444→0.348.
|
||||||
|
- [x] Update `README.md` (tool usage + gallery), `MEMORY.md` and `docs/architecture.md`.
|
||||||
|
|
||||||
|
## Visual Alignment — UI Paths and Art Loader
|
||||||
|
|
||||||
|
Completed 2026-11-01.
|
||||||
|
|
||||||
|
|
||||||
|
### Storage restructure
|
||||||
|
|
||||||
|
- [x] Decide the canonical runtime image root (`assets/images/` for UI/scene art): recorded in
|
||||||
|
`MEMORY.md` and [ADR-0014](docs/adr/0014-runtime-image-root.md).
|
||||||
|
- [x] Move the reference mockups from `docs/screens/designs/` into the runtime root (keep `docs/screens/designs/` as a docs-only copy or replace it with the new path).
|
||||||
|
- [x] Document one convention for game vs reference vs development images across `assets/textures/`, `assets/images/`, `assets/models/generated/`, `docs/screenshots/`, and `docs/screens/designs/` (in `docs/architecture.md`, ADR-0014).
|
||||||
|
- [x] Re-run `godot --headless --path . --import` to regenerate `.import` sidecars after any move.
|
||||||
|
- [x] Confirm `.gitignore` still excludes development-only outputs (concepts, Blender sources, raw AI fabrics) under the new layout; Blender `.blend` sources are now untracked and ignored.
|
||||||
|
|
||||||
|
|
||||||
|
### Documentation path updates
|
||||||
|
|
||||||
|
- [x] Update `README.md` paths (screen-designs section, confirmed-assets links, the `assets/images/scenes` resize example).
|
||||||
|
- [x] Update `docs/architecture.md`, `PLAN.md`, and ADR references: docs/screens/designs/ is now explicitly the reference-only snapshot; runtime art lives in assets/images/ (ADR-0014).
|
||||||
|
- [x] Update `tools/screen_designs.py` docstrings and mark the old paths in `DONE.md` as historical.
|
||||||
|
|
||||||
|
|
||||||
|
### Code path updates
|
||||||
|
|
||||||
|
- [x] Point `tools/screen_designs.py generate` at the new design output path and keep `compare`/`judge` reading the right locations.
|
||||||
|
- [x] Update GDScript `preload()` paths if game textures move (no runtime material/model textures moved; UI art added under assets/images/).
|
||||||
|
- [x] Update capture output directories if captures relocate (none did; QA captures stay in docs/screenshots/).
|
||||||
|
|
||||||
|
|
||||||
|
### Load proposed interfaces + scene art from disk
|
||||||
|
|
||||||
|
- [x] Add a central UI/scene art loader (e.g. `src/game/ui/art.gd`) that loads the mockup-derived images from the new runtime root, with a procedural fallback when a file is missing.
|
||||||
|
- [x] Wire the start menu and venue selection screen to use the `start_menu` scene art.
|
||||||
|
- [x] Wire the pause overlay to `pause_overlay` scene art (backdrop + opaque panel cover).
|
||||||
|
- [x] Wire the settings panel to `settings_panel` art.
|
||||||
|
- [x] Wire the shift-review screen to `shift_review` art (backdrop + opaque panel cover).
|
||||||
|
- [x] Wire the wand popup to `wand_screening` art.
|
||||||
|
- [x] Style the radial menu and finish the remaining HUD chrome against their reference images.
|
||||||
|
|
||||||
|
|
||||||
|
### Verify against the mockups
|
||||||
|
|
||||||
|
- [x] Regenerate the staged captures and run `screen_designs.py compare` (11 good, 0 bad; verified in a clean HEAD worktree).
|
||||||
|
- [x] Run `screen_designs.py judge` and clear every `diff` verdict (7 match, 4 review, 0 diff).
|
||||||
|
- [x] Add the capture + compare step as a repeatable smoke so drift is caught early (`tools/check_screenshots.sh`).
|
||||||
|
|
||||||
|
|
||||||
|
## Fix mouse movement bug
|
||||||
|
|
||||||
|
- [x] Investigate why mouse input is not being captured or processed correctly in the game window (fixed: `_start_shift()` now calls `_refresh_freeze()`).
|
||||||
|
|
||||||
|
|
||||||
|
## Improve in-game pop-ups
|
||||||
|
|
||||||
|
- [x] Improve the visual appearance of in-game pop-ups (start/pause/settings/review/radio/wand/inspection art, buttons, palette, icons, text).
|
||||||
|
|
||||||
|
## Visual Alignment With Rendered Mockups
|
||||||
|
|
||||||
|
Completed 2026-11-01. Every screen with an AI reference now loads or matches its mockup: the
|
||||||
|
runtime image root (ADR-0014), the UI/scene art loader, the menus/panels/HUD, and — last — the
|
||||||
|
scene lighting, fog and post-processing, which had been held until the realism pass landed.
|
||||||
|
`screen_designs.py compare` **11 good / 0 bad**; judge on the two scene shots: `01-venue-overview`
|
||||||
|
**match** (0.90), `05-late-night-avenue` **review** (0.10), 0 diff. Lighting: morning sun 34°
|
||||||
|
elevation with a phase `sun_yaw`, warm day haze (`fog_color` 0.87/0.83/0.76, density 0.0034,
|
||||||
|
energy 0.5), stronger night glow, street albedo 0.62. Remaining differences (camera height,
|
||||||
|
marquee text, hand-authored tree shapes) are content, not grading.
|
||||||
|
|
||||||
|
### Visual alignment with rendered mockups
|
||||||
|
|
||||||
|
#### Align in-game visuals
|
||||||
|
|
||||||
|
- [x] Make the venue selection screen match the `start_menu` mockup (layout, palette, background).
|
||||||
|
- [x] Make the HUD match the `targeting_npc` / `escalation_hud` mockups (focus ring, escalation meter, log, hints).
|
||||||
|
- [x] Align the pause, settings, and shift-review panels to their mockups.
|
||||||
|
- [x] Align the radio and wand panels to their mockups.
|
||||||
|
- [x] Align the body-camera timeline to its mockup.
|
||||||
|
- [x] Align scene lighting, fog, and post-processing for `venue_overview` and `late_night_avenue`: lowered the morning sun to 34° (`sun_yaw` is now a phase value), warmed and thickened the day haze, raised the night glow, and brightened the street albedo. `judge` moved `01-venue-overview` to **match** (0.90) and `05-late-night-avenue` from diff to **review** (0.10); `compare` stays 11 good / 0 bad.
|
||||||
|
- [x] Fix the body-camera REC/clock overlay overlapping the shift/rep/crowd status in the top-right HUD.
|
||||||
@@ -4,6 +4,13 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
|
|
||||||
## Decisions
|
## Decisions
|
||||||
|
|
||||||
|
- The visual-alignment path/loader/verification work is complete and recorded in `DONE.md`;
|
||||||
|
the only open visual task is scene lighting/fog, held until the current realism pass lands.
|
||||||
|
- Editable Blender sources under `assets/models/blender_src/` are gitignored and untracked
|
||||||
|
(46 `.blend` files removed from the index on 2026-11-01); the `.gdignore` marker stays tracked.
|
||||||
|
- `screen_designs.py judge` default `google/gemini-2.5-flash-lite` worked on 2026-11-01
|
||||||
|
(7 match / 4 review / 0 diff); `--model` remains available.
|
||||||
|
|
||||||
- Graphics v0.6.0 plan (2026-11-01): NPCs move to Blender-authored skinned meshes
|
- Graphics v0.6.0 plan (2026-11-01): NPCs move to Blender-authored skinned meshes
|
||||||
(`docs/plan-graphics-v0.6.md`, ADR-0013). `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()`
|
||||||
@@ -38,15 +45,37 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
avatars. Head-turn offsets use `+basis.z` for the same reason. Covered by
|
avatars. Head-turn offsets use `+basis.z` for the same reason. Covered by
|
||||||
`test_yaw_faces_the_movement_direction`.
|
`test_yaw_faces_the_movement_direction`.
|
||||||
|
|
||||||
|
- **Image root (ADR-0014, 2026-11-01):** `assets/images/` is the runtime root for composed
|
||||||
|
interface/scene art (`ui/`, `scenes/`); tiled PBR textures stay under `assets/textures/`;
|
||||||
|
`docs/screens/designs/` and `docs/screens/concepts/` stay reference-only; QA captures stay in
|
||||||
|
`docs/screenshots/`. When a mockup becomes runtime art, copy/process it into `assets/images/`
|
||||||
|
with a new name (no overwrites) and keep a fallback in code.
|
||||||
|
**Mockup copies:** 21 design references live in `assets/images/ui/`; `docs/screens/designs/`
|
||||||
|
remains the reference-only copy. `tools/screen_designs.py` reads/writes the runtime root.
|
||||||
|
|
||||||
## Handoff (read this first)
|
## Handoff (read this first)
|
||||||
|
|
||||||
- **Visual-alignment pass planned (2026-11-01):** `TODO.md` gains a "Visual
|
- **Status + active passes (2026-11-01, moved from `TODO.md`):** v0.6.0 shipped — the Blender
|
||||||
alignment with rendered mockups" section. Goal: restructure generated-image
|
character/gear/prop library is integrated, AO maps are baked and wired, and the environment
|
||||||
storage, move the reference mockups out of `docs/screens/designs/` into a
|
textures are lifted to 1024² with normal maps (see `DONE.md`). Headless **227/227**, Python
|
||||||
runtime-accessible root (e.g. `assets/images/`), load the proposed UI/scene
|
**86**; the scheduled presentation pass is complete and the realism pass is adopted
|
||||||
art at runtime (start menu, selection screens, HUD, panels), and make the game
|
(per-phase skyline panoramas, v2 surface tiles, retuned lighting). Active in `TODO.md`:
|
||||||
match the mockups — verified by `screen_designs.py compare` + `judge`. Not
|
- **Visual alignment with rendered mockups:** the AI references in `docs/screens/designs/`
|
||||||
started; no code moved yet.
|
define the intended look of every screen. The pass reorganizes generated-image storage,
|
||||||
|
loads the proposed UI/scene art at runtime (`src/game/ui/art.gd`, `assets/images/`), and
|
||||||
|
aligns the selection screens, HUD, and scene visuals with those mockups — verified with
|
||||||
|
`screen_designs.py compare` + `judge`.
|
||||||
|
- **Realism pass** (plan: `PLAN.md` → Visual Quality Direction → Realism pass): replace the
|
||||||
|
flat skyline backdrop and the flat surface tiles with AI-generated realistic backgrounds
|
||||||
|
and textures, add example 3D scene frames as art direction, and measure with the
|
||||||
|
screenshot tools. Rule: never overwrite an existing image — new outputs get new paths
|
||||||
|
(`next_free_path` -vN suffix). Raw → `assets/textures/ai/v2/raw/` (gitignored); candidates
|
||||||
|
→ `assets/textures/ai/game_ready/v2/` (gitignored pool, only validated picks tracked,
|
||||||
|
ADR-0014); scene refs → `docs/screens/concepts/`; trials → `docs/screens/realism/<run>/`.
|
||||||
|
Realism report 2026-11-01-v2 mean judge scores: backdrop 2.6 → 3.6 (v2 day + night
|
||||||
|
skyline) → **4.0** (v2 day + dusk skyline for the Evening phase); texture detail 1.2 →
|
||||||
|
1.6–1.75; overall 1.6 → 2.0. Scores swing ±1–2 between runs (trend only); the
|
||||||
|
`characters` score moved 3.0 → 1.0 with identical NPCs, showing the noise.
|
||||||
|
|
||||||
- **Phase 2 — AI texturing (this agent, DONE 2026-11-01).** Phase 1 assets were
|
- **Phase 2 — AI texturing (this agent, DONE 2026-11-01).** Phase 1 assets were
|
||||||
already in the tree (untracked) and are preserved. Generated six seamless AI
|
already in the tree (untracked) and are preserved. Generated six seamless AI
|
||||||
@@ -129,6 +158,36 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
flat plane, so avoidance (not a baked mesh) routes guests around props. Placements live in
|
flat plane, so avoidance (not a baked mesh) routes guests around props. Placements live in
|
||||||
`PROP_PLACEMENTS` with `placement_problems()` validation; variants come from `variant_for(index)`.
|
`PROP_PLACEMENTS` with `placement_problems()` validation; variants come from `variant_for(index)`.
|
||||||
`smoke_props.gd` must be windowed because the guard reads captured-mouse input.
|
`smoke_props.gd` must be windowed because the guard reads captured-mouse input.
|
||||||
|
- **Realism pass (2026-11-01, completed + adopted):** `tools/scene_concepts.py`
|
||||||
|
(`list`/`generate`/`process`/`promote`/`audit`/`realism`) never overwrites an image
|
||||||
|
(`next_free_path` adds `-vN`; `process` skips existing unless `--new`; `promote` keeps an
|
||||||
|
existing pick). Raw AI output: `assets/textures/ai/v2/raw/` (gitignored). Candidate pool:
|
||||||
|
`assets/textures/ai/game_ready/v2/` (gitignored) and the **tracked runtime assets** are
|
||||||
|
`.../v2/picks/{skyline_day,skyline_dusk,skyline_night,brick_facade,sidewalk_pavers,asphalt,
|
||||||
|
asphalt_wet,awning_canvas}.png` (+ `_normal`). Concepts `docs/screens/concepts/` (committed,
|
||||||
|
`.gdignore`, targets in its README). Runs `docs/screens/realism/<run>/` (PNG captures
|
||||||
|
gitignored; `report.{json,md}` + `sheet.jpg` committed).
|
||||||
|
`src/test/capture_realism.gd` runs five stages (day 0 s / evening 620 s / late 760 s /
|
||||||
|
joke_shop 700 s / studio 700 s; `--stages=` subset) and swaps textures by the material's
|
||||||
|
*original* albedo path. **Gotcha:** in the SceneTree script, do not overwrite `_phase` after
|
||||||
|
`_begin_stage()` sets `done`, or the run loops forever between stage/shoot (`_queue` empty).
|
||||||
|
**Gotcha:** `elapsed_s = 620` is *Evening* (dusk), 700+ is Late. Godot 4.3
|
||||||
|
`StandardMaterial3D` has no `fog_enabled`; the skyline is a `ShaderMaterial` with
|
||||||
|
`render_mode unshaded, cull_disabled, fog_disabled` + `ALPHA_SCISSOR_THRESHOLD` so the
|
||||||
|
panorama's own haze shows. Backdrop plane is 90 m tall with 2 UV repeats (~200×90 m per
|
||||||
|
repeat, near the 2:1 panorama aspect). Legacy `assets/textures/skyline.png` is no longer
|
||||||
|
loaded but stays on disk for the `test_world` asset check.
|
||||||
|
**Phase look:** day sun 0.62 / exposure 0.6 / ambient 0.22; evening sun 0.12 / exposure
|
||||||
|
0.72 / dark violet sky; late exposure 0.95 / ambient 0.10 with the wet asphalt street and a
|
||||||
|
bright skyline tint (1.5) so the night windows read. Stripes: `stripe_period()` (detrended
|
||||||
|
autocorrelation) + `align_stripes()` (resample to whole periods) replace the edge crossfade
|
||||||
|
for `awning_canvas`; `audit_striped_tile()` compares the wrap step with the harshest interior
|
||||||
|
step.
|
||||||
|
**Judge:** `google/gemini-2.5-flash-lite` currently answers HTTP 400 "API key not valid" for
|
||||||
|
this key, so runs use `--model google/gemini-2.5-flash`; scores are noisy (±1–2), so
|
||||||
|
`realism --repeats 3` averages and `summarize()` reports a like-for-like mean over the shots
|
||||||
|
every set captured. Final: overall 0.8→1.0, backdrop 0.6→1.6, metric gap 0.444→0.348.
|
||||||
|
`screen_designs.py judge` gained one retry for the same transient 400.
|
||||||
- **Blender asset library (v0.6.0, integrated 2026-11-01):**
|
- **Blender asset library (v0.6.0, integrated 2026-11-01):**
|
||||||
`tools/blender_assets.py` (`build`/`render` in Blender; `audit`/`sheet`/`list` stdlib) writes
|
`tools/blender_assets.py` (`build`/`render` in Blender; `audit`/`sheet`/`list` stdlib) writes
|
||||||
`assets/models/blender/{npc,npc_gear,props}/*.glb`, `manifest.json` (integration source of
|
`assets/models/blender/{npc,npc_gear,props}/*.glb`, `manifest.json` (integration source of
|
||||||
@@ -180,6 +239,16 @@ Session memory for durable decisions, state, and gotchas. Keep concise, remove o
|
|||||||
adopted (custom runner covers it without an editor plugin).
|
adopted (custom runner covers it without an editor plugin).
|
||||||
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
|
- Do not re-open `override_access`. Do not bind wand to `W`. Do not remove the radio easter egg.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
- Runtime UI/scene art is loaded through `src/game/ui/art.gd` (`assets/images/ui/` then `scenes/`); missing files return null so panels keep procedural fallbacks.
|
||||||
|
- Screen mockups with baked-in controls are used as backdrops plus an opaque `ArtPanel` cover, not as clickable full-screen skins.
|
||||||
|
- Radio, wand, inspection, and body-camera timeline panels use their reference art as backdrops; forms sit on transparent, padded panels over the covered mockup controls.
|
||||||
|
- HUD target names use a boxed chip under the crosshair; escalation has a five-segment bar below the text label. The body-camera REC/clock block starts at y=92 on the right so it clears the shift/rep/crowd text.
|
||||||
|
- Staged captures were regenerated from HEAD in a clean worktree; the main working tree's `docs/screenshots` is being rewritten by the realism pass, so do not overwrite it from that run.
|
||||||
|
- `tools/check_screenshots.sh` is the repeatable capture+compare smoke; both capture scripts accept `--out=res://docs/screenshots`. Judge verdicts on the staged set were 7 match / 4 review / 0 diff.
|
||||||
|
- Venue selection used to leave `guard.input_locked` true and the mouse visible; `_start_shift()` must call `_refresh_freeze()` after starting the clock.
|
||||||
|
|
||||||
## Current State
|
## Current State
|
||||||
|
|
||||||
- **v0.3.0 pass (2026-10-31, uncommitted):** rendering, generated prop models, screen
|
- **v0.3.0 pass (2026-10-31, uncommitted):** rendering, generated prop models, screen
|
||||||
@@ -544,3 +613,7 @@ session shell; leftover PLAN verbs; crowd rubberneck; emergency aftermath; body-
|
|||||||
sit/photo/film poses; real crowd audio; Joke Shop/Studio extra events; PLAN.md says GUT/GitHub.
|
sit/photo/film poses; real crowd audio; Joke Shop/Studio extra events; PLAN.md says GUT/GitHub.
|
||||||
|
|
||||||
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|
||||||
|
|
||||||
|
## Uncommitted Workstreams
|
||||||
|
|
||||||
|
- A separate realism pass is editing `PLAN.md`, `README.md`, `.gitignore`, `src/game/materials.gd`, `tools/scene_concepts.py`, `tools/test_scene_concepts.py`, `src/test/capture_realism.gd`, `assets/textures/ai/game_ready/v2/`, `docs/screens/concepts|realism/`, and regenerated Blender planter/tree assets. Do not commit or revert these while that pass is active; verify game changes in a clean `git worktree` at HEAD when its unimported textures break parsing.
|
||||||
@@ -420,6 +420,42 @@ frame budget measured by `smoke_npc_budget.gd`. See
|
|||||||
[`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md) and
|
[`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md) and
|
||||||
[ADR-0013](docs/adr/0013-blender-authored-npc-characters.md).
|
[ADR-0013](docs/adr/0013-blender-authored-npc-characters.md).
|
||||||
|
|
||||||
|
### Realism pass
|
||||||
|
|
||||||
|
The target look is the realistic 3D-game frames in `docs/screens/designs/` and the larger
|
||||||
|
example set in `docs/screens/concepts/`: hazy, layered city depth, believable materials, and
|
||||||
|
warm practical lights at night. Readability still comes first. Silhouettes, the focus ring and
|
||||||
|
the HUD must stay clear, and the GL Compatibility renderer stays.
|
||||||
|
|
||||||
|
- **Backgrounds.** The flat, black-box skyline strip is retired in favour of AI-generated
|
||||||
|
panoramic skylines (Hollywood mid-rises, palms, hills) for day, dusk and night. Each one is a
|
||||||
|
transparent-sky 4:1 strip that tiles horizontally on the existing backdrop ring, and the night
|
||||||
|
variant has lit windows.
|
||||||
|
- **Textures.** Higher-detail seamless 1024² tiles with derived normal maps for brick, granite,
|
||||||
|
sidewalk pavers, asphalt (dry and wet), steps, awning canvas and stucco, at the current UV
|
||||||
|
scales.
|
||||||
|
- **Process.** `tools/scene_concepts.py` generates (never overwriting existing images),
|
||||||
|
processes, audits and judges. `src/test/capture_realism.gd` captures the same camera shots
|
||||||
|
with the current and the candidate assets, swapped at runtime, so a candidate is compared
|
||||||
|
before any game code changes. Candidates are adopted only when the realism report (Pillow
|
||||||
|
detail metrics + vision-model realism scores) improves and `screen_designs.py judge` shows no
|
||||||
|
new `diff`.
|
||||||
|
- **Storage.** Raw AI output: `assets/textures/ai/v2/raw/` (local, gitignored). Game-ready
|
||||||
|
candidates: `assets/textures/ai/game_ready/v2/`. Scene references: `docs/screens/concepts/`.
|
||||||
|
Trial captures and reports: `docs/screens/realism/<run>/`.
|
||||||
|
- **First result (2026-11-01).** Swapping in the v2 skyline and tiles raised the judge's mean
|
||||||
|
backdrop score from 2.6 to 4.0 and texture detail from 1.2 to ~1.7. Overall realism stayed at
|
||||||
|
~2/10; the limits were lighting and exposure, flat facades and blob foliage, not textures.
|
||||||
|
- **Adopted (2026-11-01).** The v2 picks are now the runtime skyline and surface set, the phase
|
||||||
|
lighting was retuned (exposure, darker dusk/late, practical lights, wet asphalt at night), the
|
||||||
|
backdrop is a fog-free 90 m panorama ring per phase, the facade gained plinth/string
|
||||||
|
courses/cornice/pilasters/glazing bars, and the library trees and shrubs are denser. Judge
|
||||||
|
scores on the like-for-like shots rose on every sub-score (overall 0.8 → 1.0, backdrop
|
||||||
|
0.6 → 1.6) with the metric gap down 0.444 → 0.348
|
||||||
|
(`docs/screens/realism/2026-11-01-adopt/`). The remaining gap to the concepts is the low-poly
|
||||||
|
character and prop fidelity, a visible flashlight beam at night, and the entrance still being
|
||||||
|
~20 % brighter than the concept (`TODO.md` → Realism follow-ups).
|
||||||
|
|
||||||
The scenario should test the player’s ability to distinguish ordinary Hollywood Boulevard activity from a genuine security problem. The best solution is usually a simple gesture, clear direction, or credential check rather than immediate escalation.
|
The scenario should test the player’s ability to distinguish ordinary Hollywood Boulevard activity from a genuine security problem. The best solution is usually a simple gesture, clear direction, or credential check rather than immediate escalation.
|
||||||
|
|
||||||
Future venues can reuse this structure while changing the rules, equipment, staff roles, and types of access decisions.
|
Future venues can reuse this structure while changing the rules, equipment, staff roles, and types of access decisions.
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ Crop uses the image center by default; `--x` and `--y` select an explicit crop o
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 tools/asset_pipeline.py crop assets/textures/source.png assets/textures/crop.png --width 256 --height 128
|
python3 tools/asset_pipeline.py crop assets/textures/source.png assets/textures/crop.png --width 256 --height 128
|
||||||
python3 tools/asset_pipeline.py resize assets/textures/source.png assets/images/backgrounds/scene.png --width 1920 --height 1080 --fit cover
|
python3 tools/asset_pipeline.py resize assets/textures/source.png assets/images/scenes/scene.png --width 1920 --height 1080 --fit cover
|
||||||
python3 tools/asset_pipeline.py seamless assets/textures/rough_tile.png assets/textures/tile.png
|
python3 tools/asset_pipeline.py seamless assets/textures/rough_tile.png assets/textures/tile.png
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ Audit accepts image files or directories. `--role auto` infers common roles from
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 tools/asset_pipeline.py audit assets/textures
|
python3 tools/asset_pipeline.py audit assets/textures
|
||||||
python3 tools/asset_pipeline.py audit assets/images/backgrounds --role background --json
|
python3 tools/asset_pipeline.py audit assets/images/scenes --role background --json
|
||||||
python3 -m unittest discover -s tools -p 'test_*.py'
|
python3 -m unittest discover -s tools -p 'test_*.py'
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -287,11 +287,11 @@ Everything below is audited and shipped in the game; development-only outputs
|
|||||||
|
|
||||||
| | |
|
| | |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|  |  |
|
|  |  |
|
||||||
|
|
||||||
- **Surface textures:** the six tiles above, loaded by `src/game/materials.gd` and `WorldBuilder`.
|
- **Surface textures:** the v2 picks above (brick, sidewalk pavers, dry and wet asphalt, awning canvas) plus their normal maps, loaded by `src/game/materials.gd` and `WorldBuilder`; the three skyline panoramas are switched per shift phase. The first-generation tiles and `assets/textures/skyline.png` are no longer loaded.
|
||||||
- **UI art:** `assets/textures/ai/game_ready/icons/` (flashlight, door lock, wand, REC) and `assets/textures/ai/game_ready/cards/` (ID, wristband, ticket, credential, guest list), loaded by `src/game/ui/hud.gd`.
|
- **UI art:** `assets/textures/ai/game_ready/icons/` (flashlight, door lock, wand, REC) and `assets/textures/ai/game_ready/cards/` (ID, wristband, ticket, credential, guest list), loaded by `src/game/ui/hud.gd`.
|
||||||
- **Generated models:** `assets/models/generated/*.glb` — bollard, bench, trash bin, planter, newspaper box, hydrant, and the NPC base — plus their colour atlases.
|
- **Generated models:** `assets/models/generated/*.glb` — bollard, bench, trash bin, planter, newspaper box, hydrant, and the NPC base — plus their colour atlases.
|
||||||
- **NPC material maps:** `assets/textures/npc/*_{albedo,normal,orm}.png` and `palette.json`.
|
- **NPC material maps:** `assets/textures/npc/*_{albedo,normal,orm}.png` and `palette.json`.
|
||||||
@@ -304,12 +304,50 @@ python3 tools/model_pipeline.py audit
|
|||||||
python3 tools/npc_pipeline.py audit
|
python3 tools/npc_pipeline.py audit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Realism pass: scene concepts, skylines and textures
|
||||||
|
|
||||||
|
The skyline, surface tiles and phase lighting were rebuilt against AI concept frames. The
|
||||||
|
concepts live in [`docs/screens/concepts/`](docs/screens/concepts/README.md); the validated
|
||||||
|
picks the game loads are in `assets/textures/ai/game_ready/v2/picks/` (day/dusk/night
|
||||||
|
panoramas, brick, sidewalk pavers, dry and wet asphalt, awning canvas, each with a normal
|
||||||
|
map).
|
||||||
|
|
||||||
|
`tools/scene_concepts.py` generates and processes new candidates, promotes the validated ones
|
||||||
|
to stable names, audits them, and scores captures against the concepts. It never overwrites an
|
||||||
|
image: new files get a `-vN` suffix, and `process` skips existing candidates unless `--new`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 tools/scene_concepts.py generate --group scene # or backdrop / texture, --variants N
|
||||||
|
python3 tools/scene_concepts.py process && python3 tools/scene_concepts.py audit
|
||||||
|
python3 tools/scene_concepts.py promote # validated picks -> v2/picks/
|
||||||
|
godot --headless --path . --import
|
||||||
|
|
||||||
|
# A/B a candidate without touching game code: the same cameras, textures swapped at runtime.
|
||||||
|
godot --path . --script res://src/test/capture_realism.gd -- --out=res://docs/screens/realism/<run>/after
|
||||||
|
godot --path . --script res://src/test/capture_realism.gd -- --out=res://docs/screens/realism/<run>/try \
|
||||||
|
--swap=res://assets/textures/ai/game_ready/v2/picks/brick_facade.png=res://assets/textures/ai/game_ready/v2/brick_facade-v2.png
|
||||||
|
|
||||||
|
# Score before/after against the concepts (Pillow detail metrics + vision judge).
|
||||||
|
python3 tools/scene_concepts.py realism --run docs/screens/realism/<run> --judge \
|
||||||
|
--model google/gemini-2.5-flash --repeats 3
|
||||||
|
```
|
||||||
|
|
||||||
|
`capture_realism.gd` runs five stages (day, evening, late, Joke Shop, studio); `--stages=day,late`
|
||||||
|
limits it while tuning. The latest run,
|
||||||
|
[`docs/screens/realism/2026-11-01-adopt/`](docs/screens/realism/2026-11-01-adopt/report.md),
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Screen design references
|
### Screen design references
|
||||||
|
|
||||||
Screen mockups and screenshot comparison use `tools/screen_designs.py`. It turns the
|
Screen mockups and screenshot comparison use `tools/screen_designs.py`. It turns the
|
||||||
screen descriptions in `docs/` (README captions, ADRs 0007–0010, `PLAN.md`, and
|
screen descriptions in `docs/` (README captions, ADRs 0007–0010, `PLAN.md`, and
|
||||||
`architecture.md`) into reference images under `docs/screens/designs/`, then uses
|
`architecture.md`) into runtime reference art under `assets/images/ui/` (with a
|
||||||
those images as the expected state to check the game's captures.
|
reference-only snapshot in `docs/screens/designs/`), then uses those images as
|
||||||
|
the expected state to check the game's captures.
|
||||||
|
|
||||||
Each screen is tagged `scene` (a realistic first-person 3D world view) or `ui`
|
Each screen is tagged `scene` (a realistic first-person 3D world view) or `ui`
|
||||||
(an in-game panel overlaid on a softened scene), and the generator appends a
|
(an in-game panel overlaid on a softened scene), and the generator appends a
|
||||||
@@ -350,9 +388,9 @@ 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 eleven README captures plus the start menu,
|
||||||
pause overlay, settings, shift review, radial menu, emergency radio, wand
|
pause overlay, settings, shift review, radial menu, emergency radio, wand
|
||||||
screening, Joke Shop queue, TV Studio arrival, crowd panic, responder arrival,
|
screening, Joke Shop queue, TV Studio arrival, crowd panic, responder arrival,
|
||||||
body-camera timeline, and the escalation HUD. All 19 have an AI reference in
|
body-camera timeline, and the escalation HUD. All 21 have an AI reference in
|
||||||
`docs/screens/designs/`; the eleven screens with staged captures are also compared
|
`assets/images/ui/` (snapshot in `docs/screens/designs/`); the eleven screens with
|
||||||
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
|
||||||
@@ -368,6 +406,10 @@ default 0.6 — expected when a concept mockup is more stylised than the game),
|
|||||||
`compare` after regenerating the game screenshots with
|
`compare` after regenerating the game screenshots with
|
||||||
`src/test/capture_screenshots.gd`.
|
`src/test/capture_screenshots.gd`.
|
||||||
|
|
||||||
|
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
|
||||||
|
no display is available) and then runs `screen_designs.py compare`.
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
1. Download the Godot 4.3 editor (official build) and put `godot` on your PATH.
|
1. Download the Godot 4.3 editor (official build) and put `godot` on your PATH.
|
||||||
@@ -484,7 +526,7 @@ Implemented so far:
|
|||||||
- Godot 4.3 project scaffold, input map, procedural world builder
|
- Godot 4.3 project scaffold, input map, procedural world builder
|
||||||
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
|
- Venue-driven simulation core: `ShiftCoordinator`, `VenueScenario`, `EventScheduler`, `NPCController` + FSM, `AccessVerifier`, `EscalationManager`, `RadioSystem`, `IncidentRecorder`, `ReputationEvaluator`, `CrowdSystem`
|
||||||
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
|
- Three authored scenarios (Hollywood Boulevard building, The Joke Shop, Late Night TV Studio) with access policies, NPC archetypes, and event pools
|
||||||
- Headless unit tests: **208 passing** (access rules and venue-correct access loadout, escalation, radio cooldown/battery, NPC reaction determinism, door lock, flashlight perception, persistence round-trip, settings round-trip, input remaps, navmesh, step colliders, skyline alpha, scenario data, full-shift simulation, wand screening, responder dispatch, localization strings, focus cone, action wheel, session shell, PLAN verbs and incident recording, crowd presentation, emergency aftermath, body-camera timeline, NPC theater poses, audio, accessibility, authored scenario content, string formatting, `.tres` venue round-trip, surface materials and environment, focus ranking and outfit/gait helpers, generated prop models, web export preset, prop atlas material, player movement, NPC character layers/LOD/queue, input bindings)
|
- Headless unit tests: **227 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`)
|
||||||
|
|||||||
@@ -1,228 +1,22 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
Godot 4.3 prototype. Latest release **v0.5.0** (NPC characters and player movement). Headless
|
## Realism follow-ups (v0.6.1 candidates)
|
||||||
suite **222/222** plus **68** Python tooling tests; the session, PLAN-verb, crowd, emergency,
|
|
||||||
timeline, audio, scenario-content, props, NPC-budget, movement, and windowed focus/radial smokes
|
|
||||||
pass. Anonymous downloads are enabled on the host.
|
|
||||||
|
|
||||||
The scheduled presentation pass is complete (see `DONE.md`). The next scheduled pass is the
|
- [x] Fixed ground exposure for the entrance view: the morning sun now sits at 34° elevation
|
||||||
graphics-quality work in [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md).
|
instead of 50°, so the facade shades the near sidewalk and props cast long shadows. Ground
|
||||||
|
luminance went 95 → **83** against the concept's 78 (it was 173 before the realism pass),
|
||||||
> **Blender asset library integrated (2026-11-01):** 8 NPC character variants, 18 gear pieces,
|
with the boulevard at 82 and the street at 81.
|
||||||
> and 20 street/venue props are now loaded by `NpcAvatar` and `WorldBuilder` from
|
- [-] Make the flashlight read in the dark: the `06-night-flashlight` concept shows a visible
|
||||||
> `assets/models/blender/` (manifest as source of truth, see
|
beam, but a Compatibility spot light only brightens the near wall. A cheap fake cone (an
|
||||||
> [`docs/blender-assets.md`](docs/blender-assets.md)). The procedural rig and primitive props
|
additive mesh or a light-shaft quad) would sell it, and the night mockup expects it.
|
||||||
> remain offline fallbacks; AO/ORM baking is the remaining Phase 4 follow-up.
|
- [ ] NPC skin/clothing still reads as low-poly next to the concepts (judge `characters` ≈ 0–1).
|
||||||
|
The Blender library has the budgets for one more detail pass (fingers, sleeves, faces).
|
||||||
## Graphics quality — Blender-authored NPC characters (v0.6.0)
|
- [x] Re-check the `screen_designs.py judge` default model (`google/gemini-2.5-flash-lite`): on
|
||||||
|
2026-11-01 it returned 7 match / 4 review / 0 diff without a provider error; `--model`
|
||||||
Detailed plan: [`docs/plan-graphics-v0.6.md`](docs/plan-graphics-v0.6.md) · [ADR-0013](docs/adr/0013-blender-authored-npc-characters.md)
|
override is documented in `README.md`.
|
||||||
|
- [ ] Add the two venue stages to the committed gallery (they are capture-only today) and give
|
||||||
### Phase 0 — Toolchain spike and contract freeze
|
the Joke Shop and studio their own geometry so their concept comparisons are geometric,
|
||||||
|
not just lighting.
|
||||||
- [x] Verify `flatpak run org.blender.Blender --version` reports Blender 5.2.x and runs headless in this shell.
|
|
||||||
- [x] Run a minimal headless Blender export using an absolute `--python` path (sandbox cwd is `/app/blender`); confirm the output file lands where expected.
|
|
||||||
- [x] Record the exact working invocation (flatpak + absolute paths) in `MEMORY.md`.
|
|
||||||
- [x] Freeze the NPC asset contract in `docs/plan-graphics-v0.6.md` and ADR-0013: file paths, bone names, material slots, triangle budget.
|
|
||||||
- [x] Fix the material-slot set (`skin` / `cloth` / `pants` / `accessory` / `hair`) and the ORM packing (R=occlusion, G=roughness, B=metallic).
|
|
||||||
- [x] Choose and record the initial tier-0 triangle/vertex budget (≤ ~6000 tris / ~4000 verts) in the plan.
|
|
||||||
- [x] Spike: Godot 4.3 imports the `.glb` as a `PackedScene` with a `Skeleton3D`; no clips are needed because `_animate()` drives the bones at runtime.
|
|
||||||
|
|
||||||
### Phase 1 — Blender authoring + export pipeline
|
|
||||||
|
|
||||||
- [x] Author the low-poly base humanoid in Blender: torso, articulated arms/legs, head with a face front, hands, shoes.
|
|
||||||
- [x] Rig with an armature whose bones mirror the node contract (`Head`, `HipL/R`, `KneeL/R`, `ShoulderL/R`, `ElbowL/R`, `HandL/R`); origin at the feet, +Y up.
|
|
||||||
- [x] UV-unwrap the mesh into a power-of-two layout, one region per material slot.
|
|
||||||
- [x] Save the editable source as `assets/models/npc/npc_base.blend` (committed).
|
|
||||||
- [x] Add `tools/npc_pipeline.py` with `list` / `build` / `audit` subcommands, run through the Blender flatpak.
|
|
||||||
- [x] `build` exports `assets/models/generated/npc_base.glb` plus the material textures.
|
|
||||||
- [x] Bake neutral albedo per slot, normal maps (fabric weave, denim, knit), and the packed ORM map.
|
|
||||||
- [x] Bake ambient occlusion into the albedo or the ORM R channel (the Compatibility renderer has no SSAO).
|
|
||||||
- [x] `audit` enforces UVs in [0,1], expected bone names, triangle/vertex budget, feet at y≈0, and material-slot presence.
|
|
||||||
- [x] Reuse the `model_pipeline.py` colour-space discipline (linear factors vs sRGB textures) in the exporter.
|
|
||||||
- [x] Run `godot --headless --path . --import` and confirm `npc_base.glb` imports without errors.
|
|
||||||
|
|
||||||
### Phase 2 — AI-assisted texturing
|
|
||||||
|
|
||||||
- [x] Generate seamless clothing albedos (shirt, trousers, jacket, hi-vis vest, coat, dress) with `tools/asset_pipeline.py generate` (OpenRouter, `openai/gpt-5-image-mini`) — written to `assets/textures/npc/ai/` (512×512).
|
|
||||||
- [x] Tile-edge blending on each fabric — applied automatically by `generate --role tile` (`make_seamless`); the `tile` audit's edge check confirms continuity.
|
|
||||||
- [x] Run `asset_pipeline.py audit` on the outputs — 6 good, 0 bad (role `tile`).
|
|
||||||
- [x] Commit the validated textures under `assets/textures/npc/ai/` (tracked in the v0.6.0 asset commit).
|
|
||||||
- [x] Derive per-role outfit palettes via `model_pipeline.dominant_colors` — written to `assets/textures/npc/palette.json` (`npc_pipeline.py palette`).
|
|
||||||
- [x] Bake normal/roughness procedurally and layer the AI albedos on top — `npc_pipeline.py prepare` + Blender `build` keeps the AI albedo for `cloth`/`pants` and regenerates normal/ORM; GLB audit ok (1204 tris / 2488 verts).
|
|
||||||
- [x] Regenerate the staged captures and run `screen_designs.py judge` after the Phase 3 integration (11 good / 0 bad in `compare`; judge: no diff).
|
|
||||||
|
|
||||||
### Phase 3 — Godot integration
|
|
||||||
|
|
||||||
- [x] Add `NpcAvatar._load_model()` that instantiates the imported `npc_base.glb` `PackedScene`.
|
|
||||||
- [x] Keep `_build_body()` as the offline fallback; choose per-avatar and record `loaded_model` / `fallback_avatar` for tests.
|
|
||||||
- [x] Map `outfit_for()` onto the model's material slots so seed variety, `layer_for`, `hand_item_for`, and archetype colors survive.
|
|
||||||
- [x] Keep accessory attachments (cap / hood / backpack / sunglasses / lanyard) under `Rig` / `Head`.
|
|
||||||
- [x] Add `SurfaceMaterials` baked-map recipes (`npc()` / `skin()` / `cloth()`); stop calling `Materials.flat()` for the body.
|
|
||||||
- [x] Add `_set_limb_rotation()` so `_animate()` / `_idle_layer()` write to bones or pivots; keep `Rig/Head` findable by the focus cone.
|
|
||||||
- [x] Update `test_npc_character`, `test_npc_theater`, and `test_target_cycle` for the skinned path (or document why they stay on the fallback).
|
|
||||||
- [x] Re-measure `smoke_npc_budget.gd`; tune `LOD_TIERS` if the skinned rig is heavier up close.
|
|
||||||
- [x] Re-verify the focus-cone smoke (`smoke_focus_radial.gd`) and the movement smoke.
|
|
||||||
|
|
||||||
### Phase 4 — Environment and lighting lift ✅
|
|
||||||
|
|
||||||
- [x] Bake AO for the prop set through the Blender library (replacements above) or into the ORM/albedo maps behind the existing `WorldBuilder` contract; keep the procedural fallback.
|
|
||||||
- [x] Regenerate higher-resolution brick / concrete / asphalt textures via `asset_pipeline.py` with normal maps, keeping the current UV scales; apply the same map discipline to the library's street materials.
|
|
||||||
- [x] Evaluate a desktop-only Forward+ export preset (SSAO/SSIL/volumetrics); keep the Web preset on GL Compatibility with `thread_support=false`.
|
|
||||||
- [x] Record the renderer decision in an ADR addendum or `MEMORY.md`.
|
|
||||||
- [x] Regenerate `docs/screenshots/` with `capture_screenshots.gd` and run `screen_designs.py compare`.
|
|
||||||
|
|
||||||
### Phase 5 — Verification and release
|
|
||||||
|
|
||||||
- [x] Headless suite green: fallback build, outfit determinism, `Rig/Head` presence, material recipe assertions, `npc_pipeline.py audit`, and `blender_assets.py audit` + manifest tests (skip Blender builds with a reason when Blender is absent).
|
|
||||||
- [x] Windowed smokes pass: `smoke_npc_budget.gd`, `smoke_movement.gd`, `smoke_focus_radial.gd`, `smoke_props.gd`.
|
|
||||||
- [x] `screen_designs.py compare` and `judge` show no regressions; `blender_assets.py sheet` contact sheets reviewed for the character/gear/prop library.
|
|
||||||
- [ ] Bump `config/version` to `0.6.0`.
|
|
||||||
- [ ] Update `README.md`, `docs/architecture.md` (Level 2 gains `tools/npc_pipeline.py`), and mark ADR-0013 Accepted.
|
|
||||||
- [ ] Publish the release per `docs/RELEASING.md`.
|
|
||||||
|
|
||||||
## Visual alignment with rendered mockups
|
|
||||||
|
|
||||||
The AI-rendered references in `docs/screens/designs/` (start menu, pause, settings,
|
|
||||||
shift review, radial menu, HUD, scene views) describe the intended look of every
|
|
||||||
screen. This pass reorganizes how generated images are stored, makes the game load
|
|
||||||
the proposed interface/scene art from disk, and aligns the selection screens, HUD,
|
|
||||||
and scene visuals with those mockups — verified with
|
|
||||||
`tools/screen_designs.py compare` + `judge`.
|
|
||||||
|
|
||||||
### Storage restructure
|
|
||||||
|
|
||||||
- [ ] Decide the canonical runtime image root (e.g. `assets/images/` for UI/scene art) and record it in `MEMORY.md` and an ADR.
|
|
||||||
- [ ] Move the reference mockups from `docs/screens/designs/` into the runtime root (keep `docs/screens/designs/` as a docs-only copy or replace it with the new path).
|
|
||||||
- [ ] Document one convention for game vs reference vs development images across `assets/textures/`, `assets/images/`, `assets/models/generated/`, `docs/screenshots/`, and `docs/screens/designs/`.
|
|
||||||
- [ ] Re-run `godot --headless --path . --import` to regenerate `.import` sidecars after any move.
|
|
||||||
- [ ] Confirm `.gitignore` still excludes development-only outputs (concepts, Blender sources, raw AI fabrics) under the new layout.
|
|
||||||
|
|
||||||
### Documentation path updates
|
|
||||||
|
|
||||||
- [ ] Update `README.md` paths (screen-designs section, confirmed-assets links, the `assets/images/backgrounds` resize example).
|
|
||||||
- [ ] Update `docs/architecture.md`, `PLAN.md`, and ADR-0010/0011/0012/0013 references to `docs/screens/designs/`.
|
|
||||||
- [ ] Update `tools/screen_designs.py` docstrings and mark the old paths in `DONE.md` as historical.
|
|
||||||
|
|
||||||
### Code path updates
|
|
||||||
|
|
||||||
- [ ] Point `tools/screen_designs.py generate` at the new design output path and keep `compare`/`judge` reading the right locations.
|
|
||||||
- [ ] Update GDScript `preload()` paths (`materials.gd`, `hud.gd`, `world_builder.gd`) if the game textures move.
|
|
||||||
- [ ] Update `capture_screenshots.gd` / `capture_prop_gallery.gd` output directories if captures relocate.
|
|
||||||
|
|
||||||
### Load proposed interfaces + scene art from disk
|
|
||||||
|
|
||||||
- [ ] Add a central UI/scene art loader (e.g. `src/game/ui/art.gd`) that loads the mockup-derived images from the new runtime root, with a procedural fallback when a file is missing.
|
|
||||||
- [ ] Wire the start menu and venue selection screen to use the `start_menu` scene art.
|
|
||||||
- [ ] Wire the pause overlay, settings, shift review, radial menu, and HUD chrome to their reference images.
|
|
||||||
|
|
||||||
### Align in-game visuals
|
|
||||||
|
|
||||||
- [ ] Make the venue selection screen match the `start_menu` mockup (layout, palette, background).
|
|
||||||
- [ ] Make the HUD match the `targeting_npc` / `escalation_hud` mockups (focus ring, escalation meter, log, hints).
|
|
||||||
- [ ] Align the remaining panels (pause, settings, shift review, radio, wand, timeline) to their mockups.
|
|
||||||
- [ ] Align scene lighting, fog, and post-processing for `venue_overview` and `late_night_avenue`.
|
|
||||||
|
|
||||||
### Verify against the mockups
|
|
||||||
|
|
||||||
- [ ] Regenerate the staged captures and run `screen_designs.py compare` (no gross drift).
|
|
||||||
- [ ] Run `screen_designs.py judge` and clear every `diff` verdict (target `match`/`review`).
|
|
||||||
- [ ] Add the capture + compare step to CI or a repeatable smoke so drift is caught early.
|
|
||||||
|
|
||||||
## Improve in-game pop-ups
|
|
||||||
|
|
||||||
- [ ] Improve the visual appearance of in-game pop-ups (layout, button style, palette, icons, and text styling).
|
|
||||||
|
|
||||||
## Realistic backgrounds, textures and scene references
|
|
||||||
|
|
||||||
Goal: replace the outdated flat skyline backdrop (`assets/textures/skyline.png`, black boxes
|
|
||||||
with dot windows) and the flat-looking surface tiles with AI-generated, more realistic
|
|
||||||
backgrounds and textures. Add a larger set of example 3D scene images as art direction, and
|
|
||||||
measure the in-game result against that target with the screenshot tools. Plan:
|
|
||||||
[`PLAN.md` → Visual Quality Direction → Realism pass](PLAN.md#realism-pass).
|
|
||||||
|
|
||||||
**Rule for every step: never overwrite an existing image.** New outputs get new paths. When a
|
|
||||||
path is taken, the tools pick the next free `-vN` suffix. Raw AI output stays on disk under
|
|
||||||
`assets/textures/ai/v2/raw/` (gitignored like the other raw AI folders). Processed game-ready
|
|
||||||
candidates go to `assets/textures/ai/game_ready/v2/`, scene references to `docs/screens/concepts/`,
|
|
||||||
and trial captures and reports to `docs/screens/realism/<run>/`.
|
|
||||||
|
|
||||||
### Step 1 — Tooling (`tools/scene_concepts.py`)
|
|
||||||
|
|
||||||
- [ ] Add a catalogue of prompts in three groups: `scene` (16:9 example 3D game frames),
|
|
||||||
`backdrop` (4:1 skyline panoramas with transparent sky), and `texture` (seamless PBR
|
|
||||||
surface tiles). Each entry has a name, prompt, role and target path.
|
|
||||||
- [ ] `generate [--group] [--only] [--variants N]`: call the OpenRouter image API through
|
|
||||||
`generate_textures.generate_image` (key from the repo `.env`), save raw output, and never
|
|
||||||
overwrite (`next_free_path`). Print every file written.
|
|
||||||
- [ ] `process`: turn raw backdrops into 2048×512 RGBA strips that tile horizontally (edge
|
|
||||||
crossfade, sky made fully transparent, hard alpha for the alpha-scissor material). Turn raw
|
|
||||||
textures into seamless 1024² tiles (`asset_pipeline.make_seamless`) plus a normal map
|
|
||||||
(`make_normal_maps.normal_map`). Skip outputs that already exist.
|
|
||||||
- [ ] `audit`: run `asset_pipeline.audit_image` on the processed candidates (`backdrop` /
|
|
||||||
`tile` roles) and fail on any bad result.
|
|
||||||
- [ ] `realism`: for each trial capture, report the Pillow detail metrics (edge density,
|
|
||||||
contrast, colour spread, saturation) next to the matching concept image. Optionally ask a
|
|
||||||
vision model (`google/gemini-2.5-flash-lite`) for 0–10 realism scores (lighting,
|
|
||||||
materials, texture detail, backdrop, overall) with concrete fixes. Write a new JSON +
|
|
||||||
Markdown report per run.
|
|
||||||
- [ ] Unit tests (`tools/test_scene_concepts.py`): catalogue shape, the no-overwrite path
|
|
||||||
picker, backdrop/tile processing on synthetic images, metrics, and the judge payload/parse
|
|
||||||
(offline, no network).
|
|
||||||
|
|
||||||
### Step 2 — Example 3D scene images
|
|
||||||
|
|
||||||
- [ ] Generate 3D-game-style example frames for every venue and time of day: Hollywood entrance
|
|
||||||
(morning, golden hour, rainy night), boulevard skyline view (day, dusk), Joke Shop alley
|
|
||||||
(evening, close-up of the door), studio stage door (night arrival), sidewalk material
|
|
||||||
close-up, entrance steps and podium, crowd-control barrier line, and a responder arrival
|
|
||||||
wide shot.
|
|
||||||
- [ ] Review the set and record the visual targets each frame sets (sky, haze, material detail,
|
|
||||||
backdrop depth) in the report.
|
|
||||||
|
|
||||||
### Step 3 — Backgrounds (replace the outdated skyline)
|
|
||||||
|
|
||||||
- [ ] Generate skyline panoramas for day, dusk and night (lit windows): Hollywood/Los Angeles
|
|
||||||
mid-rise blocks, palm silhouettes, the hills on the horizon, a transparent sky, and a
|
|
||||||
straight-on view, in several variants each.
|
|
||||||
- [ ] Process them into `assets/textures/ai/game_ready/v2/skyline_{day,dusk,night}.png`,
|
|
||||||
seamless horizontally for the 3× UV repeat around the backdrop ring.
|
|
||||||
|
|
||||||
### Step 4 — Textures
|
|
||||||
|
|
||||||
- [ ] Generate higher-detail seamless tiles: red brick facade, granite/limestone facade
|
|
||||||
(studio), sidewalk concrete pavers with joints, asphalt with aggregate, wet night asphalt,
|
|
||||||
stone steps, striped awning canvas, and stucco wall.
|
|
||||||
- [ ] Process them into 1024² game-ready tiles plus normal maps in
|
|
||||||
`assets/textures/ai/game_ready/v2/` and audit them.
|
|
||||||
|
|
||||||
### Step 5 — In-game trial captures (no game-code change)
|
|
||||||
|
|
||||||
- [ ] Add `src/test/capture_realism.gd`. It boots the Hollywood venue, captures a fixed shot
|
|
||||||
list (entrance day, boulevard/skyline day, boulevard night), and can swap textures at
|
|
||||||
runtime from `--skyline=` / `--brick=` / `--concrete=` / `--asphalt=` user arguments. The
|
|
||||||
swap finds materials by their current texture, so baseline and candidate frames use the
|
|
||||||
same camera. Writes to `user://screenshots/realism/<tag>/`.
|
|
||||||
- [ ] Capture the baseline (current assets) and the candidate set (v2 skyline + textures), and
|
|
||||||
copy them into `docs/screens/realism/<run>/{baseline,candidate}/`.
|
|
||||||
|
|
||||||
### Step 6 — Compare against the realistic target
|
|
||||||
|
|
||||||
- [ ] Run `scene_concepts.py realism` on baseline and candidate. Record the metric deltas and the
|
|
||||||
vision scores, and note which candidate textures/backdrops win.
|
|
||||||
- [ ] Note the remaining realism gaps (sky/fog, lighting, building geometry, NPC fidelity) as
|
|
||||||
follow-up tasks below.
|
|
||||||
|
|
||||||
### Step 7 — Adopt the winners (after the in-flight normal-map/AO work is committed)
|
|
||||||
|
|
||||||
- [ ] Point `WorldBuilder.T_SKYLINE` at the chosen v2 skyline (separate day/night textures through
|
|
||||||
`set_night_mode`), and retune `albedo_color` for the realistic strip.
|
|
||||||
- [ ] Switch `materials.gd` / `world_builder.gd` surface preloads to the chosen v2 tiles + normal
|
|
||||||
maps, keeping the current UV scales. Update `test_materials.gd` / `test_world.gd`.
|
|
||||||
- [ ] Regenerate `docs/screenshots/` with `capture_screenshots.gd`, then run
|
|
||||||
`screen_designs.py compare` + `judge` and `scene_concepts.py realism`. There must be no
|
|
||||||
`diff` verdict regressions, and realism scores must not drop.
|
|
||||||
- [ ] Update `README.md` (tool usage + gallery), `MEMORY.md` and `docs/architecture.md`.
|
|
||||||
|
|
||||||
## Future ideas (optional, not scheduled)
|
## Future ideas (optional, not scheduled)
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1007 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1004 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1000 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 954 KiB |
|
After Width: | Height: | Size: 910 KiB |
|
After Width: | Height: | Size: 971 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1021 KiB |
@@ -836,8 +836,8 @@
|
|||||||
],
|
],
|
||||||
"path": "assets/models/blender/props/planter_box.glb",
|
"path": "assets/models/blender/props/planter_box.glb",
|
||||||
"replaces": "generated/planter_box.glb",
|
"replaces": "generated/planter_box.glb",
|
||||||
"triangles": 924,
|
"triangles": 1324,
|
||||||
"vertices": 874
|
"vertices": 2780
|
||||||
},
|
},
|
||||||
"protest_sign": {
|
"protest_sign": {
|
||||||
"attach": "hand",
|
"attach": "hand",
|
||||||
@@ -892,14 +892,14 @@
|
|||||||
"round_planter": {
|
"round_planter": {
|
||||||
"bounds_godot": {
|
"bounds_godot": {
|
||||||
"max": [
|
"max": [
|
||||||
0.394,
|
0.432,
|
||||||
1.12,
|
1.12,
|
||||||
0.375
|
0.36
|
||||||
],
|
],
|
||||||
"min": [
|
"min": [
|
||||||
-0.39,
|
-0.36,
|
||||||
0,
|
0,
|
||||||
-0.38
|
-0.363
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"category": "props",
|
"category": "props",
|
||||||
@@ -908,8 +908,8 @@
|
|||||||
"foliage"
|
"foliage"
|
||||||
],
|
],
|
||||||
"path": "assets/models/blender/props/round_planter.glb",
|
"path": "assets/models/blender/props/round_planter.glb",
|
||||||
"triangles": 920,
|
"triangles": 1240,
|
||||||
"vertices": 896
|
"vertices": 2418
|
||||||
},
|
},
|
||||||
"scba_tank": {
|
"scba_tank": {
|
||||||
"attach": "back",
|
"attach": "back",
|
||||||
@@ -1063,14 +1063,14 @@
|
|||||||
"street_tree": {
|
"street_tree": {
|
||||||
"bounds_godot": {
|
"bounds_godot": {
|
||||||
"max": [
|
"max": [
|
||||||
1.019,
|
1.179,
|
||||||
3.65,
|
3.62,
|
||||||
1.117
|
1.102
|
||||||
],
|
],
|
||||||
"min": [
|
"min": [
|
||||||
-1.077,
|
-0.941,
|
||||||
0,
|
0,
|
||||||
-1.016
|
-1.082
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"category": "props",
|
"category": "props",
|
||||||
@@ -1082,8 +1082,8 @@
|
|||||||
],
|
],
|
||||||
"path": "assets/models/blender/props/street_tree.glb",
|
"path": "assets/models/blender/props/street_tree.glb",
|
||||||
"replaces": "WorldBuilder cone trees",
|
"replaces": "WorldBuilder cone trees",
|
||||||
"triangles": 1472,
|
"triangles": 2592,
|
||||||
"vertices": 1396
|
"vertices": 5620
|
||||||
},
|
},
|
||||||
"sunglasses": {
|
"sunglasses": {
|
||||||
"attach": "head",
|
"attach": "head",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
@@ -0,0 +1,81 @@
|
|||||||
|
# ADR-0014: Canonical runtime image root and image conventions
|
||||||
|
|
||||||
|
- **Status:** Accepted (2026-11-01)
|
||||||
|
- **Date:** 2026-11-01
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The project now contains several kinds of images, and their locations overlap:
|
||||||
|
|
||||||
|
- hand-authored and AI-generated **surface textures** under `assets/textures/`
|
||||||
|
(`ai/game_ready/`, `ai/game_ready/v2/`, `npc/`),
|
||||||
|
- **screen mockups** under `docs/screens/designs/`,
|
||||||
|
- **scene references** under `docs/screens/concepts/`,
|
||||||
|
- **QA captures** under `docs/screenshots/` and `docs/screens/realism/`,
|
||||||
|
- **raw AI output** under gitignored `assets/textures/ai/*/raw/`.
|
||||||
|
|
||||||
|
The visual-alignment pass needs the game to load proposed interface and scene
|
||||||
|
art at runtime. That art is currently only in the docs tree, which is not the
|
||||||
|
right place for resources the build must ship and which contributors expect to
|
||||||
|
be documentation-only. Without a convention, UI art, tiled materials, reference
|
||||||
|
mockups, and screenshots will keep being confused for one another.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
1. **`assets/images/` is the canonical runtime root for composed image art** —
|
||||||
|
interface art, backgrounds, and full-frame scene art that the game loads as
|
||||||
|
an image, not as a tiled material.
|
||||||
|
- `assets/images/ui/` — screen and panel art used by the UI layer (start
|
||||||
|
menu/venue selection background, pause/settings chrome, HUD plates).
|
||||||
|
- `assets/images/scenes/` — composed scene/background art loaded directly as
|
||||||
|
an image (not repeated as a surface texture).
|
||||||
|
2. **Tiled material textures stay under `assets/textures/`.** Brick, concrete,
|
||||||
|
asphalt, fabric, skyline strips used with UV repetition, and model maps are
|
||||||
|
materials, not composed screen art. Raw AI output stays in gitignored
|
||||||
|
`assets/textures/ai/*/raw/`; validated environment candidates stay under
|
||||||
|
`assets/textures/ai/game_ready/v2/`.
|
||||||
|
3. **`docs/screens/` remains reference-only.** `designs/` holds mockups and
|
||||||
|
`concepts/` holds larger art-direction sets; neither is shipped or loaded by
|
||||||
|
the game. When a reference becomes runtime art, it is copied/processed into
|
||||||
|
`assets/images/` with a new descriptive name, following the no-overwrite
|
||||||
|
rule (`-vN` suffixes from the asset tooling).
|
||||||
|
4. **QA output stays in `docs/`.** `docs/screenshots/` holds the README/catalogue
|
||||||
|
captures and `docs/screens/realism/<run>/` holds trial captures/reports.
|
||||||
|
These are not runtime resources and may be regenerated.
|
||||||
|
5. **Naming.** Files under `assets/images/` are lowercase `snake_case` PNGs,
|
||||||
|
`<screen>_<variant>.png`, at the native UI size (1280×720 for 16:9 screens)
|
||||||
|
or the size the scene actually uses. Every runtime image needs a procedural
|
||||||
|
or neutral fallback in code so a missing file never breaks a screen.
|
||||||
|
6. **Imports.** Runtime images are normal Godot textures: commit the PNG, let
|
||||||
|
`godot --headless --path . --import` regenerate `.import` sidecars, and keep
|
||||||
|
development-only images out of `assets/images/`.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- One obvious place for art the game actually loads, separate from references
|
||||||
|
and QA captures.
|
||||||
|
- Builds/exports can include `assets/images/**` without also shipping mockups,
|
||||||
|
screenshots, or raw AI output.
|
||||||
|
- The no-overwrite rule and variant naming make visual experiments reversible
|
||||||
|
and keep the docs references stable.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- A reference image that becomes runtime art exists in two places (docs copy +
|
||||||
|
processed runtime copy); contributors must keep the processed copy current.
|
||||||
|
- Moving existing mockups later is a path migration that touches docs, tools,
|
||||||
|
and `preload()` paths — tracked as the remaining visual-alignment storage
|
||||||
|
tasks.
|
||||||
|
|
||||||
|
## Alternatives considered
|
||||||
|
|
||||||
|
- **Use `docs/screens/designs/` as the runtime root.** Rejected: docs are not
|
||||||
|
ship-ready gameplay resources, and mixing references with runtime art makes
|
||||||
|
exports and cleanup brittle.
|
||||||
|
- **Put everything in `assets/textures/`.** Rejected: composed UI/scene art is
|
||||||
|
not a tiled material; mixing it with PBR tiles hides the distinction and
|
||||||
|
invites incorrect import settings.
|
||||||
|
- **Keep images only in code / procedural UI.** Rejected: the visual-alignment
|
||||||
|
pass is explicitly about using the rendered mockups as the target look.
|
||||||
@@ -81,10 +81,29 @@ The player interacts with NPCs, venue entrances, access artifacts, equipment, st
|
|||||||
- `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/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures.
|
- `tools/asset_pipeline.py` generates and audits role-aware textures; `tools/screen_designs.py` generates screen references and judges captures.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
### Asset storage conventions
|
||||||
|
|
||||||
|
The canonical rules live in [ADR-0014](adr/0014-runtime-image-root.md). In short:
|
||||||
|
|
||||||
|
| Location | Contents | Loaded at runtime? |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `assets/images/ui/` | Composed screen/panel art (start menu, HUD chrome, mockup-derived backgrounds) | Yes |
|
||||||
|
| `assets/images/scenes/` | Composed full-frame scene/background art | Yes |
|
||||||
|
| `assets/textures/ai/game_ready/` (+ `v2/`) | Tiled/PBR surface textures, model maps, skyline strips | Yes, as materials |
|
||||||
|
| `assets/models/generated/`, `assets/models/blender/` | 3D props/characters and manifests | Yes |
|
||||||
|
| `docs/screens/designs/`, `docs/screens/concepts/` | Reference mockups and art-direction sets | No (reference only) |
|
||||||
|
| `docs/screenshots/`, `docs/screens/realism/` | README/catalogue captures and QA reports | No (generated QA) |
|
||||||
|
| `assets/textures/ai/v2/raw/`, Blender `.blend` sources | Raw AI output / editable sources | No (gitignored or `.gdignore`d) |
|
||||||
|
|
||||||
|
When reference art becomes runtime art, copy or process it into `assets/images/` with a
|
||||||
|
new descriptive name (never overwrite an existing image) and keep a procedural fallback
|
||||||
|
in code.
|
||||||
|
|
||||||
## 6. Runtime View
|
## 6. Runtime View
|
||||||
|
|
||||||
### Routine interaction
|
### Routine interaction
|
||||||
@@ -167,6 +186,7 @@ Architecture decisions are recorded as ADRs:
|
|||||||
- [ADR-0011: Aim-free selection and precision walk](adr/0011-aim-free-selection-and-precision-walk.md)
|
- [ADR-0011: Aim-free selection and precision walk](adr/0011-aim-free-selection-and-precision-walk.md)
|
||||||
- [ADR-0012: Surface materials and generated props](adr/0012-surface-materials-and-generated-props.md)
|
- [ADR-0012: Surface materials and generated props](adr/0012-surface-materials-and-generated-props.md)
|
||||||
- [ADR-0013: Blender-authored NPC characters and baked materials](adr/0013-blender-authored-npc-characters.md)
|
- [ADR-0013: Blender-authored NPC characters and baked materials](adr/0013-blender-authored-npc-characters.md)
|
||||||
|
- [ADR-0014: Canonical runtime image root and image conventions](adr/0014-runtime-image-root.md)
|
||||||
|
|
||||||
## 10. Quality Requirements
|
## 10. Quality Requirements
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ render about 2.5 min.
|
|||||||
- Blender is Z-up. The glTF exporter converts to Godot Y-up.
|
- Blender is Z-up. The glTF exporter converts to Godot Y-up.
|
||||||
- **Front = Blender −Y = Godot +Z**, the face direction that
|
- **Front = Blender −Y = Godot +Z**, the face direction that
|
||||||
`NpcAvatar.yaw_towards()` assumes.
|
`NpcAvatar.yaw_towards()` assumes.
|
||||||
|
- **Foliage** (`street_tree`, `planter_box`, `round_planter`) is a cluster of many small
|
||||||
|
flat-shaded clumps plus outer clumps that break the silhouette, not one smooth blob. That is
|
||||||
|
how the realism pass made the street greenery read as leaves; the three assets carry fresh AO
|
||||||
|
maps (`street_tree` is 2,592 triangles).
|
||||||
- Grounded assets have their origin on the floor (`min y ≈ 0`). The two
|
- Grounded assets have their origin on the floor (`min y ≈ 0`). The two
|
||||||
exceptions are `wall_lantern` (origin on the wall plate, at mount height) and
|
exceptions are `wall_lantern` (origin on the wall plate, at mount height) and
|
||||||
`marquee` (origin at the wall where the canopy meets it, at canopy height).
|
`marquee` (origin at the wall where the canopy meets it, at canopy height).
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Scene concepts: the realistic target look
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
| Concept | Visual targets it sets |
|
||||||
|
| --- | --- |
|
||||||
|
| `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 |
|
||||||
|
|
||||||
|
Cross-cutting targets, for comparison with the 2026-11-01 captures in
|
||||||
|
`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,
|
||||||
|
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.
|
||||||
|
After Width: | Height: | Size: 1.3 MiB |