Tal Siach

Tutorial · Yalla Delivery, Tel Aviv · September 2026

How to build a game of your own city with an AI agent

I built Yalla Delivery, a scooter-courier game set in a Tel Aviv that locals recognize, with an AI coding agent, open map data, Blender and Three.js. This is the method in the order to do it, with the prompts. Save it, then hand it to your agent.

Two ways to use this. Read the eight steps and do them for your city. Or send this link (or the Markdown) to your LLM, tell it which city and which game you have in mind, and let it work from here. The second way is the one I'd pick.
Get the kickoff prompt Download as Markdown
Dizengoff Square. Real assets from the game, lit by the time of day. Drag to look around.
Lit by the sun over Tel Aviv

Exported from the game's Blender source, cropped to 120 m around the fountain. 237k triangles, 1.2 MB.

The one idea

There is no magic prompt. There is a loop: give the agent real map data and dated photos, split the scene into named parts, judge the actual render against the real photo, fix the biggest miss, repeat.

You don't need to be a game engineer. You need a small first milestone, a method you can copy, and prompts you can paste. That's this page. My part was picking the scope, the gameplay, what mattered visually, and looking at every render. The agent wrote the Blender Python, wired up Three.js, wrote the tests and ran them.

What you'll build

A browser game with one loop the player repeats:

inputkeyboard or touch: accelerate, sprint, brake, reverse, hop
motionscooter physics, ground height, blockers, collisions with cars, buses and pedestrians
orderthe pickup circle stops the scooter; a timer and food condition start
deliveryreach the customer's circle before the timer runs out; they react; you get paid
progressevery three deliveries the level gets harder; coffee, health and shield pickups help
endout of health or time: end-of-shift score, restart
Riding the promenade at Frishman beach on a phone
The promenade at Frishman, on my phone. Beach, buses, the striped hotel.
Under the promenade pergola, on a phone
Under the pergolas, heading to the Frishman pickup.

And the pipeline that makes the city look like your city:

01
OpenStreetMap + municipal open data
Roads, bike lanes, building footprints
02
Shared local coordinates
Metres, one origin, one axis contract
03
Python inside Blender
One module per landmark, reproducible
04
GLB export
Static merged, material roles and moving parts kept
05
Three.js in the browser
Game loop, navigation, checks

What you need

1Define one loop

Before any world exists, write down what the player does every thirty seconds and how they know they won or lost. Pick up an order, reach a destination, clear success and failure feedback. Nothing else.

You get: a one-page brief with loop, controls, success, failure, restart, and what's out of scope.

Prompt · establish the loop01
Build a browser-playable game about [local activity]. State the immediate objective, level objective, progression and lose condition. Keep the tone affectionate. Make the first playable loop coherent before adding content. Use an original, unbranded visual identity. List what the player does every 30 seconds and how they know they succeeded.

2Lock the ground truth

Pick one map origin (longitude, latitude), one reference camera with position, heading and field of view, and the footprint of one building. Pull roads and bike lanes from OpenStreetMap and footprints from your city's open data. Collect street photos and write down when each was taken.

Keep a ledger from the first download: URL, retrieval date, photo date, footprint and road IDs, and a column that says measured or estimated. The day you downloaded a map and the day a photo was taken are different things, and filenames lie.

For Tel Aviv the origin was longitude 34.774207, latitude 32.077963. In Blender, X is east, Y is north, Z is up. Three.js gets [x, z, -y]. Every asset lives on that one grid. It's a flat local approximation, which is fine for a compact district.

The in-game navigation map
The in-game map, built from the same coordinates as the world
Crossings and signs on Dizengoff
Crossings and signs placed from map data, then checked against photos

You get: a source folder with the ledger, the footprint IDs and the dated reference photo. Without one shared origin every asset lands somewhere slightly different and nobody recognizes the street.

Prompt · reference a real place02
Reconstruct [specific 100 to 200 m section] from real evidence. Gather street and bike-lane geometry, building footprints, dated street-level photos and a matching aerial. Record source URLs, IDs, retrieval dates and photo capture dates. Lock one hero camera with coordinates, heading and field of view. Distinguish measured geometry from photo estimates and invented detail. Do not start with a generic city and label it afterward.

3Graybox the real place

Plain boxes for the actual road, sidewalk and main buildings, at true scale, on the real footprints. Ride through it. Does a scooter fit? Do the curbs make sense? Does the block feel the right length? Fix scale here, while it's cheap.

You get: a screenshot of the graybox from the locked camera, next to the photo. I skipped this step once, modeled a whole corner of Rothschild on the wrong scale, and threw it away.

4Model one landmark in Blender

One Python module per landmark, with a build() function, its source data next to it, and named parts. Original geometry from the photos and the footprint. Compare silhouette, window widths, balcony rhythm, facade depth, colors and paving against the photo. Don't paste photos onto facades; it keeps the style consistent and you're not redistributing anyone's pictures.

Two things stay separate on purpose: parts that move (water, traffic lights, character limbs) stay as their own nodes, and materials that can change (scooter paint, skin tone, glass, metal, paving) keep their own material role so the game can swap them without touching geometry. Save the Python, the .blend, the .glb, a preview render and a short note on what you assumed.

