Skip to content
Kiln1.7Get Kiln

Describe a 3D model, or hand your agent a photo, sketch or concept art. It writes the model as a program, Kiln shows it what it built, and you keep a GLB with its source.

A Gothic cathedral seen from the ground at its south-west corner: twin west towers about 80 m tall, three deep portals, a rose window, flying buttresses and a lead spire over the crossing. In front of the south tower stands a 6 m walking mech in olive armour, small against the building, with a rotary cannon and a rail cannon with glowing coils.
Both models below, placed together for this picture at their true sizes: a 6 m mech in front of a 100 m spire.

MIT · runs on your machine · MCP, CLI and TypeScript library · setups for 7 coding agents

Text to 3D is one way into Kiln. Walk Meridian Sanctuary , a world built with Kiln assets, or browse the gallery.

A walking mech you can drive from code.

A 6 m walker with named joints, pistons that follow them and a Walk clip whose feet don't slide. All of it is there for your game code to find.

Pilot a version of this walker in a desktop browser mech defense demo.Play H-7 pre-alpha

The finished walking mech in three-quarter view: olive armour with chipped edges and hazard stripes, a rotary cannon on its right arm, a long rail cannon with glowing cyan coils on its left, a glass cockpit and a shoulder missile pod, standing on two digitigrade legs with hydraulic pistons.

Drag to orbit after opening. The model starts stationary.

Open it, then choose Walk in the Animation menu.

See all 3 revisions and their prompts
  1. The agent's six-view contact sheet of the first saved revision: front, right, back, left, top and three-quarter, each with a yellow label.

    Revision 1

    First prompt

    A rigged walker with a Walk clip. Each toe stays within 0.4 mm of where it lands.

    Its source, 1,430 lines, Mech revision 1
    Read the prompt, 149 words
    Mech, prompt 1
    Make a heavy walking mech for a three.js game, about 6 m tall. Two digitigrade legs, an armoured torso that turns at the waist, a cockpit with a glass canopy, a shoulder-mounted missile pod and two heavy arms: a rotary cannon on the right and a claw on the left. Every joint has to be its own named pivot (hip, knee, ankle, toe, waist, shoulder, elbow) so I can drive it from code, and the hydraulic pistons on the legs should really follow the joints. Add one looping Walk clip where the feet plant without sliding and the torso sways and counter-rotates. It should look like it came out of a AAA concept: layered armour plates with panel lines, weathered paint, hazard stripes, exposed cables and machinery at the joints. Keep the GLB under 5 MB so it loads in a browser. Save it when you're happy with it.
  2. Close view of the shoulder armour on the first revision: flat olive paint with a few specks.The same shoulder on the second revision: chipped edges down to bare metal, grime in the panel lines, rust streaks, bolts, louvred vents and layered plates.

    Revision 2

    Art note

    Chipped paint, grime in the panel lines, rust from the joints and real gunmetal. Height, joints and clip untouched.

    Its source, 1,763 lines, Mech revision 2
    Read the prompt, 136 words
    Mech, prompt 2
    Good bones. Three notes from me.
    
    The paint still reads as flat olive with specks on it. I want wear you can believe: chipped paint showing bare metal along plate edges, grime settled into the panel lines, oil and rust streaks running down from the joints and bolts, and lower legs that are darker and dustier than the torso.
    
    The shoulders, forearms and feet are plain boxes and wedges next to the detail on the legs. Give them layered plates, bevelled edges, bolts and vents, and make the feet read as armoured toes with rubber soles.
    
    The cannon barrels and joint machinery should read as real gunmetal, with some sharp highlights.
    
    Keep the height, every joint name, the Walk clip and the 5 MB limit, and save it as a new revision of the same asset.
  3. The mech on revision 2, with a three-fingered claw on its left arm.The mech on revision 3 from the same camera, with a long rail cannon and glowing coils in place of the claw.

    Revision 3

    One swap

    The claw becomes a rail cannon. The Walk data stays identical, byte for byte.

    Its source, 1,814 lines, Mech revision 3
    Read the prompt, 40 words
    Mech, prompt 3
    Swap the left claw for a long rail cannon with glowing coils along the barrel. Keep the Walk clip, every joint name and every other part as they are, and save it as a new revision of the same asset.
How the feet stay planted
Solving a leg
function solveLeg(sgn, f, pelvisPos, qP) {
  const foot = footState(f);
  const cp = Math.cos(foot.psi), sp = Math.sin(foot.psi);
  const px = foot.cx + (-SK.tipX * cp - SK.toeH * sp);
  const py = foot.cy + (-SK.tipX * sp + SK.toeH * cp);
  const pz = sgn * SK.legZ;
  const hipOff = new THREE.Vector3(0, 0, sgn * SK.legZ).applyQuaternion(qP);
  const dx = px - (pelvisPos[0] + hipOff.x), dy = py - (pelvisPos[1] + hipOff.y), dz = pz - (pelvisPos[2] + hipOff.z);
  const y2 = -Math.hypot(dy, dz);
  const rho = Math.atan2(dz / y2, dy / y2);
  const g = GAMMA(f) * D2R;
  const ax = dx - LM * Math.sin(g), ay = y2 + LM * Math.cos(g);
  const d = Math.min(Math.hypot(ax, ay), (LT + LS) * 0.995);
  const a = Math.acos(Math.max(-1, Math.min(1, (LT * LT + d * d - LS * LS) / (2 * LT * d))));
  const aT = Math.atan2(ay, ax) + a;
  const kx = LT * Math.cos(aT), ky = LT * Math.sin(aT);
  const aS = Math.atan2(ay - ky, ax - kx);
  const aM = Math.atan2(-Math.cos(g), Math.sin(g));
  const tH = wrapA(aT - AT0), tS = wrapA(aS - AS0), tM = wrapA(aM - AM0);
  const qHip = qP.clone().invert().multiply(qx(rho)).multiply(qz(tH));
  const qToe = qx(rho).multiply(qz(tM)).invert().multiply(qz(foot.psi));
  return { hip: qHip, knee: qz(wrapA(tS - tH)), ankle: qz(wrapA(tM - tS)), toe: qToe };
}
Drive it from three.js
three.js, for mech.glb
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const gltf = await new GLTFLoader().loadAsync('mech.glb');
scene.add(gltf.scene);

const mech = gltf.scene.getObjectByName('HeavyWalkerMech');
const mixer = new THREE.AnimationMixer(mech);
mixer.clipAction(THREE.AnimationClip.findByName(gltf.animations, 'Walk')).play();

const { walkSpeedMps } = mech.userData.rig;
const waist = mech.getObjectByName('Joint_Waist');
const barrels = mech.getObjectByName('Joint_CannonSpin_R');
const coils = new Set();
mech.traverse((node) => {
  if (node.material?.name === 'Glow_RailCoil') coils.add(node.material);
});

// Once a frame. Walk plays in place, so your game moves the body.
function update(dt, { aim = 0, spin = 0, charge = 2.2 } = {}) {
  mixer.update(dt);
  waist.rotateY(aim); // Walk sets the waist, so add your aim after the mixer.
  barrels.rotateX(spin * dt); // Walk leaves the barrels, wrist and hatches to you.
  for (const coil of coils) coil.emissiveIntensity = charge;
  gltf.scene.translateX(walkSpeedMps * dt); // +X is forward.
}

