# NEMOCITY — Architecture Contract (v1, June 12 2026, ~7pm) > **This file is the single source of truth for the parallel build.** Every builder agent reads > this FIRST and writes ONLY the files it owns (see File Ownership). When in doubt, follow the > schemas here exactly — the integrator fixes drift, but don't create it. ## One-liner Ask the city for a building — a 9B Nemotron city hall reads your petition, the deterministic engine zones it, and you (and every other visitor on Earth) watch it rise, floor by floor, in ONE shared persistent miniature city. Cars commute, rush hour jams the bridge, and the AI City Engineer reads real traffic telemetry and fixes it while you watch. - **Name:** NEMOCITY — "the tiny city the internet builds." (nano = Nemotron Nano + the hackathon's small-model thesis; -polis = city.) - **Tagline:** "Ask for a building and watch it rise — one tiny persistent city the whole internet builds, with a 9B Nemotron running city hall." - Track: 🍄 Thousand Token Wood. Hackathon: Build Small (Gradio + HF). Deadline June 15 morning. - Awards targeted: NVIDIA team-judged RTX 5080 (Nemotron load-bearing — the model's raw JSON plan is shown in the UI on every action), TTW podium, Community Choice (shared persistent city), Best Demo (timelapse + FPV walk footage), Judges' Wildcard, badges: offbrand, sharing, fieldnotes (+ offgrid/llama stretch). ## Non-negotiable design rules 1. **The "her" pattern** (org-celebrated judge taste): the deterministic engine owns ALL city state, placement, geometry, and traffic facts. The LLM only interprets petitions into a tiny JSON (no coordinates, EVER) and narrates. The engine clamps/repairs everything; a visitor action ALWAYS yields visible construction. 2. **One petition at a time** — single serialized queue, visitors see their position. 3. **The landing page must be gorgeous with ZERO GPU.** The whole city renders client-side from the event JSON; cars/citizens/day-night simulate deterministically in the browser. Judges evaluate while GPUs sleep. 4. **Determinism end-to-end.** All motion is a pure function of (event list, simTime). NO `Math.random()`, NO `Date.now()` inside sim/render logic (the shared clock anchor in main.js is the single allowed wall-clock read). NO `position += v*dt` accumulation — always evaluate `position(t)` absolutely (the godseed life.js idiom). This makes replay, timelapse, shared sync, and headless screenshots free. 5. **ONE `@spaces.GPU` call per user action** (one-shot JSON generation, model resident on cuda, duration=240). The multi-call loop crashes ZeroGPU — June 12 lesson, never relitigate. 6. **Moderation before execution** (charset/length + folded wordlist; LLM judge OFF by default). LLM-proposed building NAMES also pass the wordlist. One slur on a storefront during judging week ends every award. 7. **≤32B params total, ONE model:** `nvidia/NVIDIA-Nemotron-Nano-9B-v2`. 8. **Copy/naming:** never use "wish", "god", "remember/remembers", "Book of ___" in USER-FACING copy (rival differentiation + GODSEED separation). The user-facing words: **petition**, **city hall**, **City Engineer**, **ledger**. (Wire format & Python internals KEEP godseed's `wish_id`/`wish_*` names verbatim — zero-risk code reuse; UI copy is the only rename layer.) 9. Frame: a FLAT city grid (true SimCity feel). NOT a planet, NOT an island. Plus a first-person walk mode ("Walk the streets") — verified unclaimed across all 385 rival submissions. ## Repo layout & FILE OWNERSHIP (do not touch files you don't own) ``` nemocity/ ARCHITECTURE.md (this file — read-only for everyone) app.py ← AGENT-SERVER (adapt from godseed; already copied here) requirements.txt ← AGENT-SERVER README.md ← AGENT-SERVER (HF Space card w/ full YAML tags — see Deploy) server/ ← AGENT-SERVER (sse.py, persistence.py, schemas.py, ratelimit.py — copied, adapt envs/fields) engine/ ← AGENT-ENGINE constants.py (canonical: grid, river, building table, road classes, traffic constants, palette-relevant hues) genesis.py (the exact genesis event list — see Genesis) world.py (copied from godseed — keep the Feature/load/apply/state_dict machinery; adapt _observation + validation hook) tools.py (NEW: kind-synonym map, clamp tables, event validation — engine-side "tool" specs for the 4 event types) city.py (derived state from events: occupancy grid, road graph + street names, population, growth_radius) placement.py (the never-fails placement scorer + connector BFS) traffic.py (static assignment: trip gen, A*, demand map, Traffic Index, fix candidates + predicted index) summary.py (≤600-char city summary for the LLM prompt) moderation.py (copied — adapt env names GODSEED_→CITY_) queue_worker.py (copied — adapt: one-shot planner drive, fix-kind jobs, plan SSE event) mind/ ← AGENT-MIND prompts.py (build + fix one-shot prompts; persona; tool docs from engine tables) backends.py (copied — adapt: env names, ONESHOT only, model id, /no_think + strip stays) validate.py (lenient parse for the BUILD and FIX JSON schemas; balanced-brace extraction + salvage) planner.py (one-shot grant(): prompt → generate → parse → clamp → engine acts; fix(): stats → generate → choice) mock_scripts.py (keyword→BUILD-JSON scripts exercising every kind; fix script; drives local dev + demos) moderation_judge.py (copied; off by default via CITY_JUDGE) web/ index.html, style.css ← AGENT-UI (HUD per Visual Bible; element ids are the contract) main.js ← AGENT-UI (copied — adapt SSE applier, petition form, HUD, mode buttons, mock boot, window.__app harness) mock/world.json ← generated by tools/gen_web.py (AGENT-ENGINE writes the generator; integrator runs it) mock/feed.js ← AGENT-UI (scripted petition feed for ?mock=1 demos) lib/ (vendored three r160 + addons + PointerLockControls — already in place; read-only) city/ constants.js ← generated by tools/gen_web.py from engine/constants.py (AGENT-RFOUND hand-seeds it from THIS contract; gen overwrites later — values must match this doc) rng.js (copied verbatim — mulberry32; read-only) util.js ← AGENT-RFOUND (cellToWorld/worldToCell/key/clamp/lerp/eases/cityCenter) scene.js ← AGENT-RFOUND (copied — adapt: fog, camera start, tilt-shift+grade passes, MSAA target, rig-swap hook, daylight wiring) ground.js ← AGENT-RFOUND (ground chunks, river water, vertex-color lawn, contact-shadow quads API, occupancy mirror + isWalkable) world.js ← AGENT-RFOUND skeleton; INTEGRATOR owns final wiring (event dispatch → subsystems) replay.js (copied verbatim; read-only until integrate) buildings.js ← AGENT-RKIT (the 19-kind procedural kit, global window InstancedMesh, hue/variant jitter) construction.js ← AGENT-RKIT (dirt lot → scaffold → crane → floor-by-floor rise → finish; progress = f(ev.t, simTime)) roads.js ← AGENT-RTRAFFIC (road/bridge/sidewalk/crosswalk meshes from road cells; canvas atlas; lamp posts) traffic.js ← AGENT-RTRAFFIC (road graph, A* + path cache, trip gen, 10Hz car CA, congestion EMA, Traffic Index, heatmap overlay) vehicles.js ← AGENT-RTRAFFIC (instanced car kit rendering of traffic.js car states; head/taillights; blob shadows) citizens.js ← AGENT-RTRAFFIC (instanced pedestrians on sidewalk loops) sky.js ← AGENT-RCAM (sun arc, hemisphere, fog colors, gradient sky dome, stars; exported pure daylight(simTime)) camera.js ← AGENT-RCAM (orbit/pan/zoom rig, gaze(point,{hold}), landing choreography, bounds) fpv.js ← AGENT-RCAM (pointer-lock walk: WASD+shift, occupancy collision w/ axis slide, enter/exit) tools/ shot.mjs (copied — AGENT-UI adapts selectors/harness; the screenshot-and-LOOK loop is mandatory) gen_web.py ← AGENT-ENGINE (emits web/city/constants.js + web/mock/world.json from engine constants/genesis) tests/ ← test_engine.py + test_traffic.py (ENGINE), test_mind.py (MIND), test_api.py (SERVER) traces/ (runtime output — wishes.jsonl; gitkeep only) ``` Build waves: **Wave 1 (parallel):** ENGINE, MIND, SERVER, RFOUND, UI. **Wave 2 (parallel):** RKIT, RTRAFFIC, RCAM. **Wave 3:** INTEGRATOR. **Wave 4:** verify (pytest + headless screenshots). ## The grid - 64×64 cells; cell coords `(cx, cz)` each in `[-32, 31]`. `CELL = 4` world units (= 4 m; 1 unit = 1 m — human scale, FPV-ready). City plane = 256×256 u at y=0. - World position of cell center: `x = cx*4 + 2`, `z = cz*4 + 2`. +X = east, +Z = south. - A cell holds at most ONE of: road | water | building-footprint | park | empty. - Buildings occupy `w×d` rectangular footprints, anchor = top-left (min cx, min cz) cell. - **The river** (load-bearing: guarantees the traffic bottleneck + a beauty anchor). Water cell columns per row, formula (identical in `engine/constants.py` and `web/city/constants.js`): ``` riverCols(cz) = cz <= -5 ? [7, 8] : cz <= 3 ? [8, 9] : [9, 10] ``` Water cells are unbuildable and uncrossable except on bridge cells (road cells over water). - `growth_radius` = max Chebyshev distance of any developed (non-water) cell from (0,0), min 6. Placement penalizes beyond `growth_radius + 2` → the city accretes outward, ring by ring. ## Shared sim clock (every visitor sees the same city at the same moment) - `CITY_EPOCH_S = 1781222400` (June 12 2026 00:00 UTC; constant in engine + web constants). - `simTime = serverNow - CITY_EPOCH_S` (seconds). main.js estimates `serverNow` once from `server_now` in `/api/state` (and SSE hello), then free-runs on the fixed-step clock, slewing ±2% toward the server clock when a heartbeat shows >1.5 s drift. Never snap. - ONE in-game day = `DAY_S = 240` seconds. `dayHours = (simTime % 240) / 240 * 24`. - Rush hours: bell curves at dayHours 8 and 18 (σ≈1.2h) — judges see a rush within ~2 min. - Day/night: `daylight(simTime)` ∈ [0,1], pure function in sky.js — smooth sunrise centered dayHours 5.5, sunset centered 19.5 (transitions ~1.5h wide). Night is short and gorgeous. - Construction progress (any client, incl. late joiners): `progress = clamp((CITY_EPOCH_S + simTime - ev.t) / DURATION(kind), 0, 1)`. - `tick(dt)`/`seek(t)` fixed-step core (already in scene.js) MUST keep working: timelapse, replay, and shot.mjs depend on it. ## Building table (CANONICAL — engine/constants.py is the source; gen_web.py mirrors to JS) `kind: {w×d, floors min–max, residents, jobs, attract, duration_s}` | kind | w×d | floors | residents | jobs | attract | duration | |---|---|---|---|---|---|---| | house | 1×1 | 1–2 | 4 | 0 | 0 | 20 | | townhouse | 1×1 | 2–3 | 6 | 0 | 0 | 20 | | apartments | 2×2 | 4–7 | 16 | 0 | 0 | 45 | | cafe | 1×1 | 1 | 0 | 3 | 5 | 20 | | shop | 1×1 | 1–2 | 0 | 4 | 4 | 20 | | market | 1×2 | 1 | 0 | 8 | 6 | 30 | | bank | 2×1 | 2–4 | 0 | 12 | 2 | 30 | | office | 1×1 | 3–8 | 0 | 40 | 1 | 30 | | tower | 2×2 | 8–16 | 0 | 60 | 2 | 45 | | school | 2×2 | 1–2 | 0 | 10 | 3 | 30 | | hospital | 3×3 | 3–6 | 0 | 25 | 2 | 45 | | fire_station | 2×1 | 2 | 0 | 8 | 1 | 30 | | warehouse | 2×2 | 1 | 0 | 10 | 0 | 30 | | factory | 3×2 | 1–2 | 0 | 18 | 0 | 45 | | park | 2×2 | 0 | 0 | 0 | 8 | 20 | | plaza | 1×1 | 0 | 0 | 0 | 6 | 20 | | stadium | 4×4 | 1 | 0 | 15 | 9 | 45 | | church | 2×1 | 1 | 0 | 2 | 3 | 30 | | town_hall | 2×2 | 2 | 0 | 6 | 4 | 45 | - Mixed-use feel comes from variety + placement affinities, not more kinds. - **Synonym map** (engine/tools.py — the model can never pick a kind we lack): skyscraper/ highrise→tower, apartment/apartment building/condo→apartments, coffee shop/diner/restaurant/ bakery→cafe, store/boutique/pharmacy→shop, mall/grocery/supermarket→market, police station/ police→fire_station, library/museum/city hall→town_hall, temple/mosque/chapel→church, garden/playground→park, fountain/square→plaza, arena/stadium→stadium, clinic→hospital, gym→shop, hotel→apartments, factory/plant→factory, anything unknown→**house**. - `population = Σ residents × build_progress` (a finishing tower visibly ticks the HUD up). - Citizens (pedestrians): `clamp(ceil(population/5), 6, 80)`. - Demand-driven infill: after a granted petition, if `jobs > housing_capacity*1.15`, engine appends ONE bonus house/apartments event (same wish_id, normal scorer, near the new jobs), note blurb "New families are moving in." Max 1 infill per petition. ## Roads & the road graph - Roads are CELLS. Classes: `street` {capacity 2, speed 1.0 cells/s, 1 dash lane marking}, `avenue` {capacity 6, speed 1.6, wider look, double yellow center}. Road cells over water render as BRIDGES (raised deck + railings; same graph semantics). - Graph (derived IDENTICALLY in Python `engine/city.py` and JS `traffic.js`): node = road cell; edge between 4-adjacent road cells. Intersection = road cell with ≥3 road neighbors. - **Street names:** each maximal straight run of road cells laid in one event gets a name from a curated list indexed by `crc32(event_id) % len(list)` ("Main St" and "1st Ave" and "Old Bridge" fixed in genesis). Names power LLM stats ("Old Bridge carries 3.1× its capacity") + HUD. - **Engine-routed roads only — the LLM never outputs geometry:** 1. Placing a building with no road frontage auto-routes a CONNECTOR: BFS over empty cells from footprint perimeter to nearest road cell (max length 8), Manhattan path, emitted as its own `lay_road` event in the same wish. 2. Traffic fixes lay engine-routed bypass roads (BFS avoiding jammed cells; water crossable at 4× cost — fixes may deliberately build a second bridge). - `road_version` = count of road-mutating events; all path caches key on it. ## Traffic model (client-side presentation; Python mirror for facts) - Fixed **10 Hz logic tick** (accumulator inside the existing 60 Hz fixed-step; render interpolates). RNG = mulberry32 from event seeds only. - **Trip generation** (static OD, gravity; recompute only when buildings change): each completed residential building emits `residents` commuters; commuter `i` picks a destination via seeded roulette over job/attract buildings, `weight = (jobs + 2*attract) / (1 + manhattanDist^1.5)`, `seed = building.seed ^ i`. - **Cars:** visible cars `N = clamp(round(population * 0.8 * rushFactor(simTime)), 8, 120)`, `rushFactor = 0.35 + 0.65 * (bell(dayH,8,1.2) + bell(dayH,18,1.2))` (bell = gaussian, capped at 1). Each car = one commuter loop home→work (dwell 10–20 s seeded)→home, phase-offset seeded. - **Pathfinding:** A* over road cells, `cost(cell) = (1/speed(class)) * (1 + 2*demandRatio(cell))` — congestion-aware so fixes visibly reroute. Cache per (origin, dest, road_version); on bump, re-solve incrementally ≤20 paths/frame. - **Movement — queueing cellular automaton** (no physics): car = scalar progress along its path; per tick `speed = base * clamp(capacity / max(occ(nextCell), 1), 0.25, 1)`; if `occ(nextCell) ≥ 2*capacity` the car HOLDS. occ = integer car count per road cell. Cars visibly slow, bunch, queue back from the bridge. Intersection yield = deterministic priority (lower car index). U-turn at dead ends. - **Congestion:** per road cell `cong = EMA(occ/capacity, τ=5 s)`. **Traffic Index** = `round(100 * mean(top-15 cong cells))`, color-coded on the HUD live. - **Heatmap overlay** (toggle): one InstancedMesh of road quads, green < 0.5 / yellow < 1.0 / red ≥ 1.0, instanceColor updated at 2 Hz. Jammed segments ALSO get an in-world additive red underglow strip (#E84F3D) — utility visible from orbit, not just HUD. - **Python mirror** (`engine/traffic.py`): same trip gen + A* + demand map from the same event list/constants (static assignment, no CA). This feeds the LLM stats + fix candidates, so the ENGINE owns the facts; live car queueing is presentation and may drift a car or two, harmless. - **ACCEPTANCE (engine agent must verify, tune capacities/CAR rate until true):** genesis city + ~3 extra houses west jams the Old Bridge (cong ≥ 1.0 red) at rush hour in mock mode. ## The traffic-fix mechanic (V0-CRITICAL — the prize-winning beat; never let it slip) 1. Client shows live Traffic Index; when any cell holds cong ≥ 1.0 for 10 s → pulsing chip "Traffic alert: Old Bridge" + button **[Ask the City Engineer]**. 2. `POST /api/fix` → engine gate: if Python static assignment max demandRatio < 0.8 → 409 "Traffic is flowing smoothly." Else enqueue a fix job (global cooldown 120 s, 2/hr/client). 3. Engine computes stats snapshot: top-5 cells by demand/capacity WITH street names, worst intersection, traffic_index, and 2–4 pre-validated CANDIDATE FIXES, e.g. `{id:"F1", action:"new_road", desc:"second bridge at Oak St, 7 cells", predicted_index:41}` (predicted by re-running static assignment with the candidate applied). Actions v0: `new_road` (bypass/bridge) and `upgrade_avenue` (repaint a named street's cells to avenue). 4. **ONE** @spaces.GPU Nemotron call: input {stats, candidates} → output `{"diagnosis":"≤160 chars citing the real numbers","choice":"F1","blurb":"≤120"}`. Invalid choice/parse failure → engine applies best predicted candidate + canned diagnosis. 5. Engine appends ONE `apply_fix` event (exact cells + diagnosis + metrics_before/predicted); SSE `world_delta`. Every client: road_version bumps, paths re-solve, the new road paints in over 4 s, queued cars peel onto it, red drains green over ~20 s, HUD animates "78 → 41". ## Placement algorithm (engine/placement.py — deterministic, NEVER fails, Python-only) Input: kind (post-synonym), w×d, floors (clamped), anchor from the "near" hint, resolved fuzzily: named building → its centroid; street name → midpoint; "center"/"downtown" → (0,0); "river" → nearest water-adjacent developed cell; null/unresolvable → centroid of all buildings. 1. Candidates = empty cells within Chebyshev radius R of anchor; R starts 6, +4 until ≥1 valid. 2. VALID = footprint fits on empty non-water cells AND (perimeter touches a road OR connector BFS ≤8 exists). 3. SCORE: `+30*(1 - dist_to_anchor/R)` `+20*roadFrontage` `+3/developed-8-neighbor (cap +18)` + affinities: cafe/shop +12 if house/apartments ≤3 cells; office/bank/tower `+10*(1 - dist_to_center/12)` (downtown skyline emerges); house/townhouse/apartments +8 if cafe/shop/park ≤4, −6 if factory/warehouse ≤3; factory/warehouse −10 if residential ≤3, +8 if industrial ≤4 (an industrial quarter self-organizes); park −25 if another park ≤6; `−8*max(0, chebyshev_from_center − (growth_radius+2))` (ring growth). 4. floors: office/tower `clamp(base + round(4*(1 − dist_to_center/10)), range)` — taller downtown. 5. Tie-break: seeded jitter `U(0,1)` from `crc32(wish_id:candidate_index)`. 6. Emit `place_building` (exact cells FINAL) + optional connector `lay_road`. Re-derive occupancy after EACH building within a multi-building petition (siblings cluster, never overlap). ## Event schema (append-only; byte-compatible with godseed Feature: id, wish_id, tool, args, seed, t) `seed = crc32(f"{wish_id}:{call_index}") & 0x7fffffff`. City-at-T = pure fn of (events t≤T, T). ```json {"id":"e_000017","wish_id":"w_000005","tool":"place_building", "args":{"kind":"cafe","name":"Cafe Luna","cx":3,"cz":-2,"w":1,"d":1,"floors":1,"hue":35,"variant":2}, "seed":1830293847,"t":1781230000.0} {"id":"e_000018","wish_id":"w_000005","tool":"lay_road", "args":{"cells":[[3,-1],[4,-1],[5,-1]],"klass":"street","name":"Olive St"},"seed":482919,"t":1781230000.5} {"id":"e_000031","wish_id":"w_000009","tool":"apply_fix", "args":{"action":"new_road","cells":[[5,-6],[6,-6],[7,-6],[8,-6],[9,-6]],"klass":"avenue", "name":"Oak St Bridge","diagnosis":"Old Bridge carries 3.1x capacity at rush — a second crossing cuts the index 78→41.", "metrics_before":{"traffic_index":78,"worst":"Old Bridge"},"metrics_predicted":{"traffic_index":41}}, "seed":99182,"t":1781231100.0} {"id":"e_000032","wish_id":"w_000009","tool":"note","args":{"text":"New families are moving in.","kind":"infill"},"seed":7,"t":1781231101.0} ``` Derived, never stored: occupancy, road graph + names, road_version, population, demand map, growth_radius. WishTrace persists per petition exactly like godseed (text, moderation, RAW LLM JSON, event ids, ms_total) → `traces/wishes.jsonl` → HF dataset (Sharing badge + NVIDIA evidence). ## Genesis (epoch 0 — engine/genesis.py is canonical; web/mock/world.json is GENERATED from it) wish_id "genesis", t = CITY_EPOCH_S. Order: roads, then buildings, then a note. Roads: - **Main St** — avenue, cx=0, cz −12..12. - **1st Ave** — avenue, cz=0, cx −12..16, EXCEPT the two river cells. - **Old Bridge** — **street** class (the bottleneck by design), cells (8,0),(9,0) over water. - **River Rd** — street, cx=13, cz −6..6. - **Elm St** — street, cz=−5, cx −8..0. - **2nd St** — street, cx=−5, cz −5..3. Buildings (anchor top-left; every footprint touches a road; engine must assert validity): - town_hall 2×2 @ (−2,−3) — faces Main St. - office 1×1, 5 floors @ (1,−2); cafe 1×1 @ (1,1); market 1×2 @ (−1,1). - park 2×2 @ (−4,1) — beside 2nd St + 1st Ave. - houses 1×1 @ (−1,−6), (−4,−6), (−6,−4) — Elm/2nd St cluster. - EAST of the river (jobs/homes that force bridge commutes from day one): factory 3×2 @ (14,−3); warehouse 2×2 @ (14,1); houses @ (14,3), (14,−5) — all on River Rd. - note: {"text":"Nemocity is listening. Ask for a building.","kind":"milestone"} Genesis population ≈ 20, jobs ≈ 95, one street-class bridge carrying every river crossing. ## LLM one-shot schemas (mind/ — small, flat, enum-heavy; a 9B nails these) **BUILD** — input: petition text (≤160 chars) + engine summary (≤600 chars: city name, pop, counts by kind, named landmarks/streets, traffic index). Output: ```json {"intent":"build","blurb":"≤140 chars, warm city-planner voice", "buildings":[{"kind":"cafe","name":"Cafe Luna","near":"the park","floors":4,"hue":35}], "decline_reason":null} ``` - buildings 1..3; kind = table enum (synonyms repaired by engine); name ≤24 chars (wordlist- checked, default derived from petition words); near = free text the ENGINE resolves; floors/ hue optional. intent "decline" (+reason) only for nonsense — moderation already gated abuse. - Parse failure after 1 retry → deterministic fallback: one house, name from petition words, blurb "The city granted a home." Something ALWAYS builds. **FIX** — input: {stats, candidates} as in the fix mechanic. Output: `{"diagnosis":"≤160","choice":"F1","blurb":"≤120"}`. Invalid choice → best predicted candidate. **Prompting** (mind/prompts.py): persona = terse municipal planner AI ("You are city hall of one shared miniature city. The engine owns all facts; you only translate petitions into permits. Build generously — a district request deserves 2–3 buildings. Never refuse a buildable thing."). Tool/kind docs rendered from engine tables (single source). NO multi-example few-shot (GODSEED leakage bug) — ONE inline example-shape JSON + "your own values, JSON only". Backend: copied ZeroGPUBackend (resident cuda at load, @spaces.GPU(duration=240), /no_think system slot, strip, temperature 0.4 for JSON, max_new_tokens 700, lenient parse + 1 retry). ## HTTP API + SSE (server — keep godseed wire names; adapt fields) ``` GET /api/state → {world:{version,epoch,features:[...]}, queue, wishes_recent, server_now} POST /api/wish {text} → {wish_id, position} (petition; 400 poetic reason on moderation reject) POST /api/fix → {wish_id, position} (409 if traffic is smooth; cooldowns) GET /api/stream → SSE (X-Accel-Buffering: no) GET /api/wishes[, /{id}]→ ledger index / full trace (replay) GET /api/turn?wish_id= → {token} (cookie-bound; ZeroGPU browser-invoke dance — copied) @app.api("grant") → gradio endpoint the petitioner's browser calls (their GPU quota) GET / → web/ static (mounted AFTER launch — the route-eviction trick, copied) ``` SSE events (godseed names + ONE new event): ``` {type:"hello", world_version, epoch, server_now} {type:"queue", length, current} {type:"wish_started", wish_id, text} {type:"plan", wish_id, plan:{...raw validated LLM JSON...}} ← NEW: City Hall paperwork (NVIDIA evidence, shown in UI) {type:"tool_call", wish_id, call_index, tool, args} {type:"world_delta", feature:{...}} {type:"wish_granted", wish_id, epitaph, epoch} (epitaph = the blurb) {type:"wish_rejected", wish_id, reason} {type:"heartbeat", server_now} ``` Env vars: `CITY_BACKEND` (mock|zerogpu; llamacpp stretch), `CITY_DATASET`, `CITY_JUDGE`, `CITY_INVOKE`, `CITY_MOCK_DELAY`, `CITY_SECRET`, `CITY_HF_MODEL`, `HF_TOKEN`, `PORT`. Rate limits: 3 petitions/hr/client (cookie+IP), 1 pending/client, queue cap 50, fix cooldowns. ## Visual Bible — "Golden Hour Toybox" (miniature diorama / tilt-shift) **Thesis: the city should feel like a hand-built miniature model village on a sunlit table — small enough to love, alive enough to watch grow.** ("Build Small" made literal.) Palette (hex — `web/city/palette.js` carries these; AGENT-RFOUND owns it. constants.js holds only engine-mirrored values since gen_web.py overwrites it): - Ground: lawn `#8FC474` (±3% per-cell lightness jitter, vertex colors), park `#6FB257`, dirt lot `#CFB78F`. Water `#58AFC7` (darken 12% center). Sidewalk `#D6D2C4` w/ 0.06 u curb lip. - Roads: asphalt `#565B66` (warm dark gray, never black), markings warm-white `#F5F1E6`, center-line yellow `#EFC75E`. - Facades (8, seeded ±6° hue ±5% lightness jitter): cream `#F4E9D0`, terracotta `#E07856`, butter `#F2CC8F`, coral `#EC9AA2`, powder blue `#8FB8D8`, dusty teal `#7FB69E`, sage `#A9B98A`, brick `#BD6B6E`. Civic white `#F8F4EA` (bank/town_hall/hospital/church). - Roofs: clay `#C06B4F` (houses/church), slate `#5C6470` (apartments/school), charcoal `#3F454F` (offices/towers), gravel `#D9D5CB` (flat commercial — HVAC boxes read). - Sky: day zenith `#7BC1E8` / horizon `#FFE9C2`; night zenith `#141C36` / horizon `#2C3760` (indigo, never black). Fog = horizon color (day near 140 far 420; night near 100 far 360). - Emissives (night money colors): window glow `#FFC97A`, streetlamp `#FFD9A0`, headlight `#FFF6DC`, taillight/signal red `#FF5340`, signal amber `#FFB13D`, signal green `#43D17C`, neon teal `#45E0C0`, neon pink `#FF6FA6`, construction orange `#FF8A3D`, congestion red underglow `#E84F3D`. Lighting: ONE shadow-casting DirectionalLight (the sun), golden-hour default `#FFCE96` @ 2.4, elev 28°, az 235°; arcs with the day cycle (noon `#FFE3BB` @2.8 elev 62°; dusk `#FF9E62` @1.2; night = moon `#8FA8D8` @0.15). PCFSoftShadowMap, map 2048 (1024 small), ortho frustum fit to city bounds +10%, texel-snapped, re-fit only on growth; bias −0.00035, normalBias 0.5. Casters: building InstancedMeshes + trees ONLY. Cars/citizens/trees use instanced radial-gradient blob quads (sells the miniature). Hemisphere fill sky `#BCD7EA`/ground `#C7B18E` @0.6 day → `#2B3450`/`#161B28` @0.3 night. NO AmbientLight. RoomEnvironment PMREM, envMapIntensity 0.25 per-material. Max 4 PointLights citywide (active construction, newest build). Window emissives stagger on over ~8 s at dusk (in-shader hash threshold — zero CPU). Postprocessing (in order): RenderPass → UnrealBloomPass (DAY 0.32/0.35/0.85 — pastel facades must NOT glow in daylight; NIGHT 0.70/0.45/0.62; lerp by daylight) → tilt-shift H pass → tilt-shift V pass (+ grade folded in: saturation +8%, warm shadow lift +0.02, vignette 0.25/0.75) → OutputPass. Tilt-shift = classic separable 9-tap Gaussian, weights [.051 .0918 .12 .1531 .1633 .1531 .12 .0918 .051], per-fragment radius `maxBlur * smoothstep(bandHalf, bandHalf+falloff, abs(vUv.y - focusY))`, focusY tracks the orbit target's screen y, bandHalf 0.13, falloff 0.22, maxBlur 2.2 px × pixelRatio. Amount: 1.0 god view → lerp to 0 between camera heights 60→25 m → **0.0 in FPV (hard requirement — DoF in first person is nauseating)**. MSAA: composer target `samples: 4` (2 on small). NO BokehPass, NO SSAO — fake AO: baked dark edges in the road atlas + instanced contact-shadow quads under every building (footprint ×1.25, opacity 0.22) + tree blobs ×0.5. Roads/ground: ground = one plane per 16×16-cell chunk, vertex-colored per cell. Roads = flat quads y=0.02, ONE InstancedMesh, per-instance UV offset into a procedurally-drawn 512² canvas atlas (8 tiles: street straight, avenue straight, intersection, crosswalk approach, T-junction, parking edge, dirt, plaza paving) — dashes/stop lines/crosswalks PAINTED in the atlas, zero extra geometry, 6 px soft dark edge baked. Sidewalk curb strips instanced on road cells adjacent to zoned cells. Street furniture: instanced lamp posts every 3rd road cell (emissive head + fake light-pool quad at night), hydrants/mailbox dots at corners, 10% density. Buildings (19 kinds): assembled from a shared low-poly part kit (wall box, gabled/flat roof, awning, AC boxes, water tower, chimney, steeple, smokestack, drive-thru-style signage on shop/ cafe, fire-escape strip on apartments) — ONE InstancedMesh per part archetype with instanceColor; whole city ≈ 10–14 draw calls. Windows: ONE GLOBAL InstancedMesh citywide, emissive atlas, in-shader night flicker. Signature silhouettes matter more than detail: water towers on apartments, AC clusters, awnings + sidewalk tables on cafes (neon at night), sawtooth factory roof + smokestack, hospital cross, church steeple, stadium light masts, town_hall dome. Motion: cars = two-box kit (body + cabin, dark skirt fakes wheels), 7 seeded paint colors, right-lane offset, ease at intersections, ±2° pitch bobble on accel/brake; night headlight emissive dots + 2 short additive cone quads + taillights. Citizens = instanced capsule + head, 2-tone seeded clothes, 1.5 Hz walk bob; spawn near homes dawn / shops midday / drain home at dusk. Construction (the "watch it being built" payoff): [0,.12] dirt + dust ring → (.12,.30] orange scaffold wireframe pops to height (+ barrier cubes + blinking amber) + kit crane (mast, counterweighted jib rotating 0.15 rad/s) on ≥4-floor builds → (.30,.90] floors rise in quantized easeOutBack steps → (.90,1] scaffold drops, windows light bottom-to-top, sparkle + floating name label ("Cafe Luna — built for visitor #12"). Roads: a roller prop sweeps the path painting asphalt over 4 s; bridges add a deck-drop. Idle cranes over a skyline = a city mid-boom. Landing choreography (first paint <1 s, ZERO model calls, no spinner ever): T+0 frame one IS the screenshot — golden hour, long shadows, camera LOW (~10 m) behind a moving car on Main St, tilt-shift full. T0–3.5 s slow dolly forward along the avenue. T3.5–7 s single eased crane up + pull back to god view (38° pitch, downtown rule-of-thirds left, skyline against warm horizon). T7–10 s gentle 0.5°/s drift; a guaranteed construction event plays in view (if the live queue is empty the client keeps one scripted "welcome build" so a crane is ALWAYS rising when a judge arrives); ticker types its first headline; petition input pulses once. Any input cancels → orbit camera. Walk button drops to FPV (tilt-shift fades 0.4 s). HUD ("museum placards around a diorama" — labels NEXT TO the model, never chrome OVER it): fonts = Bricolage Grotesque 600/800 (display), Schibsted Grotesk 400/500 (UI), Spline Sans Mono (ticker/queue). Panels: warm frosted glass — `rgba(252,249,242,0.78)`, blur(14px), 1px `rgba(60,50,40,0.12)` border, radius 14px, text `#2A2620`; panels stay light at night (lit placards in a dark gallery). Layout: top-left city name + stat chips (population odometer, buildings, Traffic Index color-coded, day clock, "Built by N visitors"); bottom-center ONE rounded petition field + Build button (placeholder cycles: "a ramen shop near the park…", "a fire station downtown…"), lifecycle chips above it (queued → city hall is reading (animated ellipsis) → under construction → built, each with jump-camera link); bottom edge 28 px news-ticker (mono, LLM blurbs as headlines: "MAYOR CUTS RIBBON ON CAFE LUNA — TRAFFIC ON OLD BRIDGE UP 12%"); top-right: Walk toggle, sound toggle, PHOTO button (fades ALL UI for clean screenshots). Accents: terracotta #E07856 primary, congestion red only for traffic warnings. A "City Hall paperwork" drawer shows the raw Nemotron JSON per petition (NVIDIA evidence). Chrome <15% of screen; every panel fades 250 ms. Sound (stretch, OFF until toggled): WebAudio-synthesized only — filtered-noise traffic hum, bird blips day / cricket ticks night, soft thunk per construction floor, marimba chime on grant, single honk when a jam forms. ## FPV walk mode (web/city/fpv.js) - Vendored `lib/addons/controls/PointerLockControls.js` (r160) for look; fpv.js adds WASD (target 5 m/s, Shift 9 m/s, exponential accel/decel) integrated in the FIXED-STEP tick. - Eye height 1.65 m; camera near 0.1 far 1500 (fog covers the horizon). - Collision: occupancy-grid only — player circle r=0.35 m; test X and Z displacement independently against building cells, cancel only the blocked axis (axis-slide). Roads, sidewalks, parks, plazas walkable; water blocks (except bridge cells); clamp to city plot −2-cell margin with soft vignette hint. - Enter: "Walk" button / F key → requestPointerLock, 300 ms fade, spawn at nearest road cell to camera look-point. Exit: pointerlockchange (NOT keydown ESC) → restore orbit rig over player. - ONE camera, one scene — FPV is a controller swap via scene.js's rig-swap hook. Tilt-shift amount = 0 in FPV. Mobile: hide the Walk button on touch (v0); dual-zone joystick is stretch. ## Perf budgets (enforced, not hoped) Targets: 60 fps mid laptop, <300 draw calls, <1.2 M tris, pixelRatio ≤2 (1.7 small). Caps: buildings ≤400, cars ≤120, pedestrians ≤80, trees/props ≤1500, road cells ≤600. InstancedMesh per part-archetype (NEVER one Group per building — godseed's per-structure PointLight habit dies at city scale). Static meshes matrixAutoUpdate=false. Roads/river/ground rebuilt only on road events. A* cached per road_version, incremental re-solve ≤20 paths/frame. Degrade ladder (fps<45 for 3 s or hardwareConcurrency≤4): halve cars+peds → bloom off → shadows off → pixelRatio 1. LOD: beyond 180 m swap buildings to untextured-box instance set, hide pedestrians. All canvas atlases generated once at boot. dispose() discipline on construction particles. ## Local dev + verification - Python 3.12 venv via uv: `uv venv -p 3.12 .venv && uv pip install -r requirements.txt` (mock backend needs NO ML deps — fastapi/uvicorn/gradio/pydantic/hub only). - `CITY_BACKEND=mock PORT=7900 .venv/bin/python app.py` → http://localhost:7900 - Renderer standalone: `python3 -m http.server 8123 --directory web` + `?mock=1` (web/mock/world.json + feed.js; zero backend). - **The screenshot-and-LOOK loop is mandatory** (don't ship the first thing that renders): `node tools/shot.mjs` variants — god view day, god view night, street FPV, construction close-up, heatmap on. window.__app harness (seek/tick/stats) must keep working. - pytest: engine (placement determinism, clamps, genesis validity, traffic acceptance), mind (parse/salvage/fallback), api (SSE flow, rate limits, fix gate, injected fakes). ## Blueprint Update (v1.1 contract — June 12 PM. ⚠️ NOT part of the v0 build wave: v0 agents ## and the v0 integrator IGNORE this section entirely. It ships as its own wave after v0 verifies.) User-requested: petitions like "a Korean BBQ restaurant" must produce a building that looks UNIQUE — not just the generic cafe model. Mechanism: **bones + LLM-designed decoration**. The kit archetype is the bones (walls/floors/windows/roof — unchanged, instanced, fast); Nemotron additionally emits a compact STYLE BLUEPRINT the deterministic renderer interprets. No 3D-gen model (slow, ugly, non-deterministic, breaks zero-GPU replay); the LLM becomes the *architect* — a stronger Nemotron-load-bearing story, and the blueprint JSON shows in the paperwork drawer. Backwards compatible: `place_building.args.style` is OPTIONAL. Absent/partial style → engine fills a seeded per-kind default pack, so old events and fallback builds render unchanged-or-richer. ### style schema (LLM-emitted inside each buildings[] entry; engine clamps EVERYTHING) ```json "style": { "facade_hue": 12, "trim_hue": 350, "roof": "flat|gabled|hipped|sawtooth|dome|pagoda", "roof_color": "clay|slate|charcoal|gravel|copper", "windows": "grid|tall|arched|round|shoji", "awning": {"hues": [350, 40], "shape": "flat|scalloped"}, "sign": {"style": "hanging|vertical|rooftop|window", "neon_hue": 0, "icon": "bowl|flame|cup|leaf|star|fish|bread|music|cross|book|gear|heart|moon|paw|cart|none"}, "props": ["lanterns", "smoke_vent"], "vibe": "charcoal smoke and red neon" } ``` - Enum-heavy on purpose (9B-reliable). Engine: unknown enum → dropped/default; hues → 0..360; `props` ≤4 from: lanterns, string_lights, plants, umbrellas, barrels, crates, smoke_vent, chimney_smoke, banner, menu_board, bike_rack, flag, grill_smoke. `vibe` ≤40 chars is TOOLTIP/ticker text only — NEVER rendered as world geometry. - The sign renders the building **name** (already wordlist-moderated — the only world text) + icon glyph + neon hue. Sign textures live in ONE shared canvas atlas (256×128/slot, grown in chunks); sign quads instanced with per-instance UV offset. Icons = ~16 pre-drawn glyphs. - Props are instanced prop archetypes (a lantern string = sagging line + emissive spheres; smoke = ONE shared particle system with per-emitter offsets). All bounded: ≤4/building. - Seeded default packs per kind (engine table): e.g. cafe → menu_board+awning+window sign; factory → smoke stack already in kit. Defaults keyed by `seed` so two unstyle'd houses differ. - Prompt addition (mind): "Design the building too: pick a roof, windows, awning, a sign icon and neon color, and up to 3 props that match the petition's culture/cuisine/mood. A Korean BBQ wants flame icon, smoke_vent, grill_smoke, red neon; a ramen shop wants bowl icon, lanterns, banner." max_new_tokens 700 → 900. - File ownership for this wave: ENGINE (tools.py style clamp tables + default packs + constants), MIND (prompts/validate/mock_scripts style), RKIT (buildings.js decor layer: sign atlas, prop archetypes, roof/window variants), UI (paperwork drawer shows style; tooltip vibe). gen_web.py mirrors the style enums. ## Deploy (June 12 night / 13 morning — see hf-spaces-deploy-pins memory for war stories) 1. README YAML: `sdk: gradio`, `app_file: app.py`, **NO sdk_version** (transformers≥5.4 has nemotron_h IN-TREE, pairs with default gradio 6.18/hub≥1.5 — godseed's final shipped recipe). `models: [nvidia/NVIDIA-Nemotron-Nano-9B-v2]`, `datasets: [AndresCarreon/nemocity-world]`, tags: `build-small-hackathon, track:wood, sponsor:nvidia, achievement:offbrand, achievement:sharing, achievement:fieldnotes, thousand-token-wood, nemotron, nvidia, simulation, city-builder, world-building, three-js, multiplayer` (+offgrid/llama if the llamacpp path ships). README must LINK demo video + social post (placeholders until June 13/14). 2. requirements.txt: fastapi>=0.115, uvicorn>=0.30, pydantic>=2.7, huggingface_hub>=0.30, transformers>=5.4, accelerate, einops, sentencepiece. **NEVER pin gradio/spaces/torch** (image force-installs them). NO mamba-ssm/causal-conv1d. dtype= (not torch_dtype=). 3. app.py invariants (already copied): `import spaces` before torch when CITY_BACKEND=zerogpu; gr.Server (no gr.Blocks); launch(prevent_thread_lock=True) THEN mount_static() route eviction; ensure_worker lazy start; SSE X-Accel-Buffering: no; SameSite=None+Secure cookies. 4. Space: `build-small-hackathon/nemocity` + dataset `AndresCarreon/nemocity-world`. Secrets: HF_TOKEN; vars: CITY_DATASET, CITY_BACKEND=mock first. `request_space_hardware('zero-a10g')`. Never set_space_sleep_time on ZeroGPU. Deploy mock → verify landing/SSE/persistence → flip CITY_BACKEND=zerogpu → one real signed-in petition → tail logs. 5. If the 9B fails to load: fall back to mock granting, KEEP SERVING the city (copied posture).