# AI Methodology Report — structure & evidence map

*Working scaffold for the "AI Methodology Report" deliverable (tools · workflows ·
alternatives considered · contribution to decisions). Feeds the **20% "Effectiveness of
AI Integration"** score. This file is an outline + evidence index built from the repo as
of 2026-07-17 — not the final prose. Deliverable master lives on Drive; this is the
knowledge scaffold.*

---

## 0. Framing (half a page)

- **AI as a design-process instrument, not installed park tech.** The brief rewards AI used
  for research, analysis, ideation, scenario testing, visualisation and decision-making —
  installing sensors in the park is explicitly *not* required. Every number below was
  produced by an AI/computational workflow and traced to a design decision.
- **One-line thesis (already in `report/slides.md`):** *"A park people already love for eight months of the year, and avoid for four: the evidence points to where shade, cooling and access can change that."*
  (Reworded 2026-08-17: the earlier "doesn't cool, doesn't shade, is hard to reach — we can
  prove where each fix belongs" over-stated three absolutes and "prove"; the new line also
  carries the review-corpus finding that the park is loved in winter and avoided in summer.)
- **Method thesis (added 2026-08-17, now the spine of §01 in the HTML):** *an open, local,
  verifiable pipeline in which AI is competent everywhere it is asked to act, with closed tools
  only at the edge.* Three reasons stated: accessible (re-runnable from the repo), AI-legible
  (agents are competent with open tools whose docs/source are public, and guess with closed
  ones), local context (models are stateless; the project — data, scripts, corrections,
  rejections — stays on the local drive under git). Proprietary tools (AutoCAD, Revit,
  Illustrator) sit at the edge, fed by conversion (LibreDWG/vector-PDF in; IFC4, layer-tagged
  SVG, true-scale PDF out); nothing comes back into the core by hand.
