# Modular Stairs

> A straight stair run for the 2 m grid modular kit that climbs exactly one 3 m storey: 15 risers of 0.2 m from the floor top (0.1 m) to 3.1 m, 1.75 m wide to fit between walls, from z = +1.875 (the bottom faces +Z) to z = -2, where the top step meets an upper floor tile placed one cell further at y = 3. Origin at the center of the 2 × 4 m footprint. Solid stone or brick steps between side walls, or timber treads on stringers, with an optional parapet or handrail per side.

![Modular Stairs preview](https://codels.download/m/modular-stairs.png)

Multi-view sheet (3/4, front, side, top): https://codels.download/m/modular-stairs.sheet.png

## Facts

- Category: Buildings › Modular Kit
- Size (W × H × D): 1.75 × 4.08 × 3.88 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,136 · Meshes: 91 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: grid, house, railing, staircase, stairs, tower, low-poly, stylized, fantasy, medieval, castle, dungeon, interior, adventure, platformer, roguelike, rpg, building, modular, platform, brick, stone, wood, game-ready, mobile-friendly, parametric, color-gray, size-large, poly-low
- Page: https://codels.download/models/modular-stairs

## Files

| Format | URL |
|---|---|
| three.js ES module (`createModularStairs()`) | https://codels.download/m/modular-stairs.js |
| React Three Fiber component (`<ModularStairs />`) | https://codels.download/m/modular-stairs.jsx |
| Instancing module (`createModularStairsInstances(count, place)`, one draw call per material) | https://codels.download/m/modular-stairs.instanced.js |
| Standalone HTML demo | https://codels.download/m/modular-stairs.html |
| glTF binary | https://codels.download/m/modular-stairs.glb |
| glTF binary, Meshopt-compressed (2–3× smaller; GLTFLoader needs `setMeshoptDecoder(MeshoptDecoder)`) | https://codels.download/m/modular-stairs.glb?compress=meshopt |
| glTF JSON | https://codels.download/m/modular-stairs.gltf |
| OBJ (vertex colors) + MTL | https://codels.download/m/modular-stairs.obj · https://codels.download/m/modular-stairs.mtl |
| STL | https://codels.download/m/modular-stairs.stl |
| CodelSpec JSON | https://codels.download/m/modular-stairs.json |

## Parameters

Append them as query parameters to any URL above to get a customized variant (e.g. `?style=...`).

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `style` | select | stone \| brick \| plaster \| wood | stone | stone |
| `railing` | select | none \| left \| right \| both | right | right |
| `tint` | color | #rrggbb | #ffffff | #ffffff |

## Parts

- sideCore (extrude · mortar)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone)
- coping (extrude · dressed)
- sideCore (extrude · mortar)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone2)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone)
- sideBlock (extrude · stone3)
- sideBlock (extrude · stone3)

## How to use

Save the code below as `modular-stairs.js`, then:

```js
import { createModularStairs } from './modular-stairs.js';
const model = createModularStairs();
scene.add(model);
```

## Code

