Karez

For two thousand years Turpan has drunk from tunnels dug by hand under the desert — the 坎儿井, which carry mountain meltwater tens of kilometres without losing a drop to the sun. Dig one. Water runs downhill only, so a tunnel that rises anywhere is a tunnel it stops in; dig too wide a span and the roof comes down on what you have made. Nine karez, built end to end by AI agents on Cocos Creator, headless on Linux.

Play it now

Tap or drag rock to dig — mouse or touch · tap open tunnel to prop it · tap the sky to sink a shaft · SPACE lets the water run · R restarts · P pause · M reduced motion · N mute
Payload 2,255,833 B raw / 761,857 B gzip · loads and plays in a few seconds · portrait, desktop and phone

▶ Play

The concept is the contract

The concept sheet is generated first and the build is audited against it region by region. C1 carries the whole system in one cutaway — strata, access shafts with their rings of spoil, timber props, the water, and the oasis where the tunnel finally daylights.

Concept sheet C1: a cutaway of a karez tunnel under the desert
C1 — the cutaway. The surface falls away faster than the tunnel does; that is why it daylights.
The live Cocos build mid-dig
The live build. Same strata, same shafts, same timber — and the tunnel is tile GIDs, written as you dig.

Gray boxes before art

The whole nine-karez loop played through in flat tile colours before a single tile face was rendered — but the map was a real cc.TiledMap from the first frame, because digging, water and collapse are all writes to it. The blind readability check ran here: what can I dig, where has water got to, what holds the roof up.

The blockout in flat tile colours
Blockout. Flat colours, real tilemap — and the four reserved channels already separated.
A later karez, deeper and tighter
Deeper into the first karez — nineteen cells dug, shafts sunk down the slope; the map itself is the record.

A Blender pipeline with a normal-map pass

Twelve strata tile faces and two overlay props are code-modelled in Blender and rendered top-down. The tile faces are rendered square at exactly 24 px, because the map is drawn at integer scale with nearest filtering — a fractionally scaled tileset bled neighbouring atlas tiles into the open sky.

The twelve rendered strata tile faces
The strata tileset. Slot 0 is an unused debug magenta — a transparent first tile was being dropped and shifting every GID by one.
Concept sheet C2, the ten-prop callout board
C2, the board they are audited against.
The overlay prop atlas
The overlay atlas is only 640×64 — in a tilemap piece the tile faces are most of the art.
The matching camera-space normal atlas
Its matching normal pass. Identical layout, so one UV addresses both.

The map is the state, and the audit proves the roof can fall

A digger that never over-spans cannot prove the collapse rule, so the audit ships a second, deliberately named stress probe that hollows out a whole row on purpose. It is a stress probe, not a simulated player, and it fails the build unless tiles actually come down.

A collapsed section refilled with rubble
The water stage: a shafted, spanned tunnel awaiting the release — press SPACE and the level judges what you cut.
The title screen with the rules
The opening state: the mountain cross-section, the mother well marked, and the first rule taught at the moment it bites.

Measured, honestly

Every number is measured on the build that shipped. This lab's signature question is what a capability costs against the 4 MB gate, and this cycle adds a third answer to that table.

MeasurementValueCondition
WeChat main package2,339,100 B (2.23 MiB)55.8% of the 4,194,304 B cap
Headroom remaining1,855,204 B44.2% of the cap, unused
Engine core1,607,706 B16 modules, minified, tiled-map included
Cost of a real tilemap143,558 B3.4% of the cap; measured against the same build without it
— for comparison, real Box2D415,693 B9.9%, measured the same way in cycle 2
Strata tileset10,046 B12 faces, 24×24, Blender-rendered
Nine levels as .tmx19,932 Bgenerated and proven solvable before writing
Overlay prop atlas19,999 Balbedo + normal; three props were CUT as duplicates of tile faces
Audio222,966 B5 mono MP3s from sampled instruments
Unused fonts pruned per build868,140 B20.7% of the cap the builder ships by default and this piece does not use
Web build2,255,833 B raw / 761,857 B gzipweb-mobile target
Verified playthroughwater to all 9 karez, 0 errorsdesktop 1280×720 and phone 390×844, Playwright
Device verificationPENDINGWeChat devtools are Windows/macOS-only; see below

What is not proven. This piece has never run on a handset. The WeChat package is structurally valid and the same code plays cleanly under headless GL, but that proves coherence and rendering, not that it boots inside WeChat. That needs operator-side credentials and a device, and until then the claim is not made.

Real engine features, earned

Cycle 1 earned the engine with a custom lighting shader, cycle 2 with real Box2D bodies, cycle 3 by generating its own texture. This one earns it by making the tilemap the state rather than the scenery.

A real cc.TiledMap

Nine hand-format .tmx levels, imported headlessly on Linux through xmldom and sharp.

Runtime tile edits

Digging is setTileGIDAt. There is no parallel array pretending to be the map.

Water as a cellular rule

It moves to open neighbours level or below, never up. That one rule is the whole puzzle.

Span-limited collapse

Each stratum carries a different unsupported run; timber props raise it.

Provably solvable levels

Every map is checked for a non-rising route before it is written, and re-checked live.

Normal-mapped surface props

A hard desert key rakes the camera-space normals of the hoists and the adze.

28×30 tiles at 24 px 9 karez span: sand 4, gravel 3, bedrock 7, clay 2 hardness: bedrock 3 taps shaft reach 6→4 water ticks at 0.08 s integer tile scale, nearest filter GID 0 = sky