The level audit
The geometric rules a level passes without anybody looking at a picture of it, and the repair a generation makes before it gives up. Every generated level is audited (apps/worker/src/audit.ts, before its preview and its cache), every bundled level is held to it with no repair (packages/catalogue/src/levels-audit.test.ts), and random specs are built and audited on every pull request and every night (apps/worker/src/fuzz.ts).
The rules
auditLevel(level, { factsOf, keep, rules }) runs them all (or those rules names) and answers one finding per fault: its rule, its severity, the placements it is about, where, a sentence naming the pieces, the point and its district, and what a repair would drop to clear it.
| Rule | What it finds | Allowed |
|---|---|---|
props-in-each-other | Two props whose cores share a quarter of the smaller one's footprint and 15 cm of height | Two barriers (fences, guardrails, bollards); two of nature (trees, bushes, rocks); a flat pad |
prop-in-building | A prop whose core shares a quarter of its footprint with a building's, the building's own faces over it and under it | At the building's anchors; in a building people walk into; on its roof |
buildings-in-each-other | Two buildings' cores sharing more than half a square metre | |
not-resting | A piece floating (everything under its foot more than 12 cm below) or sunk (everything more than 25 cm above, a metre for nature); a boat off the water | What rests on the water is measured at its waterline |
in-the-road | A piece more than 30 cm inside a carriageway, on the road's level | What is made for the road (a traffic cone) |
z-fighting | Faces of one piece, or of two, in one plane, facing the same way, in two colours | Undersides lying on the ground |
paint-over-paint | Two patches of the level's paint over each other, whatever their colours | |
roads-joined | A road the players' spawn's road cannot reach (a warning) |
A piece's core (cores.ts) is the box round its lowest metre, turned with it: boxes round whole pieces meet everywhere in a city (a tree's crown over a bench, a lamp's arm over a bin: 2,214 false pairs on main-riverbend), cores only where the pieces stand in each other.
Only the pieces of the shared kits are judged as pieces: factsOf (@foi/catalogue's pieceFacts, from the kit library) tells their tags, what they rest on (a kit sidecar's rests: water for the boats and buoys, road for the traffic cone), their anchors and whether people walk into them. A level's own meshes (its ground, its paint, its roads' carriers) and the unit blocks are no pieces to judge; without factsOf only the faces, the paint and the roads are.
The roads' lines are no rule: they give way to the level's paint as they are laid (../road-paint.ts), so no step of a line ever lies over a crossing, a stop line or a grate.
The repair
repairLevel(level, options) audits, drops what may be dropped, and audits again, three rounds at most (a dropped container leaves the one stacked on it floating). It never moves anything:
- Dropped: a faulty prop of a shared kit (of two props in each other, the smaller), and the triangles of the level's own paint that lie under other paint.
- Never dropped: buildings, structures, the ground, blocks, and what
keepsays (a generation keeps what stands on one of the level's named places). A fault there is the generator's: the build reports it, naming the piece and the point, and says that anotherseedusually clears it.
The z-fighting search (coplanar.ts) searches each distinct mesh once, in its own frame, and across pieces only the planes two pieces' faces share: 2.3 s and half a gigabyte on main-riverbend's 943,000 triangles, where searching every placed triangle took 5 s and 1.3 GB. The rest of the audit takes about a second there.