The street
The layout comes first. The paint comes last.
Each pass keeps the camera and the positions of the one before. The plan and the blocks are data we can check; image models paint on top of a structure they cannot change.
-
Plan
Real rules become data: traffic keeps left, a 4 m median, a railway 10.4 m above the road.
-
Blocks
Every object is a box in world units, checked before anything is drawn.
-
Flat render
Colors and readable shapes on the same camera: the color template the paint must follow.
-
Painted, twice
Two paint passes keep every object in place, yet change the details and even the style. That drift is why the layout file, not an image, is the source of truth.
Swipe to see every pass
Characters
One master image, many motions.
How our test character went from one drawing to sprites that move, in six steps. She is a stand-in while we build the pipeline; her final look is not decided.
-
A drawing, then a rig
We started from both ends: a picture with the right look, and a skeleton that can move.

Design
An image model draws her from a written brief. It looks right, but it is one picture: no parts, no second angle.

All in code
A 15-joint skeleton with IK, and springs for hair and shirt. Every pose is correct, but the surface looks like vector art.
-
Code as a guide
Next, the rig guided the image model. Same model, same prompt, two runs each. We measured how closely the result follows the guide's shape, how often the arms stay clear of the body so code can cut them out, and thigh width against height, which is 0.134 in the design.


Color template
- Follows the shape 87–90%
- Arms clear of the body 53–61%
- Thigh to height 0.10
Follows the shape best and keeps the arms clear for cutting, but it also copies the rig's slimmer legs.


Stick figure
- Follows the shape 64–67%
- Arms clear of the body 0–35%
- Thigh to height 0.14
Legs come out right, but the arms stick to the body and the dashed guides end up painted into the picture.
no template
No template
- Follows the shape 75%
- Arms clear of the body 37–41%
- Thigh to height 0.12
Closest to the design's look, with no control over the pose.
What we learned. A guide controls the pose, but the model also copies the rig's proportions, and stick-figure lines leak into the picture. ControlNet would lock the shape, but it needs open models on a GPU of our own; the image APIs we use take reference images and text only. So code stopped drawing guides for her look.
-
One master, edited kept
We approved one master image in a neutral pose. Every new image is an edit of that master, never of the previous edit, so small changes cannot pile up.

The master, approved once 
A key pose, edited from it What holds, what drifts
Face and proportions hold. Hair and shirt follow the new pose on their own.
Small details, like the seams of the shorts, can still change between edits.
The key poses become the first and last frames for video.
-
Video between two key poses tested
Video models fill in the motion between two frames we have already approved: the master as the first frame, a key pose as the last.
Same first and last frame, three models. - Pose change. Seedance 2.0 Fast lands on the last frame with a 95% shape match, feet sliding 1% of her height. Kling 3.0 Std: 94% and 2%. Veo 3.1 Lite ignores the last frame: 64% and 9%.
- Dance loop. With the first frame repeated as the last, Seedance closes the loop. Veo 3.1 Lite does not come back (76%).
- 360° turn. One Veo 3.1 Lite clip gives eight matching directions; back, hair, shirt and sunglasses hold.
First and last frames are the strongest control we have, so the model choice follows the job.
-
Code keeps the video on model
Video models drift in color, zoom in a little, slide the feet and repaint what should stay still. Each of those errors is something code can measure and undo.
Color drift and sliding feet
Over four seconds the model pulls her colors away from the master and lets her feet wander. Code finds her feet in every frame and pins them to one point. Then it pulls her colors, and the background's, back toward the master.
The dance loop from Seedance 2.0 Fast. 16.6 → 3.9color distance from the master, median per frame1.3% → 0.8%largest foot slide, as a share of her heightColor distance from the master, per frame
Raw videoAfter codeShow the numbers
Time (s) Raw video After code 0.00 4.68 1.83 0.08 10.68 3.53 0.17 16.11 3.83 0.25 15.85 3.79 0.33 16.23 3.97 0.42 18.34 4.43 0.50 18.68 4.47 0.58 17.55 4.33 0.67 17.6 4.09 0.75 15.99 3.54 0.83 15.68 1.99 0.92 12.32 1.94 1.00 12.47 1.98 1.08 15.74 3.93 1.17 16.64 4.19 1.25 16.52 4.31 1.33 16.92 4.25 1.42 18.33 4.47 1.50 18.67 4.59 1.58 17.55 4.36 1.67 17.72 3.91 1.75 15.83 4.17 1.83 15.85 2.01 1.92 11.78 1.93 2.00 14.49 1.86 2.08 15.73 4.07 2.17 16.42 4.2 2.25 16.39 4.35 2.33 17.14 4.47 2.42 17.72 4.43 2.50 18.27 4.38 2.58 18.52 4.68 2.67 17.28 4.5 2.75 15.9 2.08 2.83 16.02 2.15 2.92 12.76 3.15 3.00 13.09 3.21 3.08 13.18 2.1 3.17 13.29 2.09 3.25 17.25 4.15 3.33 18.01 4.44 3.42 18.6 4.33 3.50 19.03 4.67 3.58 18.87 4.66 3.67 18.09 4.44 3.75 17.01 4.28 3.83 13.42 3.95 3.92 6.47 2.04 4.00 5.66 4.16 A slight zoom, and a background that should stay still
We asked for leaves, flowers, clouds and water to move, and nothing else. The model also zoomed in 1.7%, shifted the frame by 7 × 9 px and repainted every pixel. The zoom and the shift never change during the clip, so code measures them once and undoes them. Then it finds what really moves, about 15% of the frame, matches its colors to the painting and pastes the original back everywhere else.
Middle and right: difference from the painting; brighter means further. Tested on an earlier concept of the street. - Raw clip 19.4
- Zoom and shift undone 11.5
- Still areas pasted back 0.07
Mean difference from the painting in areas that should not move, per pixel, 0–255.
-
Sprites
Frames picked from the fixed clips become sprites. What still needs our eyes: expressions that change on their own, crossed legs, and the gap between the legs when we cut her out.