```js
/**
 * Modular Stairs — Codels 3D model library (https://codels.download/models/modular-stairs)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,136 · Size (W × H × D): 1.75 × 4.08 × 3.88 m
 *
 * Usage:
 *   import { createModularStairs } from './modular-stairs.js';
 *   
 *   const model = createModularStairs();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Extrude a 2D outline along Z (centered). bevel = [thickness, size, segments].
function extrude(outline, depth, holes = [], bevel = null) {
  const shape = new THREE.Shape(outline.map(([x, y]) => new THREE.Vector2(x, y)));
  for (const hole of holes) shape.holes.push(new THREE.Path(hole.map(([x, y]) => new THREE.Vector2(x, y))));
  const options = bevel
    ? { depth, bevelEnabled: true, bevelThickness: bevel[0], bevelSize: bevel[1], bevelSegments: bevel[2] }
    : { depth, bevelEnabled: false };
  return new THREE.ExtrudeGeometry(shape, options).translate(0, 0, -depth / 2);
}

export function createModularStairs() {
  const root = new THREE.Group();
  root.name = 'ModularStairs';

  // Materials
  const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0x7c7871, roughness: 0.95, flatShading: true });
  const stone2Mat = new THREE.MeshStandardMaterial({ name: 'stone2', color: 0x67635c, roughness: 0.95, flatShading: true });
  const stone3Mat = new THREE.MeshStandardMaterial({ name: 'stone3', color: 0x8b867c, roughness: 0.95, flatShading: true });
  const mortarMat = new THREE.MeshStandardMaterial({ name: 'mortar', color: 0x3f3c38, roughness: 1, flatShading: true });
  const dressedMat = new THREE.MeshStandardMaterial({ name: 'dressed', color: 0x9a9488, roughness: 0.9, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(1.35, 0.06, 0.2883);

  // Parts
  const sideCore = new THREE.Mesh(extrude([[1.98, 0], [-1.855, 0], [-1.855, 0.4655], [1.7417, 3.25], [1.98, 3.25]], 0.17), mortarMat);
  sideCore.name = 'sideCore';
  sideCore.position.set(-0.775, 0, 0);
  sideCore.rotation.set(0, deg(90), 0);
  root.add(sideCore);
  const sideBlock = new THREE.Mesh(extrude([[2, 0], [1.3832, 0], [1.3832, 0.4375], [2, 0.4375]], 0.1961), stone2Mat);
  sideBlock.name = 'sideBlock';
  sideBlock.position.set(-0.775, 0, 0);
  sideBlock.rotation.set(0, deg(90), 0);
  root.add(sideBlock);
  const sideBlock2 = new THREE.Mesh(extrude([[1.3582, 0], [0.4048, 0], [0.4048, 0.4375], [1.3582, 0.4375]], 0.1882), stoneMat);
  sideBlock2.name = 'sideBlock';
  sideBlock2.position.set(-0.775, 0, 0);
  sideBlock2.rotation.set(0, deg(90), 0);
  root.add(sideBlock2);
  const sideBlock3 = new THREE.Mesh(extrude([[0.3798, 0], [-0.522, 0], [-0.522, 0.4375], [0.3798, 0.4375]], 0.1936), stone2Mat);
  sideBlock3.name = 'sideBlock';
  sideBlock3.position.set(-0.775, 0, 0);
  sideBlock3.rotation.set(0, deg(90), 0);
  root.add(sideBlock3);
  const sideBlock4 = new THREE.Mesh(extrude([[-0.547, 0], [-1.5331, 0], [-1.5331, 0.4375], [-0.547, 0.4375]], 0.1986), stone2Mat);
  sideBlock4.name = 'sideBlock';
  sideBlock4.position.set(-0.775, 0, 0);
  sideBlock4.rotation.set(0, deg(90), 0);
  root.add(sideBlock4);
  const sideBlock5 = new THREE.Mesh(extrude([[-1.5581, 0], [-1.875, 0], [-1.875, 0.4375], [-1.5581, 0.4375]], 0.1952), stone2Mat);
  sideBlock5.name = 'sideBlock';
  sideBlock5.position.set(-0.775, 0, 0);
  sideBlock5.rotation.set(0, deg(90), 0);
  root.add(sideBlock5);
  const sideBlock6 = new THREE.Mesh(extrude([[2, 0.4625], [1.3701, 0.4625], [1.3701, 0.8875], [2, 0.8875]], 0.1989), stone2Mat);
  sideBlock6.name = 'sideBlock';
  sideBlock6.position.set(-0.775, 0, 0);
  sideBlock6.rotation.set(0, deg(90), 0);
  root.add(sideBlock6);
  const sideBlock7 = new THREE.Mesh(extrude([[1.3451, 0.4625], [0.4131, 0.4625], [0.4131, 0.8875], [1.3451, 0.8875]], 0.19), stone2Mat);
  sideBlock7.name = 'sideBlock';
  sideBlock7.position.set(-0.775, 0, 0);
  sideBlock7.rotation.set(0, deg(90), 0);
  root.add(sideBlock7);
  const sideBlock8 = new THREE.Mesh(extrude([[0.3881, 0.4625], [-0.2845, 0.4625], [-0.2845, 0.8875], [0.3881, 0.8875]], 0.1991), stoneMat);
  sideBlock8.name = 'sideBlock';
  sideBlock8.position.set(-0.775, 0, 0);
  sideBlock8.rotation.set(0, deg(90), 0);
  root.add(sideBlock8);
  const sideBlock9 = new THREE.Mesh(extrude([[-0.3095, 0.4625], [-1.1885, 0.4625], [-1.1885, 0.8875], [-0.3095, 0.8875]], 0.1966), stoneMat);
  sideBlock9.name = 'sideBlock';
  sideBlock9.position.set(-0.775, 0, 0);
  sideBlock9.rotation.set(0, deg(90), 0);
  root.add(sideBlock9);
  const sideBlock10 = new THREE.Mesh(extrude([[-1.2135, 0.4625], [-1.8589, 0.4625], [-1.3099, 0.8875], [-1.2135, 0.8875]], 0.1968), stone3Mat);
  sideBlock10.name = 'sideBlock';
  sideBlock10.position.set(-0.775, 0, 0);
  sideBlock10.rotation.set(0, deg(90), 0);
  root.add(sideBlock10);
  const sideBlock11 = new THREE.Mesh(extrude([[2, 0.9125], [0.9413, 0.9125], [0.9413, 1.3375], [2, 1.3375]], 0.1943), stoneMat);
  sideBlock11.name = 'sideBlock';
  sideBlock11.position.set(-0.775, 0, 0);
  sideBlock11.rotation.set(0, deg(90), 0);
  root.add(sideBlock11);
  const sideBlock12 = new THREE.Mesh(extrude([[0.9163, 0.9125], [0.2094, 0.9125], [0.2094, 1.3375], [0.9163, 1.3375]], 0.189), stone3Mat);
  sideBlock12.name = 'sideBlock';
  sideBlock12.position.set(-0.775, 0, 0);
  sideBlock12.rotation.set(0, deg(90), 0);
  root.add(sideBlock12);
  const sideBlock13 = new THREE.Mesh(extrude([[0.1844, 0.9125], [-0.3913, 0.9125], [-0.3913, 1.3375], [0.1844, 1.3375]], 0.1963), stone3Mat);
  sideBlock13.name = 'sideBlock';
  sideBlock13.position.set(-0.775, 0, 0);
  sideBlock13.rotation.set(0, deg(90), 0);
  root.add(sideBlock13);
  const sideBlock14 = new THREE.Mesh(extrude([[-0.4163, 0.9125], [-1.2776, 0.9125], [-0.7286, 1.3375], [-0.4163, 1.3375]], 0.1941), stone2Mat);
  sideBlock14.name = 'sideBlock';
  sideBlock14.position.set(-0.775, 0, 0);
  sideBlock14.rotation.set(0, deg(90), 0);
  root.add(sideBlock14);
  const sideBlock15 = new THREE.Mesh(extrude([[2, 1.3625], [1.2666, 1.3625], [1.2666, 1.7875], [2, 1.7875]], 0.1898), stoneMat);
  sideBlock15.name = 'sideBlock';
  sideBlock15.position.set(-0.775, 0, 0);
  sideBlock15.rotation.set(0, deg(90), 0);
  root.add(sideBlock15);
  const sideBlock16 = new THREE.Mesh(extrude([[1.2416, 1.3625], [0.478, 1.3625], [0.478, 1.7875], [1.2416, 1.7875]], 0.1939), stone2Mat);
  sideBlock16.name = 'sideBlock';
  sideBlock16.position.set(-0.775, 0, 0);
  sideBlock16.rotation.set(0, deg(90), 0);
  root.add(sideBlock16);
  const sideBlock17 = new THREE.Mesh(extrude([[0.453, 1.3625], [-0.5869, 1.3625], [-0.5869, 1.4472], [-0.1474, 1.7875], [0.453, 1.7875]], 0.194), stoneMat);
  sideBlock17.name = 'sideBlock';
  sideBlock17.position.set(-0.775, 0, 0);
  sideBlock17.rotation.set(0, deg(90), 0);
  root.add(sideBlock17);
  const sideBlock18 = new THREE.Mesh(extrude([[2, 1.8125], [1.1093, 1.8125], [1.1093, 2.2375], [2, 2.2375]], 0.1908), stone3Mat);
  sideBlock18.name = 'sideBlock';
  sideBlock18.position.set(-0.775, 0, 0);
  sideBlock18.rotation.set(0, deg(90), 0);
  root.add(sideBlock18);
  const sideBlock19 = new THREE.Mesh(extrude([[1.0843, 1.8125], [0.5089, 1.8125], [0.5089, 2.2375], [1.0843, 2.2375]], 0.1961), stone2Mat);
  sideBlock19.name = 'sideBlock';
  sideBlock19.position.set(-0.775, 0, 0);
  sideBlock19.rotation.set(0, deg(90), 0);
  root.add(sideBlock19);
  const sideBlock20 = new THREE.Mesh(extrude([[0.4839, 1.8125], [-0.1151, 1.8125], [0.4339, 2.2375], [0.4839, 2.2375]], 0.1957), stone3Mat);
  sideBlock20.name = 'sideBlock';
  sideBlock20.position.set(-0.775, 0, 0);
  sideBlock20.rotation.set(0, deg(90), 0);
  root.add(sideBlock20);
  const sideBlock21 = new THREE.Mesh(extrude([[2, 2.2625], [1.4011, 2.2625], [1.4011, 2.6875], [2, 2.6875]], 0.1996), stoneMat);
  sideBlock21.name = 'sideBlock';
  sideBlock21.position.set(-0.775, 0, 0);
  sideBlock21.rotation.set(0, deg(90), 0);
  root.add(sideBlock21);
  const sideBlock22 = new THREE.Mesh(extrude([[1.3761, 2.2625], [0.478, 2.2625], [0.478, 2.2717], [1.0151, 2.6875], [1.3761, 2.6875]], 0.1902), stoneMat);
  sideBlock22.name = 'sideBlock';
  sideBlock22.position.set(-0.775, 0, 0);
  sideBlock22.rotation.set(0, deg(90), 0);
  root.add(sideBlock22);
  const sideBlock23 = new THREE.Mesh(extrude([[2, 2.7125], [1.1186, 2.7125], [1.1186, 2.7677], [1.5964, 3.1375], [2, 3.1375]], 0.1969), stoneMat);
  sideBlock23.name = 'sideBlock';
  sideBlock23.position.set(-0.775, 0, 0);
  sideBlock23.rotation.set(0, deg(90), 0);
  root.add(sideBlock23);
  const sideBlock24 = new THREE.Mesh(extrude([[2, 3.1625], [1.6286, 3.1625], [1.7417, 3.25], [2, 3.25]], 0.189), stoneMat);
  sideBlock24.name = 'sideBlock';
  sideBlock24.position.set(-0.775, 0, 0);
  sideBlock24.rotation.set(0, deg(90), 0);
  root.add(sideBlock24);
  const coping = new THREE.Mesh(extrude([[-1.875, 0.45], [1.7417, 3.25], [2, 3.25], [2, 3.33], [1.7417, 3.33], [-1.875, 0.53]], 0.24), dressedMat);
  coping.name = 'coping';
  coping.position.set(-0.755, 0, 0);
  coping.rotation.set(0, deg(90), 0);
  root.add(coping);
  const sideCore2 = new THREE.Mesh(extrude([[1.98, 0], [-1.855, 0], [-1.855, 1.2155], [1.7417, 4], [1.98, 4]], 0.17), mortarMat);
  sideCore2.name = 'sideCore';
  sideCore2.position.set(0.775, 0, 0);
  sideCore2.rotation.set(0, deg(90), 0);
  root.add(sideCore2);
  const sideBlock25 = new THREE.Mesh(extrude([[2, 0], [1.3986, 0], [1.3986, 0.4375], [2, 0.4375]], 0.1894), stone3Mat);
  sideBlock25.name = 'sideBlock';
  sideBlock25.position.set(0.775, 0, 0);
  sideBlock25.rotation.set(0, deg(90), 0);
  root.add(sideBlock25);
  const sideBlock26 = new THREE.Mesh(extrude([[1.3736, 0], [0.5788, 0], [0.5788, 0.4375], [1.3736, 0.4375]], 0.1937), stone2Mat);
  sideBlock26.name = 'sideBlock';
  sideBlock26.position.set(0.775, 0, 0);
  sideBlock26.rotation.set(0, deg(90), 0);
  root.add(sideBlock26);
  const sideBlock27 = new THREE.Mesh(extrude([[0.5538, 0], [-0.1664, 0], [-0.1664, 0.4375], [0.5538, 0.4375]], 0.1896), stoneMat);
  sideBlock27.name = 'sideBlock';
  sideBlock27.position.set(0.775, 0, 0);
  sideBlock27.rotation.set(0, deg(90), 0);
  root.add(sideBlock27);
  const sideBlock28 = new THREE.Mesh(extrude([[-0.1914, 0], [-1.0571, 0], [-1.0571, 0.4375], [-0.1914, 0.4375]], 0.1945), stone2Mat);
  sideBlock28.name = 'sideBlock';
  sideBlock28.position.set(0.775, 0, 0);
  sideBlock28.rotation.set(0, deg(90), 0);
  root.add(sideBlock28);
  const sideBlock29 = new THREE.Mesh(extrude([[-1.0821, 0], [-1.875, 0], [-1.875, 0.4375], [-1.0821, 0.4375]], 0.1906), stone3Mat);
  sideBlock29.name = 'sideBlock';
  sideBlock29.position.set(0.775, 0, 0);
  sideBlock29.rotation.set(0, deg(90), 0);
  root.add(sideBlock29);
  const sideBlock30 = new THREE.Mesh(extrude([[2, 0.4625], [0.9877, 0.4625], [0.9877, 0.8875], [2, 0.8875]], 0.1985), stone3Mat);
  sideBlock30.name = 'sideBlock';
  sideBlock30.position.set(0.775, 0, 0);
  sideBlock30.rotation.set(0, deg(90), 0);
  root.add(sideBlock30);
  const sideBlock31 = new THREE.Mesh(extrude([[0.9627, 0.4625], [-0.0209, 0.4625], [-0.0209, 0.8875], [0.9627, 0.8875]], 0.1905), stone2Mat);
  sideBlock31.name = 'sideBlock';
  sideBlock31.position.set(0.775, 0, 0);
  sideBlock31.rotation.set(0, deg(90), 0);
  root.add(sideBlock31);
  const sideBlock32 = new THREE.Mesh(extrude([[-0.0459, 0.4625], [-0.6631, 0.4625], [-0.6631, 0.8875], [-0.0459, 0.8875]], 0.19), stone2Mat);
  sideBlock32.name = 'sideBlock';
  sideBlock32.position.set(0.775, 0, 0);
  sideBlock32.rotation.set(0, deg(90), 0);
  root.add(sideBlock32);
  const sideBlock33 = new THREE.Mesh(extrude([[-0.6881, 0.4625], [-1.875, 0.4625], [-1.875, 0.8875], [-0.6881, 0.8875]], 0.1936), stoneMat);
  sideBlock33.name = 'sideBlock';
  sideBlock33.position.set(0.775, 0, 0);
  sideBlock33.rotation.set(0, deg(90), 0);
  root.add(sideBlock33);
  const sideBlock34 = new THREE.Mesh(extrude([[2, 0.9125], [1.3112, 0.9125], [1.3112, 1.3375], [2, 1.3375]], 0.1905), stone3Mat);
  sideBlock34.name = 'sideBlock';
  sideBlock34.position.set(0.775, 0, 0);
  sideBlock34.rotation.set(0, deg(90), 0);
  root.add(sideBlock34);
  const sideBlock35 = new THREE.Mesh(extrude([[1.2862, 0.9125], [0.5774, 0.9125], [0.5774, 1.3375], [1.2862, 1.3375]], 0.1885), stoneMat);
  sideBlock35.name = 'sideBlock';
  sideBlock35.position.set(0.775, 0, 0);
  sideBlock35.rotation.set(0, deg(90), 0);
  root.add(sideBlock35);
  const sideBlock36 = new THREE.Mesh(extrude([[0.5524, 0.9125], [-0.0515, 0.9125], [-0.0515, 1.3375], [0.5524, 1.3375]], 0.189), stone3Mat);
  sideBlock36.name = 'sideBlock';
  sideBlock36.position.set(0.775, 0, 0);
  sideBlock36.rotation.set(0, deg(90), 0);
  root.add(sideBlock36);
  const sideBlock37 = new THREE.Mesh(extrude([[-0.0765, 0.9125], [-0.8892, 0.9125], [-0.8892, 1.3375], [-0.0765, 1.3375]], 0.1916), stone3Mat);
  sideBlock37.name = 'sideBlock';
  sideBlock37.position.set(0.775, 0, 0);
  sideBlock37.rotation.set(0, deg(90), 0);
  root.add(sideBlock37);
  const sideBlock38 = new THREE.Mesh(extrude([[-0.9142, 0.9125], [-1.875, 0.9125], [-1.875, 1.2], [-1.6974, 1.3375], [-0.9142, 1.3375]], 0.1934), stone2Mat);
  sideBlock38.name = 'sideBlock';
  sideBlock38.position.set(0.775, 0, 0);
  sideBlock38.rotation.set(0, deg(90), 0);
  root.add(sideBlock38);
  const sideBlock39 = new THREE.Mesh(extrude([[2, 1.3625], [1.1886, 1.3625], [1.1886, 1.7875], [2, 1.7875]], 0.1977), stoneMat);
  sideBlock39.name = 'sideBlock';
  sideBlock39.position.set(0.775, 0, 0);
  sideBlock39.rotation.set(0, deg(90), 0);
  root.add(sideBlock39);
  const sideBlock40 = new THREE.Mesh(extrude([[1.1636, 1.3625], [0.5441, 1.3625], [0.5441, 1.7875], [1.1636, 1.7875]], 0.1892), stoneMat);
  sideBlock40.name = 'sideBlock';
  sideBlock40.position.set(0.775, 0, 0);
  sideBlock40.rotation.set(0, deg(90), 0);
  root.add(sideBlock40);
  const sideBlock41 = new THREE.Mesh(extrude([[0.5191, 1.3625], [-0.2095, 1.3625], [-0.2095, 1.7875], [0.5191, 1.7875]], 0.199), stone2Mat);
  sideBlock41.name = 'sideBlock';
  sideBlock41.position.set(0.775, 0, 0);
  sideBlock41.rotation.set(0, deg(90), 0);
  root.add(sideBlock41);
  const sideBlock42 = new THREE.Mesh(extrude([[-0.2345, 1.3625], [-0.8475, 1.3625], [-0.8475, 1.7875], [-0.2345, 1.7875]], 0.196), stoneMat);
  sideBlock42.name = 'sideBlock';
  sideBlock42.position.set(0.775, 0, 0);
  sideBlock42.rotation.set(0, deg(90), 0);
  root.add(sideBlock42);
  const sideBlock43 = new THREE.Mesh(extrude([[-0.8725, 1.3625], [-1.6651, 1.3625], [-1.1161, 1.7875], [-0.8725, 1.7875]], 0.1911), stone3Mat);
  sideBlock43.name = 'sideBlock';
  sideBlock43.position.set(0.775, 0, 0);
  sideBlock43.rotation.set(0, deg(90), 0);
  root.add(sideBlock43);
  const sideBlock44 = new THREE.Mesh(extrude([[2, 1.8125], [1.2843, 1.8125], [1.2843, 2.2375], [2, 2.2375]], 0.1965), stone3Mat);
  sideBlock44.name = 'sideBlock';
  sideBlock44.position.set(0.775, 0, 0);
  sideBlock44.rotation.set(0, deg(90), 0);
  root.add(sideBlock44);
  const sideBlock45 = new THREE.Mesh(extrude([[1.2593, 1.8125], [0.4487, 1.8125], [0.4487, 2.2375], [1.2593, 2.2375]], 0.1933), stone3Mat);
  sideBlock45.name = 'sideBlock';
  sideBlock45.position.set(0.775, 0, 0);
  sideBlock45.rotation.set(0, deg(90), 0);
  root.add(sideBlock45);
  const sideBlock46 = new THREE.Mesh(extrude([[0.4237, 1.8125], [-0.4958, 1.8125], [-0.4958, 2.2375], [0.4237, 2.2375]], 0.1979), stone2Mat);
  sideBlock46.name = 'sideBlock';
  sideBlock46.position.set(0.775, 0, 0);
  sideBlock46.rotation.set(0, deg(90), 0);
  root.add(sideBlock46);
  const sideBlock47 = new THREE.Mesh(extrude([[-0.5208, 1.8125], [-1.0839, 1.8125], [-0.5349, 2.2375], [-0.5208, 2.2375]], 0.1998), stone3Mat);
  sideBlock47.name = 'sideBlock';
  sideBlock47.position.set(0.775, 0, 0);
  sideBlock47.rotation.set(0, deg(90), 0);
  root.add(sideBlock47);
  const sideBlock48 = new THREE.Mesh(extrude([[2, 2.2625], [1.3965, 2.2625], [1.3965, 2.6875], [2, 2.6875]], 0.1883), stone2Mat);
  sideBlock48.name = 'sideBlock';
  sideBlock48.position.set(0.775, 0, 0);
  sideBlock48.rotation.set(0, deg(90), 0);
  root.add(sideBlock48);
  const sideBlock49 = new THREE.Mesh(extrude([[1.3715, 2.2625], [0.3599, 2.2625], [0.3599, 2.6875], [1.3715, 2.6875]], 0.2), stone3Mat);
  sideBlock49.name = 'sideBlock';
  sideBlock49.position.set(0.775, 0, 0);
  sideBlock49.rotation.set(0, deg(90), 0);
  root.add(sideBlock49);
  const sideBlock50 = new THREE.Mesh(extrude([[0.3349, 2.2625], [-0.349, 2.2625], [-0.349, 2.3815], [0.0464, 2.6875], [0.3349, 2.6875]], 0.1927), stone3Mat);
  sideBlock50.name = 'sideBlock';
  sideBlock50.position.set(0.775, 0, 0);
  sideBlock50.rotation.set(0, deg(90), 0);
  root.add(sideBlock50);
  const sideBlock51 = new THREE.Mesh(extrude([[-0.374, 2.2625], [-0.5026, 2.2625], [-0.374, 2.3621]], 0.1881), stone2Mat);
  sideBlock51.name = 'sideBlock';
  sideBlock51.position.set(0.775, 0, 0);
  sideBlock51.rotation.set(0, deg(90), 0);
  root.add(sideBlock51);
  const sideBlock52 = new THREE.Mesh(extrude([[2, 2.7125], [0.9276, 2.7125], [0.9276, 3.1375], [2, 3.1375]], 0.1964), stone3Mat);
  sideBlock52.name = 'sideBlock';
  sideBlock52.position.set(0.775, 0, 0);
  sideBlock52.rotation.set(0, deg(90), 0);
  root.add(sideBlock52);
  const sideBlock53 = new THREE.Mesh(extrude([[0.9026, 2.7125], [0.1392, 2.7125], [0.1392, 2.7594], [0.6276, 3.1375], [0.9026, 3.1375]], 0.1941), stone2Mat);
  sideBlock53.name = 'sideBlock';
  sideBlock53.position.set(0.775, 0, 0);
  sideBlock53.rotation.set(0, deg(90), 0);
  root.add(sideBlock53);
  const sideBlock54 = new THREE.Mesh(extrude([[2, 3.1625], [0.998, 3.1625], [0.998, 3.4243], [1.2089, 3.5875], [2, 3.5875]], 0.1923), stone3Mat);
  sideBlock54.name = 'sideBlock';
  sideBlock54.position.set(0.775, 0, 0);
  sideBlock54.rotation.set(0, deg(90), 0);
  root.add(sideBlock54);
  const sideBlock55 = new THREE.Mesh(extrude([[0.973, 3.1625], [0.6599, 3.1625], [0.973, 3.4049]], 0.1966), stone3Mat);
  sideBlock55.name = 'sideBlock';
  sideBlock55.position.set(0.775, 0, 0);
  sideBlock55.rotation.set(0, deg(90), 0);
  root.add(sideBlock55);
  const sideBlock56 = new THREE.Mesh(extrude([[2, 3.6125], [1.3773, 3.6125], [1.3773, 3.7179], [1.7417, 4], [2, 4]], 0.1978), stoneMat);
  sideBlock56.name = 'sideBlock';
  sideBlock56.position.set(0.775, 0, 0);
  sideBlock56.rotation.set(0, deg(90), 0);
  root.add(sideBlock56);
  const sideBlock57 = new THREE.Mesh(extrude([[1.3523, 3.6125], [1.2411, 3.6125], [1.3523, 3.6986]], 0.1883), stone2Mat);
  sideBlock57.name = 'sideBlock';
  sideBlock57.position.set(0.775, 0, 0);
  sideBlock57.rotation.set(0, deg(90), 0);
  root.add(sideBlock57);
  const coping2 = new THREE.Mesh(extrude([[-1.875, 1.2], [1.7417, 4], [2, 4], [2, 4.08], [1.7417, 4.08], [-1.875, 1.28]], 0.24), dressedMat);
  coping2.name = 'coping';
  coping2.position.set(0.755, 0, 0);
  coping2.rotation.set(0, deg(90), 0);
  root.add(coping2);
  const step = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.24, 0.2583), stoneMat);
  step.name = 'step';
  step.position.set(0, 0.12, 1.7158);
  root.add(step);
  const tread = new THREE.Mesh(boxGeo, dressedMat);
  tread.name = 'tread';
  tread.position.set(0, 0.27, 1.7308);
  root.add(tread);
  const step2 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.44, 0.2583), stone2Mat);
  step2.name = 'step';
  step2.position.set(0, 0.22, 1.4575);
  root.add(step2);
  const tread2 = new THREE.Mesh(boxGeo, dressedMat);
  tread2.name = 'tread';
  tread2.position.set(0, 0.47, 1.4725);
  root.add(tread2);
  const step3 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.64, 0.2583), stone3Mat);
  step3.name = 'step';
  step3.position.set(0, 0.32, 1.1992);
  root.add(step3);
  const tread3 = new THREE.Mesh(boxGeo, dressedMat);
  tread3.name = 'tread';
  tread3.position.set(0, 0.67, 1.2142);
  root.add(tread3);
  const step4 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.84, 0.2583), stoneMat);
  step4.name = 'step';
  step4.position.set(0, 0.42, 0.9408);
  root.add(step4);
  const tread4 = new THREE.Mesh(boxGeo, dressedMat);
  tread4.name = 'tread';
  tread4.position.set(0, 0.87, 0.9558);
  root.add(tread4);
  const step5 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 1.04, 0.2583), stone2Mat);
  step5.name = 'step';
  step5.position.set(0, 0.52, 0.6825);
  root.add(step5);
  const tread5 = new THREE.Mesh(boxGeo, dressedMat);
  tread5.name = 'tread';
  tread5.position.set(0, 1.07, 0.6975);
  root.add(tread5);
  const step6 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 1.24, 0.2583), stone3Mat);
  step6.name = 'step';
  step6.position.set(0, 0.62, 0.4242);
  root.add(step6);
  const tread6 = new THREE.Mesh(boxGeo, dressedMat);
  tread6.name = 'tread';
  tread6.position.set(0, 1.27, 0.4392);
  root.add(tread6);
  const step7 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 1.44, 0.2583), stoneMat);
  step7.name = 'step';
  step7.position.set(0, 0.72, 0.1658);
  root.add(step7);
  const tread7 = new THREE.Mesh(boxGeo, dressedMat);
  tread7.name = 'tread';
  tread7.position.set(0, 1.47, 0.1808);
  root.add(tread7);
  const step8 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 1.64, 0.2583), stone2Mat);
  step8.name = 'step';
  step8.position.set(0, 0.82, -0.0925);
  root.add(step8);
  const tread8 = new THREE.Mesh(boxGeo, dressedMat);
  tread8.name = 'tread';
  tread8.position.set(0, 1.67, -0.0775);
  root.add(tread8);
  const step9 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 1.84, 0.2583), stone3Mat);
  step9.name = 'step';
  step9.position.set(0, 0.92, -0.3508);
  root.add(step9);
  const tread9 = new THREE.Mesh(boxGeo, dressedMat);
  tread9.name = 'tread';
  tread9.position.set(0, 1.87, -0.3358);
  root.add(tread9);
  const step10 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 2.04, 0.2583), stoneMat);
  step10.name = 'step';
  step10.position.set(0, 1.02, -0.6092);
  root.add(step10);
  const tread10 = new THREE.Mesh(boxGeo, dressedMat);
  tread10.name = 'tread';
  tread10.position.set(0, 2.07, -0.5942);
  root.add(tread10);
  const step11 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 2.24, 0.2583), stone2Mat);
  step11.name = 'step';
  step11.position.set(0, 1.12, -0.8675);
  root.add(step11);
  const tread11 = new THREE.Mesh(boxGeo, dressedMat);
  tread11.name = 'tread';
  tread11.position.set(0, 2.27, -0.8525);
  root.add(tread11);
  const step12 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 2.44, 0.2583), stone3Mat);
  step12.name = 'step';
  step12.position.set(0, 1.22, -1.1258);
  root.add(step12);
  const tread12 = new THREE.Mesh(boxGeo, dressedMat);
  tread12.name = 'tread';
  tread12.position.set(0, 2.47, -1.1108);
  root.add(tread12);
  const step13 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 2.64, 0.2583), stoneMat);
  step13.name = 'step';
  step13.position.set(0, 1.32, -1.3842);
  root.add(step13);
  const tread13 = new THREE.Mesh(boxGeo, dressedMat);
  tread13.name = 'tread';
  tread13.position.set(0, 2.67, -1.3692);
  root.add(tread13);
  const step14 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 2.84, 0.2583), stone2Mat);
  step14.name = 'step';
  step14.position.set(0, 1.42, -1.6425);
  root.add(step14);
  const tread14 = new THREE.Mesh(boxGeo, dressedMat);
  tread14.name = 'tread';
  tread14.position.set(0, 2.87, -1.6275);
  root.add(tread14);
  const step15 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 3.04, 0.2283), stone3Mat);
  step15.name = 'step';
  step15.position.set(0, 1.52, -1.8858);
  root.add(step15);
  const tread15 = new THREE.Mesh(new THREE.BoxGeometry(1.35, 0.06, 0.2583), dressedMat);
  tread15.name = 'tread';
  tread15.position.set(0, 3.07, -1.8708);
  root.add(tread15);

  root.traverse((o) => {
    if (o.isMesh) {
      o.castShadow = true;
      o.receiveShadow = true;
    }
  });
  return root;
}

export default createModularStairs;
```

---
Codels — 3D models as code for three.js. Search more: https://codels.download/api/v1/models?q=<query> · Guide: https://codels.download/llms.txt
