Godot Lab · 2D · Tilemap + Light2D

Lamplighter's Round

Dusk falls on a stone harbor village and you are its lamplighter. Carry your hand-flame through the cobbled lanes and light all ten street lamps before full night — every lamp you light becomes a real dynamic light that pools over the cobbles. Wind gusts snuff your flame if you're caught out in the dark; rekindle at any lit lamp or the wick-house brazier. The whole game is the engine's 2D lighting: every sprite in it is a Blender render with a matching normal-map pass, so lamplight rolls across cobble bumps, coat folds and cottage stone in real time.

Play it now

WASD / arrows to walk · E or Space to light a lamp · touch: left joystick + right button · tap once for sound · game data 2.8 MB (+ engine wasm, cached after first load)

▶  Play

The concept is the contract

Made by AI, exported by the real Godot 4 engine. The piece started as a concept painting; every named element in it was then authored as a real asset, and every audit round judged the live build against the painting.

AI concept painting
Concept key art — the contract the piece is audited against
Concept prompt

Top-down three-quarter view of a tiny stone harbor village at dusk, winding cobblestone lanes, slate-roofed stone cottages with warmly glowing windows, cast-iron street lamps with amber flames casting pools of warm light on the cobbles, a small lamplighter figure in an oilskin coat carrying a brass pole-lantern, deep indigo-violet twilight sky.

Lamplighter's Round live in the engine
The same village live in the engine — two lamps lit, the hand-flame lighting the lamplighter home

Rendered twice, lit for real

The lamplighter, six cottages, every prop and every ground tile were modelled in Blender and rendered twice from the game camera — once for colour, once encoding camera-space surface normals — and shipped as CanvasTextures, so all ten street lamps, the hand-flame and the brazier are true PointLight2D sources whose light rolls across the relief of cobbles and coats. Cottages carry LightOccluder2D polygons and cast real 2D shadows.

lamplighter walk frames beside their normal-map pass
The shipped walk frames (top) beside their camera-space normal passes (bottom) — the second render is what the lamps actually light

Lanes, particles and shimmering water

The lanes are a TileMap whose cobble-to-grass edges use a 47-variant blob autotile set, with seamless-variant tiles (edge-locked, interior re-jittered) breaking repetition. Wind gusts, lamp flames, ember bursts, fireflies and chimney smoke are GPUParticles2D; the harbor water is a shader whose scrolling normal maps come from a Blender-baked heightfield, so lamplight shimmers on the swell.

the shipped tile atlas with 47 blob autotile variants
The shipped atlas: eight base tiles (top row) and the 47 cobble-over-grass blob variants the autotiler picks from, diffuse pass

A walk from four real directions

The walk cycle is a rigged Blender armature rendered from four real directions — no mirrored frames, so the normal maps stay physically correct. Ambience and chimes are sampled instruments from the platform's audio stack. One engine quirk is preserved in the ledger: 2D normal maps render pitch-black until you give each light a height above the canvas plane.

walk cycle rendered from four real directions
Six walk frames from each of the four real directions — no mirrored frames, so every normal map stays physically correct

Measured, honestly

The lab audits with Playwright on this host's software renderer (no GPU), so the frame-rate row below is a worst case — real hardware runs the compatibility renderer far faster.

MeasurementValueConditions
Game data (.pck)2.81 MBrelease export — art 2.0 MB + sampled audio 1.1 MB source
Engine payload (.wasm)35.4 MBGodot 4.3 web runtime, fixed cost, browser-cached after first load
Verified full round10/10 lamps lit, win score 2080AStarGrid2D autopilot with gust-snuff + relight drills, every audit round
Dynamic lights on screen12 shadow-casting + 13 window glowsplus the carried hand-flame; all over normal-mapped sprites
Audit roundsblockout 3 · art 5fix-all-then-re-audit until a round found nothing, then one confirming
Audit frame rate~1–2 fpsSwiftShader software GL — worst case; game time stays real via physics step catch-up

Real engine features, earned

Normal-mapped Light2D

Every sprite ships as a CanvasTexture pair — colour + camera-space normals — so lamplight genuinely rolls across cobble bumps and coat folds.

Occluder shadows

Six cottages carry LightOccluder2D polygons; lamp pools break correctly against stone walls.

47-blob autotiling

A TileMap whose cobble-to-grass edges resolve through 47 mask-driven blob variants, with edge-locked seamless alternates breaking repetition.

GPU particles ×6

Lamp flames, ember bursts, wind gusts, fireflies, chimney smoke and the hand-flame — all GPUParticles2D.

Normal-mapped water

A canvas shader scrolling Blender-baked heightfield normals, so every lamp shimmers on the harbor swell.

Pathfinding autopilot

An AStarGrid2D agent plays the whole round for every audit — lighting, getting snuffed, relighting, winning.

walk 230 px/sdusk 170 s warmth radius 170 pxact radius 90 px light height 72 px47 blob masks 64 px tilesarrows + WASD + touch 6-frame walk × 4 real directionssampled chimes + ambience