The Cinema Hotel in Blender
First Blender pass of the Cinema Hotel, 14,660 triangles
First assembly of the square
First assembly of the square in the browser

You get: five files with the same base name, plus triangle count and dimensions. If the script can rebuild the asset from scratch, the asset is real. If it can't, you have a screenshot.

Prompt · delegate one asset03
Build only [named building] in Blender from the supplied photos and footprint. Return a reproducible Python module, .blend, preview and a short source/assumption report. Use metres and the provided geographic origin. Preserve the actual plan; match facade rhythm, balconies, ground floor and signs. Keep articulated parts as separate nodes and keep material roles separate. No downloaded 3D assets. Do not edit the parent project or deploy anything. Give the parent exact orientation, dimensions and triangle count.

5Load it in Three.js and ride one delivery

GLTFLoader, camera, lights, shadows, scooter movement. Pickup, ride, drop, hit something, restart. Nothing else yet. The surfaces you ride on are the meshes the renderer draws, with ground-height and blocker queries on top, so what you see and where you can ride can't drift apart.

Water goes in GPU shaders on elapsed time, so it moves the same at any frame rate and the CPU never rebuilds the mesh. Repeated people and vehicles are instanced: one mesh, many copies, one draw call. That's how 487 pedestrians cost roughly what a few do.

Fountain, frame A
The fountain, from the shader
Frishman and the promenade
Frishman meets the promenade
The promenade
The promenade assembled

You get: a screen recording of one complete loop in the browser.

6Ask "where is this?" before you show the answer

This is the step that makes the city recognizable, and most people do it backwards. Don't show the agent the photo and ask "does it match?" Run the review in two stages. First, a fresh reviewer that has seen nothing gets a render with a neutral filename and one question: which street is this, and which way are we looking? Only after it answers do you show the matched photo and ask for the differences. Show the photo first and you've contaminated the test.

My bar is three blind identifications in a row. A fresh AI critic is useful evidence. The real test is a local looking at the screen and saying "I ride there every day."

The fountain before the critique round The fountain after the critique round
beforeafter
The fountain before and after one critique round. Drag the handle.

You get: a list of tells, ranked by how much each one hurts recognition.

Prompt · the blind review, two stages04

Send stage one alone. Send stage two only after it answers.

Stage one. You are an independent critic. From this neutrally named render alone, identify the street or place and the viewing direction. State your confidence and what you based it on. Do not ask for hints.

Stage two, sent only after stage one is answered. Here is the dated reference photo from the same angle. List the differences in street geometry, scale, facade proportions, signs, cars, materials and lighting. Rank the three changes with the greatest recognition benefit. Do not reward labels for fixing incorrect geography.

7Fix one thing, then measure

Take the top tell and fix only that. Same camera, same coordinates. Rebuild, capture the same view, have a different critic compare. Then measure the real browser build before you add anything: frames per second, draw calls, triangles, with the device and method written next to the number.

Named parts make this safe. When the fountain looked wrong, the instruction was "change only fountain_metal and water_jet, keep the camera." The agent couldn't accidentally touch the hotel.

Tell the agent what matters. My message, verbatim, typos included:

“i think the wow factor is less from trees its more form street shapes building roads signs cars”

That one message turned the project. Foliage went on hold and the effort moved to street geometry, footprints, signs and cars. The agent optimizes what it can measure. You tell it what people actually recognize. Expect to send a message like this, and look at the render from the player's camera, not the aerial showcase, when you decide.

You get: before and after from the same camera, and one number with the device and method next to it.

Prompt · fix the bottleneck05
Pick the highest-impact mismatch from the critique. Change only the responsible asset or system. Preserve coordinates and camera. Rebuild, capture the same view and have a different critic compare. Report the actual result even if the improvement is small. Measure performance using the same device and method as last time, and say what they were.

8Grow it one tested section at a time

Repeat steps 2 to 7 for the next block. Keep the same origin, the same file layout and the same review. Three things I'd decide early:

Opera Square
playableOpera Square assembled
Carmel Market
scenic studyCarmel Market connected to the route
Navigation on a phone
Navigation at phone width
The delivery-area briefing map in the game
The briefing screen before a shift: the connected district in pink, the rest marked coming soon. Players should know where the game ends.

Keep a log at every milestone: the exact prompt, the sources, before and after, the validation result, one reusable lesson. It's what let me write this page.

Prompt · keep the evidence trail06
After each meaningful milestone, save the exact prompt, sources, before/after render, script/build, validation result and one reusable lesson. Mark retrospective summaries as summaries. Keep concept art separate from actual screenshots. Never record a test as passed unless it ran.

Worked example: Dizengoff Square

The whole method on one square, small enough to follow.

The source packet

The municipal footprint for the Cinema Hotel, the OSM ways for the circular bike route and the roads that meet the square, a restoration architect's photo of the fountain and the hotel, and a street photo of the striped cafe corner with an unverified date, marked as such. Measured: the footprint, the road centerlines, the bike loop. Estimated from photos: balcony depth, ground-floor heights, awnings, furniture.