// Pose the legs yourself and the pistons need aiming again.
// Each one stores what it follows.
const pistons = [];
mech.traverse((node) => {
  if (node.userData.aimAt) pistons.push(node);
});
function aimPistons() {
  mech.updateMatrixWorld(true);
  for (const piston of pistons) {
    const target = mech.getObjectByName(piston.userData.aimAt).getWorldPosition(new THREE.Vector3());
    const direction = piston.parent.worldToLocal(target).sub(piston.position).normalize();
    piston.quaternion.setFromUnitVectors(new THREE.Vector3().fromArray(piston.userData.aimRestDir), direction);
  }
}

A 144 m Gothic cathedral, written as one program.

Towers about 80 m tall, a 100 m lead spire, ribbed vaults, carved portals and stained glass, inside and out. Because it's one program, two more bays took one short prompt.

The cathedral isn't fully polished yet. A better revision will replace this one here.

The finished Gothic cathedral from the ground at the south-west: twin west towers, three deep portals, a rose window, stepped buttresses, flying buttresses and a lead spire over the crossing, in weathered stone with the sun baked in.

Drag to orbit after opening. The model starts stationary.

Open it, then choose Look inside to stand in the nave. It's a heavy model, so it needs a reasonable graphics card, and it hasn't been tried on a phone.

CC0-1.0 : use both for anything. Its oak and iron textures come from Poly Haven, also CC0.

Prompts
10
Triangles
4.0 M
GLB
15.9 MB
The view down the cathedral nave from the floor: clustered piers, ribbed vaults, statues on the piers, stained glass in the apse, and ruby and cobalt light from the south windows lying on the paving between the piers on the right.

Stand in the nave.

The sun baked into the stone also comes through the south windows, so each one lands on the floor in its own colours, between the columns.

