assets
The geometry factory: everything modelled in Blender (5.2 or later, driven through its MCP server or headless, see Blender from Claude Code). Blender makes the meshes; the Babylon.js Editor project (apps/level-editor) places them; apps/tools turns the placed scene into level data. Nothing here is read by the game at run time: the exports are committed where their consumers live (apps/level-editor/assets/kits/ for the kits the editor places, apps/client/public/models/ for the vehicle and character models).
| Path | What |
|---|---|
blender/foi_export.py | The export: a kit (.glb with modifiers applied and custom properties as extras, plus a .foi.json sidecar naming every piece's kind, collider and centre lines) or a model (one .glb). blender -b <file.blend> --python assets/blender/foi_export.py -- --out <dir>, or export_kit(out) / export_model(out) from the MCP server. |
blender/foi_kit.py | Helpers for building pieces procedurally: faces with flat colours (Builder: boxes, prisms, cylinders, cones, wedges, ribbons), one material per colour, kit collections, centre-line curves. |
blender/kits/city.py | The city kit: unit buildings with facades (scaled by the level like the unit blocks they replace), a slab, a terrace, a ramp, stairs with their hidden slope, trees, a lamp post, a bench, a barrier, containers, a bus shelter, a fountain, a billboard, a pier, a bridge deck. |
blender/kits/roads.py | The roads kit: street pieces (kerbs and sidewalks; the tarmac is drawn by the game from the centre line) with their centre lines: straights, bends of two radii, a T, a crossroads. |
blender/kits/downtown.py | The downtown kit: buildings at their real size, two or three colour variants each (glass and stone towers, offices, apartments, corner blocks, shop rows, townhouses, warehouses, hotels, cafés, their fronts facing +Y), every building with its OpenStreetMap-style tags, the look its variant leans to and its anchors, and street and hill furniture (trees, lamps, traffic lights, bins, hydrants, bollards, planters, a kiosk, guardrails, rocks, a radio mast, an obelisk, picnic tables, telescopes, a tunnel portal's frame). |
blender/kits/civic.py | The civic kit: the building families the downtown kit lacks, at their real size, two or three colour variants each, read from above by their roofs: a police station (a blue roof, a radio mast, two painted cruiser bays), a hospital (a helipad, a red cross, an ambulance bay under a canopy), a fire station (a red roof, three engine doors, a hose tower), a town hall (a portico, a bell tower), a school (an L round a yard with a painted court), a courthouse (a copper dome), a library (a glass pyramid), a post office (a yellow parapet); a supermarket (a big sign on its roof), a mall (anchor stores, a glazed atrium), a bank one walks into (a portico over a doorway 4 m wide, a banking hall with its counter and the manager's desk, the vault's steel gate and its strongroom of safe-deposit boxes; its upper floors the part bank-upper-<variant>, a structure from 4.6 m up that the game fades over a player inside), a gas station (pumps under a canopy), a body shop (an open bay, open to the sky), a car rental (a lot of three bays), a restaurant (parasols), a bar (neon); a detached house; a factory (a sawtooth hall, a chimney, a loading dock), a depot (loading doors over van bays), a power station (chimneys, a cooling tower); a bus station (a platform under a canopy) and a surface car park. Each says what it is (tags, amenity=hospital), what its variant looks like (look) and where its anchors are (anchors: its entrance and what it does, some with the level block the generator puts there: a garage, vehicle spawners, the vault's gate as a door and its security camera) and the parts that stand with it (the bank's upper floors). Pieces with a bay, a lot, a canopy cars drive under or an inside one walks into collide as their triangles. |
blender/kits/interiors.py | The interiors library of the walk-in buildings, one style for all: storeys 4.5 m apart, a floor slab with its holes (a flight's, a lift's shaft, an atrium), outer walls with doorways and windows, the lintels the storey above draws, railings, the anchors of a flight of stairs or an escalator, a lift and a ladder (blocks the generator puts in the level), and the fittings (counters, tables and benches, beds, shelves, plants). Each storey above the ground floor is a part of its own, never with a ceiling: the game fades it over a player under it. |
blender/kits/landmarks.py | The landmarks kit: five buildings one walks into and climbs. A mega-mall (three floors round an atrium under a skylight, an up and a down escalator, a stair core and a lift to a roof car park, six shops, a food court), a general hospital (reception, A&E and its pharmacy, two wards, an operating theatre, the billing department, a helipad up a ladder), a mensa (a double-height dining hall, the serving line, the kitchen and its back door, a mezzanine), a castle (a mound and its ramp, a wall walk all round, a gatehouse, a dungeon, a watchtower up a 12 m ladder, a keep of two halls and a roof, a bridge) and a ski lodge (the ski hire, the boot room's lockers, a restaurant and its terrace, a bar under a snowy gable). Each says its tags, its look, its anchors (a place on every floor) and its parts. |
blender/kits/compound.py | The compound kit: what a walled compound is built of, at its real size: a wall 4 m long and 3 m high on a plinth (and its post, and a length fallen in with a 4 m gap and rubble), gate pillars and a barrier's post, a guardhouse, the headquarters, a lab one walks into (a 4 m doorway, its roof a piece of its own that fades over a player inside, lab benches, server racks, the Calm Pod), a two-storey annex with fire stairs up its side (two rail variants, the hidden slope a walker climbs, an invisible stop at the landing's end), a loading shed with its dock, camera masts, hedges, planters, crates, a dumpster, vending machines, a break shelter, a sculpture, a logo sign and a sign of repairs pending. |
blender/kits/street.py | The street kit: what dresses a town's streets, yards, building sites, lake shores and volcano slopes, at its real size. The street (a bus stop's sign, a mailbox, a newspaper box, a phone booth, an advertising pillar, a parking meter, a pay machine, a bike rack, an e-scooter, a street sign with a blank plate, a wheelie bin, recycling bins, a cash machine, an A-board, a café table under its parasol, a market stall under a striped awning, a flower bed), yards and parks (a fence panel 2 m long, a garden shed, a trampoline, a washing line, a barbecue, a swing set, a slide, a basketball hoop), works (a traffic cone, a roadworks barrier, a site fence, a site cabin, a cement mixer, a pallet of bricks, a scaffold 4 m wide on two levels, a tower crane 30 m tall), parked cars (a hatchback, a sedan, a van, a pickup, the size of the game's own) and a car park (a pad of asphalt 16 × 12 m and 4 cm thick, two rows of four painted bays, nothing to collide with), the lake (a jetty 16 m long whose deck stands 0.5 m over its base, a rowboat, a swan pedalo, reeds, a beach umbrella, a sun lounger, a lifeguard tower) and the volcano (basalt rocks, a fumarole, a warning sign, a seismograph hut). Props collide as hulls (the washing line, the reeds and the car park not at all, the crane as its triangles), the jetty is a structure walked on; the light ones carry a breakable mass, the parked cars theirs (1,100 to 1,800 kg), so a hard hit shoves them. |
blender/kits/nature.py | The nature kit: what grows, lies and stands on a region's plots between the towns, at its real size. Flora (a round, a wide and a flowering bush, a clipped hedge 2 m long, a flower bed, wild flowers, heather, reeds; an oak, a birch, a fruit tree, two autumn trees, a poplar, a cypress, a palm, a dead tree; a saguaro, a barrel cactus, a dry shrub; a vineyard's row 8 m long), rocks (two boulders, a large one under its moss, a flat stone, a cairn), the farm (a round and a stack of square hay bales, a beehive, a woodpile, a post-and-rail fence and a dry-stone wall 4 m long, a five-bar gate, a well, a trough with its pump, a scarecrow, a windpump) and the wayside (a finger post, a shrine, a log bench, a picnic table, a hunter's hide, a viewing telescope, a viewpoint's railing, ruins: a broken wall, an arch, a tower's stump; a dome and a ridge tent, a campfire whose logs and flames are the material flame the client lights, a log seat, a stump, a fallen log, a rusty wreck, two gravestones and a grave, an allotment's shed, a cold frame, a compost bin). Props: the trees, the saguaro, the arch and the tower collide as their triangles, the flowers, heather, reeds, dry shrub and campfire not at all, the rest as hulls; the light ones carry a breakable mass. blender -b --factory-startup --python assets/blender/kits/nature.py -- --out apps/level-editor/assets/kits rebuilds it. |
blender/kits/urban.py | The urban kit: what a city's roofs carry, what floats in its harbour and what its squares and sites are busy with, at its real size. The roofs (nothing collides with them: an air conditioner and a row of three, a ventilation plant, a cooling tower, a mushroom vent and a row of three, a stair head, a timber water tank on its legs, a skylight, a solar array, a satellite dish, an antenna mast, a lattice cell tower, a planter of shrubs, a terrace with loungers under a parasol, a chimney stack, a billboard, a pigeon loft, a pool, a greenhouse, a run of pipes, a helipad's painted disc), the harbour (a river barge 26 m long with gravel and coal in its hold, a tugboat, a fishing boat, a channel buoy that a car knocks loose, a ship-to-shore gantry crane whose boom carries a container over the road), the streets (a food truck, a hot-dog cart, a fruit stand, a flower stall, a bronze statue on its plinth, a carousel 9 m across, a builder's skip, a portable toilet, a cable drum). It borrows the street kit's palette and shapes. blender -b --factory-startup --python assets/blender/kits/urban.py. |
blender/kits/osm.py | The OpenStreetMap kits, from packages/catalogue/src/osm/recipes.json. A building for each of its 125 building recipes, bld-<key>-<variant> (shop=bakery → bld-shop-bakery-a; a second variant for 17 of them in another look of the same family, the other roof of its kind and 8 % shallower), drawn by its form (osm_forms.py) at its size, storeys and roof, in its look and accent, with its sign and glyph (on a panel on its roof too, facing up, so the top-down camera reads a bakery's bread or a pharmacy's cross), its frontage and its tags, look and anchors (entrance, a counter with its shop block, loading_dock, driveway, yard, a car dealer's lot_<n> vehicle spawners, prop_<n> naming the street kit's piece the town generator stands there: a kindergarten's swings and slide, a market hall's stalls, a dealer's parked cars), in five kits by its recipe's kit: osm-civic, osm-commercial, osm-residential, osm-industrial, osm-leisure (142 pieces, 44 to 892 triangles). The 19 facilities of the kit osm-facilities (a sculpture, a bike-share dock, bleachers, a boundary stone, a static caravan, a basketball court, a drinking fountain, an EV charger, an information board, a memorial, an outdoor gym, a parcel locker, a pumpjack, a street cabinet, a toilet block, a tomb, a utility pole, a vending machine, a wayside cross; 30 to 260 triangles). Writes packages/catalogue/src/osm/buildings.generated.json (every archetype's tag, kit, family, landuse, size, footprint, variants, tags, anchors, looks, noun, count and doc), which cityparts.py adds to the town generator's buildings. blender -b --factory-startup --python assets/blender/kits/osm.py -- --out apps/level-editor/assets/kits rebuilds them all; a piece over its budget stops it. |
blender/kits/osm_forms.py | The OpenStreetMap buildings' eleven forms (osm.py), each drawing a recipe resolved for one variant and giving its anchors: a shopfront (a shop window under an awning or a glazed front, a sign band, windows above), a house (a porch or a sign board; its drive, farmyard or fenced play yard beside it), a terrace (a semi-detached pair, a motel row behind its walkway canopy), a block (punched windows, strips or ribbons by its look; a portico of columns on a stone one), a hall (a glazed entrance, its sign big on its roof; a glasshouse, a stadium's bowl of stands round a pitch), a shed (roller doors in its gable end, a barn's braced doors and cupola on its red roof, a loading dock on an apron behind; a row of garages), a canopy (a carport, a market hall, a car wash), a kiosk (a hut, a hatch; a felt round ger), a chapel (a church's tower and spire or a chapel's bell-cote; a mosque's dome and minaret), a tower (a windmill, a storage tank, a lattice mast, a silo) and a lot (a car dealer's bays before its showroom, self-storage units). |
blender/kits/osm_parts.py | What the OpenStreetMap buildings are made of: facades (windows and ribbons 2 cm into the wall and 8 cm proud, doors 4 cm in, shop windows under their transom, awnings, roller doors under their housing, porches, chimneys), roofs (a gable along X or Y, a hip, a mono pitch, a barrel, a sawtooth, a parapet ring, a dome, a pyramid), signs (a band over the front, a blade, a pylon, a panel lying on the roof facing up or the top of a box rising through a pitched one) and the recipes' 7 × 7 glyphs as boxes 6 cm proud of their panel, in a colour that reads on it, their lit pixels merged into rectangles. |
blender/levels/citygen.py | The generic side of a city generator: roads with height profiles, junctions and their rounded kerb corners, one conforming ground (a constrained Delaunay triangulation of road bands, corners, zones and cuttings, each layer at its height, walls where they meet), an occupancy map of footprints. No bpy. |
blender/levels/cityparts.py | What every city generator shares (bpy): the downtown and civic buildings' footprints, kits and heights, then the OpenStreetMap kits' generated archetypes (buildings.generated.json, after the hand-made ones), what their sidecars say of them (tags, looks, anchors), and their frontage along a street (fronts on the pavement's back line or set back behind it, never touching; a district's landmarks first), the game's frame, the placer, the ground's mesh, zebra crossings and the hidden road pieces carrying the centre lines. |
blender/levels/generate.py | The spec-driven generator: blender -b --factory-startup --python assets/blender/levels/generate.py -- --spec <spec.json> --out <dir> [--seed <n>] validates a level spec (one line per problem, exit code 1), hands it to its template (grid-town: town.py; city: city.py, which builds the plan the city solver resolved, --plan <plan.json>) and writes the level's kit (.glb + .foi.json), its recipe and its named places (<name>.places.json). Deterministic: the spec's seed is all its randomness. See Levels. |
blender/levels/town.py | The grid-town template: a town on a grid of kerbed blocks from a spec (blocks, block size, street width, avenues, districts with their building mix (archetypes, tags, <key>=*, family:<family> and landuse:<landuse> wildcards sharing their weight by how common each building is), satire theme, landuse, title, density and landmarks, parks, street furniture): one road per street line with the outer ring's corners rounded, rounded kerbs, traffic lights and zebra crossings at every junction, buildings along every street, parks with paths and a fountain, spawn rows on the southern street (a region's town has none, unless the region's start names it: four on its first east-west avenue), a themed district's buildings named after its brands, its lots laid as lawns behind set-back fronts, the blocks the buildings' anchors carry (a garage in a body shop, locked cars on a car rental's, a depot's and a car park's bays, shops at a supermarket's, a gas station's and a shop row's counters, the hospital's and the police's spawn points, the vault's gate and camera in a bank), a building's parts with it, a district block per block of the grid, the dressing of a lived-in town (dressing.py); places for junctions, parks, buildings (with their tags and names), their anchors and spawns. Its walled compounds are compounds.py's. The themes are packages/catalogue/src/themes.json. Builds test-generated-town, test-buildings, test-osm-buildings, test-landmarks and test-compound. |
blender/levels/relief.py | A town of a region on the region's land (generate.py --relief): the corner levels under its footprint, the seam of the region's ground round it, the roads that end at it; every street's profile between its level junctions, a smooth ground between the streets held at the pavements and the seam, buildings on pads. Builds test-tiles-town's old_town. |
blender/levels/compounds.py | A grid town's walled compounds (the spec's compounds): a block behind a wall set back behind a lawn, its main gate (pillars, a barrier and a door locked by keycard, a guardhouse), a delivery gate with a loading shed and a locked van, a gap, an annex across the back wall with fire stairs, the headquarters, a lab one walks into, a car park, a break shelter, cover; its cameras and its guards (NPC spawners on schedules: shifts, a break an hour each, a round of the yard) by its security; its places (<name>.gate, .gap, .roof_stairs, .lab_pod, …) and spawn points for a mission's guards. Drawn in the compound's own frame and turned to the gate's side; every piece on the town's occupancy map. Builds test-compound's Zenful Campus. |
blender/levels/dressing.py | A town lived in, what a grid town's dressing: "lived-in" asks for (none, the default, leaves a town as it was, byte for byte), on a random stream of its own: mostly the street kit's pieces placed by town.py's placer. Before the buildings, car parks on some lots (a painted pad of bays, cars parked in them, a pay machine; places carpark_<n>) and one construction site (a fenced yard, a cabin, a cement mixer, pallets of bricks, a scaffold, a tower crane; the place site), each on a level pad on sloping land. After them, the kerbside furniture by district theme within 1.2 m of the kerb (bins, benches, mailboxes, newspaper boxes; parking meters in the depot and the town hall's district; bike racks and e-scooters on the campus; phone booths and advertising pillars in the old town), a bus stop with its shelter on the avenues every 120 m or so (places bus_stop_<n>), a street sign at each junction, a billboard by every road coming in, the back yards by theme (fences, sheds, trampolines, washing lines, barbecues…) and the parks (a playground, or an old town's market stalls round its square, the place market). Dresses test-tiles-town's old_town. |
blender/levels/curves.py | The generator of test-curves, the first hillside's curves, kept for driving feel on the curves a region's roads cannot make: a city on a grid of kerbed blocks (avenues crossing at a roundabout, a crescent around a garden, a park with a pond and a sinuous drive, a plaza, a car park with a deck, a ring road with sweeping corners and a wavy boulevard along the hills, buildings of the downtown kit along every street) under a range of hills (the main avenue runs under the central hill through a tunnel, a serpentine of hairpins climbs the east hill to a lookout, a bumpy dirt rally track crosses the western hills, the north road bridges a gully). blender -b --factory-startup --python assets/blender/levels/curves.py writes the level's own kit (terrain, tunnel roof, paint, road pieces) and test-curves.recipe.json. |
blender/levels/network.py | A street network drawn freely, for a city that is no grid (riverbend.py): street styles (a parkway, an avenue, a boulevard, a street, a lane, a one-way lane, a roundabout's ring), and a Net the streets are drawn into as polylines, each cut onto the road it starts or ends on (start_on, end_on), spanning between two (span), closed into a loop in parts, a roundabout as arcs between its arms, a cul-de-sac with its turning circle; problems() says what would break the ground before anything is built (a bend tighter than the road is wide, two junctions too close, two roads meeting too sharply to round). No bpy. |
blender/levels/citylife.py | What makes a free city lived in, by district, from the shared kits (every footprint read from the kit library, packages/catalogue/src/kits.generated.json): car parks and building sites before the buildings take the lots, the pavements' furniture every dozen metres and bus stops on the avenues, a car on the houses' drives, container yards, what stands in the yards, jetties, boats and reeds on a river, roadworks, billboards round a ring road, and paint (stop lines, manholes and drains, cycle lanes); and from the urban kit, what the roofs carry (rooftops: on the free spots the kit library gives a building's flat roof, by the building's family and its district's lean, the largest things once a roof), ships and buoys on a reach of the river and cranes along a quay before the buildings take its lots. |
blender/levels/city.py | The city generator, Riverbend's engine: a plan (roads, roundabouts, rivers, hills, districts and their styles from packages/catalogue/src/city/styles.json, parks, places; plan_from_json reads the city solver's) built as a city: one conforming ground with the rivers' channels, bridges, the buildings walked along every street by district, the street furniture, the parks and squares, lookouts on the hills a road climbs, and the dressing (citylife.py). generate.py --plan and riverbend.py build through it. |
blender/levels/riverbend.py | The generator of main-riverbend, the flagship city: its network (network.py: 86 roads, 16.7 km, a river with seven bridges), its districts by style and its parks, a plan city.py builds (byte for byte the city it built before); one conforming ground (citygen.py: every road band, rounded corner, pavement strip, square, park and the river's channel a constraint), its thirteen districts with their mixes, landmarks, street trees, kerbside furniture and yards, its buildings walked along every street (cityparts.frontage: the landmarks first, the big before the small, an infill of the narrow ones, the outbuildings behind) and its dressing (citylife.py). blender -b --factory-startup --python assets/blender/levels/riverbend.py writes the level's own kit (terrain, bridges, paint, road pieces), main-riverbend.recipe.json and its places, lifted 4 m so the river's bed is over the level's floor; RIVERBEND_DRAFT=1 leaves the buildings out for a look at the streets in seconds. |
blender/levels/drift_pad.py | The generator of test-drift-pad, the mini level of the tyres' effects and of the seats: an asphalt skidpad 44 m across with a painted circle, a dirt patch with a dirt track across it, a run up to the city kit's ramp and a shipping container. Writes the level's own kit (pad, dirt, the roads' markers) and test-drift-pad.recipe.json. |
blender/models/vehicles.py | The twenty-three vehicle classes (the police car in its livery with a light bar; the taxi with its roof sign, the bus, the ambulance and the fire truck with their light bars, the fire truck's ladder, the garbage truck's compactor; the pickup's open load bed behind its crew cab, the black limo's six seats in three rows with a door each, the delivery scooter's top box, the ice-cream van in its own pastels with a serving hatch on its kerb side under a striped awning and a giant cone on its roof, the tractor's big lugged rear wheels drawn bigger than the simulation's and its open seat in a roll frame) and the semi's trailer: a body per class sized to the simulation's chassis (packages/sim/src/vehicle-classes.ts; its convex hull, with the wheels and the doors above the body's floor, becomes the collider) and wheels as children where the ray-cast wheels sit (in the body's frame; the client turns the front pair about each tyre's middle as the car steers), and before the driver of everything on four wheels or more a steering wheel, <class>-steering (its origin on its middle, its local Z along the column, one mesh per size shared by the classes), which the client turns as the car steers and the hulls leave out. A model's frame is its node's own (origin at the chassis centre); the classes stand in a row in the file only to be seen side by side, and the game ignores where a node is placed. The windows are panes over holes in the body with a grey interior up to their sills, so the client draws the glass see-through; every closed vehicle's doors are children <class>-door-<tag> cut out of its sides (panels.py), their origin on the hinge, with their doorway and swing. Every seat is an empty under the body, <class>-seat-<n> (the driver's first), at the hips of whoever sits there (low enough for a head under the roof, a car's front row under the windscreen's top), with its pose (driver, passenger, rider, pillion), its view (open on the buggy and the two-wheelers; closed behind a car's glass), its door (the doorway that serves it) and its legs (hidden where the hips sit inside a car's or a van's solid interior, which the client draws without legs so none pokes out under the body). Writes vehicles.glb; npm run models:hulls turns the bodies into packages/sim/src/vehicle-hulls.json and npm run models:check keeps them in step. |
blender/models/weapons.py | The weapons people hold and what flies: a pistol, the tranquilizer, a pump shotgun, a rifle, a rocket launcher, a grenade and the rocket a launcher fires, each a top-level object named by it, its origin on the grip (where the right fist holds it), its barrel along +Y, the end its shot leaves by an empty <name>-muzzle. The client puts a weapon in the fist as the figure is posed and flies the rocket and a thrown grenade as the projectiles; writes weapons.glb. |
blender/models/panels.py | Plane geometry for the vehicles' panels, no Blender: a side profile minus convex holes (doors, windows) as convex pieces that weld into one shell without T-junctions, a polygon kept inside an outline, and prisms built from them (a body side with its openings, a door with its window). |
blender/models/character.py | The character: a 1.8 m low-poly figure standing on the origin (the game places it by its capsule centre), facing +Y (its toes, nose and chest that way), with the body material the client tints; no armature: a hierarchy of ten rigid parts (character an empty at the feet; character-torso from the hips, carrying character-head at the neck and the short sleeves character-arm-l and -r at the shoulders, each carrying its bare forearm and hand character-forearm-l / -r at the elbow; character-leg-l and -r at the hips, each carrying its shin and shoe character-shin-l / -r at the knee), each with its origin at its joint, which the client turns to pose the figure. Writes character.glb. |
blender/models/animations.py | The character's clips: 81 simplistic keyframed motions of those parts (and of the empty at the feet: a crouch drops it, a roll turns it; the city's idlers sit on a bench, smoke, sweep, walk a dog, eat and lean on a vendor's counter), each pose written as a few angles and planted on the ground by forward kinematics, keyed one after the other on Blender's timeline (linear, as the client samples them), read back off the curves into apps/client/public/models/animations.json (per clip its duration, loop, layer and stride; per part its keys). build(), sheet([...]) and export_clips(path) from the MCP server; headless blender -b --factory-startup --python assets/blender/models/animations.py -- --out apps/client/public/models. See Animation. |
blender/models/companions.py | The companions, in the character's frame (facing +Y, its left −X, standing on its origin): a brown dog 0.6 m at the shoulder, its body dog (with its red collar) and the parts the client swings at their joints, dog-leg-fl, -fr, -rl, -rr (at the shoulders and hips), dog-head (at the neck's root) and dog-tail (at its root), 244 triangles; and cart, a street sweeper's two-wheeled bin cart 1.2 m long, its handle toward −Y, a broom and a shovel standing in it, 160 triangles. Writes companions.glb; headless blender -b --factory-startup --python assets/blender/models/companions.py -- --out apps/client/public/models. |
Conventions
- Metres, Blender's Z up; +Y is a piece's forward (the game's +z) and +X its right as seen in the top view, which is the game's screen. The tools turn the glTF frame (+Y up) into the game's with one rule,
game = (−x, y, −z), and nowhere else. - A kit
.blendsorts its pieces into the top-level collectionsTerrain,Structures,Buildings,PropsandRoads(the piece's kind); the custom propertycollider(trimesh,hull,none) says how it collides (terrain and structures as trimeshes, buildings and props as hulls, roads not at all, by default),renderfalse hides it (a collider nobody sees),breakable(kg) makes it a light piece a vehicle with the kinetic energy of a mid-size car at 60 km/h knocks loose (a hydrant, a lamp; a truck at a crawl;packages/sim/src/breakables.ts). A curve inCentrelinesparented to a piece is one of its roads, withwidth,lanes,lanesBackandspeedas custom properties. - Pieces the level scales (buildings, slabs, terraces, ramps, stairs) are modelled at unit size around the unit blocks' origins; props and road pieces at their real size with the origin on the ground. Vehicles are modelled around the chassis centre, facing +Y.
- Low poly: flat colours (the Principled BSDF's base colour, no textures), flat shading, a few hundred triangles per piece; the game draws them with a sun and a sky light. The budgets, in triangles: a prop 150, a small building (a café, a house, a bar) 300, a building 800, a tall or ornate one (a tower of many windows, a town hall, a courthouse, a hotel) 3,000. The
civickit's buildings take 184 to 1,330, thedowntownkit's 84 to 2,844; the OpenStreetMap kits' are held to 600 (a shopfront, a house, a kiosk, a canopy), 900 (a block, a hall, a chapel) and 700 (the rest), a facility to 300. - What a building is and does. A building piece carries custom properties the export writes into the sidecar:
tags, a JSON list of OpenStreetMap-style tags (["building=hospital", "amenity=hospital"]:building=its form, and what it is for underamenity=,shop=,tourism=,office=,industrial=,power=,parking=),look, the colour its variant leans to (white,stone,brick,glass,concrete,pastel,metal,bold; a district's theme prefers some), andanchors, a JSON object of its named points ({"entrance": {"at": [x, y, z], "facing": [fx, fy]}}in its own frame, on the ground or a floor, looking alongfacing), each with the level block the generator puts there when it has one (block:garagewith itssizeand prices,vehicle-spawnerwith its class, owner, lock and respawn,shopwith what it sells,spawnwith its role,doorwith itssizeand its kind and lock,camerawith its sweep, range and period) or the piece of another kit it stands there (piece:street/swing-set), andparts, a JSON list of pieces of its kit placed with it at its origin and turned as it is (a building one walks into keeps its upper floors apart, a structure the game fades over a player inside, so that nothing of the building stands over a floor of its own and the navigation finds the way in). The generator (assets/blender/levels) reads them from the sidecar: the tags and a place per anchor (<district>.<archetype>_<n>.<anchor>) go into a generated level's places, the blocks into its recipe. The catalogue (packages/catalogue/src/buildings.ts) lists the same tags and anchor names, and its tests hold the two together. - No coplanar faces. No two faces of a piece lie in one plane, facing the same way, over any area: the renderer would flicker between their colours (z-fighting). A detail starts 2 cm inside its wall and stands proud of it (a door or an entrance 4 cm, so its buried back never meets a window's where they cross); a cornice is a ring around the body it crowns, never a slab across its roof; stripes lie side by side; a part that would poke through another's face stops at it or goes into the other's volume. Only the faces turned down on a building's or a prop's base plane, which rest on the ground, are left alone.
packages/world/src/coplanar.test.tschecks every placed piece of every level andapps/tools/src/kits.test.tsevery piece of every kit; both are innpm test. - The generators are the source of truth for what they generate: change the script and run it again. Hand-modelled
.blendfiles, when they come, live next to the scripts and are committed as they are (binary, see.gitattributes). - After regenerating a shared kit (any but a level's own
test-*ormain-*kit), runnpm run kits:exportand commitpackages/catalogue/src/kits.generated.jsonwith the kit: the kit library, every piece's kind, collider, footprint and bounds measured on its triangles, triangle count, tags (its sidecar's, else words derived from its kit, kind and name), anchors, breakable mass, roads and parts, which the catalogue and the MCP server show Claude.npm run level:checkbuilds it again from the kits and fails when it drifts (see Levels).
Blender from Claude Code
Blender can be driven from Claude Code (the kits, the vehicles and the character are modelled that way). Blender 5.1+ ships an official MCP extension (blender.org/lab/mcp-server): once installed and started from its preferences (Blender's Online access must be on), it listens on localhost:9876, but that socket is only a bridge and not an MCP endpoint. The MCP server is a separate stdio process in Blender's blender_mcp repository, launched by Claude Code itself; it needs uv:
git clone https://projects.blender.org/lab/blender_mcp.git ~/repos/blender_mcp
claude mcp add blender -- uv --directory ~/repos/blender_mcp/mcp run blender-mcpThe clone can live anywhere (on Windows give --directory the full path, C:\Users\<you>\repos\blender_mcp\mcp); because the path is per machine the server is registered in the local scope and not in .mcp.json. claude mcp get blender must report it connected; a git pull in the clone updates it. Two configurations that look right do not work with this add-on: an http://localhost:9876 entry (the socket speaks no HTTP) and the third-party package uvx mcp-for-blender, which uses the same port with a different protocol and hangs on every call.