Give Hollywood and the TV Studio the same queue story and validate every venue's placements
Full build / Import + headless tests (push) Successful in 42s
Full build / Full desktop build + optional release (push) Skipped

This commit is contained in:
zwitschi committed 2026-11-06 20:55:52 +01:00
1 parent efa062833f
commit a196a35342
18 files changed
+55 -9

No files matched your search

+2
View File
@@ -9,6 +9,8 @@ Semantic Versioning.
### Fixed
- The red event banners are lit from the top down at night instead of reading as flat red cards.
- Hollywood and the TV Studio got the same queue treatment, and the TV Studio's props no longer sit
in the entrance steps.
- The Joke Shop has a readable queue: a velvet rope line leading to the check-in podium, a thicker
bike-rack barricade on the curb side, and a planter no longer clipping the palm foliage.
- Street lamps now throw a warm pool on the pavement instead of dimly washing the whole walkway.
+4
View File
@@ -134,6 +134,10 @@ canonical implemented-features list in `docs/project/development-status.md`.
multiplier into every `_marquee_emissive` entry, which flattens any gradient. It now reads
`mat.get_meta("night_energy", 2.0)`, so a multi-strip panel can keep its top-to-bottom ratio
(the event banners: 2.6 → 1.4).
- **`placement_problems()` was only gated for the Joke Shop.** Its test validated one venue's prop
list, so the TV Studio carried six violations (props inside the steps/door exclusion and off the
sidewalk) unnoticed. `test_every_venue_placement_clears_the_sidewalk_and_the_approach` now runs the
validator on all three venues. When adding a venue or a prop, that test is the gate.
- **Venue lights must keep `omni_attenuation == 1.0`** — `test_world.test_venue_lights_use_physical_falloff`
enforces physical falloff on every Omni/Spot in all three venues, so a "pool" cannot come from
sharpening the curve. Use `omni_range` + energy instead: 10 m / energy 8 gives a brighter pool and
+6 -1
View File
@@ -980,7 +980,12 @@ scorecard source, this milestone is the actionable list.
18 → 22 mm; the old sizes read as wire at 8 m.
- [x] **West palm / planter overlap.** The planter box sat under the west palm canopy (palm spans
x −15.0…−11.0 there) and the foliage cards clipped its lip; it moved 1.6 m clear.
- [ ] The same queue/set-dressing review for Hollywood and the TV Studio.
- [x] **Hollywood and TV Studio review.** Hollywood: the lone stanchion and single barricade became
a three-post rope line into the check-in podium plus a curb barricade. TV Studio: **six
placement violations** surfaced once the validator was applied to it — three props sat inside
the steps/door exclusion and off the sidewalk at z 4.2–4.4; re-placed into a rope line +
podium + two barricades. `test_every_venue_placement_clears_the_sidewalk_and_the_approach`
now runs the validator on all three venues, so this cannot regress.
- [ ] Sidewalk light pool at the Joke Shop: the entrance walkway measures 20.7/255 against 3.0 on
the side pavement, so a pool exists but only at the door; the queue area itself is unlit.
- [ ] Build one real-photo comparison for street furniture and record the accepted mismatches.
+11
View File
@@ -365,6 +365,17 @@ Readability at 8 m drove the thickness pass: bike-rack frame 22 → 28 mm, bars
Measured at night afterwards: the entrance walkway sits at 20.7/255 against 3.0 on the side pavement,
so the door pool exists; the queue area itself is still unlit and stays queued as a follow-up.
### Hollywood and the TV Studio
Hollywood had one stanchion and one barricade, which read as stray street furniture; it now has the
same three-post rope line into the check-in podium, with a barricade on the curb.
The TV Studio had **never been validated**: `placement_problems()` was only applied to the Joke Shop
in its test, and running it on the studio reported six violations — three props at z 4.2–4.4 sat
inside the steps/door exclusion and outside the sidewalk bounds. They are re-placed as a rope line,
podium and two curb barricades, and `test_every_venue_placement_clears_the_sidewalk_and_the_approach`
now validates all three venues so the gap cannot reopen.
## Scorecard skeleton
Verdicts use `qa-review` semantics: **P0** (blocker: wrong scale, broken normals, budget fail),
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 KiB