See all 9 revisions and their prompts
  1. Four labelled views the agent rendered of its first revision: the rose window in flat primary colours, the pale west front, the view down the nave with blocky coloured light on the floor, and the east end.

    Revision 1

    First prompt

    The plan, the vaults, the statues and the stained glass.

    Its source, 2,853 lines, Cathedral revision 1
    Read the prompt, 205 words
    Cathedral, prompt 1
    Build a massive Gothic cathedral, the kind of model that makes a professional 3D artist stop and look. True scale: about 130 m long with twin west towers about 80 m tall. A nave of nine bays with side aisles, transepts, and an apse ringed with radiating chapels. Flying buttresses with crocketed pinnacles on every bay, and gargoyles along the walls. A west front with three deep portals, robed saints in the door jambs, carved tympana over the doors, a gallery of kings, and a great rose window with real stone tracery. The statues have to read as sculpted figures, not blocks. Stained glass in every window, as real art: the rose and the big windows should depict figures and scenes in leaded panes, not just coloured squares. Use real textured PBR materials: weathered limestone with carved detail in the normals, patinated lead roofs, aged oak doors with iron straps, gilded accents. The inside has to hold up too: clustered columns, triforium, clerestory and ribbed vaults, statues in niches and glass that colours the view. Keep the GLB under 15 MB so it can load in a browser. Build it from parameters so the design can change later. Save it when you're happy with it.
  2. The central west portal in revision 1: clean pale stone, smooth melted-looking statues in the door jambs and flat figures in the arches.The same portal in revision 2, from the same camera: weathered stone with soot and rain streaks, sculpted figures in the jambs and arches, and canopies floating high above the statues.

    Revision 2

    First art note

    Sculpted saints with real faces, medieval glass, and a sun baked into the stone.

    Its source, 3,775 lines, Cathedral revision 2
    Read the prompt, 649 words
    Cathedral, prompt 2
    Strong bones. The plan, the vaults and the view down the nave are right, and I believe the scale. As art it isn't there yet, and this has to stop a professional 3D artist. I looked at it from the ground outside, up close at the portals and from inside. My notes, most important first.
    
    The statues look like melted candles. Faces have no real features, hands are mittens, feet are two balls and the heads jam straight into the canopies. The figures in the door arches are thin cut-outs floating on the stone, and the lintel's reliefs are buried so only stray bits poke out. Sculpt them like the real thing at Chartres and Reims: long columnar bodies, deep folds you could put a finger in, real faces with brow, nose, lips, hair and beards, hands that grip what they hold, feet on a carved base and room above the head. Make them different people: a bishop in a mitre, a crowned king, a veiled queen, an apostle with a key, a smiling angel, the Virgin and Child on the central door post. I would rather have fewer figure types that are truly good than many that are poor. Carve the tympana as scenes, with figures that overlap and turn to each other, not a row of people on wallpaper.
    
    The glass looks like clip art: flat primary colours and cartoon people. Real medieval glass is deep ruby and cobalt with no two panes quite alike, black lead lines, and brown painted shading that draws faces, hair and drapery. The rose should be the most beautiful thing in the building. From outside, glass should read dark and deep with the colour only hinting through. Right now the windows are as bright as toys outside, and some wash out to pale pink at an angle. The colour belongs inside.
    
    The stone has no age and no depth. Outside it is one clean cream everywhere, so you can't feel how deep the portals are. This building has stood for 700 years: soot in the recesses, rain streaks under every ledge and sill, each block a slightly different colour, darker and greener toward the ground. The viewer has no cast shadows, so bake the light in: a low sun from one side, so the portals go deep, the galleries go dark behind their columns and every ledge throws a shadow below it. The printed quatrefoil pattern on the portal walls and tympana looks like wallpaper, so carve it or remove it. The tower walls are flat ashlar with thin lines stuck on, so give them real blind arcades and relief. Inside, warm the stone, and let it go darker low in the aisles and lighter up in the vault. The coloured light on the floor looks like painted tiles: make it soft pools with the shape of the windows.
    
    Materials should hold up close: lead roofs with visible sheets, seams and streaked patina instead of stretched noise, stone with tool marks instead of round pockmarks, and gold that looks like gold instead of mustard. The altar's gold box should become a carved retable or go.
    
    Faults I can see. A free-standing column sticks out of the north transept front, between the portal and the big window. The flying buttresses are thick flat boards: make them real arches, thin and pierced, with a sloped top. The bell openings are dark walls with nothing in them: make them real openings with louvres. The arches around the apse look like fangs hanging from above instead of springing from the piers.
    
    Keep the plan, the dimensions and the parameters. Keep the GLB under 15 MB and leave about 1 MB free, because I will want changes later. Textures are only 1.4 MB of the file, so spend your bytes on what gets looked at closely. Save it as a new revision of the same asset.
  3. The west front in revision 2 from the ground, floating with no ground around it, with flat wall plates at the tower corners and thin sheets sticking out over the portals.The same view in revision 3: paved ground, buttresses that step back as they rise with sloped caps, and diagonal piers at the corners.

    Revision 3

    Second art note

    Real ground, stepped buttresses, carved portals and glass that reads dark from outside.

    Its source, 3,960 lines, Cathedral revision 3
    Read the prompt, 700 words
    Cathedral, prompt 3
    I'm back, and thanks for the honest report. The nave, the vaults and the rose seen from outside are what I wanted, and the stone finally looks old. Here's what comes next, most important first.
    
    A correction before that. I told you the build limit was 120 seconds, and your kiln_save still failed after about a minute. I don't know why yet, so plan on 60. With this machine quiet, your saved revision builds in 32 seconds, so most of those failures were other jobs on the machine rather than your program. You have more room than you thought.
    
    It has no ground. Apart from a paved patch at the west doors, the building floats. Give it real ground all the way round: worn flagstones for about 20 m, a step or two up to each door, rough grass or packed earth at the edge, and dark grime where the walls meet it. Make the ground its own named part, so it can be taken away if the building is later placed in a town. Keep its top a few centimetres above y = 0, so it doesn't fight with a viewer's ground plane.
    
    The corners aren't real architecture. At the corners of the towers and transepts, thick wall plates stick out past the corner and overlap each other, and high on the towers some hang in the air with a slanted edge. Around the apse and along the sides, the buttresses are huge plain boxes, and the set-offs on the west front's buttresses are thin sheets that stick out like awnings. Build real buttresses: solid piers tied into the wall, narrower as they rise, stepping back in two or three stages, each step a sloped stone cap that belongs to the pier. Where two meet at a corner they should meet cleanly, or run diagonally as one. From any angle, nothing should float, overlap or pass through anything else.
    
    Inside. Fix the light bug you found: the piers on one side are still blue-grey. The shadows on the vaults and piers have hard-edged bands, and the light pools on the floor break into hard-edged islands up close. Make them smooth gradients.
    
    The portals, up close. The canopies over the door statues float far above their heads on thin sticks, like hanging lamps. Bring each one down to just above its head, with the figure standing against its column. The tympanum figures stand on shelves like dolls, in front of a wall of blocks. Carve them out of the stone as relief, with no block joints behind them. The gold frame around Christ is a thin wire with angels passing through it, so make it a carved frame, gilded. The kneeling figures have pumpkin-shaped skirts. From the ground the gallery kings are faceless slivers, so give them bodies and crowns. The queen and the Virgin need different faces. The door straps end in curls that read as the number 3, so make them forged hinges. Remove the yellow blotches like coins at the foot of the portal walls, and the little L-shaped chips scattered around the rose.
    
    The glass. From outside, the windows read as flat purple with red specks. Make them nearly black, with faint lead lines and only a hint of colour, the way the rose already does. Inside, the grounds lean magenta, so keep them ruby and cobalt. The high apse windows have a white ladder across the middle: take it out. I still want the rose to be the most beautiful thing in the building, so look at it from inside and make it so.
    
    The roofs look like a patchwork quilt from above. Make long lead sheets running down the slope, with raised seams and streaks.
    
    Then, if there's room, what your report left open: rain streaks on the apse, chapels and buttress sides, and a shadow under every main ledge.
    
    Keep the plan, the parameters and the height. Keep the GLB under 15 MB and leave at least 1 MB and some build time free, because I'll ask for a change that adds geometry afterwards. Save it as a new revision of the same asset, then tell me plainly what's done and what isn't.
  4. The whole south side of the cathedral in revision 3, with its low flèche over the crossing.The same view after the revision: a longer nave and a tall lead spire over the crossing.

    Revision 4

    Two bays and a spire

    One short prompt. Of the 1,621 meshes before it, 1,610 kept their exact shape: 971 stayed put and 639 moved east together.

    Its source, 4,055 lines, Cathedral revision 4
    Read the prompt, 38 words
    Cathedral, prompt 4
    Add two more bays to the nave and raise a lead-covered spire over the crossing, about 100 m to the tip. Leave everything else as it is and save it as a new revision of the same asset.
  5. The nave floor before the light revision: flat painted bands of pink and blue laid across the paving, running under the piers.The nave floor after the light revision: soft slanted lanes of red and blue light from the south windows, with the shadows of the piers cut through them and colour climbing the feet of the north piers.

    Revision 5

    Light from the windows

    Light traced from the south windows falls on the floor, with the piers' shadows cut through it. 1,705 of 1,715 meshes didn't move.

    Its source, 4,203 lines, Cathedral revision 5
    Read the prompt, 259 words
    Cathedral, prompt 5
    One fault, from looking inside. The coloured light on the nave floor isn't light. It's painted patches: they lean the wrong way for the sun you baked into the stone, their colours aren't the colours of the glass, and they run straight through the piers as if the piers weren't there.
    
    Make it real, and baked like the rest. Use the same sun as the stone, P.sun, low from the south-west. For each point of the floor, trace back towards the sun. If the ray clears the south arcade without hitting a pier and comes through a south aisle window, the floor takes that window's colour at that height, from its actual panes or a close average of them. Otherwise it takes nothing. So each window throws a long slanted pool that runs north and east across the floor, with the shape of its lancets and tracery softened, and the piers cut clean shadows through it. Keep the edges soft, and keep it subtle enough that the paving still reads through it. If the same rays land on the north piers or walls and you can bake that cheaply, do it. If not, leave it and say so.
    
    Leave everything else as it is: the plan, the height, the stone and the glass. Keep the GLB under 15 MB. You have about 0.3 MB free, so take the budget out of the old patches. Keep the build inside the limit. Save it as a new revision of the same asset, then tell me plainly what's done and what isn't.
  6. The nave floor from above the west end in revision 5: long slanted bands of coloured light run the whole way across the nave and onto the far piers.The same view in revision 6: each south window lands as its own ruby or cobalt pool, passing between the piers and stopping around the middle of the nave.

    Revision 6

    A higher sun

    Each window now lands between the columns, and all the stone re-baked to match.

    Its source, 4,240 lines, Cathedral revision 6
    Read the prompt, 356 words
    Cathedral, prompt 6
    I looked at the floor light again and it still isn't right. At this sun it runs the whole way across the nave, past the columns and up the north piers, and your own number says almost none of it could get past the buttresses outside.
    
    Fix it by moving the sun. Set P.sun to about [0.11, 0.79, -0.61]: about 52 degrees up and about 10 degrees west of due south. I tried a few suns on a scratch copy of your source, with the outside counted. With this one each south aisle window lands as its own window-shaped pool that passes between the piers and stops around the middle of the nave, short of the north piers. Further west, the buttresses and piers cut the pools into thin streaks. Adjust it a little if your own checks say so, and tell me if you do.
    
    Count everything in the trace, including the outside: buttresses, flyers, pinnacles, towers and transepts. No light passes through stone. Tell me what share of the rays reaching a window now clear everything.
    
    Start the floor image at the south aisle wall, because light now lands in the aisle, and end it just past where the last light falls, so the texels go where the light is. Where rays stop on a pier, that's now the south faces of the south piers, so put the pier skins there. The north piers should get nothing.
    
    The colour reads as pink and lavender with pale blobs. Make it read as ruby and cobalt light falling on stone, with the paving still showing through, and soften the pale patches so they don't look like spots.
    
    Re-bake the stone from this same sun, inside and out, and keep the portals deep. The west front now only gets raking light. Don't add a second sun to brighten it. If it goes dull, tell me.
    
    Leave the plan, the height and the glass as they are. Keep the GLB under 15 MB and the build inside the limit. Save it as a new revision of the same asset, then tell me plainly what's done and what isn't.
  7. The west front in revision 6 from the ground: with the sun now high and to the south, the front is dull and flat.The same view in revision 7: the west front reads as soft daylight, paler and clearer, with the portals still deep.

    Revision 7

    Softer daylight

    The west front takes light from the sky and the sunlit forecourt, with the portals still deep.

    Its source, 4,289 lines, Cathedral revision 7
    Read the prompt, 210 words
    Cathedral, prompt 7
    Two things from looking at this revision. The floor is right, so don't change it.
    
    The light on the south piers isn't right. Up close it reads as dark red and blue paint running up the column, blotchy and darker than the stone around it. Light can't make stone darker. Make it read as light falling on stone: brighter than the stone it lands on, smooth, with soft edges. If the overlay can't do that at any height, fade it out low on the pier, by about 3 m, or take it off and say so. Check it close up from the south aisle, camera at [24, 2, -10.5] looking at [0, 3, -5], as well as from the nave.
    
    The west front is what people see first, and it has gone dull. Keep the one sun, but shaded walls really do get light from the sky and off the sunlit paving. Lift that on the west front until it reads as soft daylight, with the portals still deep. Check it from [165, 1.6, -115] looking at [5, 66.6, 9].
    
    Everything else stays. Keep the GLB under 15 MB and the build inside the limit. Save it as a new revision, then tell me plainly what's done and what isn't.
  8. Where the nave meets the north transept in revision 7: two buttresses run into each other at the corner, their two gargoyles biting through each other at the same height, and the windows between them are blank dark glass.The same corner in revision 8: the transept buttress steps back and stands clear of the nave buttress, one gargoyle throws water from the corner, and the windows show their red and blue panes and figures.

    Revision 8

    An architect's review

    Six faults fixed at their cause: colliding buttresses, open tower roofs, solid transept windows, shapeless canopies, blank glass outside and flicker inside.

    Its source, 4,936 lines, Cathedral revision 8
    Read the prompt, 1,352 words
    Cathedral, prompt 8
    Thanks. You're on a new, faster machine now, in a new session, so read KILN_PROGRESS.md first. The saved revision builds in about 30 seconds here, so you have room to work. Start from revision r_028002e80aa342a1a55d2d35311420bf.
    
    I've looked at this as an architect and a 3D modeller would, and too much of it is one module stamped down wherever it lands, with nobody deciding what happens where two things meet. I want quality, not patches. Fix the rule that causes each fault, in the parameters and the plan, so that changing the plan can't bring it back. Get one example of each fix right and look at it before you repeat it. Here's my list, most important first. +X is west and +Z is north.
    
    1. The corners where the nave and choir meet the transepts. Two buttresses collide at all four corners: each stands 5.7 m along its wall from the inner corner and sticks out 5.2 m, so their bases overlap by nearly a metre, and their two gargoyles are at the same height, biting through each other. One has to lead. Keep the nave and choir buttresses at full depth, so their rows run unbroken, and step the transept buttress back so it stops about 0.8 m clear, still with real stages. Don't join them into one L-shaped mass: that would seal a pit against the windows with no way for the water out. A gargoyle is a water spout, so give each corner one, on the full-depth buttress, throwing water away from the building. Have the program work this out from the plan, and count any solid footprints that collide. That count should be zero. Look from [6, 13, 38] towards [-13, 11, 17], from [-4, 16.5, 27] towards [-11.4, 15.3, 19], and from [-60, 12, 34] towards [-50, 12, 18].
    
    There's a stone block indoors that shouldn't be there. The choir buttress nearest each transept stands about 1 m inside the transept's east aisle. The nave leaves out its matching buttress, and the choir should too. Check from [-40.5, 1.7, 24] towards [-44, 5, 15]. Around the apse, the gargoyles over the chapels are almost on the buttress lines, and they run into the buttress gargoyles and the piers. Centre them on their chapels. One more pair clashes near [-57.4, 15.3, -19]. No gargoyle should touch another gargoyle, or go through stone other than the stone it grows from.
    
    2. The tops of the two west towers. The roof is an octagon floating in a square tower with nothing joining it to the walls. Look over the parapet and you see straight down past it to a floor about 19 m below. Replace it with a square lead roof with four hips and rolled seams, sitting on a wall plate, with a lead gutter behind the parapet, so there's no gap anywhere. Keep the gilt finial and the overall height. The walls up there have no inner face, so from some angles they vanish and you see the nave roof through them. Give the upper walls and parapets real inner faces. Close the bell chamber behind the louvres, so it reads as a dark room and not as boards floating in a shaft. Don't make materials double-sided to hide this. Then go looking for any other wall you can see through from above or behind. Check from [68, 86, 30] towards [54, 69, 13], from [33, 75, 14.5] towards [55, 68, 14.5], and from [61, 72.5, 8.7] towards [48.5, 62, 8.9].
    
    3. The windows on the transept fronts. They aren't openings. The wall behind them is solid, and the glass sits 2 cm in front of it with a frame stuck on. They're also too wide, so the corner piers cut through the glass: at 4.65 m wide they run about 0.3 m into the pier. The tracery reads as cheap: the circle comes out as a hexagon, the bars end in stubs, and pieces poke past the frame. The string courses stop short and leave odd stubs beside the window head. Cut real openings through the wall, with moulded sides that splay inwards and the glass set back about 0.45 m, so the stone throws depth around it. Size each window from the wall that's really there between the portal and the corner pier, about 3.4 m wide, with its mouldings clear of both. Redraw the glass to fit rather than squeezing the figures. Draw the tracery the way a mason does, with a compass: one continuous stone shape with the lights cut out of it, then given depth, with curves smooth enough that a circle is a circle. Each string course runs up to the window's moulding and stops against it. Do the same on the towers' outer sides, where the windows are also stuck on solid wall, and look for anywhere else this happens. Check from [-21.5, 12, 39] towards [-21.5, 16.5, 27.2] and from [-28, 7, 34] towards [-18.5, 10, 27.2].
    
    4. The canopies over the statues on the piers. Each is a 2 m cone with three solid triangles, pushed into the pier. From the floor it's a lump, and I can't tell what it's meant to be. Replace it with a clean half-hexagon canopy about 1.1 m tall: three crisp pointed arches, a closed vaulted underside because that's the side you see from the floor, a simple cornice and a low top, properly tied into the pier. No spire. Clean beats busy here. Keep room above the statue's head. Check from [21, 1.7, 0] towards [28.2, 9, 5.4], from [25.2, 9.2, 2] towards [28.2, 9.2, 5.36], and down the nave from [47, 2, 0] towards [-60, 12, 0].
    
    5. The glass from outside. I pushed you too far on this. It should stay darker than it is from inside, but today it reads as black holes with a faint lattice. Most windows have no figures on the outside at all. I want dark jewels. Put each window's real panes on the outside, as the rose already does. Mirrored shared geometry should cost almost no bytes, but tell me what it really costs. Raise the outside glow so the ruby and cobalt show as deep, saturated colour with the lead lines visible. Try two or three levels side by side and choose. Make the surface smoother, and tilt each pane very slightly so that panes catch the sky differently, without the grazing washout to pale pink coming back. Compare single shots, not grids. Check from [165, 1.6, -115] towards [5, 66.6, 9], from [-21.5, 12, 39] towards [-21.5, 16.5, 27.2], and along the south side.
    
    6. Flicker in the glass from inside. Panes are stacked in layers 3.5 mm apart, and some only 0.35 mm apart, so a browser viewer can't tell which is in front at a distance or at a grazing angle. Cut each upper pane out of the panes below it, so all the glass of a window lies in one plane. If that costs too much build time, use whole layer steps of at least 15 mm with no fractional steps, and tell me you did. Nothing may rely on a viewer's depth settings, because people will download this file. The inside of the glass should otherwise look as it does now. Don't change the rose's design.
    
    Leave everything else as it is: the plan, the dimensions, the sun, the floor light, the statues, the portals, the stone and the roofs of the nave. Keep the GLB under 15 MB and the fresh build under 60 seconds. You start with only about 50 KB free, so find the bytes first. Take them from detail nobody sees up close, not from the statues, portals or rose.
    
    Keep KILN_PROGRESS.md current as you go, with the working program reference and the next action. Save one new revision of the same asset when all of it is finished, as a child of r_028002e80aa342a1a55d2d35311420bf. Then tell me plainly what's done, what isn't, what you changed your mind about, the GLB size, the triangle and mesh counts, the build time, and the footprint collision count.
    Read what was sent while it worked, 87 words
    Cathedral, prompt 8, message 2
    One change while you work: the limit is now 16 MB, not 15. Keep the GLB under 16,000,000 bytes. Everything else in my list stands.
    
    Use the extra room so you don't have to cut what people look at. If you've already thinned the crossing spire, the gilded cresting or the apse stonework for the sake of the old limit, put back whatever a viewer would notice. Don't spend it on new detail, and keep the fresh build under 60 seconds. Carry on from where you were.
  9. The west rose and the two tower windows beside it from outside in revision 8: the coloured glass reads, but dark.The same view in revision 9: the rose and tower windows show brighter reds and blues, still darker than the glass seen from inside.

    Revision 9

    Brighter glass outside

    One number: the windows show more of their colour from outside, still darker than from within.

    Its source, 4,936 lines, Cathedral revision 9
    Read the prompt, 148 words
    Cathedral, prompt 9
    One change. The glass from outside is right in kind now, dark jewels with their real panes, but it's still a little too dark: in daylight the colours barely come through. I tried a few strengths on a scratch copy of your file, changing only how much the outside glass glows. About 0.3 reads best, roughly twice what it is now, and it still stays clearly darker than the glass from inside. Set P.glassOuterGlow to about 0.3, then look at the west rose and both transept fronts from outside to check they read as coloured glass, not lamps.
    
    Leave everything else as it is: the plan, the stone, the inside glass and the light on the floor. Keep the GLB under 16,000,000 bytes and the build inside the limit. Save it as a new revision of the same asset, then tell me plainly what's done and what isn't.