A dance loop: one beat, 8 frames
One second of the fixed loop, every third frame.

8 directions from one turn
One 360° clip, so every angle matches.
Six image models, one set of tasks
Same prompt, references and size for each model, one sample each, so take single results with a grain of salt. No model won every task, so we pick a model per job.
A new master from the design and a written pose. All six look right. None put the head at 10% of the frame as asked, so framing is left to code.






The same master, edited into a dance pose. Shirt and hair follow the pose in all six. FLUX.3 shrinks the figure and shifts the frame.






Master plus a stick-figure pose. GPT Image 2.5, Seedream Pro and Qwen follow the pose; NB2, FLUX.3 and Seedream Flash paint the dashed guides into the picture.






Relight a clean daytime plate to night. Code aligns each result to the day plate and measures how far it moved: NB2 0.08 px, with 93% of edges within 3 px; Seedream 5.0 Pro 0.11 px; GPT Image 2.5 and FLUX.3 1.8–2.3 px; Qwen Image 3 Pro shifted the whole picture by 20 px. Tested on an earlier concept of the street.






Motion in the game
The street is painted once. Only what moves is animated.
A finished scene is a still picture. People, animals and vehicles are separate sprites on top, moving along lanes and anchors from the scene file. Nothing redraws the street frame by frame.
Plate planned
The approved painting, plus a clean version without people and vehicles, made as an edit of the same image. Tried on an earlier concept.
Sprites tested
Separate sprites for characters, animals and vehicles. Tested on our main character; not yet placed in the street.
Placement built
IsoBlock's Godot adapter puts each moving sprite on the scene's lanes and keeps it in the right draw order.
Runtime.add_actor(root, "walker", size, start, sprite) Runtime.move_actor(root, "walker", next_point)Light and weather next
Day to night, rain and steam over the same plate, as shaders and particles in Godot or as relit plates.
Why we built IsoBlock
Agents can't see the screen. Image models can't count.
An agent working in a game engine cannot see what it just did. An image model paints well but places things loosely. IsoBlock gives both of them the scene as data: the agent reads and checks the layout as text and numbers, and the image model gets an exact order of boxes, sizes and anchors.
| Job | Tiled | Godot editor | Agent in Godot | IsoBlock |
|---|---|---|---|---|
| Lay out a scene before there is art | Tiles and objects, no rules | Empty boxes, no rules | A script or a screenshot for every question | Anchors, zones, lanes and relations; checks with measured values |
| Arrange things once art exists | Good, by eye | Best: see it, adjust it | Weak: screenshots only | Keeps the positions; drag in its editor |
| Draw order around long objects | Left to the engine | Y-sort by node origin; long objects sort wrong | Write your own | Slices and sort keys, checked in Godot |
| Order art from image models | — | — | — | Boxes, block renders, sizes, anchors, states |
| Into Godot | Its exporter skips image-collection tilesets | Native | Native | Runtime file and adapter, within 0.49 px of its renders |
| Gameplay, animation, light, UI | — | Yes | Code yes; feel needs a person | No, by design |
Not proven yet. Parts of IsoBlock overlap Godot: its editor, its scene tree, its pathfinding. We have not yet compared IsoBlock with working directly in Godot on a full scene. Its one real use so far caught two layout conflicts before any art, and showed us six gaps to fix.
Open source, MIT license
IsoBlock
A layout tool for 2D isometric scenes. One scene file holds every object's position in world units; people and agents edit the same file, and one approved layout goes to the engine, to image generation and to graybox gameplay.
- Checks for visibility, clearance, overlaps, lanes, walkable reach, capacity and draw order.
- Made for agents: a short text summary, small patches that respect locks, variants compared by measured values.
- Solver that places objects from relations and names the rules in conflict.
- Outputs: SVG and PNG, a runtime file for engines, boxes for image generation, a Godot adapter.
- Editor: one offline HTML page with locks and a live check panel.
npm ci && npm run build
node dist/isoblock.mjs check tests/fixtures/yard.scene.json
- failc4clearance: crates 0.2 apart, minimum 0.5
- failc7lane_reaches: haul lane misses the right edge
- failc8visible: figure 40% hidden by the tree
- passc1–c3, c5, c6, c9
The sample scene in IsoBlock's tests, with three deliberate mistakes.
Choosing the engine
Godot, after a trial an agent could run.
The target is a native phone app, and the most demanding part of the game is light over painted scenes: 2D lights with normal maps, water, rain, cloud shadows.
Phaser is the easiest engine for agents: TypeScript, runs in a browser, takes its own screenshots. Picking it for that alone would serve the builder, not the game. So we tested whether an agent could run Godot.
| Godot 4.7 | Defold | Flutter + Flame | Phaser 4 + Capacitor | |
|---|---|---|---|---|
| Phone app | Native export | Native, small | Native Flutter app | Inside a WebView |
| 2D light with normal maps | Built in | Write your own | Write your own | Built in |
| Web preview | Heavy | Light | Not measured | Fastest |
| Runs in our agents' sessions | Yes, with renders | Downloads blocked | SDK blocked | Yes |
| Scene editor | Full: scenes, animation, light, particles | Yes | None | None |
Trial E1: can an agent run Godot?
A builder agent loaded IsoBlock's sample scene into Godot 4.7.1. The maintainer agent ran it again in another container and matched every number.
- 0.49 pxlargest gap from IsoBlock's renders, 5 scenes, 213 objects
- Identicalrenders, byte for byte, across runs and sessions
- 0.00046largest error on 13 golden projection vectors
- 28.3 MBdebug Android build, made without Gradle
- 10 MBgzipped web engine, single-threaded build
- 2.3 sone edit, run and compare loop
A 2D light reading a normal map worked too. We chose Godot 4.7 with GDScript. IsoBlock stays outside the engine, and a small GDScript loader reads its files.
Popular routes we skipped
three.js
A 3D rendering library, not an engine: no editor, no scene format, no native phone build. For a painted 2D street on a fixed camera, we would be writing our own engine to get less than Godot.
Blender through MCP
An agent can drive Blender through MCP, and it demos beautifully. On a fixed isometric camera, modeling and rigging every object costs more than it returns. We would open Blender for many angles or true normal maps.
One-prompt games, image-to-3D
Great for a first minute. A game we keep updating needs saves that survive updates, art that stays consistent across hundreds of assets, and scenes we can change without starting over.
How we work
Agents build. We decide.
IsoBlock reached version 0.8 in eight reviewed stages, each one through the same loop.
Spec first
A maintainer agent (Claude) writes the specification and the expected test results.
Build
A builder agent (Claude Code) implements one stage on its own branch.
Review
The maintainer checks the branch's behavior against the expected results.
Merge
One of us reads the review and merges the stage.
A lesson from going public. Agent tools add links to their sessions in commits and pull requests. We strip them by rule and open pull requests ourselves.
Notes from shipped games
Studios solved several of our problems with structure long before image models. We borrow their ideas, not their budgets.
3D under 2D
With a single artist for its first year, Dead Cells rendered 3D models into pixel-art frames with normal maps, so retakes did not need redrawing by hand.
Game Developer, 2018Outfits as parts
Spine builds mix-and-match characters from per-item skins at runtime, so animations never depend on one outfit.
Spine User Guide: SkinsMain characters stay hard
Rovio fine-tuned image models on its own art. Season-pass backgrounds went from 20 days to 4, but main characters stayed short of its bar.
Summary of a GDC 2025 talk