After

Width:  |  Height:  |  Size: 515 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 KiB

After

Width:  |  Height:  |  Size: 666 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 KiB

After

Width:  |  Height:  |  Size: 757 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 KiB

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

+16 -8
View File
@@ -129,9 +129,13 @@ const VENUE_SPECS := {
{"zone": "mid_block", "prop": "round_planter", "x": 12.8, "z": 7.0},
{"zone": "curb", "prop": "a_frame_sign", "x": -9.8, "z": 7.0, "rot": 15.0},
{"zone": "curb", "prop": "traffic_cone", "x": 9.6, "z": 10.0},
{"zone": "curb", "prop": "crowd_barrier", "x": 3.0, "z": 10.9},
{"zone": "curb", "prop": "stanchion", "x": -2.6, "z": 10.9},
{"zone": "entrance", "prop": "security_podium", "x": 8.0, "z": 6.1, "rot": -15.0},
# Hollywood queue: a rope line into the check-in podium, barricades at the
# curb. The single stanchion and lone barricade read as stray street furniture.
{"zone": "entrance", "prop": "stanchion", "x": 5.4, "z": 7.4},
{"zone": "entrance", "prop": "stanchion", "x": 6.3, "z": 7.4},
{"zone": "entrance", "prop": "stanchion", "x": 7.2, "z": 7.4},
{"zone": "entrance", "prop": "security_podium", "x": 8.4, "z": 6.5, "rot": -95.0},
{"zone": "curb", "prop": "crowd_barrier", "x": 5.0, "z": 10.4},
],
},
"joke_shop": {
@@ -211,11 +215,15 @@ const VENUE_SPECS := {
"masonic_facade": true,
},
"prop_placements": [
{"zone": "entrance", "prop": "stanchion", "x": -2.8, "z": 4.4},
{"zone": "entrance", "prop": "stanchion", "x": 2.8, "z": 4.4},
{"zone": "entrance", "prop": "crowd_barrier", "x": -5.2, "z": 4.2},
{"zone": "entrance", "prop": "crowd_barrier", "x": 5.2, "z": 4.2},
{"zone": "curb", "prop": "security_podium", "x": 4.6, "z": 5.9, "rot": -15.0},
# Same queue story as the Joke Shop: a rope line west of the approach lane
# into the check-in podium, barricades on the curb. The old placements sat at
# z 4.2-4.4, which is inside the steps/door exclusion and off the sidewalk.
{"zone": "entrance", "prop": "stanchion", "x": 2.6, "z": 7.6},
{"zone": "entrance", "prop": "stanchion", "x": 3.5, "z": 7.6},
{"zone": "entrance", "prop": "stanchion", "x": 4.4, "z": 7.6},
{"zone": "entrance", "prop": "security_podium", "x": 5.6, "z": 6.7, "rot": -95.0},
{"zone": "curb", "prop": "crowd_barrier", "x": 2.2, "z": 10.4},
{"zone": "curb", "prop": "crowd_barrier", "x": -5.0, "z": 9.6},
],
},
}
+16
View File
@@ -96,6 +96,22 @@ func test_joke_shop_uses_the_real_sunset_strip_layout() -> bool:
root.free()
return a and a2 and b and c and d and e and f and g and g2 and h
## The placement validator was only applied to the Joke Shop, so the TV Studio kept
## three props inside the steps/door zone and off the sidewalk without anyone
## noticing. Every venue is checked now.
func test_every_venue_placement_clears_the_sidewalk_and_the_approach() -> bool:
var problems: Array[String] = []
for venue in ["hollywood_building", "joke_shop", "tv_studio"]:
var root := Node3D.new()
var builder := WorldBuilder.new(root, venue)
var placements: Array = builder.spec.get("prop_placements", [])
for problem in WorldBuilder.placement_problems(placements):
problems.append("%s: %s" % [venue, problem])
root.free()
return TestUtils.check(problems.is_empty(),
"every venue's props sit on the sidewalk and clear the approach (%s)"
% ", ".join(problems.slice(0, 5)))
func test_joke_shop_geometry_stays_inside_the_map_budget() -> bool:
var root := Node3D.new()
var builder := WorldBuilder.new(root, "joke_shop")