The parameters: change a number, change the building
The parameters
const P = {
  preview: 'all',          // 'all', or 'size' (true buffer bytes, fast), 'stats' (per-mesh list), 'textures' (map payload), 'unique' (no instances), 'statues' (test row)
  // Plan
  naveBays: 11, bay: 6.6, naveSpan: 13, aisleSpan: 6.6,
  xWest: 62,               // west face of the towers
  towerDepth: 14, towerWidth: 14,
  choirBays: 3, transeptBays: 2,
  apseSides: 7,
  // Elevation
  pierTop: 15, aisleCrown: 21, triforiumSill: 21.8, triforiumTop: 26.6,
  vaultSpring: 26.6, vaultCrown: 39.6, eaves: 41.4, roofPitch: 1.6,
  aisleWallTop: 23, aisleRoofHigh: 26.2,
  towerTop: 72, spireTip: 80,
  flecheTip: 100,          // top of the cross on the lead spire over the crossing
  // Detail
  jambStatues: 5, kings: 16, seed: 1163,
  archFigureTris: 720, statueTest: ['apostle', 'bishop', 'king', 'queen', 'angel', 'virgin'],
  storyWindows: 3, clerestoryWindows: 3, // unique window cartoons (more = richer, larger GLB)
  // Glass
  glassCameMin: 0.0125,
  glassGlow: 1.05, glassOuterGlow: 0.3, glassOuterRough: 0.5, glassOuterMetal: 1, glassOuterSheen: 0.018, glassTilt: 0.035, // outside: how much colour shows by day, how smooth the sheet; metal with a base this dark reflects about 2% of the sky, half of what a dielectric would; how far a pane lies out of true (a slope; 0.035 is two degrees)
  westSkyFill: 0.14, westGroundFill: 0.72, // daylight on the west front from the open sky and the sunlit forecourt: the same sun, seen second-hand
  sun: [0.11, 0.79, -0.61], lightVariantBytes: 250000, wallTessellation: 5, // baked sun, about 52 degrees up and 10 degrees west of due south; bytes allowed for per-side vertex light; metres between lit wall vertices
  chapelFacets: 5,
};
The diff for two bays and a spire
Two bays and a spire
--- cathedral-3.kiln.js
+++ cathedral-4.kiln.js
@@ -8,7 +8,7 @@
 const P = {
   preview: 'all',          // 'all', or 'size' (true buffer bytes, fast), 'stats' (per-mesh list), 'textures' (map payload), 'unique' (no instances), 'statues' (test row)
   // Plan
-  naveBays: 9, bay: 6.6, naveSpan: 13, aisleSpan: 6.6,
+  naveBays: 11, bay: 6.6, naveSpan: 13, aisleSpan: 6.6,
   xWest: 62,               // west face of the towers
   towerDepth: 14, towerWidth: 14,
   choirBays: 3, transeptBays: 2,
@@ -18,7 +18,7 @@
   vaultSpring: 26.6, vaultCrown: 39.6, eaves: 41.4, roofPitch: 1.6,
   aisleWallTop: 23, aisleRoofHigh: 26.2,
   towerTop: 72, spireTip: 80,
-  flecheTip: 74,
+  flecheTip: 100,          // top of the cross on the lead spire over the crossing
   // Detail
   jambStatues: 5, kings: 16, seed: 1163,
   archFigureTris: 720, statueTest: ['apostle', 'bishop', 'king', 'queen', 'angel', 'virgin'],
@@ -1528,7 +1528,7 @@
   }
 }
 // Crockets up an edge from p to q (3D), with `dir` the outward direction in the frame