- **Two additions the same day (from the Tan cross-read + Makoto's churn point):** (a) *built for
  churn* — edge tools/models/services turn over in weeks (Seedance 2.5 released 31 Jul, in use by
  mid-Aug; five models compared, three retired in a fortnight; published prices wrong on every
  check), so the method is designed for substitution: thin seam to the model (our own conditioning
  images / camera paths / prompt), endpoint + version + measured cost recorded per run, the no-AI
  baseline kept as permanent fallback, model choice as a dated decision with a stopping rule;
  (b) the latent/deterministic rule stated outright — *agents decide what to run; open,
  deterministic code computes; no number in this report was produced by a language model.*
- **"Process" widened beyond analysis (same rewrite):** five modes, each with its section —
  analyse (§05), orchestrate (§03, incl. the bot mailbox), model (§07), generate (§08),
  operate (§07). Plus the "what stayed human" sentence (every design move, dimension, go/no-go,
  send) — this closes the SAFE *Scope* item from `critique_tifa_2025.md` without a table — and
  the review-corpus limit (heat is what the tools measure best, not all the park is for).
- **Moved out of framing:** the paid-cool-play / 2.8 km paragraph now lives in the area-2 card.
- **Novelty claim to lean on:** there is **no confirmed hot-arid Gulf precedent** for
  AI-in-the-design-process for parks (every case study in `research/tech_scan.md` is
  milder/wetter). Our rigorous hot-arid application is itself a contribution — but borrowed
  cooling numbers are presented as *"a method that transfers, not a result that replicates."*

---

## 1. The AI operating model & workflow  → answers **"workflows"**

This is our strongest differentiator and the jury rarely sees it. Lead with it.

- **Multi-agent orchestration.** Work was run as a named agent team **`alsafa2`** — eight
  role-specialised Claude Code agents (solutions, coder, writer, researcher, areamap,
  **flir**, historian, plateau) coordinating over a shared message bus (`agmsg`, SQLite
  store), each bound to a subdirectory of this repo. Division of labour is visible in the
  folder structure itself.
- **Deep-research with adversarial verification.** The technology scan
  (`research/tech_scan.md`) was produced by a 5-angle deep-research workflow: **23 sources
  fetched, 92 claims extracted, 25 adversarially verified by 3-vote panels — 23 confirmed,
  2 refuted.** Per-claim confidence and verification status are stated inline; the two
  refuted claims were *kept and flagged*, not deleted.
- **Human-in-the-loop, reproducible.** Every finding is a versioned Python script that
  prints its own sanity stats; methods deliberately mirror the earlier Al Karama study for
  comparability. Human field knowledge repeatedly *overrides* the AI (see §5).
- **IP-disciplined.** Competition CAD (`asbuilt_plan.dwg`) is converted **locally**
  (LibreDWG), never uploaded to online converters, per Schedule 6 IP terms.

*Figures: folder/agent map; the deep-research verification funnel (92→25→23).* 

---

## 2. Tool inventory  → answers **"tools"**

Single table; every entry open-source / peer-reviewed unless noted. Map each to the 8 areas.

| Tool / model | Role | Source / basis |
|---|---|---|
| Google Earth Engine + Landsat 8/9 C02, ERA5-Land, Sentinel-2 | LST, 10-yr climate, NDVI, 1972–2025 timelapse | cloud remote sensing |
| **thermofeel 2.2.0** (ECMWF) | UTCI / MRT | Di Napoli et al. 2020 (ERA5-HEAT method) |
| **SOLWEIG** (`solweig-gpu 1.2.22`, GPLv3) | 1 m spatial MRT/UTCI, intervention matrix | UMEP/SOLWEIG |
| Meta/WRI 1 m canopy height | tree geometry (214 patches) | global canopy model |
| In-house vector shadow engine (EPSG:32640) | hourly ground shade, design day 2025-08-01 | NOAA solar position |
| **OSMnx / NetworkX** | walkshed, betweenness, isochrones, heat-dose routing | network analysis |
| **scipy** (csgraph / ndimage) | shade-seeking ABM, fountain-siting overlay | graph + raster |
| **OpenFOAM** (+ trimesh STL) | wind / porous-edge CFD | external case |
| **iNaturalist v1 API** | ground-truth species IDs | citizen science |
| Google Maps reviews (Outscraper) | 1,152-review corpus → 6 personas, seasonality, complaint clusters | public review mining + LLM close-read |
| **i-Tree** coefficients (Nowak & Crane) | tree ecosystem-service ledger | US Forest Service |
| **FLIR C3** + Planck extraction | thermal field validation of the shade model | handheld IR |
| Insta360 X3/X4 → COLMAP → Brush/Luma/Polycam | 360 capture → photogrammetry / Gaussian splat | SfM / 3DGS |
| **deck.gl / pannellum** | interactive 3D explorer + in-map 360 | web viz |
| Pandoc → Beamer/XeLaTeX; Cloudflare Pages | report + gated deployment | build/deploy |
| Claude Code + `agmsg`; deep-research skill | orchestration & research workflow | multi-agent |

*(Planned but not yet built — roadmap in §8: ComfyUI+ControlNet→Wan 2.1, Wallacei+Ladybug,
JuPedSim/NetLogo, Stable Diffusion XL/WeDesign, LLM personas.)*

---

## 3. Evidence pipelines mapped to the 8 AI-use areas  → answers **"contribution to decisions"**

For each area: *question → AI method → finding → design decision.* One panel each.

1. **Site & context analysis** — 50-yr Landsat timelapse + LST + demography. *Green flat
   for a decade while population +54%; park cool island only **+0.4 °C** (rank 9/14 in
   Dubai).* → redevelopment must *actively* add shade/canopy; the site's problem is public
   shade, not raw air temperature (benchmark: green ≠ LST cooling, R²=0.03).
2. **User & community analysis** — DDSE official stats + OSM POI + isochrones (*7,913
   residents; **159 households within 5 min of both park and a nursery***) **+ the complete
   Google-review corpus** (`reviews/`): 1,152 reviews 2013–2026 retrieved via Outscraper,
   446 texts close-read by LLM (incl. 32 Arabic) → **six evidence-anchored personas**
   (Playground Parent, Booked-Court Footballer, Quiet-Seeker, Morning Mover, Generational
   Local, Cat Steward), theme counts (kids 125 / family 82 / calm 63), **behavioural
   seasonality (Dec–Feb ≈ 3.5× Aug review volume, only 9/446 texts mention heat — summer
   demand is suppressed, not expressed → independently confirms the UTCI story)**, and the
   2026 1★ cluster (DM-app court bookings refused at the gate — governance, not space).
   → protect the enclosed watchable geometry; legible court-booking state at the gate;
   design for the summer absence. Full write-up `reviews/findings.md`/`.pdf`.
3. **Environmental analysis** — thermofeel UTCI (10 yr) + SOLWEIG + shade engine + CFD.
   *Peak UTCI **52.6 °C** open vs **48.0 °C** under canopy (−4.6 °C); extreme heat every
   summer, not exceptional.* → shade as the primary comfort lever; night = open sky +
   ventilation, not roofs.
4. **Ideation & alternative generation** — intervention matrix (6 scenarios) + expansion
   scenario. *Combined package (trees + retentive paving + mist + reflective roads)
   **−1.27 °C over 45% of the park**; parking→park adds **+28% shade**.* → the concept's
   quantified move-set.
5. **Design optimisation** — fountain-siting weighted overlay; shade-ABM β-sweep. *Best
   water-feature cell 0.90 suitability (NW, upwind/shaded); β=4 detour buys −19% sun time.*
   → sites the water feature; puts shade on the central desire line rather than rerouting.
6. **Sustainability & resilience** — i-Tree tree-benefit ledger; canopy preservation tiers.
   *In-park canopy stores **108 t CO₂**, sequesters **3.6 t/yr**; Tier-A 5 patches = 96% of
   services; cluster **#113 = 59% of in-park shade**.* → "protect #113" (≈15–20 new trees)
   as the cheapest green infrastructure.
7. **Circulation / UX simulation** — OSMnx walkshed + betweenness + heat-dose gates.
   *Porous edge: 5-min catchment **261→323 households (+24%)**; one corridor carries 293
   households; at 15:00 no cool route exists.* → 3 new openings + street-tree the 3 loaded
   corridors.
7b. **The analysis as a playable thing (added 2026-09-06)** — *Shade Run*, a small game on the
   Proposal 2 model whose only rule is the hourly shade model (fatigue in sun, recovery in
   shade, six appointments in the film's order). Two real days by one of us exposed a 130 m
   crossing with no cool line → the Ehsan station moved to the majlis in the model, and a
   walking-shade study along the loop → seven planting/canopy proposals (issue #16; loop
   shade 21 → 38% at 14:00 at drawn crown sizes). Draft paragraph + two figures:
   `report/shade_run_section.md`, `report/img/game/`. Game: `game/shade-run/`.
8. **Visualisation & communication** — deck.gl 3D explorer (Realistic/Analysis presets),
   in-map 360, findings site. → jury-facing artefacts; analysis shadows *numerically match*
   the model (same engine).

---

## 4. Methodological integrity — the differentiators (a full page)

These are what separate "we asked an AI" from "we ran a verified analysis." Foreground them.

- **Two-method cross-validation.** SOLWEIG open-air peak UTCI **52.6 °C** independently
  reproduces the ERA5-Land + thermofeel point calc **52.6 °C**; park-comparison PCI
  **+0.47 °C** reproduces the centre-ring PCI **+0.40 °C**. Independent methods, same answer.
- **Closed predict → field-verify loop (FLIR).** The shade/SOLWEIG model *predicted* the
  ranking (NE playground worst, SW canopy best) **before** the site visit; handheld FLIR
  then measured **10.5 °C sun–shade ΔT**. A sensitivity test (emissivity 0.90–0.98 ×
  reflected 0–40 °C) shifts absolutes by ≤±1.5 °C but the load-bearing contrast by **<±0.5 °C**
  → conclusion robust.
- **Cloud → field species check.** Satellite canopy blobs were grounded with **iNaturalist**
  observations — the critical tree #113 now carries real species names (Neem, *Cordia*,
  *Plumeria*).
- **Honest negatives retained (credibility asset, not weakness):**
  - Shade-ABM: cumulative heat-dose *does not drop* — the whole park is "extreme," so
    detours can't escape it → *add shade on straight lines instead.*
  - SOLWEIG structurally under-models mist → mist justified from wet-bulb-depression instead.
  - Recon photogrammetry is **parallax-limited** on a forward walk (held across every tool) →
    documented as a capture-geometry limit + orbit re-shoot plan.
  - High-albedo paving **worsens** pedestrian UTCI (+0.38 °C) → *rejected* for pedestrian space.

---

## 5. Alternatives considered & rejected  → answers **"alternatives considered"** directly

The deliverable explicitly asks for this; the repo already documents a rich rejection log.

| Considered | Rejected for | Chosen instead |
|---|---|---|
| deck.gl real-time sun shadows (`_SunLight`) | shadow-acne + picking bind errors; wouldn't match analysis | pre-computed shadow PNGs from the *same* shade engine |
| Space-syntax (angular) betweenness | low discrimination on a homogeneous villa grid | OD-weighted network betweenness |
| High-albedo (reflective) paving | model showed it *worsens* pedestrian UTCI | water-retentive paving for pedestrian zones |
| ETH global canopy height | misreads buildings as canopy in urban areas | Meta/WRI 1 m canopy |
| Local Gaussian-splat (COLMAP/Brush on M1) | parallax-limited walk; local build blocked | hosted Luma/Polycam + orbit re-shoot |
| "Fountain" read from the DXF | it's the **Tamtam café**, not a fountain (pano + Maps) | siting re-framed as *new* water feature |
| Online DWG converters | Schedule 6 IP risk | local LibreDWG conversion |

---

## 6. Limitations, caveats & ethics (half a page — put it *in*, don't hide it)

- **Climate transfer** is the single biggest caveat: borrowed cooling figures are methods,
  not guaranteed results here.
- Model limits already enumerated in the READMEs: ERA5-Land single ~9 km point; shade-UTCI
  MRT≈Ta (optimistic); opaque tree crowns (over-count); 97.5% default building heights;
  FLIR shot positions ±10 m; LST = morning surface snapshot ≠ afternoon comfort.
- **Generative-AI IP/originality risk** (Schedule 6) and **LLM-persona bias** (flagged in the
  tech scan) — state the guardrails: geometry-conditioned generation only ("AI constrained
  by our own simulation"), personas as pilot/complement to a real accessibility method.

---

## 6.5 The design model itself — from CAD to a correctable 3D twin

*Inserted after §6 rather than renumbered, to keep the §7.x references below stable.
Condensed from `report/sections/proposal2_3d_pipeline.md` (2,573 words), which stays in
the repo as the long form. §7 depends on this section: the geometry that constrains the
generative work is the geometry built here.*

Proposal 2 starts from one authored artefact — Jiin's AutoCAD drawing — and everything
downstream is a projection of it rather than a second model that could drift.

**Two extraction routes, and the one that won.** `extract_dwg.py` walks the raw DWG object
graph via LibreDWG. The file fights back: 284,664 raw LINE entities, 127,818 of them under
5 cm, behind 385 self-intersecting hatch boundaries. AutoCAD's own **vector PDF export**
turned out to be the better source, because it has already resolved every hatch into filled
paths, so the boundaries that break the DWG reader never arise. `extract_pdf.py` reads
41,520 paths across the 20 layers AutoCAD preserves as PDF optional-content groups and fits
them into the DWG's metre frame, giving a **median alignment residual of 0.05 m** and a
fitted scale agreeing to **0.1%** with the scale derived independently from the multi-sport
court's known 41.2 m side.

That route also retired a false alarm worth recording, because it is the kind of error that
survives if nobody re-measures: bounding boxes built from the *broken* rings put the drawn
park at ~253 × 148 m against a surveyed ~165 × 92 m, a 1.5× mismatch that looked like a
drawing error and was reported as one. Filtering to non-self-intersecting rings gave
159.8 × 68.1 m for the same layers. **The inflation was an artefact of our own reader, not
the drawing.** The retraction is recorded in `proposal_2/README.md`, alongside the reader
traps this section deliberately does not repeat — scanline strip decomposition, even-odd
fill by ring nesting, the first-ring-only bug (fixed 13 Aug, recurred 15 Aug), arc
direction, and the ACI colour table.

**Missing elevations, made legible instead of silently guessed.** The DWG carries no
elevation data, so every wall, roof, sail rim and kerb in the 3D model is a height somebody
decided on — and until that decision is visible it is indistinguishable from fact. Every
value lives in one place (`HEIGHTS` in `build_scene.py`), and `HEIGHTS_SCHEDULE.md`
restates each with its basis and a confidence label (confirmed / med / low).

A table alone does not close the loop, because a spreadsheet is a poor way to judge whether
a sail rim at 5.7 m actually clears a slide. `height_review.py` reads the built GLB and
renders, per geometry group, a two-panel card: plan location beside an elevation silhouette
with the assumed height called out. Those became an annotatable 21-page PDF so Jiin could
mark it up by hand. She did, the same afternoon:

| Element | Before | After |
|---|---|---|
| Court & perimeter wall | 2.5 m assumed | **2.0 m confirmed** |
| Perforated metal canopy | 4.0 m slab | 4.0 m, reclassified to 4–6 mm laser-cut plate |
| Fixed benches | 0.44 m seat | 0.44 m seat + **0.78 m backrest** |
| Mushroom fountains | assumed family | **3.5 / 3.0 / 2.5 m** |
| Splash-shelter bench | 0.40 m | 0.42 m |

**First review card to a deployed, corrected 3D model: under an hour, on the same visit.**
Two properties matter more than the speed. The sheet asked Jiin to *check* rather than
assume whether the sail canopies clear the slide and the obstacle wall; her answer — the
tree house clears, but the slide and obstacle wall were not yet modelled and so could not
be checked — is recorded as an **open item rather than papered over**. And
`HEIGHTS_SCHEDULE.md` states explicitly that tree heights at maturity drive the shade and
UTCI analysis elsewhere in this report, so if those numbers move the environmental claims
move with them. The discipline is not manufactured certainty; it is **uncertainty made
legible and cheap to correct**.

**One source, three outputs.** `build_scene.py` builds one in-memory model, and each output
is a projection of it: the **web viewer** (three.js, design-day sun slider, per-CAD-layer
solo, fifteen named fly-to viewpoints); the **Blender scenes** (headless rebuild of the same
GLB, per-layer PBR keyed to the DWG's own colours, the same NOAA solar maths as the viewer,
plus a 12-second day/night loop across 122 real lights); and the **IFC4 export**, which
imports `build_scene.py` as a module so it cannot diverge, emitting 56 elements each
carrying an `AlSafa2` property set recording its source CAD layer and its height basis
("assumed, see HEIGHTS_SCHEDULE.md"). **The uncertainty travels with the geometry into any
BIM tool that opens the file.** That export replaced a planned manual remodel in Revit for
the handoff — a second independent redrawing that could have disagreed with the CAD for no
reason.

**Manufacturer equipment, including the failure case.** Three pieces of catalogue equipment
arrived as manufacturer 3D DWGs, none with usable brep data. The **MUGA fence** kept real
2D placement — INSERT entities tracing the actual court perimeter at z = 0/1000/2000 mm,
confirming a 3 m fence — so it was built on that real perimeter rather than a guessed box.
The **sensory dome**'s structural detail layers carried ~115,000 real 3D coordinates, giving
a measured 8.1 m diameter and 4.0 m height. The **outdoor gym** is the honest failure:
its DWG fails LibreDWG's section decompression outright, so rather than fabricate a
plausible gym, `build_gym.py` states in its header "SOURCE FILE UNREADABLE, ask Jiin to
re-export as R2013/R2000", the massing is catalogue-based at a generic 2.4 m from Jiin's own
reference photo, and `HEIGHTS_SCHEDULE.md` flags it "low" so nobody downstream mistakes it
for measured geometry.

**What this pipeline does and does not feed.** Its output is the geometry the generative
stage is constrained by — and the record should be precise about how far that has actually
been carried. The **stills** pipeline conditions on proposal-2 passes (measured 2026-08-08,
`anim/tools/README.md`). The **film** clips to date were all captured from **proposal 1**
(`capture_orbit.js` defaults to `proposal_1/view_proposal.html`); re-capture against the
corrected proposal-2 model is pending, and §7.6 states the division of labour that governs
both. Massing, position, count and dimension come from here; surface finish — rope-net
texture, perforation detail, photoreal materials — is delegated downstream.

*Artefacts: `proposal_2/` — `extract_dwg.py`, `extract_pdf.py`, `build_scene.py`,
`HEIGHTS_SCHEDULE.md`, `height_review.py`, `export_ifc.py`, `blender_scene.py`,
`day_night_cycle.py`, `view_proposal.html`, `equipment/`. Commits `6bc7ecc`, `0cf5d2c`,
`fddfd2c`/`2208830`/`b764445`/`b1483eb` (the 15 Aug review loop, 11:00–11:55), `bb41acf`,
`00243d5`. Long form: `report/sections/proposal2_3d_pipeline.md`.*

---

## 7. Visualisation — constraining generative AI with our own simulation  → the mandatory 1-min film

*The strongest story here is not "we used AI video". It is a documented search for a way to
be photoreal **without fabricating**, in which each failure narrowed the answer. Written up
as a method, this is a contribution in itself.*

### 7.0 The requirement, stated so it can be tested

Deliverable ⑧ requires a 1-minute film. Generative models invent plausible parks. Our film
sits beside measured claims — 554 m loop, 34→43% noon shade, +24% walkshed — so any frame
contradicting them discredits the analysis that produced them. Requirement:
**photorealism that cannot alter geometry.**

### 7.1 Baseline — deterministic, no AI at all

`anim/slideshow/` — real GLBs, real NOAA design-day sun (2025-08-01), scripted cameras,
frozen animation clocks, captured headlessly. Proves the narrative works before any
generation, and remains the fallback. **Data callouts and before/after wipes stay here
permanently** — a claim is never generated.

### 7.2 Attempt 1 — ask in words (instruction-edit models)

`anim/prototypes/p1`–`p4`. Models: FLUX.1 Kontext, nano-banana, Qwen-Image-Edit.

- **Failed.** Layout drifted; a palm avenue appeared that the design does not contain.
- **Publishable finding:** a ~200-word engineered constraint prompt performed *worse* than
  the words "make it realistic" on the same model. Constraint language degrades the image
  without holding geometry.
- **Diagnosis:** these APIs expose no conditioning input and no strength parameter. Fidelity
  was never controllable, only requestable.

### 7.3 Attempt 2 — supply the geometry (ControlNet-conditioned diffusion)

`anim/tools/passes.js`, `make_lineart.py`, `make_comfy_workflow.py`; RealVisXL + ControlNet
Union, run locally in ComfyUI.

- **The key methodological move:** conditioning images are *rendered from our own 3D scene* —
  depth, surface normals and line art — not estimated from a picture by a monocular depth
  model. Our depth map is a measurement; an estimated one is a guess. This is the difference
  the whole claim rests on.
- **Worked:** tree positions and counts preserved, where prompt-only methods had deleted
  ~75% of crowns.
- **Failed, instructively:** empty margins caused invented context (a beige void, then sand
  dunes when cropped tighter); sports courts rendered as swimming pools; and a single colour
  word in a corrective clause ("the **blue** rectangles are courts") bled across the frame
  and turned every tree crown blue.
- **Also measured:** on 16 GB unified memory throughput collapsed ~10x across successive runs
  (3 → 30 s/iteration) and recovered only on restart — viable for finals, not for iteration.

### 7.4 Attempt 3 — condition on motion (video-reference models)

`anim/tools/capture_orbit.js`, `anim/prototypes/p6`/`p7`; Seedance 2.5 via fal.

- Camera paths are **rendered from our own scene** (eased spline through waypoints that reuse
  the slideshow's own shot poses), so the camera move is ours rather than invented.
- **Worked:** geometry held through a 16 s continuous flythrough *including a large scale
  change* (135 m → 45 m altitude).
- **Findings:**
  - A style reference image **overrides** structural conditioning at 4 s, but much less at
    16 s. A moving camera gives the model parallax to infer real structure from — so
    **short tests actively mislead**, and look-dev must be judged at production duration.
  - A video reference constrains **motion** as well as geometry: our viewer's oscillating
    figures were faithfully reproduced as mechanical crowds until we removed them.

### 7.5 Which model, and what it costs

Five video models were tested on an identical conditioning clip and prompt, so the only
variable is the model. Rates below are **measured from account balances, not quoted** —
published prices proved wrong every time we checked them.

| Model | Conditioning it accepts | Layout | Paths | Descent | Measured rate | 60 s film |
|---|---|---|---|---|---|---|
| **MiniMax H3** | video + image references | ✅ | ✅ | ✅ | $0.16/s @768P · $0.259/s @2K | ~$10–16 |
| **Seedance 2.5** | video + image references | ✅ | ✅ | ✅ | $0.254/s @480p · ~$0.47/s @720p | ~$15–33 |
| Wan VACE 14B | depth / pose control video | ✅ | ❌ | ❌ | $0.04/s | ~$2.40 |
| Wan 2.2 | video (loose) | ❌ | ❌ | — | $0.04/s | ~$2.40 |
| Grok Imagine | video edit | partial | — | — | $0.47/s | ~$28 |

**Resolution and duration ceilings**, which constrain the deliverable independently of
quality. A competition film wants the highest resolution available, and a *continuous*
camera move is limited by the per-generation duration cap:

| Model | Resolution range | Max per generation | Reference-clip limit |
|---|---|---|---|
| **MiniMax H3** | 768P → **4K** (768P / 2K / 4K) | 15 s | 15 s total across refs |
| **Seedance 2.5** | 480p → **720p** | **30 s** | 1.8–30.2 s per clip |
| Wan VACE 14B | 240p → 720p | 241 frames (≈15 s @16 fps) | — |
| Wan 2.2 | 480p → 720p | ~5 s observed | — |
| Grok Imagine | output matches the input clip (1024×768 observed) | 15 s | **8.7 s input** |

The two survivors trade against each other: **H3 reaches 4K but caps at 15 s**, so a
60 s film is four takes; **Seedance caps at 720p but generates 30 s**, so the same film
is two takes with fewer joins. For a beat-based cut the duration cap is irrelevant and
resolution wins; for a single continuous flythrough the reverse.

**Three findings worth stating as method, not as shopping notes.**

**a. Depth is necessary but not sufficient for landscape.** VACE followed our depth video
faithfully — tree positions, sail clusters, site outline — and still produced a park with
**no path network**, because paths are coplanar with the grass: same distance, same grey.
Depth describes *buildings*; a park is described by its *surfaces*. Our stills pipeline had
already encoded this by weighting line art 0.9 against depth 0.6; VACE demonstrated what
happens when only the 0.6 can be supplied. This is why a full beauty render — carrying
height, surface change, colour and material boundary at once — outperforms a single
geometric channel.

**b. A style reference is treated as content, not as a look — in every model tested.**
Adding a photoreal reference still improved realism and imported a football pitch and a
canopy density the design does not have, on **both** Seedance and H3, despite an explicit
instruction not to copy anything absent from the video reference. Two vendors, same
failure: this is a property of the technique, not of a product. Prompt-level constraints
do not govern reference conditioning.

**c. Published prices are unreliable.** Grok Imagine was quoted at $0.05/s and billed
$0.47/s (9x). MiniMax H3 was quoted $0.08/s and $0.13/s and billed exactly 2x both. Every
figure in this report is measured from account balance deltas.

**What we chose, and when we stopped looking.** MiniMax H3 at 768P — $0.16/s measured,
about **$9.60 for a 60 s film** — as the cheapest option that holds layout, paths, the
descent and people. 2K is reserved for hero shots at $0.259/s; 4K exists (≈$0.32/s
extrapolated) but was judged unnecessary.

Two further candidates were priced and **not** tested: Wan 2.6 and 2.7 reference-to-video,
published at $0.10/s for 720p — which, at the 2x published-to-measured multiplier observed
throughout, would land near $0.20/s and therefore *above* H3 at 768P.

The search was stopped deliberately at that point, and the reasoning is worth recording
because it is a project-management judgement rather than a technical one: model shopping
had cost ~$5, a further test costs $2–4, and the maximum remaining saving on a single film
was ~$5. Expected return had fallen to roughly zero while the submission deadline stayed
fixed. **The cost of finding a cheaper tool exceeded the cost of the tool.**

Incidentally, image references are billed at zero on both surviving models — only the video
reference is charged. So the fidelity-versus-beauty choice in §7.6 is never a budget
question; both options cost the same.

**Self-hosting was tested, not just costed.** A rented L40S (RunPod, $1.02/hr) ran LTX-2.3
with its Union depth+edge IC-LoRA — see `anim/tools/RUNPOD_LTX.md` for the runbook. It
confirmed the economics (first generation 142 s cold, then **36–45 s**, about **$0.01 per
clip** against $2.40 on the API — a four-point parameter sweep costs pennies) and rejected
the quality: structurally faithful but stylised, visibly below MiniMax H3.

It also produced the clearest statement of the depth finding. Feeding our *rendered* depth
video through the correct IC-LoRA architecture placed every object correctly and then
rendered tree crowns as **teal umbrella shapes**, with the entire ground as uniform paving
and no path network. Feeding the **beauty render** through the identical graph kept layout,
surfaces and paths. **Depth places objects; it cannot describe them, and it cannot see
changes between coplanar surfaces.** Confirmed across Wan VACE, LTX IC-LoRA, the stills
pipeline's empirical 0.9/0.6 lineart-to-depth weighting, and both surviving video models
performing best on a full beauty render.

**Self-hosting the chosen model was then tested too, and failed in an instructive way.**
H3's Community Licence excludes the US, EU, UK and South Korea from local deployment, so
the pod was taken in RunPod's **AP-IN-1** (India). An earlier note in this report said H3
needed four GPUs; that figure comes from MiniMax's own model card (`--num-gpus 4`) and is
true of the reference implementation, but the ComfyUI-packaged quantised weights run on
**one** H100 80 GB — 52.3 GB resident. The economics worked: **425–458 s per 5 s clip at
$3.29/hr = $0.39–0.42 a clip**, against ~$2.40 on fal.

The output did not. Across five runs — varying the prompt tagging, the sampler chain and
the text encoder — the model produced beautiful, photoreal, prompt-faithful Dubai parks,
none of which were ours, while *the same model through fal* reproduces our site outline,
loop path, tennis court and villa grid almost exactly. The runbook is
`anim/tools/RUNPOD_H3.md`; the node graphs, timings and status of all seven executions are
preserved in `anim/tools/h3_evidence/`.

The diagnostic run is the one that half-worked. Anchoring the generation on the first
frame of our render (`MiniMaxH3ImageToVideo`) produced **our park at frame 0** and a
different park by four seconds. So our geometry reaches the model and is legible to it;
what fails is specifically the reference-conditioning path. That yields a finding worth
more than the saving it was chasing:

> **A hosted endpoint is not merely the same open weights with a bill attached.** The
> serving stack — quantisation, the reference pipeline, conditioning we cannot inspect from
> outside — is part of the product. Open weights do not make a capability reproducible.

The claim is deliberately bounded. Two branches were not eliminated: the **bf16 encoder**
(~64 GB, which will not fit beside the 34 GB DiT on one 80 GB card), and the **optimized
CUDA kernels** — the stock template ships torch cu128 while ComfyUI wants cu130, so it
falls back to the `eager` backend. The defensible statement is *not reproducible on a
single H100 with the quantised weights and the stock template*, not *impossible*.

**What this costs the project is iteration, not quality.** fal already produces a
verified-correct result, so the film is unaffected; what we do not get is the cheap sweep.
The workflow therefore stays as designed — iterate the camera in the three.js viewer for
free, and spend a generation only on a take already committed to.

### 7.6 The decision framework — what may be generated, and where

Shot type is mapped to method by whether it carries a measurable claim:

- **Aerials** carry the loop length, shade percentages and walkshed → geometry-locked.
- **Eye-level vignettes** show experience and assert no number → freer treatment permitted.
- **People are generated deliberately.** The film makes no claim about people, so the built
  design is locked and the crowd is not. Stating this rule explicitly is what makes the
  freedom defensible rather than convenient.

The same boundary runs the other way, into the 3D pipeline of §6.5, and it is drawn at what
a CAD drawing and a manufacturer's coordinates can actually answer. **Locked, because it
comes from the drawing or from real placement data:** massing, position, count, dimension,
CAD-layer colour — sail footprints, tree crown positions, court dimensions, fixture heights.
**Delegated, because no source file contains it:** surface finish — the rope-net texture
inside the sensory dome, perforation detail on the metal canopy, photoreal materials and
vegetation. The generative stage is free to invent plausible surface detail precisely
because it is never asked to invent a position, a count or a dimension.

### 7.7 Fabrication register — every invention we caught

| Fabrication | Cause | Fix |
|---|---|---|
| Palm avenue | prompt named palms while forbidding them | prompt rewritten; clause removed |
| ~75% of tree crowns deleted | no structural conditioning, default strength | ControlNet lineart at 0.9 |
| Desert / beige void background | control image had empty margins | condition on a clip that contains context |
| Sports courts → swimming pools | model misread a flat blue rectangle | two short corrective nouns |
| Every tree crown blue | the word "blue" in a corrective clause bled | describe by object and material, never colour |
| Football pitch imported | came from a style reference image | verify references against the design |
| Canopy density inflated | style reference showed a denser park | check frames against `before_after.csv` |

**This table is the section that proves the discipline is real rather than asserted.** Most
entrants will show their best frames; almost none will show what their tools got wrong and
how they caught it.

### 7.8 Reproducibility and cost

Scripts, commit hashes, exact model endpoints and measured per-second costs. Measured rather
than published rates: $0.254/s at 480p video-referenced, $0.47/s at 720p stills-to-video;
a 60 s film is ~$15 at draft resolution, ~$33 at 720p.

Self-hosting is recorded to the same standard, so that a negative result is auditable rather
than merely asserted. `anim/tools/RUNPOD_H3.md` and `anim/tools/RUNPOD_LTX.md` carry the pod
specifications, model files and sizes, the working node graphs and every trap that cost time;
`anim/tools/h3_evidence/` holds the ComfyUI run history — the complete node graph, prompt,
timing and status of all seven H3 executions — with the server log and hardware stats. Each
failed run in §7.5 can therefore be re-created exactly, which is the only way a reader can
check that the failure was the model's and not the operator's.

### 7.9 Figures and reference media

| Asset | Path / link |
|---|---|
| **Sketch → CAD → 3D → photoreal chain** | `report/img/anim_pipeline_chain.png` |
| **Low-poly cast, six of fifteen groups** (`proposal_1/characters_spec.md`) | `report/img/anim_characters_strip.png` |
| **"Asking in words failed" evidence** | `report/img/anim_words_failed.png` |
| **Seedance vs MiniMax H3, ± style reference** | `report/img/anim_seedance_vs_h3.png` · [video](https://youtu.be/tcXk7SdsRxA) |
| **Hosted vs self-hosted H3 — the same model, two results** | `report/img/anim_h3_selfhosted.png` |
| Conditioning-pass set (beauty / depth / normal / line art) | `report/img/anim_conditioning_passes.png` |
| A/B/C comparison grid, source + three strategies | `report/img/anim_abc_comparison.png` |
| Fabrication evidence — colour-word bleed turning crowns blue | `report/img/anim_fabrication_colour_bleed.png` |
| **Final comparison video** | [youtube.com/watch?v=ySVBk1CodjE](https://www.youtube.com/watch?v=ySVBk1CodjE) |
| Photoreal reference stills used for options B and C | `anim/refs/` (7 beats, 1536x1024) |
| Deterministic baseline film | `anim/slideshow/index.html` |
| **Drawn sheet — line art in, painted sheet out** (§7.10) | `report/img/sketch_board_output.png` |
| **"A line or a blank" — the cafe as building vs pond** | `report/img/sketch_line_or_blank.png` |
| **Prompt trade-off — trees fixed, plan loosened** | `report/img/sketch_prompt_tradeoff.png` |
| Line Art input handed to the model | `report/img/sketch_lineart_input.png` |
| Style references (found photo, and model-generated) | `anim/refs/sketch_style.png`, `anim/refs/sketch_style_gpt.png` |
| Rendered camera paths (video references) | `anim/tools/out/orbit/` — regenerate with `capture_orbit.js` |
| Generated takes (A / B / C, 4 s and 16 s) | `anim/prototypes/out/` — gitignored, regenerable |

**The conditioning set** — rendered from our own scene, not estimated from a picture. Depth
follows the near-is-white convention; line art is a Sobel over surface normals rather than an
edge detector on the render, so a cast shadow can never masquerade as geometry.

**The chain, in four steps.** Nothing downstream may invent geometry absent upstream. Step 2 is
Jiin's proposal-2 DWG while 1, 3 and 4 are proposal 1 — proposal 1 went from sketch to 3D by
homography with no intermediate CAD file — so this shows the *stages*, not one artifact lineage.

![Hand sketch, CAD drawing, low-poly 3D model, photoreal AI frame](img/anim_pipeline_chain.png)

**The cast**, specified in writing before being modelled (`proposal_1/characters_spec.md`):
fifteen named groups, each with an anchor coordinate and a narrative reason to exist. Logged as
illustrative characters, not simulated users, and excluded from every before/after statistic.

![Six low-poly character groups](img/anim_characters_strip.png)

**Asking in words failed** — the same source through instruction-edit models with progressively
more explicit constraints, none of which held the geometry.

![Instruction-edit comparison showing layout drift](img/anim_words_failed.png)

**The two survivors**, same conditioning and prompt, each with and without a style reference.
Down a column is the model; across a row is what a style reference does — the same thing to both.
[Watch the comparison](https://youtu.be/tcXk7SdsRxA).

![Seedance 2.5 versus MiniMax H3, with and without style reference](img/anim_seedance_vs_h3.png)

**Hosted versus self-hosted**, the same MiniMax H3 weights and the same conditioning clip.
Top right is the hosted endpoint. Bottom row is one self-hosted run at two moments: anchored
on the first frame of our render it begins as our park and is a different park four seconds
later. That gradient is the evidence — our geometry reaches the model and is legible to it,
so what fails is the reference-conditioning path, not the setup.

![Hosted H3 holds the park; self-hosted H3 starts correct and drifts](img/anim_h3_selfhosted.png)

![Conditioning passes: beauty render, depth map, surface normals, line art](img/anim_conditioning_passes.png)

**The comparison** — same sixteen seconds, same camera, four treatments. Source, our clip
alone, our clip plus a style reference, and stills animated with no 3D input.
[Watch the video](https://www.youtube.com/watch?v=ySVBk1CodjE).

![A/B/C comparison grid](img/anim_abc_comparison.png)

**Fabrication evidence** — naming a colour in a corrective instruction ("the *blue* rectangles
are sports courts") bled that word across the whole frame and turned every tree crown into a
blue sphere. Kept rather than discarded: the geometry survived, the palette did not.

![Colour-word bleed turning every tree crown blue](img/anim_fabrication_colour_bleed.png)

⚠ Generated video and conditioning images live in gitignored `out/` directories because they
are large and reproducible from the scripts. Anything the report cites has been copied into
`report/img/` so the deliverable is self-contained.

⚠ **Provenance gap:** the photoreal reference stills in `anim/refs/` were generated with
ChatGPT, but the prompt and input images are not recorded. For options B and C that is the
provenance chain the report is scored on — capture it before submission.

### 7.10 Attempt 4 — the drawn sheet, and why a non-photoreal target behaves differently

Tested 2026-08-26. §7.2–7.4 all chased photorealism. A hand-drawn presentation sheet is a
different target and fails differently: a medium that is *supposed* to wobble tolerates the
drift that made a photoreal restyle unusable. That does not make the geometry problem go
away — it changes which errors are visible.

**The chain, three stages, each auditable.**

| Stage | What it does | Script |
|---|---|---|
| 1. geometry → line drawing | Grease Pencil Line Art over the built scene: real strokes traced from our own model | `proposal_2/sketch_lineart.py` (Blender 3.5.1, headless) |
| 2. drawing → medium | the line drawing plus a style reference; the prompt permits a change of medium and nothing else | `anim/prototypes/p14_sketch_fal.py` → `fal-ai/nano-banana/edit` |
| 3. the moving transition | stage 2 is **not** used: per-frame invention flickers. A deterministic screen-space pass in the viewer instead, edges read from the depth buffer | `proposal_2/view_proposal.html` → `__viz.sketch()` |

Stage 3 is the same separation §7.6 draws between what may be generated and what may not,
applied to time rather than to space: the still can be painted by a model because a reader
compares it against the plan; the moving sequence cannot, because 172 independently invented
frames do not describe one park.

**Findings.**

- **Where the model is given a line it draws the thing; where it is given a blank it invents
  one.** One variable — whether `0_Building` was included in the line art — decided whether the
  cafe came back as a building or as a pond. This is §7.3's result restated for a non-photoreal
  target, and it is the clearest single argument for supplying geometry rather than requesting
  fidelity.
- **The looseness dial is global, not per-element.** Our tree canopies are low-poly spheres, so
  a strict prompt faithfully reproduces lollipops. Releasing the tree *silhouette* fixed the
  trees and simultaneously turned the paved palm court into water; naming the surfaces fixed the
  court and drifted the palm block off the site line. Four runs, each trading one error for
  another. There is no prompt in which the planting is free and the plan is pinned.
- **Two of the qualities we wanted were missing geometry, not missing words.** A branch armature
  under a canopy cannot be traced from a trunk cylinder and a ball, and the pencil under-drawing
  the reference has is `Road context (RTA, 2D)` and `0_Boundary_Road` — geometry we own and
  currently exclude from the line filter. Both are supply problems wearing a prompt problem's
  clothes.
- **The line filter is itself a result.** Line Art over the whole scene returns stripes rather
  than a park, because the fills are PDF hatch strips: thousands of coplanar quads, each with its
  own boundary. The rule that works is geometric rather than a hand-list — **lines where an
  object stands ≥ 0.3 m, wash below that** — and it survives a layer rename. `0_Building`
  defeats even that, because its roof is ~90 *extruded* strips whose walls are real vertical
  faces; face marks cannot exclude them, since the faces are not a lie. That is a model defect
  the screen-space pass had been hiding, as depth cannot see a seam between coplanar strips.
- **A model-generated style reference outperformed the human one, and did not leak its own
  errors.** Substituting a ChatGPT drawing of our park for the original hand-drawn photograph
  gave stronger trees, a visible under-drawing and scale figures — while keeping our decking
  where the reference itself had drawn grey paving.

**Provenance — what comes from where.** The plan never comes from a model. Stage 1 reads the
CAD-derived GLB; stage 2 receives that plan *as an image* and is instructed to change only the
medium. The style reference supplies medium, not content, which the decking result above is
direct evidence for.

⚠ **Provenance gap, the same one flagged for `anim/refs/`:** `anim/refs/sketch_style_gpt.png`
was produced in ChatGPT on 2026-08-26 from our own Line Art render, but its prompt was not
recorded. Capture it before submission, or fall back to `anim/refs/sketch_style.png`, whose role
as a found photograph needs no prompt.

**Reproducibility.** `--seed` and `--aspect` are supported — established from the endpoint's own
rejection payload rather than from documentation, which does not list them. Without a seed a
re-run is a different drawing; with one the board image is regenerable. Cost is a few cents per
image against §7.5's $0.13–0.47 per video second, so the still route is roughly two orders of
magnitude cheaper than restyling the film — read the exact per-call charges off the fal dashboard
before submission rather than quoting a published rate.

**To re-run once the design is materialised**, from `proposal_2/`:

```sh
# 1. rebuild the scene from the current GLB, then the line drawing
/Applications/Blender.app/Contents/MacOS/Blender -b --python blender_scene.py
/Applications/Blender.app/Contents/MacOS/Blender -b alsafa2_proposal2.blend \
    --python sketch_lineart.py -- --view aerial --thick 3 --expose 0.15
# 2. paint it, reproducibly
cd ../anim/prototypes && export FAL_KEY=...
python p14_sketch_fal.py --image ../../proposal_2/renders/sketch_aerial.png \
    --ref ../refs/sketch_style_gpt.png --foliage --materials --board \
    --seed 7 --aspect 16:9 --out out/board.png
```

`--view` also takes `oblique`, `top` and `cafe`; `--minh` moves the line/wash threshold and
`--skip` drops a named layer to wash only. Every prompt clause is a flag, so any published image
states the prompt that made it.

**Still open:** the branch armature. It is the one improvement that would raise both the drawing
and the model — the Blender renders, the viewer and the IFC all read the same tree — and no
prompt can substitute for it.

![Line art in, painted sheet out](img/sketch_board_output.png)

![Cafe outlined versus left blank](img/sketch_line_or_blank.png)

![Three prompts, three trade-offs](img/sketch_prompt_tradeoff.png)

---

## Glossary — terms used above

- **ComfyUI** — open-source node-graph front end for running diffusion models locally; a
  workflow is a saved graph, which doubles as auditable evidence of how an image was made.
  ([comfy.org](https://www.comfy.org/), [source](https://github.com/comfyanonymous/ComfyUI))
- **Stable Diffusion XL (SDXL)** — the open image-generation model family we run locally.
  ([paper](https://arxiv.org/abs/2307.01952))
- **RealVisXL** — a photorealism-tuned SDXL checkpoint; the checkpoint used by the
  peer-reviewed landscape pipeline we follow.
  ([model](https://huggingface.co/SG161222/RealVisXL_V5.0))
- **ControlNet** — an attachment that conditions a diffusion model on a *control image*
  (depth map, line art, edges) so output geometry follows that image instead of the prompt.
  ([Zhang et al. 2023](https://arxiv.org/abs/2302.05543))
- **ControlNet Union** — one model supporting several control types (depth, line art, …),
  chosen to halve memory use on a 16 GB machine.
  ([model](https://huggingface.co/xinsir/controlnet-union-sdxl-1.0))
- **Depth pass / normal pass / line art** — images encoding distance-from-camera, surface
  orientation and geometric edges. Ours are rendered from our 3D scene, so they are exact;
  the alternative is estimating them from a photo, which reintroduces a guess. Near-is-white
  depth follows the MiDaS convention. ([MiDaS](https://arxiv.org/abs/1907.01341))
- **img2img / denoise strength** — starting generation from an existing image; the denoise
  value sets how far it may depart from it. The structural dial the instruction-edit models
  never exposed.
- **Instruction-edit models** — image editors driven purely by an instruction, with no
  conditioning input: FLUX.1 Kontext, [nano-banana](https://fal.ai/models/fal-ai/nano-banana/edit),
  Qwen-Image-Edit.
- **Seedance 2.5** — ByteDance video model (released 2026-07-31) generating up to 30 s in one
  take and accepting image, video and audio references.
  ([announcement](https://seed.bytedance.com/en/blog/one-take-creation-flexible-referencing-introducing-seedance-2-5),
  [API](https://fal.ai/models/bytedance/seedance-2.5/reference-to-video))
- **Video reference** — a clip supplied alongside the prompt that the model follows for
  layout and camera movement. Ours is rendered from our own scene.
- **fal** — the hosted-inference provider used to run these models.
  ([fal.ai](https://fal.ai/))
- **three.js** — the WebGL library behind our browser viewers, from which every conditioning
  image and camera path is rendered. ([threejs.org](https://threejs.org/))
- **GLB** — the 3D model file exported from Jiin's DWG and used by the viewers.

---

## 8. Roadmap — planned AI for the still-open areas (from `research/tech_scan.md`)

Frame as "process continues into ideation/visualisation," with citable precedents:

- **① 1-min animation (mandatory):** **no longer roadmap — built, and the model chosen; see
  §7.** ControlNet-conditioned stills plus video-reference takes, both seeded by our own
  geometry. The model is **MiniMax H3 via fal** (§7.5); Seedance 2.5 is the validated
  fallback, and Wan was tested and rejected — do not reintroduce it here as a candidate.
  Remaining work is production, not method.
- **④ generative ideation:** Wallacei + Ladybug with **UTCI (already computed) as the GA
  fitness objective** — turns analysis into a design driver (Cairo hot-arid precedent).
- **⑤/⑦ movement:** JuPedSim → PedPy or NetLogo shade-seeking ABM over the SOLWEIG grid.
- **② community & PoD:** personas **no longer roadmap — built from the 1,152-review corpus
  (see §3.2)**. Remaining: synthetic persona portraits (privacy-preserving; demographics from
  the real avatar corpus), WeDesign-style co-design against the personas, VR accessibility
  walkthrough (with the bias caveat).
- **⑥ circular:** i-Tree Eco + Climate Positive Design Pathfinder for embodied-carbon scoring.

---

## Gaps to close before submission

1. **User & Community Analysis (area 2): largely closed** — six review-grounded personas,
   behavioural seasonality, and complaint clusters now exist (`reviews/findings.md`).
   Remaining: a direct resident channel (the Municipality's own "Your park, your vision" QR
   consultation is live in the park — two reviewers photographed it; a small on-site survey
   would close the loop) and synthetic persona portraits for the public deliverable.
2. **The mandatory 1-min animation (area 8)** — method established and validated (§7);
   remaining work is the production run and the A/B/C direction decision by the team.
   Two prerequisites sit in front of the production run:
   - **Re-capture the conditioning clips on the corrected geometry.** Every film clip to
     date came from proposal 1 (`capture_orbit.js` defaults to
     `proposal_1/view_proposal.html`); the proposal-2 model now carries Jiin's reviewed
     heights (`b764445`). The viewer cache was bumped in the same loop (`b1483eb`), so a
     stale cache would silently produce clips of the superseded model — verify the served
     model before capturing, not after.
   - **Close the `anim/refs/` provenance gap** (see the ⚠ note in §7.9). It is the one link
     in the visual chain that cannot currently be shown, and it seeded options B and C.
3. **Design optimisation (area 5)** currently = siting + ABM; the generative alternative-
   generation loop (Wallacei) is still roadmap, not evidence.
4. **Second FLIR visit** (peak 14–16h + night 21:30) to validate heat-storage — model
   currently predicts ±0 at night, contradicted by dusk paving 39–46 °C.

---

## Changelog

- **2026-08-14** — Closed the area-2 gap with the review-corpus analysis (`reviews/`): all
  1,152 Google reviews of the park retrieved (place ID decoded from the share link's feature
  ID; Outscraper export), 446 texts close-read → six personas, theme counts, behavioural
  seasonality (winter ≈3.5× August, 9/446 mention heat → suppressed demand independently
  confirms the UTCI story), and the 2026 court-booking complaint cluster. HTML report updated:
  area-2 card rewritten (chip removed), new "Community voice" subsection with four figures,
  Outscraper row in data sources, three new decision-table rows, review-bias caveat in Limits,
  roadmap ② personas marked built, gap card downgraded. Privacy line: reviewer names/faces
  stay in the internal `reviews/findings.md` only; deliverables get synthetic portraits.
  One review caught being openly AI-generated — kept as a methodological exhibit.
- **2026-08-13** — Self-hosted the *chosen* model and failed, usefully. MiniMax H3 runs on a
  single H100 (52.3 GB resident) at **$0.39–0.42 a clip** against ~$2.40 on fal, but across
  five runs it would not hold our geometry, while the same model through fal does. Corrects
  an earlier claim in this report that H3 needs four GPUs — that is MiniMax's reference
  implementation, not the ComfyUI-packaged quantised weights. The first-frame-anchored run
  localises the fault to the reference-conditioning path, giving the finding that **a hosted
  endpoint is not the same open weights with a bill attached — the serving stack is part of
  the product**. Bounded honestly: two branches (bf16 encoder, cu130 kernels) were not
  eliminated. Runbook `anim/tools/RUNPOD_H3.md`, evidence `anim/tools/h3_evidence/`, figure
  `anim_h3_selfhosted.png`. Also records two vendor-documentation traps that cost runs:
  `ref_image_size: "max"` is a no-op for video references, and the `<Video 1>` prompt tag the
  node docstring prescribes made output worse.
- **2026-08-13** — Tested self-hosting rather than only costing it: LTX-2.3 with the Union
  depth+edge IC-LoRA on a rented L40S (runbook in `anim/tools/RUNPOD_LTX.md`, ~$2.40 total).
  Confirmed ~$0.01/clip iteration and rejected the quality. Sharpened the depth finding to
  its clearest form — depth places objects but cannot describe them or see coplanar surface
  changes, now evidenced across four implementations. Recorded why self-hosting MiniMax H3
  is not available (licence excludes US/EU/UK/KR deployment; 33B across 4 GPUs).
- **2026-08-12** — Added four figures: the sketch → CAD → 3D → photoreal chain, the low-poly cast
  from `characters_spec.md` (six of fifteen groups, framed from their own bounding boxes), the
  instruction-edit evidence for §7.2, and the Seedance-vs-H3 comparison still linked to
  [the video](https://youtu.be/tcXk7SdsRxA). Added plain-language definitions of ControlNet and
  Seedance inline in the online report, which has no glossary. Noted honestly that the chain
  figure mixes proposals at step 2.
- **2026-08-12** — §7.5 now states the conclusion rather than only the comparison: MiniMax H3
  at 768P (~$9.60 per 60 s film) as the working choice, 2K for hero shots. Records Wan 2.6/2.7
  as priced-but-untested (published $0.10/s, ~$0.20/s at the observed multiplier, i.e. above
  H3), that image references are billed at zero so the fidelity/beauty choice is never a
  budget question, and the explicit stopping rule — the search was ended when the cost of
  finding a cheaper tool exceeded the remaining saving.
- **2026-08-12** — Added resolution and duration ceilings per model to §7.5. These constrain
  the deliverable independently of quality: H3 reaches 4K but caps at 15 s per generation
  (a 60 s film is four takes), Seedance caps at 720p but generates 30 s (two takes, fewer
  joins). Beat-based cuts favour resolution; a single continuous flythrough favours duration.
- **2026-08-12** — Added §7.5 "Which model, and what it costs": five video models tested on
  identical conditioning, with measured rather than published rates. Records three
  method-level findings — depth alone cannot describe a park because paths are coplanar
  with grass; a style reference is treated as content rather than a look in *every* model
  tested, which makes it a property of the technique; and published API prices were wrong
  by 2–9x in every case checked. Also documents why self-hosting on a rented GPU was
  evaluated and rejected (break-even ~15–20 takes). Subsections renumbered 7.5→7.6 onward.
- **2026-08-11** — Added §7.8 figures and reference media, including the final comparison
  video ([YouTube](https://www.youtube.com/watch?v=ySVBk1CodjE)) and three figures copied into
  `report/img/`. Mirrored §7 into the online report (`ai_methodology_report.html`): the
  three-generation experiment narrative, the conditioning-pass figure, the A/B/C comparison,
  and the fabrication register as a table with the colour-bleed render as evidence. Flagged
  the outstanding provenance gap on the ChatGPT reference stills.

- **2026-08-11** — Added §7 "Visualisation — constraining generative AI with our own
  simulation", covering the full arc of animation experiments: the deterministic baseline,
  instruction-edit models (Kontext / nano-banana / Qwen), ControlNet-conditioned diffusion in
  ComfyUI, and Seedance 2.5 video-reference takes. Added the fabrication register, the
  shot-type decision framework, and a glossary of key terms with sources. Roadmap item ①
  moved from "planned" to "built"; gap 2 updated accordingly. Renumbered Roadmap 7 → 8.
- **2026-07-17** — Initial scaffold: framing, AI operating model, tool inventory, evidence
  pipelines mapped to the 8 AI-use areas, methodological integrity, alternatives considered,
  limitations, roadmap and gap list.
