Spaces:
Sleeping
Sleeping
Town Mode: close town view by default, build_district + place_road, bank/market/house, grow-one-town steering, behold-the-world reveal, tamed needle
b0d758d verified | # GODSEED β Architecture Contract (v1, June 12 2026) | |
| > **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). Interface drift gets fixed by the | |
| > integrator β but don't create drift: when in doubt, follow the schemas here exactly. | |
| ## One-liner | |
| Type a wish β a tiny Nemotron god *plans aloud* and terraforms ONE persistent WebGL planet shared by | |
| every visitor. Tagline: **"Nine billion parameters. One shared world."** | |
| Track: π Thousand Token Wood. Hackathon: Build Small (Gradio + HF). Deadline June 15. | |
| Awards targeted: NVIDIA team-judged RTX 5080 (Nemotron load-bearing), Best Agent (visible | |
| plan-act-observe + published traces), Bonus Quest (6/6 badges), Modal slot (LoRA), TTW podium, | |
| Community Choice (shared world farms likes), Judges' Wildcard. | |
| ## Non-negotiable design rules | |
| 1. **The "her" pattern** (org-celebrated judge taste): the deterministic engine owns ALL world | |
| state and facts. The LLM only interprets the wish, narrates, and picks tool calls from a small | |
| DSL. The LLM never computes geometry, never owns state. | |
| 2. **One wish at a time.** A single serialized queue. Visitors see their queue position. Latency is | |
| reframed as liturgical pacing ("the god grants one wish at a time"). | |
| 3. **The landing page must be gorgeous with ZERO GPU.** The planet renders client-side from the | |
| world-state JSON. Live inference is the second act. Judges often evaluate while GPUs sleep. | |
| 4. **Determinism end-to-end.** Every feature carries a seed; the renderer is a pure function of the | |
| ordered feature list. This makes the Genesis Log replay (see below) free. | |
| 5. **Moderation before execution.** One swastika-shaped forest during judging week ends every award. | |
| 6. **Models β€32B total params** (hard hackathon rule). Only ONE model in the app. | |
| 7. **NAMING:** the wish archive page is called **"Genesis Log"** β NOT "Book of Wishes". A rival | |
| space (aether-garden) shipped a "Book of Ages" on June 11; avoid any perceived imitation. Also | |
| avoid the words "remember/remembers" in copy β that's their tagline. Our frame: *creation*, not | |
| memory. The god *makes*; it does not reminisce. | |
| ## Repo layout & FILE OWNERSHIP (critical β do not touch files you don't own) | |
| ``` | |
| godseed/ | |
| ARCHITECTURE.md (this file β read-only for everyone) | |
| app.py β AGENT B (server) | |
| requirements.txt β AGENT B | |
| README.md β AGENT B (HF Space card w/ full YAML tags) | |
| Dockerfile.fallback β AGENT B (in case sdk:gradio health-check fails) | |
| server/ β AGENT B (sse.py, persistence.py, schemas.py, ratelimit.py) | |
| engine/ β AGENT A (world.py, tools.py, queue_worker.py, moderation.py, summary.py, genesis.py) | |
| mind/ β AGENT C (planner.py, backends.py, prompts.py, grammar.gbnf, mock_scripts.py) | |
| web/ β AGENT D (index.html, style.css, main.js, book.html, planet/*.js, lib/ vendored three.js, mock/) | |
| tests/ β test_engine.py (A), test_api.py (B), test_mind.py (C) | |
| tools/ β AGENT D (shot.mjs β headless screenshot harness, adapted from glassblower) | |
| traces/ (runtime output β wishes.jsonl; gitkeep only) | |
| ``` | |
| Reference code to LIFT (read these, reuse patterns): | |
| - `/Users/andrescarreon/Documents/dev/buildsmall/glassblower/app.py` β FastAPI + mount_gradio_app + | |
| StaticFiles + SSE with `X-Accel-Buffering: no` header. Proven pattern. | |
| - `/Users/andrescarreon/Documents/dev/buildsmall/glassblower/web/main.js` + `web/lib/` β Three.js | |
| setup, vendored libs, postprocessing/bloom wiring. | |
| - `/Users/andrescarreon/Documents/dev/buildsmall/glassblower/tools/shot.mjs`, `shot-live.mjs` β | |
| headless Playwright screenshot harness. | |
| - Glassblower renderer learnings (hard-won): **low transmission + strong emissive** for visible | |
| glowing material (full glass transmission reads as invisible); **selective bloom threshold β0.66**; | |
| **decouple sim from rAF** with fixed-step `seek()`/`tick()` (headless Chromium throttles rAF). | |
| ## World model | |
| The world is an **append-only ordered list of Features**. World-at-epoch-N = features[0..N). The | |
| renderer derives ALL geometry deterministically from this list. Sky/weather are last-write-wins | |
| (but still stored as features so replay works). | |
| ### Feature (canonical JSON) | |
| ```json | |
| {"id": "f_000017", "wish_id": "w_000005", "tool": "spawn_flora", | |
| "args": {"lat": 12.0, "lon": 40.0, "radius_deg": 8, "kind": "glowgrass", "density": 0.7, "hue": 160}, | |
| "seed": 1830293847, "t": 1718200000.0} | |
| ``` | |
| `seed` is assigned by the engine: `seed = crc32(f"{wish_id}:{call_index}") & 0x7fffffff`. The JS | |
| renderer uses the same seed with mulberry32 for all scatter/noise decisions of that feature. | |
| ### Tool DSL β 11 tools (GBNF-friendly: flat args, numbers + enums + short strings) | |
| > The base table below is the original 9; the City Update added `spawn_life` and the Town Mode | |
| > update added `build_district` + `place_road` (full specs in those sections). The live surface is | |
| > **11 tools** β see `engine/tools.py` (`TOOL_NAMES`) for the source of truth. | |
| | tool | args (ranges clamped by engine) | | |
| |---|---| | |
| | `raise_terrain` | `lat` β85..85, `lon` β180..180, `radius_deg` 2..45, `height` 0.01..0.12 (planet radii), `roughness` 0..1 | | |
| | `lower_terrain` | `lat`, `lon`, `radius_deg` 2..45, `depth` 0.01..0.10, `roughness` 0..1 | | |
| | `spawn_flora` | `lat`, `lon`, `radius_deg` 1..30, `kind` β trees\|glowgrass\|mushrooms\|vines\|flowers\|reeds, `density` 0..1, `hue` 0..360 | | |
| | `place_structure` | `lat`, `lon`, `kind` β lighthouse\|monolith\|shrine\|village\|beacon\|arch\|tower\|warehouse\|cafe, `scale` 0.5..2.0, `hue` 0..360 | | |
| | `place_water` | `kind` β stream\|pool, `path` [[lat,lon] Γ1..5] (stream: 2..5 waypoints, becomes glowing spline on the surface β NOT carved; pool: path[0] center), `radius_deg` 1..10 (pool only), `hue` 160..260 | | |
| | `set_weather` | `kind` β clear\|rain\|snow\|embers\|mist\|storm, `intensity` 0..1 | | |
| | `set_sky` | `palette` β dawn\|dusk\|night\|aurora\|ember\|void\|gold, `star_density` 0..1, `moons` 0..3 | | |
| | `inscribe_wish` | `text` β€90 chars (the wish, possibly poeticized), `style` β orbit\|stone | | |
| | `spawn_life` | `lat`, `lon`, `radius_deg` 1..20, `kind` β carts\|birds\|fireflies, `count` 1..12 (integer), `hue` 0..360 | | |
| Engine **clamps** out-of-range numbers (doesn't reject) and rejects only unknown tools/enums with a | |
| terse observation string the model can react to. | |
| ### Genesis state (epoch 0 β MUST match between engine and renderer mock) | |
| ```json | |
| [ | |
| {"id":"f_000000","wish_id":"genesis","tool":"set_sky","args":{"palette":"void","star_density":0.9,"moons":1},"seed":7,"t":0}, | |
| {"id":"f_000001","wish_id":"genesis","tool":"raise_terrain","args":{"lat":12,"lon":40,"radius_deg":28,"height":0.05,"roughness":0.7},"seed":11,"t":0}, | |
| {"id":"f_000002","wish_id":"genesis","tool":"place_structure","args":{"lat":14,"lon":38,"kind":"monolith","scale":1.4,"hue":270},"seed":13,"t":0}, | |
| {"id":"f_000003","wish_id":"genesis","tool":"inscribe_wish","args":{"text":"speak, and it will be made","style":"orbit"},"seed":17,"t":0} | |
| ] | |
| ``` | |
| A barren obsidian world, one monolith, an orbiting invitation. Gorgeous and zero-GPU by design. | |
| ## Agent protocol (the Mind) | |
| Real plan-act-observe loop (Best Agent evidence), GBNF/JSON-constrained: | |
| 1. **Reading** (free-text generation, streamed token-by-token, β€80 tokens): the god interprets the | |
| wish aloud β mood, intent, plan sketch. This is the "plans aloud" wow moment. | |
| 2. **Turn loop** (grammar-constrained JSON, max 7 turns). Each turn the model emits exactly one of: | |
| - `{"thought": "β€160 chars", "call": {"tool": "...", "args": {...}}}` | |
| - `{"thought": "β€160 chars", "done": true, "epitaph": "β€120 chars"}` | |
| After each call the engine returns a terse observation (`"ok: mountains risen at (12,40)"` / | |
| `"rejected: unknown kind 'cactus'"`) which is appended to the context before the next turn. | |
| Planner interface (AGENT C implements; AGENT A's queue worker drives it): | |
| ```python | |
| class Planner: | |
| async def grant(self, wish: str, world_summary: str, | |
| act: Callable[[dict], Awaitable[str]], # executes a tool call, returns observation | |
| emit: Callable[[dict], Awaitable[None]] # streams SSE events (thought_token, etc.) | |
| ) -> WishTrace | |
| ``` | |
| Backends behind `GODSEED_BACKEND` env (mind/backends.py): | |
| - `mock` β deterministic keywordβplan scripts with seeded variety + artificial token delays. Local | |
| dev + headless demos. Must exercise every tool. | |
| - `llamacpp` β llama-cpp-python, **NVIDIA Nemotron-3-Nano-4B GGUF Q4_K_M** (~2.5GB, fits free 16GB | |
| CPU tier), native GBNF grammar. This is the v0 SHIP backend (earns Off the Grid + Llama Champion | |
| badges; real model, no GPU bill). Model path via `GODSEED_GGUF` env; download in code from HF hub | |
| if missing. | |
| - `zerogpu` β transformers + `@spaces.GPU`, **NVIDIA Nemotron-Nano-9B-v2** (the LIVE backend; | |
| in-tree nemotron_h class, trust_remote_code=False, kernel-free native Mamba-2 path). Constrained | |
| decoding via prompt + JSON validation + 1 retry (no GBNF in transformers; keep a strict parser). | |
| NOTE (June 12): the Nemotron-3 4B/30B repos hard-require remote code + mamba-ssm kernels, which | |
| cannot import on the ZeroGPU image β they are NOT usable on this backend. | |
| Moderation (engine/moderation.py, AGENT A): layered β (1) charset/length limits (β€140 chars, | |
| printable); (2) wordlist/regex for slurs, sexual content, hate symbols; (3) LLM yes/no judgment via | |
| the same backend (grammar-constrained `{"allowed": bool, "category": "..."}`), **default-deny on | |
| uncertainty or parse failure**. Rejections are poetic but final ("The god declines this wish."). | |
| ## Queue | |
| `engine/queue_worker.py` (AGENT A): single global asyncio worker. `submit(text, client_id) β | |
| (wish_id, position)`. Caps: 1 pending wish per client, 3/hour per client (B's ratelimit.py supplies | |
| client_id from cookie+IP hash), queue max 50 ("the god is overwhelmed; return at dusk"). Worker: | |
| pop β moderate β planner.grant() β persist trace β emit `wish_granted`. | |
| ## SSE protocol (server/sse.py β single `/api/stream` broadcast to all clients) | |
| ``` | |
| {type:"hello", world_version, epoch} | |
| {type:"queue", length, current: {wish_id, text_preview} | null} | |
| {type:"wish_started", wish_id, text} | |
| {type:"thought_token", wish_id, text} β streamed reading + turn thoughts | |
| {type:"tool_call", wish_id, call_index, tool, args} | |
| {type:"world_delta", feature: {β¦Featureβ¦}} β renderer applies live | |
| {type:"wish_granted", wish_id, epitaph, epoch} | |
| {type:"wish_rejected", wish_id, reason} | |
| {type:"heartbeat"} β every 15s | |
| ``` | |
| Set `X-Accel-Buffering: no` on the SSE response (proven necessary on Spaces β see glassblower). | |
| ## HTTP API (app.py, AGENT B) | |
| ``` | |
| GET /api/state β {world: {version, epoch, features:[...]}, queue: {...}, wishes_recent:[...]} | |
| POST /api/wish {text} β {wish_id, position} (400 w/ poetic reason if moderation fast-path rejects) | |
| GET /api/stream β SSE | |
| GET /api/wishes β [{wish_id, text, epitaph, epoch, ts}] (Genesis Log index) | |
| GET /api/wishes/{id} β full WishTrace (for deterministic replay) | |
| GET / β web/index.html (StaticFiles) | |
| GET /book β web/book.html | |
| /panel β minimal gr.Blocks mounted via mount_gradio_app (satisfies "Gradio app" rule: | |
| altar console β submit a wish, view raw world JSON, link to traces dataset) | |
| ``` | |
| `app.py` must work under plain `python app.py` (uvicorn.run, port = `$PORT` or 7860) β HF sdk:gradio | |
| runs the script directly. ZeroGPU REQUIRES sdk:gradio, so make this work; Dockerfile.fallback is | |
| break-glass only. | |
| ### WishTrace (persisted, one JSONL line per granted wish β traces/wishes.jsonl) | |
| ```json | |
| {"wish_id":"w_000005","text":"...","submitted_at":0,"moderation":{"allowed":true,"category":null}, | |
| "reading":"...","turns":[{"thought":"...","call":{...}|null,"observation":"..."}], | |
| "epitaph":"...","feature_ids":["f_000017"],"model":"...","backend":"llamacpp","ms_total":48211} | |
| ``` | |
| Persistence (server/persistence.py, AGENT B): rebuild world from JSONL on boot (genesis + every | |
| trace's features). After each granted wish: append JSONL; push `traces/wishes.jsonl` to an HF | |
| dataset repo (`HF_TOKEN` + `GODSEED_DATASET` envs; skip silently if unset β local dev). The dataset | |
| IS the persistence across Space restarts (download on boot if local file missing) AND the Sharing | |
| is Caring badge AND Best Agent evidence. | |
| ## Renderer (web/, AGENT D β the WOW is here; budget most effort) | |
| Three.js (vendor from glassblower web/lib). Composition: | |
| - **Planet**: icosphere (subdiv ~6), vertex displacement = sum of feature gaussians (raise/lower) | |
| modulated by seeded noise Γ roughness. On `world_delta`, lerp the displacement in over ~2s | |
| (terrain visibly *rises*). Obsidian-dark base material, biome tinting near flora. | |
| - **Flora**: InstancedMesh per kind, emissive, seeded scatter within radius_deg, scale-in animation | |
| staggered by seeded delay. Glowgrass = shader points; trees/mushrooms = low-poly kit. | |
| - **Water**: TubeGeometry along great-circle spline through waypoints, emissive glow (low | |
| transmission + emissive β glass learnings), gentle flow shader. Pools = glowing discs w/ ripple. | |
| - **Structures**: small low-poly procedural kit (lighthouse with rotating beam, monolith, shrine, | |
| village cluster w/ lit windows, beacon, arch), emissive accents. | |
| - **Weather**: GPU particles (rain streaks / snow / embers / mist planes / storm = rain+flashes). | |
| - **Sky**: palette-driven gradient + stars (Points, density param) + 0..3 moons + aurora bands | |
| (palette `aurora`). Background environment affects planet lighting tint. | |
| - **Inscriptions**: `orbit` = glowing text ring slowly orbiting (canvas texture on curved plane); | |
| `stone` = text plaque at lat/lon. | |
| - **Bloom**: UnrealBloomPass, selective, threshold β0.66. Cap pixelRatio β€2. Must hold ~60fps on a | |
| laptop, degrade gracefully on phones (reduce instances/subdiv). | |
| - **The god's gaze**: on `tool_call`, camera eases to the target lat/lon, then resumes slow | |
| auto-orbit. This is the demo money-shot. | |
| - **Sim/replay core**: fixed-step `tick()`/`seek(t)` decoupled from rAF (headless-safe, makes | |
| Genesis Log replay + demo capture free). | |
| UI (index.html): full-bleed canvas. Wordmark "GODSEED" (letterspaced display serif β e.g. Cormorant | |
| Garamond via Google Fonts), thin HUD: wish input ("make a wish"), queue chip ("3rd in line Β· the god | |
| grants one wish at a time"), thought ticker (mono font, streaming), epoch counter ("Epoch 17 Β· 23 | |
| wishes granted"). Deep-space black, gold/violet accents. NO generic AI-gradient-purple-on-dark-card | |
| look β aim for liturgical-modern, like a Kinfolk issue about a small god. Footer: "Genesis Log" link. | |
| book.html (Genesis Log): list of granted wishes (epitaphs); click one β replay THAT wish: render | |
| world at features[0..K), then animate wish K's deltas with its recorded thoughts replayed in the | |
| ticker. Pure client-side from `/api/wishes/{id}`. Zero GPU. Shareable URL `#w_000005`. | |
| `web/mock/` : a static mock world JSON (genesis + ~10 varied wishes exercising ALL 8 tools) + a | |
| scripted SSE-like event feed (JS array) so the renderer is fully developable + screenshottable with | |
| NO backend: `python3 -m http.server 8123 --directory web` + `?mock=1`. | |
| **AGENT D self-verifies**: adapt glassblower `tools/shot.mjs`, screenshot at multiple sim times, | |
| LOOK at the PNGs, iterate until genuinely beautiful. Don't ship the first thing that renders. | |
| ## Local dev | |
| - Python 3.12 venv via uv (`uv venv -p 3.12 .venv && uv pip install -r requirements.txt`). | |
| System 3.14 is too new for the ML stack. | |
| - `GODSEED_BACKEND=mock PORT=7891 .venv/bin/python app.py` | |
| - requirements.txt: keep base CPU-light (fastapi, uvicorn, gradio, pydantic, huggingface_hub, | |
| llama-cpp-python). torch/transformers/spaces go in a clearly-marked ZeroGPU block (commented or | |
| extras) until the benchmark decision. | |
| ## City Update (v1.1 contract β June 12 PM) | |
| Player-requested ("building games": cafeterias, big buildings, warehouses, cars). | |
| Three additions, same diorama soul. Backwards compatible: old features render | |
| unchanged; additions are additive enums + ONE new tool (copy that says "exactly | |
| 8 tools" must be updated to 9 everywhere: README, ARCHITECTURE intro, prompts). | |
| 1. **New structure kinds** (place_structure enum += `tower`, `warehouse`, `cafe`): | |
| - `tower` β tall slender multi-tier block, dense lit windows, slow-pulsing | |
| rooftop light. The "big building". | |
| - `warehouse` β long low gabled hall, one big glowing door, sparse windows. | |
| - `cafe` β small warm box: awning plane, spill of warm light on the ground, | |
| 2-3 tiny table dots outside. Hue tints the glow. | |
| All three: low-poly procedural kit pieces matching existing style (emissive | |
| accents, seeded variation), instanced where possible. | |
| 2. **New tool #9 `spawn_life`** β moving inhabitants: | |
| `{lat, lon, radius_deg 1..20, kind: carts|birds|fireflies, count 1..12, hue 0..360}` | |
| - `carts` β tiny lantern-cart sprites that GLIDE along the nearest stream | |
| path within radius (fallback: a seeded loop around the anchor). Distant | |
| traffic at dusk. Speed slow, constant, sim-time driven. | |
| - `birds` β a small flock circuiting above the terrain at low altitude, | |
| seeded loop, slight bob. | |
| - `fireflies` β drifting glow points inside the radius, near the ground. | |
| Renderer: new `web/planet/life.js`, instanced, deterministic seeded paths | |
| driven by tick(simTime) (replay-safe, headless-safe). Engine: spec + clamps | |
| in tools.py; features append-only as usual. GBNF grammar + mock scripts + | |
| tool docs must all gain the tool (docs auto-render from as_dict β). | |
| 3. **Cinematic descent** ("visit it"): | |
| - `rig.descend(targetDir, {duration})` β swoop from orbit to ~1.06R above | |
| ground (clears terrain via the analytic height fn), slow 20-30Β° glide arc | |
| over the target with gentle look-ahead, then ease back to orbit. Fully | |
| sim-time deterministic. | |
| - Triggers: a "descend" link on the epitaph card after a wish is granted | |
| (targets the wish's last landed feature), and on Genesis Log replays after | |
| the final delta. ESC / click cancels. No free controls, no collision β | |
| it's camera liturgy, not an FPS. | |
| Build ownership when this ships: (A) engine/tools.py + mind/grammar.gbnf + | |
| mind/mock_scripts.py + tests; (B) web/planet/structures.js (new kinds only); | |
| (C) web/planet/life.js + web/planet/camera.js + main.js/book.js descend hooks. | |
| Copy updates (README 8β9 tools etc.) ride with (A). | |
| ## Town Mode (v1.2 contract β June 12 PM, "Town on the planet") | |
| User feedback: a city wish produced one tower on the far side of a planet-sized sphere β reads empty. | |
| The fix is a deliberate experience shift: the DEFAULT view is a town you build up close (SimCity feel); | |
| the full planet becomes the dramatic zoom-out reveal. Append-only world preserved; genesis UNCHANGED | |
| (the live shared world must keep rebuilding identically). All additive. | |
| ### The town anchor (engine + renderer compute IDENTICALLY) | |
| `townCenter(world)` = the seeded-weighted centroid (unit-vector mean, renormalized) of all | |
| `place_structure` + `build_district` feature directions, EXCLUDING genesis. Fallback when none exist: | |
| the genesis monolith at lat 14, lon 38. Engine exposes it in the world summary; the renderer uses it | |
| for the default camera. A town gets a deterministic name from `crc32(round(lat),round(lon))` β a small | |
| curated name list (e.g. "Lowmere", "Ashford", "Tessen") so the summary + HUD can say "the town of X". | |
| ### Density comes from each tool call, not from many (the 9B reliably plans only ~2-3 calls) | |
| New tools (now **11** β update every "9 tools" copy β 11; list build_district + place_road): | |
| | tool | args | | |
| |---|---| | |
| | `build_district` | `lat`,`lon`,`radius_deg` 2..15, `density` 0..1, `hue` 0..360 β renderer places a SEEDED neighborhood: a cluster of small houses on a rough grid, footpath/road connectors between them, and 1 occasional civic building. ONE successful call = a visible block. This is the SimCity unlock. | | |
| | `place_road` | `path` [[lat,lon] Γ2..6] β a paved, faintly-lit road spline laid ON the surface; visually DISTINCT from `place_water` glowing streams (warm stone/amber, matte, dashed centerline feel β not emissive cyan). | | |
| `place_structure.kind` enum += `bank`, `market`, `house` (single landmark homes/civic buildings; the | |
| existing low-poly kit conventions). Full set: lighthouse|monolith|shrine|village|beacon|arch|tower| | |
| warehouse|cafe|bank|market|house. | |
| ### Steering the god to GROW THE TOWN (mind/prompts.py + engine/summary.py) | |
| - summary.py: name the town + its center + building count ("The town of Lowmere stands near (14,38): | |
| 3 towers, a cafΓ©, 12 houses."). When the wish asks for buildings/a city, the god should ADD to the | |
| existing town, not scatter β build near townCenter, connect with `place_road`, and reach for | |
| `build_district` for neighborhoods. Persona gains: "You are growing one town. New buildings rise | |
| beside the old ones, linked by roads β never alone in the wilderness." | |
| - This is steering, not enforcement (keeps the "god decides" purity). The camera following density | |
| means even a stray build is visible; over wishes the town concentrates. | |
| ### Camera = two modes (web/planet/camera.js + main.js) | |
| - **TOWN view (DEFAULT on load):** camera sits LOW and close, framing a ~28Β° cap around townCenter β | |
| buildings read large, like standing over a model town. This is what visitors see first now (not the | |
| full orbit). | |
| - **WORLD view (the reveal):** a HUD control "behold the world β" eases out to the full-planet orbit | |
| (today's gorgeous wide shot) and back. The demo money-move: build the town, then pull back to show | |
| it's one patch on a shared planet. | |
| - On each `world_delta`/grant, frame the new feature WITHIN the town zoom (don't fly to the far limb). | |
| - The existing descent stays (epitaph card) β now it descends within the town. | |
| ### Tame the god-needle | |
| The orbital "god instrument" needle currently dominates the frame (huge gold double-cone). In TOWN | |
| view it must be small/high or hidden; show it prominently only during active granting (it "writes" the | |
| wish) and in WORLD view. Scale it down ~60% at rest. | |
| ### Ownership for the Town Mode build | |
| - ENGINE+MIND (A): engine/tools.py (build_district, place_road, +3 structure kinds), engine/summary.py | |
| (town name+center+counts), engine/world.py (_observation for new tools), mind/grammar.gbnf, | |
| mind/mock_scripts.py (town-growth scripts), mind/prompts.py (grow-the-town steering + 11-tool copy), | |
| tests; README/ARCHITECTURE 9β11 copy. | |
| - RENDERER (B): web/planet/structures.js (bank/market/house kit), web/planet/district.js (NEW β | |
| seeded house+road neighborhood), web/planet/roads.js (NEW β paved road splines) OR fold roads into | |
| water.js styling, web/planet/world.js wiring, needle scale-down (find it β likely sky.js or scene.js). | |
| - CAMERA+HUD (C): web/planet/camera.js (TOWN/WORLD modes + townCenter framing), web/main.js + book.js | |
| (default TOWN view, "behold the world" toggle, frame-within-town on delta), web/index.html + | |
| style.css (the toggle control). townCenter helper shared via web/planet/util.js. | |
| ## Deploy plan (not in this build phase β for context) | |
| 1. Personal benchmark Space first: llamacpp 4B on free CPU + (separately) ZeroGPU 30B-A3B; measure | |
| tok/s before committing the headline backend. | |
| 2. Org Space `build-small-hackathon/godseed`, sdk:gradio. README YAML: full track + sponsor + badge | |
| tags (copy exact tag strings from case0/her READMEs β AGENT B: fetch | |
| `https://huggingface.co/spaces/build-small-hackathon/case0/raw/main/README.md` and mirror tag style). | |
| 3. v0 ships TONIGHT (June 12) on llamacpp 4B. Social + like-farming starts immediately. | |