-function crocketsAlong(b, p, q, n, size, out, lod = 1) {
+function crocketsAlong(b, p, q, n, size, out, lod = 1, maker = addCrocket) {
   const d = [q[0] - p[0], q[1] - p[1], q[2] - p[2]], L = Math.hypot(...d);
   const dn = d.map((c) => c / L);
   let ox = out[0], oy = out[1], oz = out[2]; const od = ox * dn[0] + oy * dn[1] + oz * dn[2]; ox -= od * dn[0]; oy -= od * dn[1]; oz -= od * dn[2];
@@ -1538,9 +1538,16 @@
   for (let i = 0; i < n; i++) {
     const t = (i + 0.5) / n, pz = [lerp(p[0], q[0], t), lerp(p[1], q[1], t), lerp(p[2], q[2], t)];
     const m = [ox, dn[0], -side[0], pz[0], oy, dn[1], -side[1], pz[1], oz, dn[2], -side[2], pz[2]];
-    addCrocket(b, m, size * lerp(1, 0.78, t), lod);
+    maker(b, m, size * lerp(1, 0.78, t), lod);
   }
 }
+// A crocket beaten in lead: one thick leaf turning up off the arris with a lobe either side. Same frame as addCrocket: X out, Y along the edge
+function addLeadCrocket(b, m, s = 1) {
+  b.at(m, () => {
+    b.tube([[-0.04 * s, -0.02 * s, 0], [0.2 * s, 0.1 * s, 0], [0.34 * s, 0.3 * s, 0], [0.3 * s, 0.46 * s, 0]], (t) => [lerp(0.13, 0.015, t) * s, lerp(0.17, 0.02, t) * s], 4, { capEnd: false });
+    for (const z of [-1, 1]) b.tube([[0, 0, z * 0.04 * s], [0.16 * s, 0.1 * s, z * 0.2 * s], [0.2 * s, 0.24 * s, z * 0.3 * s]], (t) => lerp(0.07, 0.012, t) * s, 3, { capEnd: false });
+  });
+}
 
 // Crocketed pinnacle: square shaft with gablets, a spirelet with crockets and a finial.
 function addPinnacle(b, w, h, o = {}) {
@@ -2665,36 +2672,123 @@
   addCapital(F, ring, P.pierTop - 0.9, 0.9, 1.18, { leaves: 8 });
   return set;
 }
+// The spire over the crossing: an oak frame sheathed in lead. A plinth straddles the roofs, two open lantern stages stand on it,
+// and a long octagonal needle rises to a gilded orb and cross. Everything follows P.flecheTip, the ridge and the width of the crossing.
 function buildFleche(parent, x, z) {
-  const L = new Batch(TILE.lead), G = new Batch(TILE.gold), F = new Batch(TILE.fine);
-  const y0 = LAY.ridge - 2.5, yB = LAY.ridge + 7, yT = P.flecheTip - 3.2, R = 2.9, n = 8;
-  // Octagonal base and open arcaded lantern
-  L.lathe([[R + 0.4, y0], [R + 0.25, y0 + 2.8], [R + 0.5, y0 + 3], [R + 0.5, y0 + 3.3], [R, y0 + 3.5]], n, { faceted: true, phase: PI / 8 });
-  L.lathe([[R * 0.78, y0 + 3.5], [R * 0.78, yB + 0.3]], n, { faceted: true, phase: PI / 8, s: 0.34 });
-  for (let i = 0; i < n; i++) {
-    const a = i * 45, ap = R * Math.cos(rad(22.5)), side = 2 * R * Math.sin(rad(22.5));
-    L.at(M.of(M.Ry(a + 22.5), M.T(0, 0, ap)), () => {
-      for (const s of [-1, 1]) L.tube([[s * side * 0.5, y0 + 3.5, 0], [s * side * 0.5, yB, 0]], 0.13, 6, {});
-      const arc = pointedArc(side * 0.92, 2.2, 6).map((p) => [p[0], yB - 2.45 + p[1]]);
-      L.sweep(arc, traceryBar(0.13, 0.2), {});
-      G.at(M.of(M.Ry(a + 22.5), M.T(0, 0, ap + 0.1)), () => addGable(G, side * 1.04, 1.6, -0.05, 0.08, yB - 0.24, { size: 0.26, crockets: 2, finial: 0.44, lod: 0, solid: true }));
+  const L = new Batch(TILE.lead), G = new Batch(TILE.gold);
+  L.noReduce = true; // a single careful mesh, its seams and crockets are the design
+  const n = 8, PH = PI / 8, cos8 = Math.cos(PH), sin8 = Math.sin(PH), oct = { faceted: true, phase: PH };
+  const yR = LAY.ridge, tip = P.flecheTip, y0 = yR - 5.9, yP = yR + 2.7, H = tip - yP, yA = yP + 0.19 * H, yB = yA + 0.15 * H, yN1 = yB + 1.7, yT = tip - 3.3;
+  const R0 = zn * 0.73, R1 = zn * 0.66, R2 = zn * 0.5, RN = zn * 0.44;
+  const faceFrame = (k, ap) => M.of(M.Ry(k * 45), M.T(0, 0, ap));
+  const vertex = (k, R) => { const a = rad((k + 0.5) * 45); return [R * Math.sin(a), R * Math.cos(a)]; };
+  // A small gilded knop finishing a gablet or a lucarne
+  const knop = (m, s) => G.at(m, () => G.lathe([[0.05 * s, 0], [0.11 * s, 0.1 * s], [0.09 * s, 0.2 * s], [0.03 * s, 0.32 * s], [0.004, 0.72 * s]], 6));
+  const gablet = (k, ap, w, h, y, nC, sz) => {
+    const fr = faceFrame(k, ap + 0.05);
+    L.at(fr, () => {
+      L.slab([[-w / 2, y], [w / 2, y], [0, y + h]], [], -0.05, 0.05, { sb: 0.7 });
+      L.shade(0.42, () => L.face([[-w * 0.2, y + h * 0.16, 0.06], [w * 0.2, y + h * 0.16, 0.06], [0, y + h * 0.62, 0.06]]));
+      const rake = barSection(0.14, 0.2);
+      L.sweep([[-w / 2 - 0.05, y - 0.02], [0, y + h + 0.04]], rake, {}); L.sweep([[0, y + h + 0.04], [w / 2 + 0.05, y - 0.02]], rake, {});
+      crocketsAlong(L, [-w / 2, y + 0.05, 0], [-0.03, y + h * 0.97, 0], nC, sz, [-h, w / 2, 0], 0, addLeadCrocket);
+      crocketsAlong(L, [w / 2, y + 0.05, 0], [0.03, y + h * 0.97, 0], nC, sz, [h, w / 2, 0], 0, addLeadCrocket);
     });
-  }
-  L.lathe([[R + 0.2, yB - 0.05], [R + 0.34, yB + 0.1], [R + 0.2, yB + 0.26]], n, { faceted: true, phase: PI / 8 });
-  // The spire, its ribs and gilded crockets
-  L.lathe([[R * 0.98, yB + 0.26], [R * 0.72, yB + 3.2], [0.1, yT]], n, { faceted: true, phase: PI / 8 });
-  for (let i = 0; i < n; i++) {
-    const a = rad(i * 45 + 22.5 + 22.5), c = Math.cos(a), s = Math.sin(a);
-    const pts = [[R * 0.98 * c * 1.0, yB + 0.3, R * 0.98 * s], [R * 0.72 * c, yB + 3.2, R * 0.72 * s], [0.14 * c, yT - 0.2, 0.14 * s]];
-    G.tube(pts, (t) => lerp(0.1, 0.03, t), 5);
-    crocketsAlong(G, pts[1], pts[2], 7, 0.66, [c, 0.1, s], 0);
-  }
-  G.at(M.T(0, yT - 0.15, 0), () => {
-    G.lathe([[0.14, 0], [0.3, 0.28], [0.34, 0.5], [0.22, 0.72], [0.06, 0.9], [0.05, 3.2]], 10);
-    G.box(-0.06, 0.06, 2.2, 3.35, -0.06, 0.06, {}); G.box(-0.6, 0.6, 2.56, 2.72, -0.06, 0.06, {});
+    knop(M.of(fr, M.T(0, y + h - 0.02, 0)), 0.9);
+  };
+  // One open stage: a dark core, a pointed opening in every face, a clustered post at every angle, a cornice closing the top
+  const stage = (R, yBase, yTop, coreR, rPost, open) => {
+    const hs = R * sin8, ap = R * cos8, { w, sill, ys, rise, tracery } = open;
+    L.shade(0.34, () => L.lathe([[coreR, yBase], [coreR, yTop - 0.4]], n, oct));
+    L.shade(0.5, () => { L.lathe([[coreR, yTop - 0.4], [R, yTop - 0.4]], n, oct); L.lathe([[R, yBase + 0.01], [coreR, yBase + 0.01]], n, oct); });
+    for (let k = 0; k < n; k++) {
+      L.at(faceFrame(k, ap), () => {
+        L.slab([[-hs, yBase], [hs, yBase], [hs, yTop], [-hs, yTop]], [archOutline(w, sill, ys, rise, 5)], -0.14, 0.02, { noOuterSides: true, sr: 0.6, sb: 0.5 });
+        L.sweep(pointedArc(w + 0.16, rise + 0.16, 5).map((p) => [p[0], p[1] + ys]), hexBar(0.1, 0.14), { z: 0.03, caps: false });
+        if (tracery) {
+          L.at(M.T(0, 0, -0.06), () => L.lathe([[0.1, sill], [0.065, sill + 0.16], [0.065, ys - 0.08], [0.11, ys]], 5));
+          for (const s of [-1, 1]) L.sweep(pointedArc(w / 2 - 0.03, rise * 0.58, 3).map((p) => [s * w / 4 + p[0], ys + p[1]]), hexBar(0.08, 0.13), { z: -0.06, caps: false });
+          L.sweep(ringPts(0, ys + rise * 0.76, rise * 0.13, 6), hexBar(0.06, 0.1), { z: -0.06, closed: true });
+        }
+      });
+      const [px, pz] = vertex(k, R + 0.03);
+      L.at(M.T(px, 0, pz), () => L.lathe([[rPost * 1.35, yBase], [rPost, yBase + 0.22], [rPost, yTop - 0.3], [rPost * 1.35, yTop - 0.12], [rPost * 1.2, yTop]], 6));
+    }
+    L.lathe([[R + 0.02, yTop - 0.5], [R + 0.22, yTop - 0.3], [R + 0.22, yTop - 0.12], [R + 0.08, yTop]], n, oct);
+  };
+  // A raised roll standing on a sloping face, in the face's own frame: two faces, a low ridge
+  const roll = (u, ya, yb, apF, h = 0.07, w = 0.05) => {
+    const za = apF(ya), zb = apF(yb), dy = yb - ya, dz = zb - za, l = Math.hypot(dy, dz) || 1, ny = -dz / l, nz = dy / l;
+    const A0 = [u - w, ya, za], B0 = [u + w, ya, za], A1 = [u - w, yb, zb], B1 = [u + w, yb, zb], T0 = [u, ya + ny * h, za + nz * h], T1 = [u, yb + ny * h, zb + nz * h];
+    L.face([A0, T0, T1, A1]); L.face([T0, B0, B1, T1]);
+  };
+
+  // ---- The plinth: batters up out of the slates of all four roofs, its foot well below their surface all round ----
+  L.lathe([[R0, y0], [R0 - 0.16, yP - 0.62], [R0 + 0.12, yP - 0.46], [R0 + 0.12, yP - 0.2], [R0 - 0.2, yP], [R1 * 0.6, yP]], n, oct);
+  { const apF = (y) => lerp(R0, R0 - 0.16, (y - y0) / (yP - 0.62 - y0)) * cos8;
+    for (let k = 0; k < n; k++) L.at(faceFrame(k, 0), () => { for (const u of [-1.2, 0, 1.2]) roll(u, y0, yP - 0.62, apF); }); }
+
+  // ---- First stage: tall two-light openings, a gablet on every face, a pinnacle at every angle, a lead pentice behind them ----
+  stage(R1, yP, yA, R1 * 0.6, 0.26, { w: R1 * 0.56, sill: yP + 0.95, ys: yA - 3.35, rise: 2, tracery: true });
+  L.lathe([[R1 + 0.08, yA], [R2 + 0.02, yA + 1.55]], n, oct);
+  for (let k = 0; k < n; k++) {
+    gablet(k, R1 * cos8, R1 * 0.67, 2.6, yA - 0.3, 2, 0.34);
+    const [px, pz] = vertex(k, R1 + 0.02);
+    L.at(M.of(M.T(px, yA - 0.2, pz), M.Ry((k + 0.5) * 45)), () => addPinnacle(L, 0.62, 5, { simple: true, lod: 0 }));
+  }
+  // ---- Second stage: slimmer, single lancets ----
+  stage(R2, yA + 1.5, yB, R2 * 0.62, 0.18, { w: R2 * 0.53, sill: yA + 2.45, ys: yB - 2.3, rise: 1.5, tracery: false });
+  for (let k = 0; k < n; k++) gablet(k, R2 * cos8, R2 * 0.65, 1.9, yB - 0.25, 1, 0.3);
+
+  // ---- The needle: a flared foot, then eight long faces. u stays metric, so the sheets run straight up and are cut by the arrises as they close ----
+  const rTip = 0.09, RF = R2 + 0.08, rAt = (y) => (y <= yN1 ? lerp(RF, RN, (y - yB) / (yN1 - yB)) : lerp(RN, rTip, (y - yN1) / (yT - yN1)));
+  const levels = [yB, yN1]; for (const t of [0.22, 0.5, 0.75, 1]) levels.push(lerp(yN1, yT, t));
+  const apAt = (y) => rAt(y) * cos8;
+  for (let k = 0; k < n; k++) L.at(faceFrame(k, 0), () => {
+    let vv = 0;
+    for (let j = 0; j < levels.length - 1; j++) {
+      const ya = levels[j], yb = levels[j + 1], za = apAt(ya), zb = apAt(yb), wa = rAt(ya) * sin8, wb = rAt(yb) * sin8, dy = yb - ya, dz = zb - za, l = Math.hypot(dy, dz), ny = -dz / l, nz = dy / l;
+      const a = L.v(-wa, ya, za, 0, ny, nz, -wa, vv), b = L.v(wa, ya, za, 0, ny, nz, wa, vv), c = L.v(wb, yb, zb, 0, ny, nz, wb, vv + l), d = L.v(-wb, yb, zb, 0, ny, nz, -wb, vv + l);
+      L.quad(a, b, c, d); vv += l;
+    }
+    // Standing seams, each stopping where the closing arrises overtake it
+    for (const u of [-0.55, 0, 0.55]) { const rEnd = (Math.abs(u) + 0.1) / sin8; if (rEnd < RN) roll(u, yN1, lerp(yN1, yT, (RN - rEnd) / (RN - rTip)), apAt); }
+  });
+  // Rolled arrises from the flare to the tip, crockets thinning as they climb
+  for (let k = 0; k < n; k++) {
+    const vAt = (y) => { const [vx, vz] = vertex(k, rAt(y)); return [vx, y, vz]; };
+    L.tube([vAt(yB), vAt(yN1), vAt(yT - 0.05)], (t) => lerp(0.12, 0.04, t), 4, { capEnd: false });
+    const [ox, oz] = vertex(k, 1), nC = 11, y1 = yN1 + 1.2, y2 = yT - 1.5;
+    for (let i = 0; i < nC; i++) {
+      const t = (i + 0.5) / nC, ya = lerp(y1, y2, t - 0.02), yb = lerp(y1, y2, t + 0.02);
+      crocketsAlong(L, vAt(ya), vAt(yb), 1, lerp(1.2, 0.42, t), [ox, 0.12, oz], 0, addLeadCrocket);
+    }
+  }
+  // Tie-bands round the needle where the sheets are lapped
+  for (const t of [0.22, 0.5, 0.75]) { const y = lerp(yN1, yT, t), r = rAt(y); L.lathe([[rAt(y - 0.1), y - 0.1], [r + 0.08, y - 0.05], [r + 0.08, y + 0.05], [rAt(y + 0.12), y + 0.12]], n, oct); }
+  // Two tiers of lucarnes on alternate faces
+  const lucarne = (k, yD, a, c, g) => {
+    const zf = apAt(yD) + 0.06, yE2 = yD + c, yG = yE2 + g, zb0 = apAt(yD), zbE = apAt(yE2), zbG = apAt(yG);
+    L.at(faceFrame(k, 0), () => {
+      L.face([[-a, yD, zf], [a, yD, zf], [a, yE2, zf], [0, yG, zf], [-a, yE2, zf]]);
+      L.shade(0.22, () => L.face([[-a * 0.5, yD + 0.16, zf + 0.012], [a * 0.5, yD + 0.16, zf + 0.012], [a * 0.5, yE2, zf + 0.012], [0, yE2 + g * 0.55, zf + 0.012], [-a * 0.5, yE2, zf + 0.012]]));
+      L.face([[a, yD, zb0], [a, yE2, zbE], [a, yE2, zf], [a, yD, zf]]);
+      L.face([[-a, yD, zb0], [-a, yD, zf], [-a, yE2, zf], [-a, yE2, zbE]]);
+      L.face([[a, yE2, zf], [a, yE2, zbE], [0, yG, zbG], [0, yG, zf]]);
+      L.face([[-a, yE2, zf], [0, yG, zf], [0, yG, zbG], [-a, yE2, zbE]]);
+    });
+    knop(M.of(faceFrame(k, zf), M.T(0, yG - 0.02, 0)), 0.8);
+  };
+  for (let k = 0; k < n; k++) { if (k % 2 === 0) lucarne(k, yN1 + 5, 0.5, 1.25, 0.75); else lucarne(k, yN1 + 12, 0.36, 0.95, 0.55); }
+
+  // ---- The tip: a gilded collar, an orb and a cross, its head at exactly P.flecheTip ----
+  G.at(M.T(0, yT - 0.25, 0), () => {
+    G.lathe([[0.12, 0], [0.24, 0.12], [0.22, 0.22], [0.13, 0.3], [0.11, 0.44], [0.2, 0.52], [0.36, 0.68], [0.42, 0.9], [0.36, 1.12], [0.2, 1.28], [0.08, 1.36], [0.06, 2.2]], 10);
+    G.box(-0.07, 0.07, 2.2, 3.55, -0.07, 0.07, {});
+    G.box(-0.62, 0.62, 2.82, 2.98, -0.07, 0.07, {});
   });
-  place('Fleche_Lead', L, MAT.lead, { pos: [x, 0, z], parent });
-  place('Fleche_Gilt', G, MAT.gold, { pos: [x, 0, z], parent });
+  place('CrossingSpire_Lead', L, MAT.lead, { pos: [x, 0, z], parent });
+  place('CrossingSpire_Gilt', G, MAT.gold, { pos: [x, 0, z], parent });
 }
 
 // Coloured light thrown onto the paving by the south aisle windows (sun from the south-west)
@@ -3673,7 +3767,7 @@
   for (const e of PLACED) uses.set(e.batch, (uses.get(e.batch) || 0) + 1);
   for (const e of PLACED) {
     const m = e.mat;
-    if (e.batch.isFigure || m.transparent || m === MAT.glassIn || m === MAT.glassOut || m === MAT.glassOutWin || m === MAT.glassRose || m === MAT.ashlar || m === MAT.oak || m === MAT.iron || m === MAT.pave || m === MAT.flag || m === MAT.earth) continue;
+    if (e.batch.isFigure || e.batch.noReduce || m.transparent || m === MAT.glassIn || m === MAT.glassOut || m === MAT.glassOutWin || m === MAT.glassRose || m === MAT.ashlar || m === MAT.oak || m === MAT.iron || m === MAT.pave || m === MAT.flag || m === MAT.earth) continue;
     let nb = seen.get(e.batch);
     if (nb === undefined) {
       const tris = e.batch.I.length / 3, s = uses.get(e.batch) >= 8 ? repeatedShare : share; // a mesh repeated down the whole building costs the most
@@ -3700,7 +3794,8 @@
 }
 function bakeLight() {
   ROOT.updateMatrixWorld(true);
-  const CELL = 0.4, X0 = -72, Y0 = -2, Z0 = -36, NX = 365, NY = 220, NZ = 180, CK = 8, CX = (NX >> 3) + 1, CY = (NY >> 3) + 1, CZ = (NZ >> 3) + 1;
+  // The world follows the plan: from beyond the chapels to beyond the west front. A spire tip above the top simply casts no shadow up there
+  const CELL = 0.4, X0 = LAY.xa - 27.8, Y0 = -2, Z0 = -36, NX = Math.ceil((P.xWest + 12 - X0) / CELL), NY = 220, NZ = 180, CK = 8, CX = (NX >> 3) + 1, CY = (NY >> 3) + 1, CZ = (NZ >> 3) + 1;
   const grid = new Uint8Array(NX * NY * NZ), coarse = new Uint8Array(CX * CY * CZ);
   const SUN = (() => { const v = P.sun, l = len3(v[0], v[1], v[2]); return [v[0] / l, v[1] / l, v[2] / l]; })();
   const SUN2 = [[SUN[0] + 0.06, SUN[1], SUN[2] + 0.05], [SUN[0] - 0.05, SUN[1] + 0.05, SUN[2] - 0.05]].map((v) => { const l = len3(v[0], v[1], v[2]); return [v[0] / l, v[1] / l, v[2] / l]; });

How text to 3D works with Claude Code, Codex or Cursor.

Kiln is a local MCP server and CLI. Your coding agent writes 3D models as code and calls Kiln to build them and export GLBs. No model runs inside Kiln.

  1. 01

    You describe it

    In your own words, with the numbers and part names you care about, or from a photo, sketch or concept art.

  2. 02

    Your agent writes a program

    JavaScript against Kiln's geometry, material and animation helpers. Nine bays means nine bays, and named parts and pivots are there for your code to find.

  3. 03

    Kiln shows it what it built

    Rendered views, part paths and measurements go back to the agent, which edits the source.

  4. 04

    You keep the source and the GLB

    Both stay in your workspace, on your disk. A later change is an edit to that program, with a diff.

Try the mech prompt.

Install the package, create a workspace and open your agent in it, on Node.js 22 or 24 LTS. To match these models, start it with claude --model claude-opus-5-5 --effort xhigh, and approve Kiln's tools when asked.

With no supported GPU, the agent sees shape and flat colour only.

Using another agent? Change --harness claude and put its own command on the last line.

Read the installation guide
Install Kiln 1.7 and open a workspace
mkdir kiln-install
cd kiln-install
npm init -y
npm install @instruktlabs/kiln
npx --offline --no -- kiln-init ../my-assets --harness claude
cd ../my-assets
claude
Then paste the mech prompt
Make a heavy walking mech for a three.js game, about 6 m tall. Two digitigrade legs, an armoured torso that turns at the waist, a cockpit with a glass canopy, a shoulder-mounted missile pod and two heavy arms: a rotary cannon on the right and a claw on the left. Every joint has to be its own named pivot (hip, knee, ankle, toe, waist, shoulder, elbow) so I can drive it from code, and the hydraulic pistons on the legs should really follow the joints. Add one looping Walk clip where the feet plant without sliding and the torso sways and counter-rotates. It should look like it came out of a AAA concept: layered armour plates with panel lines, weathered paint, hazard stripes, exposed cables and machinery at the joints. Keep the GLB under 5 MB so it loads in a browser. Save it when you're happy with it.

Questions.

Can Claude Code make 3D models?

Yes, given a tool that lets it build a model and look at the result. Kiln gives it that, over MCP or the CLI.

What can it make?

Anything an agent can build from parts: buildings, vehicles, machines, props and rigged things that move. Kiln is working towards creatures.

Does it work with Codex, Cursor and other agents?

kiln-init ships setups for 7 coding agents, including both of those. Results vary by agent and model.

Can it work from a photo, sketch or concept art?

Yes, as a reference. Hand your agent the image and it uses it for silhouette, materials and art direction, then builds the model as a program rather than tracing the picture.

Does it need an API key?

Kiln needs no key or account of its own. Your agent signs in the way it already does.

Can I use the result in a game or in Blender?

The output is a standard GLB, and the mech's three.js code above drives the file you download. The Blender and Unity guide

Kiln 1.7.0, Claude Code 2.1.319 and 2.1.300, Claude Opus 5.5 at xhigh. CC0-1.0 to the extent of Instrukt Labs' rights.