refs: survey the sibling project and recalibrate the hero facade

Tools/sibling_asset_audit.py reads the sibling security-game project's prop
library straight from the GLB headers: 20 street props, 11.8k triangles, every
one with a Blender source. The 50 .blend sources are copied to
Art/props/blender_src/ with a manifest; nothing is imported into Unreal yet. Its
building meshes are deliberately not taken - they are Godot GLBs built around a
29.6 m facade that this project measured at 25.75 m.

The facade proportions were wrong against the photograph: 5.7 m of blank wall
above the capitals. Entablature is now 3.4 m, parapet 2.2 m, with architrave and
cornice bands and square pedestals, so the elevation reads as layered stone.
This commit is contained in:
zwitschi committed 2026-11-07 12:20:41 +01:00
1 parent 52a736bc9f
commit 5e5e5ae9b4
67 files changed
+591 -27

No files matched your search

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+288
View File
@@ -0,0 +1,288 @@
{
"source_project": "/run/media/system/DATA/Documents/06-games/security-game",
"scanned": "assets/models/blender/props + assets/models/blender_src",
"licence": "project-owned (same author); confirm before shipping",
"note": "audit only \u2014 nothing has been copied",
"props": [
{
"prop": "a_frame_sign",
"glb": "a_frame_sign.glb",
"bytes": 19120,
"blend_source": "a_frame_sign.blend",
"blend_bytes": 96742,
"triangles": 212,
"size_gltf": [
0.62,
0.965,
0.527
],
"materials": 4
},
{
"prop": "bench",
"glb": "bench.glb",
"bytes": 36268,
"blend_source": "bench.blend",
"blend_bytes": 102020,
"triangles": 560,
"size_gltf": [
1.8,
0.844,
0.522
],
"materials": 2
},
{
"prop": "bollard",
"glb": "bollard.glb",
"bytes": 10020,
"blend_source": "bollard.blend",
"blend_bytes": 92615,
"triangles": 138,
"size_gltf": [
0.25,
0.975,
0.25
],
"materials": 2
},
{
"prop": "crowd_barrier",
"glb": "crowd_barrier.glb",
"bytes": 24808,
"blend_source": "crowd_barrier.blend",
"blend_bytes": 96463,
"triangles": 388,
"size_gltf": [
2.248,
1.084,
0.613
],
"materials": 1
},
{
"prop": "double_door",
"glb": "double_door.glb",
"bytes": 33336,
"blend_source": "double_door.blend",
"blend_bytes": 101710,
"triangles": 380,
"size_gltf": [
2.165,
2.72,
0.2
],
"materials": 6
},
{
"prop": "fire_hydrant",
"glb": "fire_hydrant.glb",
"bytes": 34684,
"blend_source": "fire_hydrant.blend",
"blend_bytes": 102818,
"triangles": 610,
"size_gltf": [
0.53,
0.815,
0.47
],
"materials": 2
},
{
"prop": "handrail",
"glb": "handrail.glb",
"bytes": 15656,
"blend_source": "handrail.blend",
"blend_bytes": 93785,
"triangles": 268,
"size_gltf": [
2.209,
1.784,
0.1
],
"materials": 1
},
{
"prop": "marquee",
"glb": "marquee.glb",
"bytes": 126272,
"blend_source": "marquee.blend",
"blend_bytes": 144786,
"triangles": 2804,
"size_gltf": [
6,
2.044,
1.67
],
"materials": 3
},
{
"prop": "newspaper_box",
"glb": "newspaper_box.glb",
"bytes": 27304,
"blend_source": "newspaper_box.blend",
"blend_bytes": 99783,
"triangles": 300,
"size_gltf": [
0.44,
0.916,
0.386
],
"materials": 5
},
{
"prop": "palm_tree",
"glb": "palm_tree.glb",
"bytes": 20912,
"blend_source": "palm_tree.blend",
"blend_bytes": 100466,
"triangles": 400,
"size_gltf": [
4.0,
6.99,
3.9
],
"materials": 3
},
{
"prop": "planter_box",
"glb": "planter_box.glb",
"bytes": 63276,
"blend_source": "planter_box.blend",
"blend_bytes": 114862,
"triangles": 818,
"size_gltf": [
1.0,
1.118,
1.0
],
"materials": 4
},
{
"prop": "round_planter",
"glb": "round_planter.glb",
"bytes": 56664,
"blend_source": "round_planter.blend",
"blend_bytes": 113201,
"triangles": 808,
"size_gltf": [
0.759,
1.175,
0.736
],
"materials": 3
},
{
"prop": "security_podium",
"glb": "security_podium.glb",
"bytes": 18968,
"blend_source": "security_podium.blend",
"blend_bytes": 97217,
"triangles": 184,
"size_gltf": [
0.64,
1.167,
0.487
],
"materials": 5
},
{
"prop": "sedan",
"glb": "sedan.glb",
"bytes": 50348,
"blend_source": "sedan.blend",
"blend_bytes": 111241,
"triangles": 928,
"size_gltf": [
1.85,
1.32,
4.625
],
"materials": 6
},
{
"prop": "stanchion",
"glb": "stanchion.glb",
"bytes": 19048,
"blend_source": "stanchion.blend",
"blend_bytes": 99736,
"triangles": 434,
"size_gltf": [
1.095,
1.01,
0.34
],
"materials": 3
},
{
"prop": "street_lamp",
"glb": "street_lamp.glb",
"bytes": 22740,
"blend_source": "street_lamp.blend",
"blend_bytes": 99309,
"triangles": 428,
"size_gltf": [
1.3,
4.985,
0.5
],
"materials": 2
},
{
"prop": "street_tree",
"glb": "street_tree.glb",
"bytes": 119588,
"blend_source": "street_tree.blend",
"blend_bytes": 134001,
"triangles": 1506,
"size_gltf": [
2.191,
3.634,
2.133
],
"materials": 4
},
{
"prop": "traffic_cone",
"glb": "traffic_cone.glb",
"bytes": 13328,
"blend_source": "traffic_cone.blend",
"blend_bytes": 95292,
"triangles": 210,
"size_gltf": [
0.38,
0.69,
0.38
],
"materials": 3
},
{
"prop": "trash_bin",
"glb": "trash_bin.glb",
"bytes": 18584,
"blend_source": "trash_bin.blend",
"blend_bytes": 95841,
"triangles": 228,
"size_gltf": [
0.527,
0.92,
0.536
],
"materials": 3
},
{
"prop": "wall_lantern",
"glb": "wall_lantern.glb",
"bytes": 13752,
"blend_source": "wall_lantern.blend",
"blend_bytes": 93826,
"triangles": 180,
"size_gltf": [
0.22,
0.33,
0.365
],
"materials": 2
}
]
}
Binary file not shown.
Binary file not shown.
+8
View File
@@ -105,3 +105,11 @@ Scope: facts and traps that cost time to establish. Planned work lives in [ROADM
- **`StaticMaterial` is a struct**: `material.get_editor_property("material_interface")`, no `get_name()` on the wrapper.
- **Review screenshots are committed on the owner's instruction (2026-11-07).** They are large PNGs, so a review run adds weight to the repo; keep the shot list short and delete retired shots rather than accumulating.
## 2026-11-07 — Sibling project reuse survey
- **`security-game` holds 20 reusable street props** with Blender sources (`assets/models/blender_src/*.blend`) and Godot GLBs: bollard, bench, trash bin, stanchion, crowd barrier, street lamp, traffic cone, fire hydrant, newspaper box, palm/street trees, sedan, marquee, doors, lanterns. About 727 KB and 11.8k triangles for the set. Audit: `Tools/sibling_asset_audit.py`, manifest at `Art/props/reuse-manifest.json`; the 50 `.blend` sources are copied to `Art/props/blender_src/`.
- **Their building meshes are not reusable** — they are Godot GLBs built to a different key set (hero facade scaled to 29.6 m, a figure this project measured at 25.75 m). Do not import their venue geometry.
- **`tools/generate_textures.py` in that project is the OpenRouter image endpoint pattern** (`POST /api/v1/images`, `b64_json`, optional `reference_path` for image-to-image on the chat endpoint) and it already has procedural `brick_facade` / `seamless_concrete` / `asphalt` generators. Worth porting for our facade materials.
- **Its AI concept frames are restaged photograph references** (`.refgen.json` sidecars point at photos with a "keep geometry fixed" suffix). Useful as art direction, not as texture sources.
- **Blosm exposes `setupScript`** (`scene.blosm.setupScript` → `loadSetupScript`) for custom building materials, and ships `setup/neoclassical.py` as an example — the hook for giving OSM buildings a per-building facade style instead of flat colours.
+1 -1
View File
@@ -81,7 +81,7 @@ Follow-on work on the player avatar, after the review scene passes. None of it i
- [x] Establish a consistent scale test, named export presets, and repeatable import settings. Scale test = the three-cube calibration scene (`Art/blender/scaletest/`, regenerable via `Tools/scale_test_export.py`); named export preset `ue_metric_v1` (FBX settings in that script); named import preset `ue_metric_v1` (`FbxImportUI` settings in `Tools/ue_scale_test_import.py`). Both scripts are the templates for production asset export/import.
- [-] Collect reference photography for manual façade work. Local only, never committed: `Art/reference/` is gitignored. **72 images in eleven folders**: hero façades to 4k, the El Capitan Theatre exterior series, premiere-night staging, Ovation Hollywood, the north side, and the Lee Drug neighbour. Gaps largely closed by the Flickr/web-search pass: the hero entrance is now documented (three portals with individual short flights — the inherited "eight steps, 12 m wide" is overturned), and the 6806–6822 retail run appears in an oblique 2013 frame. Still missing: a clean isolated frame of the door recess and a night frame of 6840 itself.
- [x] Download reference photography for the two north-side buildings inside the 50 m buffer — TCL Chinese Theatre (OSM way 424105908, 6925 Hollywood Blvd) and Madame Tussaud's (way 424105889, 6933 Hollywood Blvd). Done 2026-11-06 with `Tools/commons_fetch.py` against the Wikimedia Commons API: eleven frames in the local `Art/reference/north-chinese/` and `Art/reference/north-tussauds/`, provenance in each `sidecar.json`, nothing committed.
- [-] Model hero façade for the El Capitan Entertainment Centre site. **First pass built 2026-11-07** (`Tools/hero_facade_build.py` → `Art/blender/hero/hero-facade-2026-11-07.blend` + JSON part report with evidence per part → `Tools/ue_hero_facade_import.py` → `/Game/Hollywood/ElCapitan/SM_HeroFacade`, 1892 tris, 4 materials, placed on the measured building line). Six columns at 4.96 m over the 25.75 m frontage, plinth, three portal flights (5 risers, not the old 8), entablature 2.2 m, parapet 1.6 m with motto band and medallions. **Screenshot review pending** (`Screenshots/review-04`, `review-05`). Next pass: portal recesses read from the street, banner and window placement, then materials.
- [x] Model hero façade for the El Capitan Entertainment Centre site. **Second pass built 2026-11-07** (proportions recalibrated from the 2009 photograph: entablature 3.4 m, parapet 2.2 m, architrave and cornice bands, square pedestals — the first pass had 5.7 m of blank wall above the capitals and read as a warehouse). **First pass built 2026-11-07** (`Tools/hero_facade_build.py` → `Art/blender/hero/hero-facade-2026-11-07.blend` + JSON part report with evidence per part → `Tools/ue_hero_facade_import.py` → `/Game/Hollywood/ElCapitan/SM_HeroFacade`, 1892 tris, 4 materials, placed on the measured building line). Six columns at 4.96 m over the 25.75 m frontage, plinth, three portal flights (5 risers, not the old 8), entablature 2.2 m, parapet 1.6 m with motto band and medallions. **Screenshot review pending** (`Screenshots/review-04`, `review-05`). Next pass: portal recesses read from the street, banner and window placement, then materials.
- [ ] Model surrounding block frontage.
- [ ] Model simplified background buildings directly across Hollywood Boulevard.
- [-] Build sidewalks, roads, and collision meshes. Terrain, road, sidewalks and kerbs exist (`Art/blender/terrain/`, `street/`) and are assembled in `site/site-2026-11-06.blend`; collision and details (crossing markings, kerb radii, aprons) are not built. Ground must follow the DEM: 3.94 m fall along the block, ~2 % crown between the gutters at ±10–11 m from the centreline, north sidewalk higher than south. Kerb height is an unresolved assumption — the DEM does not resolve it (`Geo/verification/2026-11-06-cross-sections.md`).
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15 -4
View File
@@ -43,11 +43,15 @@ COLUMN_BAY = 4.96
FRONTAGE_Y = 0.0 # front plane sits at the building line of the block frame
# --- assumptions -------------------------------------------------------------
# Calibrated against the 2009 façade photograph: the entablature starts a little
# over half the total height, and the parapet carries the motto at about three
# quarters. The first pass had the enframed wall carrying 5.7 m of blank stone
# above the capitals, which read as a warehouse rather than a temple.
PEDESTAL_H = 1.45 # column pedestal top; entrance platform sits on it
COLUMN_D = 0.95 # Ionic shaft diameter at the base
CAPITAL_H = 0.95
ENTABLATURE_H = 2.20
PARAPET_H = 1.60
ENTABLATURE_H = 3.40 # band between the capitals and the motto panel
PARAPET_H = 2.20 # motto panel and cornice above the entablature
PORTAL_W = 3.10 # each of the three door openings
PORTAL_H = 3.40
STEP_TREAD = 0.34
@@ -127,8 +131,8 @@ def build():
for i in range(COLUMN_COUNT):
x = -span / 2.0 + i * COLUMN_BAY
col_xs.append(x)
cylinder(f"Hero_Pedestal_{i + 1}", x, -0.55, PEDESTAL_H, PEDESTAL_H + 0.55,
0.62, stone, vertices=16)
cube(f"Hero_Pedestal_{i + 1}", x, -0.62, PEDESTAL_H + 0.27,
1.24, 1.24, 0.54, stone)
cylinder(f"Hero_Column_{i + 1}", x, -0.55, PEDESTAL_H + 0.55,
PEDESTAL_H + 0.55 + (HEIGHT - ENTABLATURE_H - PARAPET_H - PEDESTAL_H - 0.55 - CAPITAL_H),
COLUMN_D / 2.0, stone)
@@ -140,6 +144,13 @@ def build():
# --- entablature and parapet ------------------------------------------
ent_z0 = HEIGHT - ENTABLATURE_H - PARAPET_H
# Lower entablature band (architrave) standing proud of the wall, so the
# elevation reads as layered stone rather than one flat plane.
cube("Hero_Architrave", 0.0, -1.55, ent_z0 + 0.42, FRONTAGE_W, 1.65, 0.84, stone)
note("Hero_Architrave", (FRONTAGE_W, 1.65, 0.84), "assumption: stacked entablature bands")
# Cornice under the parapet.
cube("Hero_Cornice", 0.0, -1.6, HEIGHT - PARAPET_H - 0.18, FRONTAGE_W, 1.75, 0.36, stone)
note("Hero_Cornice", (FRONTAGE_W, 1.75, 0.36), "assumption: projecting cornice line")
cube("Hero_Entablature", 0.0, -0.75, ent_z0 + ENTABLATURE_H / 2.0,
FRONTAGE_W, 1.5, ENTABLATURE_H, stone)
note("Hero_Entablature", (FRONTAGE_W, 1.5, ENTABLATURE_H), "assumption: entablature depth")
+107
View File
@@ -0,0 +1,107 @@
# Audit the sibling Gig Line project for assets this project can reuse.
#
# python3 Tools/sibling_asset_audit.py # summary
# python3 Tools/sibling_asset_audit.py --manifest # write Art/props/reuse-manifest.json
#
# The sibling project (…/06-games/security-game) is a Godot 4 security game by
# the same author that researched this block first. Its street props are small,
# generic and far cheaper to reuse than to remodel; its building meshes are not
# reusable because they are Godot GLBs built to a different contract.
#
# What this tool does NOT do: copy anything, decide licence, or assume a prop
# matches this project's proportions. It reports name, size, format and whether
# a Blender source exists, so the copy list can be chosen deliberately.
import argparse
import json
import os
import struct
import sys
SIBLING = "/run/media/system/DATA/Documents/06-games/security-game"
PROPS_GLB = os.path.join(SIBLING, "assets/models/blender/props")
SRC_BLEND = os.path.join(SIBLING, "assets/models/blender_src")
OUT = "Art/props/reuse-manifest.json"
def glb_stats(path):
"""Triangle count and bounds from a GLB, without any dependency."""
with open(path, "rb") as f:
data = f.read()
if data[:4] != b"glTF":
return None
json_len = struct.unpack("<I", data[12:16])[0]
doc = json.loads(data[20 : 20 + json_len].decode("utf-8"))
tris = 0
for mesh in doc.get("meshes", []):
for prim in mesh.get("primitives", []):
idx = prim.get("indices")
if idx is not None:
tris += doc["accessors"][idx]["count"] // 3
# bounds across all positions
mins = [1e9] * 3
maxs = [-1e9] * 3
for mesh in doc.get("meshes", []):
for prim in mesh.get("primitives", []):
acc = prim.get("attributes", {}).get("POSITION")
if acc is None:
continue
a = doc["accessors"][acc]
if "min" in a and "max" in a:
mins = [min(m, v) for m, v in zip(mins, a["min"])]
maxs = [max(m, v) for m, v in zip(maxs, a["max"])]
size = [round(maxs[i] - mins[i], 3) for i in range(3)] if mins[0] < 1e8 else None
return {"triangles": tris, "size_gltf": size, "materials": len(doc.get("materials", []))}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--manifest", action="store_true")
args = ap.parse_args()
if not os.path.isdir(PROPS_GLB):
sys.exit(f"missing {PROPS_GLB}")
rows = []
for name in sorted(os.listdir(PROPS_GLB)):
if not name.endswith(".glb"):
continue
stem = name[:-4]
path = os.path.join(PROPS_GLB, name)
stats = glb_stats(path) or {}
source = os.path.join(SRC_BLEND, stem + ".blend")
rows.append({
"prop": stem,
"glb": name,
"bytes": os.path.getsize(path),
"blend_source": os.path.basename(source) if os.path.exists(source) else None,
"blend_bytes": os.path.getsize(source) if os.path.exists(source) else None,
**stats,
})
for r in rows:
src = "blend" if r["blend_source"] else "glb-only"
size = r.get("size_gltf")
dims = "x".join(f"{v:.2f}" for v in size) if size else "?"
print(f"{r['prop']:18} {r['triangles']:5} tris {dims:>18} glTF m "
f"mats {r.get('materials', 0)} {src}")
print(f"\n{len(rows)} props, {sum(r['bytes'] for r in rows)//1024} KB of GLB, "
f"{sum(r['triangles'] for r in rows)} triangles total")
print("glTF is Y-up and Blender is Z-up: the exporter swaps Y/Z, so `size_gltf` "
"lists X, height, depth — not X, Y, Z as authored.")
if args.manifest:
os.makedirs(os.path.dirname(OUT), exist_ok=True)
with open(OUT, "w") as f:
json.dump({
"source_project": SIBLING,
"scanned": "assets/models/blender/props + assets/models/blender_src",
"licence": "project-owned (same author); confirm before shipping",
"note": "audit only — nothing has been copied",
"props": rows,
}, f, indent=2)
print(f"wrote {OUT}")
if __name__ == "__main__":
main()