// live preview
// the vision
Nobody lets you drive your real neighborhood. Neighborhood City stitches OSM streets + Street View facades into a 1:1, browser-based, Animal Crossing-aesthetic driving toy — warm, chunky, low-poly, unmistakably that block. The catch: a 1:1 of a real home is a dox, so the build is password-gated and the public-reach goal is retired (pivoted 2026-06-14). The real product is the pipeline itself — point it at ANY address and get a beautiful, playable city. The private Hyde Park build is the showcase; custom bakes are the model.
read the full vision →
// milestones · north star
- ✓It exists — builds + runs: real OSM streets, drivable car, baked facade atlas, minimap, HUD
- ✓It's live (private) — neighborhood-city.walls.sh, password-gated (anti-dox); /health + /metrics stay open (no location data)
- ✓It looks like Animal Crossing — tiny-planet curvature, Kuwahara grade, warm craftsman palette, live-oak canopy, sidewalks, day/night incl. a gorgeous golden hour; recognizably Hyde Park in AC light, desktop + mobile (objective criteria met; Pat's subjective sign-off is the only thing left)
- →It looks real — real Google Street View facades baked (human-gated: Google Maps API key + spend)
- ✓The bake retargets — address → bake → playable in-game, end to end. scripts/bake.mjs takes a human address (BAKE_ADDRESS via Nominatim) or coords; the game loads any baked world via ?world=<path>. Proven: Georgetown DC drives + renders in AC style (Lap 25 screenshot).
- →Custom-bake product shape — `npm run bake:city -- "<address>"` does address → playable city in one command (Lap 27). Remaining to charge: billing + a job queue. (Facade texturing is a shared generic atlas, not a blocker; Street View is an aesthetic upgrade.)
⚑ needs you · 2
Day/night optional polish (Pat): the cycle now works (Lap 42) — sun button cycles noon/golden/night, default unchanged. Golden hour is gorgeous; night reads as a muted dusk (the Kuwahara grade lifts the darks). If you want a richer/darker night under the filter, the knobs are LIGHT_MODES[2] in App.tsx (sky/ambient/hemi). Preview with ?light=2.
Run real Street View facade bake (npm run streetview -- --fetch)Needs GOOGLE_MAPS_API_KEY in .env + billing enabled (~$ a few)
// the work · 55
- ▸
Keep making the private build gorgeous — visual/playtest laps toward 'unmistakably that block in Animal Crossing light' (the current → rung).
- ▸
To actually charge for custom bakes: a job queue (address → bake:city → hosted playable URL) + billing. The bake step is one command now (Lap 27); these are the only true remaining gaps. Human-gated on Pat (pricing + payment account) before building.
- ▸
the village district OSM building tags wrong — commercial buildings at a main intersection appear in world but tagged as generic 'yes', rendering as house-height boxes instead of 1-story storefronts. Real Street View bake would fix this.
- ✓Lap 50 (2026-06-15): in-game city picker — the live build is now a 3-continent drive-anywhere showcase. Added 2 more demo worlds (Paris 740KB, Tokyo 399KB) + a CityPicker dropdown in the HUD that switches between the 4 shipped worlds (Hyde Park/Beacon Hill/Paris/Tokyo) via ?world=, reflecting the current city and hiding for custom bakes. Deployed + verified live on the gated site: all 3 demo worlds serve 200, and switching to Tokyo shows the picker selection + a live CJK street name in the HUD. The product now demonstrates its own range, one click apart. · Jun 15
- ✓Lap 49 (2026-06-15): 'drive anywhere' is now LIVE, not just documented. Confirmed Milestone 4 truly gated (no Google key in Railway env or .env). Then shipped a second drivable city in the build: committed public/demo/beacon-hill.json (607KB public landmark, non-dox) drivable via ?world=/demo/beacon-hill.json. Verified live: deployed, serves 200 on the gated site, renders 'Beacon Hill, Boston / Pinckney Street' driving alongside the Hyde Park showcase. The live product can now demonstrate the claim, not just the docs. · Jun 15
- ✓Lap 48 (2026-06-15): audited the core driving (never examined before — only the look). PlayerCar physics + collision in App.tsx are solid: reasonable arcade feel, building collision snaps to last safe position, and safe is initialized to spawn (not origin) so a wall-hit can't teleport you to 0,0. No bug. Wall collision is basic (snap not slide) — a feel polish I can't verify in the static harness, left it. The game is now verified end to end: look + geography + bake + drive. · Jun 15
- ✓Lap 47 (2026-06-15): heavy-bake heads-up — completed the viability bracket. Lap 29 guarded too-sparse (reject empty bakes); this guards too-heavy: bake:city now warns when a bake exceeds ~6000 buildings / ~2.5MB (slow first load, esp. mobile) and nudges toward a 700-1000m radius — a heads-up, not a rejection. Verified: Charleston 1500m (7215 buildings, 2.6MB) warns; Beacon Hill 700m is clean. · Jun 15
- ✓Lap 46 (2026-06-15): the hardest geography edge holds — Tokyo bakes, Japanese names render in the HUD. Stress-tested non-Latin script + Japan's block-addressing (few named streets): Shibuya, Tokyo is viable (900 roads/3286 buildings, 292 named), branded from the Latin input, and the HUD shows real Japanese street names (井ノ頭通り) cleanly. CJK works because nothing assumed ASCII; block-addressing is fine because the viability gate counts roads not names. drive-anywhere now verified across continents, writing systems, and addressing schemes. · Jun 15
- ✓Lap 45 (2026-06-15): proved 'drive anywhere' is GLOBAL, not US-only. Every prior stress-test was American; baked Le Marais, Paris as an international test — works end to end: 1000 roads/4303 buildings, branded correctly, ~49m Haussmann blocks, the Seine present (23.2M m2 via the relation-water fix), French street names render in the HUD with diacritics. Documented as a verified international row in CITIES.md. The 'any address' claim had a silent 'US' asterisk for 12 laps; now actually verified across an ocean. · Jun 15
- ✓Lap 44 (2026-06-15): full bake:smoke verified green — all 4 city types pass (19/19 checks: showcase/coastal/downtown/cold), confirming recent visual work (day/night, branding, water/height/tree fixes) didn't regress any bake. Honest plateau: the unblocked backlog is complete — milestones 1/2/3/5 done; 4 (real Street View facades) and 6 (billing+queue) are human-gated on Pat. Laps are now verification/maintenance until Pat unblocks Street View, takes the pricing call, or redirects. · Jun 15
- ✓Lap 43 (2026-06-14): mobile verified healthy + Milestone 3 ticked (looks like Animal Crossing). Live showcase at 390x844: compact HUD, game fills screen, joystick+pedals+minimap clean — no regression from recent visual changes. Tried a moonlit-night tweak, reverted it (the Kuwahara black-lift keeps the ground bright regardless of palette; a real dark night needs StyleFX integration — left as Pat's knob). Ticked Milestone 3: oak canopy, craftsman palette, sidewalks, curvature, day/night incl. golden hour — desktop + mobile. · Jun 14
- ✓Lap 42 (2026-06-14): the day/night cycle actually works now — golden hour is gorgeous. Lap 39's dead HUD sun-button (styleOn lighting hardcoded daylight, ignored lightMode) is fixed WITHOUT changing the default: noon now holds the exact prior daylight, default=noon, styleOn reads the palette (added per-mode ambient). So the default look is byte-identical, but the sun button + ?light= cycle noon/golden/night under the AC filter. Verified all 3 + live: golden hour (warm sunset) renders on the deployed gated site. Resolved the prior 'Pat's aesthetic call' todo via a default-preserving implementation. · Jun 14
- ✓Lap 41 (2026-06-14): playtest audit of the live showcase (interior streets) — no objective rendering bugs, renders cleanly. Closed a gap in the bake:smoke guard: it tested 3 retargeted cities but never the Hyde Park showcase itself. Added a default-bake case asserting palms-ok at 27.9, 'Hyde Park, Tampa' branding, the bay (>1M m2 water). Verified: checks pass against a real HP bake; the live run's transient Overpass hiccup correctly reported SKIP not FAIL. · Jun 14
- ✓Lap 40 (2026-06-14): CITIES.md — a verified menu of drive-anywhere example bakes (Hyde Park/Beacon Hill/Georgetown/Charleston/Chicago Loop) with real commands, observed counts, and what each shows off, plus a 'what makes a good bake' guide. Companion to bake:smoke (asserts) — this documents. Verified the numbers aren't fabricated: re-baked Beacon Hill -> 591 roads/1651 buildings, exactly matching the table. · Jun 14
- ✓Lap 39 (2026-06-14): added ?light=<0|1|2> URL param (time of day) for deterministic lighting screenshots. Auditing with it found the day/night HUD sun-button is DEAD in the default AC-filter mode: the styleOn lighting branch hardcodes daylight and ignores lightMode, so golden/night palettes are dead code there. Verified the cycle works via ?style=off&light=2 (a genuinely beautiful night). Did not change the default mood (Pat's aesthetic call) — see todo. · Jun 14
- ✓Lap 38 (2026-06-14): npm run bake:smoke — codified the drive-anywhere stress test into a regression guard. bake-smoke.mjs bakes a coastal/downtown/cold-inland city and asserts each still gets right what Laps 33-37 fixed (multipolygon harbor water, real tower height, no cold-climate palms, own place branding) + base viability/schema/spawn. Network errors report SKIP not FAIL. Verified: 13/13 checks pass across Charleston/Chicago/Beacon Hill. · Jun 14
- ✓Lap 37 (2026-06-14): retargeted downtowns get their real height. buildingHeight() scaled explicit OSM height by 0.7 (a Tampa-LIDAR-to-roof-peak artifact) — correct for the showcase but ~30% too short everywhere else, flattening downtown skylines. Made it default-only (x0.95 for retargets). Verified: The Loop Chicago tallest 323m, 91 buildings >100m, renders a real tower skyline; Hyde Park heights byte-identical (showcase unchanged). With Laps 33-37 the bake handles multipolygon/spawn/climate/branding/height correctly for any address. · Jun 14
- ✓Lap 36 (2026-06-14): a retargeted bake is branded as its own city, not 'Hyde Park, Tampa'. The HUD hardcoded the Tampa place name in 4 spots (brand title+subtitle, district-over-water 'Hillsborough Bay', district fallback). Threaded a place:{title,subtitle} field through bake.mjs -> world.json -> HUD with Tampa as fallback. Verified with screenshots: Georgetown shows 'Georgetown, Washington DC / Georgetown'; the no-place showcase still shows Hyde Park (unchanged). Build clean. · Jun 14
- ✓Lap 35 (2026-06-14): climate-aware tree species — no palms in cold-climate bakes. Tree species were hardcoded Tampa-style (~15% palms everywhere), so a Boston/DC/NYC retarget sprouted palm trees. Added a latitude gate in worldGeometry.ts (palms only when |center.lat| < 34): Tampa/Charleston keep palms, Boston/DC/NYC get oaks. Verified: Georgetown DC now all-oak; Bayshore Tampa palms intact (gate is identity for Tampa, showcase unchanged). Also avoided a hollow lap: the 12 greens Lap 34 recovered for Hyde Park are all 1358-1628m out (map edge, invisible), so didn't re-bake the showcase for them. · Jun 14
- ✓Lap 34 (2026-06-14): parks & landuse get the same relation fix as water — multipolygon coverage now complete. leisure/landuse were queried way-only, dropping relation-tagged greens. Added relation[leisure]/relation[landuse] + assembly. Verified: Central Park 316->317 parks (+1 relation); Hyde Park 57->69 (Tampa had ~12 relation greens missing all along). All four area-feature classes (building/water/leisure/landuse) now query way AND relation. Committed world.json untouched. · Jun 14
- ✓Lap 33 (2026-06-14): coastal cities now get their water. Stress-testing 'drive anywhere' on Charleston SC (a peninsula) exposed a real bug: the bake fetched way[natural=water] but not relation[natural=water], and big water (harbors, rivers) is almost always multipolygon relations — so the entire Charleston Harbor was missing (grass where water should be). Tampa only worked because its bay is natural=coastline ways. Fixed in scripts/bake.mjs (relation query + water-relation assembly); bumped bake:city default radius 900->1200m. Verified: Charleston 26 tiny ponds -> 74 incl. two large water relations (harbor renders); Hyde Park showcase unaffected. · Jun 14
- ✓Lap 32 (2026-06-14): added .env.example documenting all 12 env vars (PORT, SITE_PASSWORD, PLAYS_FILE, CANONICAL_HOST, GOOGLE_MAPS_API_KEY, 7x BAKE_*) across serve.mjs/bake.mjs/bake-city.mjs/streetview.mjs — none were documented, an onboarding gap now that the bake is a product. Verified the var list by grep and each default against the code. Also live-playtested the south/Hyde Park Village edge (sparse, known, no new bug). · Jun 14
- ✓Lap 31 (2026-06-14): restored live playtesting on the gated site. The anti-dox password gate had broken the loop's own screenshot harness — shoot.mjs couldn't authenticate, and credentials-in-URL makes the app's fetch('/world.json') throw. Added --auth=user:pass (or SITE_PASSWORD env) -> Playwright httpCredentials. Verified by screenshotting the live gated home spawn (804KB game vs 70KB error before), which also confirmed Lap 30's water fix is live in production, not just locally. · Jun 14
- ✓Lap 30 (2026-06-14): playtest audit caught + fixed water flooding the inland home spawn. The #1 first-impression view showed blue water bleeding into both sides of Richardson Pl. Cause: the tiny-planet curvature shader warped two coarse circleGeometry discs (ocean-floor Y-0.5, ground Y-0.3, only 0.2m apart) so the ocean poked through. Fix in src/App.tsx: ocean backdrop -0.5->-6m + ground rebuilt as a radially-tessellated ringGeometry so curvature bends it smoothly. Verified before/after screenshots: home is clean green grass again; real bay untouched. Deployed; health ok, authed 200. · Jun 14
- ✓Lap 29 (2026-06-14): bake:city viability gate. It printed '✅ playable' even for a 0-road empty world (e.g. a remote desert address) — a custom bake you'd charge for can't be a void. Added a gate: read output counts, require ~30+ roads / 60+ buildings, else print 'too sparse', delete the artifact, exit 2; success line now shows real counts. Verified: Shoshone CA -> exit 2 (0 roads, artifact removed); Beacon Hill -> exit 0 (591 roads). Geocode-failure path already exits 1 cleanly. · Jun 14
- ✓Lap 28 (2026-06-14): refreshed README to match reality. It still called the game 'GTA Vice City-style / PS2-era', predating the Animal Crossing aesthetic, the anti-dox private pivot, and the whole custom-bake product. Rewrote it: AC framing, private-by-default callout, a Custom bakes section (bake:city + ?world=), env-driven bake target, honest 'archetype facades until Street View runs' note, roadmap mirroring VISION. Verified every referenced command/file/loader exists. · Jun 14
- ✓Lap 27 (2026-06-14): npm run bake:city — the custom-bake product in one command. scripts/bake-city.mjs geocodes an address, bakes OSM → public/cities/<slug>.json, and prints the ?world= URL to play it. Confirmed texturize.mjs is a generic per-building-KIND atlas (not per-city), so no per-city texture step is needed. Verified: bake:city 'Beacon Hill, Boston' 700 → 591 roads / 1651 buildings, renders cleanly in-game with a good street spawn. The mechanical product is complete; only billing + a queue remain to charge. · Jun 14
- ✓Lap 26 (2026-06-14): retarget spawn lands on a real street, not a back alley. The bake's no-HOME fallback snapped home to the nearest house centroid, whose nearest road is often a rank-4 service alley (5m wide, building wall 3.2m away) — the jammed-against-building spawn. Now snaps home to the nearest drivable street (rank 1-3). Verified on Georgetown: home → rank-3 residential street (0.0m), nearest wall 8.1m (was 3.2m); screenshot shows the car on a proper road with a centre line. Hyde Park untouched (real HOME parcel). · Jun 14
- ✓Lap 25 (2026-06-14): a retargeted bake is now PLAYABLE in-game. loadWorld() in src/world.ts honors ?world=<path> (same-origin static paths only). Verified by Playwright screenshot: ?world=/georgetown.json renders Georgetown DC in Animal Crossing light — clearly a different city than Hyde Park. Address → bake → playable now works end to end (Milestone 5 reached). Found: the retarget spawn lands jammed against a building (home snaps to nearest house centroid when no HOME street is known) — needs a snap-to-road fix. · Jun 14
- ✓Lap 24 (2026-06-14): address in → world out. Added geocode() (Nominatim) + BAKE_ADDRESS env to scripts/bake.mjs, resolved via top-level await so an async geocode sets CENTER before the sync projection consts. The pipeline is now literally 'address string → world.json'. Proven: BAKE_ADDRESS='Georgetown, Washington, DC' → 38.9087,-77.0653 → 468 roads / 3267 buildings (valid world). Defaults still resolve to Hyde Park; showcase untouched; build clean. · Jun 14
- ✓Lap 23 (2026-06-14): the bake retargets to ANY address. Parameterized scripts/bake.mjs via env (BAKE_LAT/LON/RADIUS, optional BAKE_HOME_NUM/STREET, BAKE_OUT) — Hyde Park stays the default so the showcase is untouched. Proven end-to-end: baked Beacon Hill, Boston (22,454 OSM elements → 551 roads, 1617 buildings, 330 parks, 1438 trees) to a temp file; defaults still produce the byte-identical Hyde Park world (deterministic bake). The data half of 'drive anywhere' is real and reproducible; remaining gap is geocoding + loading a non-default world into the running game. · Jun 14
- ✓Pivot (2026-06-14): retired the '1,000 strangers' North Star. Pat gated the whole build behind a password (anti-dox, commit 5a7e915) because the 1:1 render reveals his real home — incompatible with public reach. Asked him the fork; he chose 'keep it private'. New direction: make the private build gorgeous + prove the bake retargets to ANY address; the custom-bake pipeline is the product, the private build is its showcase. Rewrote VISION (North Star, ladder, mandate, money hypothesis, principles) and this dossier to match. · Jun 14
- ✓Share-ready: OG/Twitter cards now point to the canonical neighborhood-city.walls.sh (were pointing at the raw Railway origin). The Lap 9 Host-header trick is defeated by two proxy layers — both the walls edge proxy and Railway's own edge rewrite Host/X-Forwarded-Host to the internal Railway hostname — so the canonical host had to be pinned in serve.mjs. Also verified the /play beacon forwards through the proxy (POST /play?probe=1 → 204, count unmoved): a real stranger's play will now register. · Jun 13
- ✓It's LIVE at neighborhood-city.walls.sh — flipped status building→live so the edge proxy's /api/routes includes the wall and routes the subdomain to the Railway origin. Root cause of the never-moving counter: the subdomain had fallen through to the walls router ('no such wall'); prior laps curled /health, got 200 from the WALLS router and mistook it for the game. The game origin was serving fine all along. *.walls.sh is wildcard — no Cloudflare token was ever needed. Verified: /health→ok, /→game title+JS, /metrics→real plays. Milestone 2 reached. · Jun 13
- ✓Building detail radius 170m→300m — full windows/porches/chimneys now rendered out to 300m from home instead of 170m; neighborhood looks richer from street level and overhead. · Jun 13
- ✓Minimap N label + spawn heading fix: added 'N' north indicator to minimap canvas; fixed home spawn to face outward (onto road, away from house) instead of facing the house/south/bay. Disorientation resolved. · Jun 13
- ✓OG image refreshed to show sidewalked streetscape (Lap 17 — predates prior laps). Link previews now show sidewalks + craftsman palette + oak framing. · Jun 13
- ✓Sidewalks: warm concrete 2.2m strips alongside all residential roads — transforms 'road in a field' into a real AC-style neighborhood streetscape. · Jun 13
- ✓Bake radius 1000m→1500m — 400→833 roads, 1855→3752 buildings. a main avenue (the village district) goes from 8 buildings to 228 within 300m. World now covers full the neighborhood neighborhood. · Jun 13
- ✓Spawn override ?sx=&sz= params added for developer playtest. the waterfront playtested (looks correct). Water color deepened to #2a9fd8. Found: the village district commercial buildings missing from OSM. · Jun 13
- ✓OG preview image refreshed: clean 1200x630 shot with craftsman palette, no curvature artifact. 571KB (was 950KB). Deployed. · Jun 13
- ✓the neighborhood building palette updated to historic preservation colors: warm grays, craftsman whites, removed lavender/mint/coral. Porch+chimney frequency bumped to match real Craftsman bungalow character. · Jun 13
- ✓Controls hint fixed: now shows in lowpoly mode (was gated on photoreal-only condition). Auto-dismisses on first drive. Hidden on mobile. · Jun 13
- ✓Plays counter persists across redeploys — Railway volume mounted at /data, PLAYS_FILE env var set. Verified: counter survived a full redeploy. · Jun 13
- ✓Milestone 3 substantially complete: curvature tuned to 2600m, fog 180/860, dynamic OG URLs — screenshots look like AC on W Richardson Pl · Jun 13
- ✓OG/social meta tags + 1200x630 preview image — link shares now show title + AC neighborhood screenshot · Jun 13
- ✓Spawn moved to road in front of 1821 W Richardson Pl — oak canopy + colonial house visible immediately on first load · Jun 13
- ✓Mobile viewport pass — compact 2-col HUD; game canvas now fills ~80% of phone screen (was 25% hidden behind stacked HUD) · Jun 13
- ✓Planted dense live oak canopy — spacing 13m, 85% oak, 3-lobe 5m-radius crown arching over road (was 6 OSM-tagged trees, now hundreds procedural) · Jun 13
- ✓Incubated — repo, vision, loop, deploy skeleton; production build verified clean · Jun 13
- ✓Deployed to Railway — neighborhood-city-production.up.railway.app/health → 200 ok · Jun 13
- ✓Updated vision: Animal Crossing aesthetic + real Maps data iteration + playtest mandate + marketing gate · Jun 13
- ✓AC palette pass: pastel walls (sage, sky blue, coral, lavender, mint), colorful roofs (red tile, terracotta, forest green). Default mode → lowpoly when no API key. Curvature 2400→1800m. Deployed + verified. · Jun 13
- ✓Committed full source tree — StyleFX/curvature/params/shoot/Photoreal/world/styles were untracked; fresh clone now builds cleanly · Jun 13
- ✓Plays counter: POST /play beacon fired 5s after world loads (not HTML load); probe=1 excluded; verified 0→1 locally; deployed · Jun 13