The coordinate conversion

Every source gets converted into the same local metres before anything is modeled:

east  = (longitude - originLongitude) * 111320 * cos(originLatitude in radians)
north = (latitude  - originLatitude)  * 111320
Blender position  = (east, north, elevation)      # X east, Y north, Z up
Three.js position = [east, elevation, -north]    # X east, Y up, Z south

This keeps the building, the street sign, the riding surface and the map marker in the same place: they were all born on the same grid.

The named parts

The square's export contains, among others: facade_cinema, facade_perimeter, fountain_metal, water_water, water_jet, dizengoff_world (the ground), plus separate signal, car and character assets.

The first blind review

The reviewer named Dizengoff, helped by the hotel lettering, and couldn't say which direction it was looking. The tells it listed became the next three fixes: fountain metal, the ring road width, the cafe corner. Then the lettering came off, because real businesses stay unbranded in the game.

Mistakes to skip

Each of these cost me at least a rebuild.

And four bugs you will meet, with the fix:

Materials come out flatsymptomglass, metal and paving render as the same chalky surfacecauseroughness and metalness dropped at exportfixkeep material roles in the export scriptchecklist materials and properties from the loaded GLB after every export
The camera looks the wrong waysymptomthe opening tour shows the back of the squarecausecamera interpolation crosses a building corner and picks the wrong headingfixlock the opening focal point and clamp the interpolationchecka saved opening render compared against the reference view after every build
A join that looks connected isn'tsymptomthe GPS stalls and the scooter drops off a terrace edge with no way backcauseunbounded route projection and one edge with no attachmentfixbounded projection, validated trail recovery, explicit "no attachment" spotschecka route audit that probes every attachment physically
Merging everything kills the frame ratesymptomone huge mesh, culling does nothingcausethe whole city merged into one objectfixstatic groups with spatial boundaries, instancing for repeatscheckdraw calls and triangles measured in the real browser build

The kickoff prompt

Give this page to your agent (the Markdown download has everything, including the file layout), fill in the inputs below, and paste it as the first message. Start with one recognizable street and one playable task. It won't finish in one click. It will start in the right place.

Kickoff promptpaste as the first message

Fill in the inputs. Leave the rules alone.

Use the attached guide as a workflow for building an original browser-playable 3D game. Adapt the method to my location and idea; do not copy Tel Aviv-specific coordinates, names or geometry.

My inputs:
- Place and small starting area: [city, street or square; about 100 to 200 m]
- Player activity and objective: [what the player does and how they succeed]
- Visual direction: [stylized, low-poly, realistic proportions, etc.]
- Target devices: [desktop, mobile, or both]
- Available reference photos and maps: [links or files]
- Time and compute constraints: [optional]

First read the guide and inspect the available project and tools. Identify the essential missing inputs. Check whether you can run Blender, Node.js and a browser. State any unavailable tools instead of pretending to use them.

Create a short implementation brief: first playable loop, controls, success, failure, restart, one small geographic boundary and explicit exclusions.

Before modeling the location, collect dated references, mapped roads and building footprints. Record source URLs and IDs and separate measured facts, photo estimates and invented detail. Pick one shared origin, units, axis conversion and a locked comparison camera. Do not substitute a generic street.

Build a graybox to check scale and clearance. Then create original geometry using reproducible Blender Python scripts. Save the source, .blend, .glb, preview and source/assumption notes. Preserve named articulated parts and material roles needed for animation and customization. If multiple workers are available and appropriate, give each one bounded asset ownership and the same coordinate and export contract.

Load the exports in Three.js. Implement one complete playable task before expanding the map. Derive navigation and blockers from the same assembled world, and test the actual exports. Keep the environment recognizable from the player's camera, not just from an aerial showcase.

Capture the locked view and compare it with the dated reference. For an independent recognition test, show a fresh reviewer only the neutral render first; reveal the reference afterward. Fix the highest-impact mismatch, rebuild and repeat. Do not claim recognition based only on your own review.

Use batching, instancing and culling where appropriate. Measure the real browser build and report the device, viewport, method and remaining limits. Verify controls, collisions, completion, failure, restart and loading. If mobile is a target, distinguish responsive layout from physical-phone tests.

Keep a progress log with prompts, sources, before/after views, validation and next steps. Work locally and make each milestone reviewable. Do not publish or connect external services without authorization. Never invent successful tests, precise geography, playtest scores, development costs or elapsed time.

Start now with the tool check, the brief and the reference packet for the first section. Continue through the first runnable, reviewable milestone; do not stop after giving me a plan.

The file layout the prompt refers to

Renders from the September 2026 builds. Labels say which parts are playable and which are scenic studies.

Phone layout

What it doesn't do yet

Map data © OpenStreetMap contributors (ODbL) and Tel Aviv-Yafo open data. Blender 4.5, Three.js, Node.js 22, and an AI coding agent. Reference photos belong to their photographers and aren't redistributed here. Music: "Costa Cruising", a track of mine made with Suno. The game was called Tel Aviv Run while it was being built.

Build your own city

Save this page, pick a street, and give the kickoff prompt to your agent tonight. If you build something, show me which street people recognized first.