# Castle Gatehouse

> A fortified medieval gatehouse: a crenellated stone block pierced by a round-arched passage with voussoirs, machicolations and a carved coat of arms, flanked by two round towers with battered plinths, arrow slits, corbelled battlements and hanging banners. An iron portcullis slides up by the open amount and heavy oak gates stand open inside. A hero piece for castles, city walls and siege or tower-defense maps.

![Castle Gatehouse preview](https://codels.download/m/castle-gate.png)

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

## Facts

- Category: Buildings › Medieval & Fantasy
- Size (W × H × D): 13.92 × 12.86 × 6.35 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 3,092 · Meshes: 216 · Materials: 8
- License: CC0-1.0 (Codels built-in)
- Tags: battlements, castle-part, flag, gate, tower, low-poly, stylized, fantasy, medieval, castle, rpg, strategy, tower-defense, building, landmark, metal, stone, symmetric, parametric, color-gray, size-huge, poly-medium
- Page: https://codels.download/models/castle-gate

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `open` | number | 0 – 100 | 45 | 45 |
| `width` | number | 3 – 5 | 3.6 | 3.6 |
| `stone` | color | #rrggbb | #a39c90 | #a39c90 |
| `banner` | color | #rrggbb | #2f4f8f | #2f4f8f |

## Parts

- gatehouse (extrude · stone)
- passageFloor (box · paving)
- plinth (box · trim)
- plinth (box · trim)
- stringCourse (box · trim)
- stringCourse (box · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- keystone (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- keystone (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- voussoir (extrude · trim)
- voussoir (extrude · stone)
- faceStone (box · trim)
- faceStone (box · stone)
- faceStone (box · trim)
- faceStone (box · stone)
- faceStone (box · stone)
- faceStone (box · trim)
- faceStone (box · stone)
- faceStone (box · stone)

## How to use

Save the code below as `castle-gate.js`, then:

```js
import { createCastleGate } from './castle-gate.js';
const model = createCastleGate();
scene.add(model);
```

## Code

```js
/**
 * Castle Gatehouse — Codels 3D model library (https://codels.download/models/castle-gate)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 3,092 · Size (W × H × D): 13.92 × 12.86 × 6.35 m
 *
 * Usage:
 *   import { createCastleGate } from './castle-gate.js';
 *   
 *   const model = createCastleGate();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
  const pos = geometry.attributes.position;
  const h = (a, b, c, s) => {
    let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
    x = Math.imul(x ^ (x >>> 16), 2246822507);
    x = Math.imul(x ^ (x >>> 13), 3266489909);
    return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
  };
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
    const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
    pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
  }
  pos.needsUpdate = true;
  geometry.computeVertexNormals();
  return geometry;
}

// 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 createCastleGate() {
  const root = new THREE.Group();
  root.name = 'CastleGate';

  // Materials
  const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0xa39c90, roughness: 0.95, flatShading: true });
  const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0x868076, roughness: 0.95, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x2e2c28, roughness: 1, flatShading: true });
  const pavingMat = new THREE.MeshStandardMaterial({ name: 'paving', color: 0x6a655e, roughness: 1, flatShading: true });
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x6a4529, roughness: 0.9, flatShading: true });
  const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x303236, roughness: 0.5, metalness: 0.7, flatShading: true });
  const bannerMat = new THREE.MeshStandardMaterial({ name: 'banner', color: 0x2f4f8f, roughness: 0.85, flatShading: true });
  const goldMat = new THREE.MeshStandardMaterial({ name: 'gold', color: 0xd1a23a, roughness: 0.45, metalness: 0.5, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(7.1, 0.2, 0.12);
  const extrudeGeo = extrude([[-1.7999, 2.9216], [-1.7527, 3.3098], [-2.2883, 3.435], [-2.3498, 2.9282]], 0.16);
  const extrudeGeo2 = extrude([[-1.7424, 3.3517], [-1.6037, 3.7173], [-2.0938, 3.9671], [-2.2748, 3.4897]], 0.16);
  const extrudeGeo3 = extrude([[-1.5837, 3.7556], [-1.3615, 4.0774], [-1.7776, 4.4371], [-2.0676, 4.017]], 0.16);
  const extrudeGeo4 = extrude([[-1.3329, 4.1097], [-1.0402, 4.369], [-1.3581, 4.8179], [-1.7402, 4.4793]], 0.16);
  const extrudeGeo5 = extrude([[-1.0047, 4.3935], [-0.6584, 4.5752], [-0.8596, 5.0871], [-1.3116, 4.8499]], 0.16);
  const extrudeGeo6 = extrude([[-0.618, 4.5906], [-0.2384, 4.6841], [-0.3112, 5.2293], [-0.8069, 5.1071]], 0.16);
  const extrudeGeo7 = extrude([[-0.1955, 4.6894], [0.1955, 4.6894], [0.277, 5.4349], [-0.277, 5.4349]], 0.26);
  const extrudeGeo8 = extrude([[0.2384, 4.6841], [0.618, 4.5906], [0.8069, 5.1071], [0.3112, 5.2293]], 0.16);
  const extrudeGeo9 = extrude([[0.6584, 4.5752], [1.0047, 4.3935], [1.3116, 4.8499], [0.8596, 5.0871]], 0.16);
  const extrudeGeo10 = extrude([[1.0402, 4.369], [1.3329, 4.1097], [1.7402, 4.4793], [1.3581, 4.8179]], 0.16);
  const extrudeGeo11 = extrude([[1.3615, 4.0774], [1.5837, 3.7556], [2.0676, 4.017], [1.7776, 4.4371]], 0.16);
  const extrudeGeo12 = extrude([[1.6037, 3.7173], [1.7424, 3.3517], [2.2748, 3.4897], [2.0938, 3.9671]], 0.16);
  const extrudeGeo13 = extrude([[1.7527, 3.3098], [1.7999, 2.9216], [2.3498, 2.9282], [2.2883, 3.435]], 0.16);
  const boxGeo2 = new THREE.BoxGeometry(0.08, 3.15, 0.2);
  const boxGeo3 = new THREE.BoxGeometry(0.24, 0.55, 0.42);
  const boxGeo4 = new THREE.BoxGeometry(1.04, 0.08, 0.58);
  const cylinderGeo = new THREE.CylinderGeometry(2.28, 2.62, 1.1, 12);
  const cylinderGeo2 = new THREE.CylinderGeometry(2.2, 2.2, 8.5, 12);
  const cylinderGeo3 = new THREE.CylinderGeometry(2.28, 2.28, 0.2, 12);
  const boxGeo5 = new THREE.BoxGeometry(0.3, 0.5, 0.4);
  const cylinderGeo4 = new THREE.CylinderGeometry(2.58, 2.58, 0.6, 12);
  const cylinderGeo5 = new THREE.CylinderGeometry(2.63, 2.63, 0.1, 12);
  const boxGeo6 = new THREE.BoxGeometry(0.8916, 0.8, 0.4);
  const boxGeo7 = new THREE.BoxGeometry(0.9516, 0.08, 0.46);
  const boxGeo8 = new THREE.BoxGeometry(0.36, 1.1, 0.06);
  const boxGeo9 = new THREE.BoxGeometry(0.12, 0.85, 0.06);
  const boxGeo10 = new THREE.BoxGeometry(0.32, 0.1, 0.06);
  const cylinderGeo6 = new THREE.CylinderGeometry(0.035, 0.035, 1.25, 5);
  const extrudeGeo14 = extrude([[-0.5, 0], [0.5, 0], [0.5, -2.9], [0, -2.45], [-0.5, -2.9]], 0.04);
  const boxGeo11 = new THREE.BoxGeometry(0.12, 1.6, 0.02);
  const cylinderGeo7 = new THREE.CylinderGeometry(1.95, 1.95, 0.05, 12);
  const boxGeo12 = new THREE.BoxGeometry(0.07, 4.8, 0.07);
  const coneGeo = new THREE.ConeGeometry(0.055, 0.14, 4);
  const boxGeo13 = new THREE.BoxGeometry(3.52, 0.07, 0.06);
  const boxGeo14 = new THREE.BoxGeometry(1.76, 3.25, 0.12);
  const boxGeo15 = new THREE.BoxGeometry(1.71, 0.12, 0.03);

  // Parts
  const gatehouse = new THREE.Mesh(extrude([[-3.5, 0], [-1.8, 0], [-1.8, 2.9], [-1.7387, 3.3659], [-1.5588, 3.8], [-1.2728, 4.1728], [-0.9, 4.4588], [-0.4659, 4.6387], [0, 4.7], [0.4659, 4.6387], [0.9, 4.4588], [1.2728, 4.1728], [1.5588, 3.8], [1.7387, 3.3659], [1.8, 2.9], [1.8, 0], [3.5, 0], [3.5, 7.2], [-3.5, 7.2]], 5), stoneMat);
  gatehouse.name = 'gatehouse';
  root.add(gatehouse);
  const passageFloor = new THREE.Mesh(new THREE.BoxGeometry(3.58, 0.05, 6.2), pavingMat);
  passageFloor.name = 'passageFloor';
  passageFloor.position.set(0, 0.025, 0.6);
  root.add(passageFloor);
  const plinth = new THREE.Mesh(jitter(new THREE.BoxGeometry(1.8, 0.6, 5.2), 0.01, 1), trimMat);
  plinth.name = 'plinth';
  plinth.position.set(-2.65, 0.3, 0);
  root.add(plinth);
  const plinth2 = new THREE.Mesh(jitter(new THREE.BoxGeometry(1.8, 0.6, 5.2), 0.01, 2), trimMat);
  plinth2.name = 'plinth';
  plinth2.position.set(2.65, 0.3, 0);
  root.add(plinth2);
  const stringCourse = new THREE.Mesh(boxGeo, trimMat);
  stringCourse.name = 'stringCourse';
  stringCourse.position.set(0, 5.45, -2.55);
  root.add(stringCourse);
  const stringCourse2 = new THREE.Mesh(boxGeo, trimMat);
  stringCourse2.name = 'stringCourse';
  stringCourse2.position.set(0, 5.45, 2.55);
  root.add(stringCourse2);
  const voussoir = new THREE.Mesh(extrudeGeo, stoneMat);
  voussoir.name = 'voussoir';
  voussoir.position.set(0, 0, -2.52);
  root.add(voussoir);
  const voussoir2 = new THREE.Mesh(extrudeGeo2, trimMat);
  voussoir2.name = 'voussoir';
  voussoir2.position.set(0, 0, -2.52);
  root.add(voussoir2);
  const voussoir3 = new THREE.Mesh(extrudeGeo3, stoneMat);
  voussoir3.name = 'voussoir';
  voussoir3.position.set(0, 0, -2.52);
  root.add(voussoir3);
  const voussoir4 = new THREE.Mesh(extrudeGeo4, trimMat);
  voussoir4.name = 'voussoir';
  voussoir4.position.set(0, 0, -2.52);
  root.add(voussoir4);
  const voussoir5 = new THREE.Mesh(extrudeGeo5, stoneMat);
  voussoir5.name = 'voussoir';
  voussoir5.position.set(0, 0, -2.52);
  root.add(voussoir5);
  const voussoir6 = new THREE.Mesh(extrudeGeo6, trimMat);
  voussoir6.name = 'voussoir';
  voussoir6.position.set(0, 0, -2.52);
  root.add(voussoir6);
  const keystone = new THREE.Mesh(extrudeGeo7, stoneMat);
  keystone.name = 'keystone';
  keystone.position.set(0, 0, -2.52);
  root.add(keystone);
  const voussoir7 = new THREE.Mesh(extrudeGeo8, trimMat);
  voussoir7.name = 'voussoir';
  voussoir7.position.set(0, 0, -2.52);
  root.add(voussoir7);
  const voussoir8 = new THREE.Mesh(extrudeGeo9, stoneMat);
  voussoir8.name = 'voussoir';
  voussoir8.position.set(0, 0, -2.52);
  root.add(voussoir8);
  const voussoir9 = new THREE.Mesh(extrudeGeo10, trimMat);
  voussoir9.name = 'voussoir';
  voussoir9.position.set(0, 0, -2.52);
  root.add(voussoir9);
  const voussoir10 = new THREE.Mesh(extrudeGeo11, stoneMat);
  voussoir10.name = 'voussoir';
  voussoir10.position.set(0, 0, -2.52);
  root.add(voussoir10);
  const voussoir11 = new THREE.Mesh(extrudeGeo12, trimMat);
  voussoir11.name = 'voussoir';
  voussoir11.position.set(0, 0, -2.52);
  root.add(voussoir11);
  const voussoir12 = new THREE.Mesh(extrudeGeo13, stoneMat);
  voussoir12.name = 'voussoir';
  voussoir12.position.set(0, 0, -2.52);
  root.add(voussoir12);
  const voussoir13 = new THREE.Mesh(extrudeGeo, stoneMat);
  voussoir13.name = 'voussoir';
  voussoir13.position.set(0, 0, 2.52);
  root.add(voussoir13);
  const voussoir14 = new THREE.Mesh(extrudeGeo2, trimMat);
  voussoir14.name = 'voussoir';
  voussoir14.position.set(0, 0, 2.52);
  root.add(voussoir14);
  const voussoir15 = new THREE.Mesh(extrudeGeo3, stoneMat);
  voussoir15.name = 'voussoir';
  voussoir15.position.set(0, 0, 2.52);
  root.add(voussoir15);
  const voussoir16 = new THREE.Mesh(extrudeGeo4, trimMat);
  voussoir16.name = 'voussoir';
  voussoir16.position.set(0, 0, 2.52);
  root.add(voussoir16);
  const voussoir17 = new THREE.Mesh(extrudeGeo5, stoneMat);
  voussoir17.name = 'voussoir';
  voussoir17.position.set(0, 0, 2.52);
  root.add(voussoir17);
  const voussoir18 = new THREE.Mesh(extrudeGeo6, trimMat);
  voussoir18.name = 'voussoir';
  voussoir18.position.set(0, 0, 2.52);
  root.add(voussoir18);
  const keystone2 = new THREE.Mesh(extrudeGeo7, stoneMat);
  keystone2.name = 'keystone';
  keystone2.position.set(0, 0, 2.52);
  root.add(keystone2);
  const voussoir19 = new THREE.Mesh(extrudeGeo8, trimMat);
  voussoir19.name = 'voussoir';
  voussoir19.position.set(0, 0, 2.52);
  root.add(voussoir19);
  const voussoir20 = new THREE.Mesh(extrudeGeo9, stoneMat);
  voussoir20.name = 'voussoir';
  voussoir20.position.set(0, 0, 2.52);
  root.add(voussoir20);
  const voussoir21 = new THREE.Mesh(extrudeGeo10, trimMat);
  voussoir21.name = 'voussoir';
  voussoir21.position.set(0, 0, 2.52);
  root.add(voussoir21);
  const voussoir22 = new THREE.Mesh(extrudeGeo11, stoneMat);
  voussoir22.name = 'voussoir';
  voussoir22.position.set(0, 0, 2.52);
  root.add(voussoir22);
  const voussoir23 = new THREE.Mesh(extrudeGeo12, trimMat);
  voussoir23.name = 'voussoir';
  voussoir23.position.set(0, 0, 2.52);
  root.add(voussoir23);
  const voussoir24 = new THREE.Mesh(extrudeGeo13, stoneMat);
  voussoir24.name = 'voussoir';
  voussoir24.position.set(0, 0, 2.52);
  root.add(voussoir24);
  const faceStone = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.4746, 0.3173, 0.06), 0.008, 3), trimMat);
  faceStone.name = 'faceStone';
  faceStone.position.set(-2.7013, 5.3972, 2.515);
  root.add(faceStone);
  const faceStone2 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.8275, 0.2988, 0.06), 0.008, 4), stoneMat);
  faceStone2.name = 'faceStone';
  faceStone2.position.set(2.813, 4.4241, 2.515);
  root.add(faceStone2);
  const faceStone3 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.51, 0.3064, 0.06), 0.008, 5), trimMat);
  faceStone3.name = 'faceStone';
  faceStone3.position.set(2.9791, 4.0467, 2.515);
  root.add(faceStone3);
  const faceStone4 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.767, 0.2579, 0.06), 0.008, 6), stoneMat);
  faceStone4.name = 'faceStone';
  faceStone4.position.set(2.7652, 5.2711, 2.515);
  root.add(faceStone4);
  const faceStone5 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.5204, 0.2512, 0.06), 0.008, 7), stoneMat);
  faceStone5.name = 'faceStone';
  faceStone5.position.set(-2.6572, 4.3764, 2.515);
  root.add(faceStone5);
  const faceStone6 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.6424, 0.2484, 0.06), 0.008, 8), trimMat);
  faceStone6.name = 'faceStone';
  faceStone6.position.set(2.8063, 6.0559, 2.515);
  root.add(faceStone6);
  const faceStone7 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.4768, 0.3051, 0.06), 0.008, 9), stoneMat);
  faceStone7.name = 'faceStone';
  faceStone7.position.set(-1.5173, 5.7723, 2.515);
  root.add(faceStone7);
  const faceStone8 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.814, 0.3082, 0.06), 0.008, 10), stoneMat);
  faceStone8.name = 'faceStone';
  faceStone8.position.set(-2.5019, 6.1497, 2.515);
  root.add(faceStone8);
  const portcullisGroove = new THREE.Mesh(boxGeo2, darkMat);
  portcullisGroove.name = 'portcullisGroove';
  portcullisGroove.position.set(-1.78, 1.615, 1.75);
  root.add(portcullisGroove);
  const portcullisGroove2 = new THREE.Mesh(boxGeo2, darkMat);
  portcullisGroove2.name = 'portcullisGroove';
  portcullisGroove2.position.set(1.78, 1.615, 1.75);
  root.add(portcullisGroove2);
  const corbel = new THREE.Mesh(boxGeo3, trimMat);
  corbel.name = 'corbel';
  corbel.position.set(-3.15, 6.9, 2.67);
  root.add(corbel);
  const corbel2 = new THREE.Mesh(boxGeo3, trimMat);
  corbel2.name = 'corbel';
  corbel2.position.set(-2.3625, 6.9, 2.67);
  root.add(corbel2);
  const corbel3 = new THREE.Mesh(boxGeo3, trimMat);
  corbel3.name = 'corbel';
  corbel3.position.set(-1.575, 6.9, 2.67);
  root.add(corbel3);
  const corbel4 = new THREE.Mesh(boxGeo3, trimMat);
  corbel4.name = 'corbel';
  corbel4.position.set(-0.7875, 6.9, 2.67);
  root.add(corbel4);
  const corbel5 = new THREE.Mesh(boxGeo3, trimMat);
  corbel5.name = 'corbel';
  corbel5.position.set(0, 6.9, 2.67);
  root.add(corbel5);
  const corbel6 = new THREE.Mesh(boxGeo3, trimMat);
  corbel6.name = 'corbel';
  corbel6.position.set(0.7875, 6.9, 2.67);
  root.add(corbel6);
  const corbel7 = new THREE.Mesh(boxGeo3, trimMat);
  corbel7.name = 'corbel';
  corbel7.position.set(1.575, 6.9, 2.67);
  root.add(corbel7);
  const corbel8 = new THREE.Mesh(boxGeo3, trimMat);
  corbel8.name = 'corbel';
  corbel8.position.set(2.3625, 6.9, 2.67);
  root.add(corbel8);
  const corbel9 = new THREE.Mesh(boxGeo3, trimMat);
  corbel9.name = 'corbel';
  corbel9.position.set(3.15, 6.9, 2.67);
  root.add(corbel9);
  const frontParapet = new THREE.Mesh(new THREE.BoxGeometry(7.05, 0.75, 0.5), stoneMat);
  frontParapet.name = 'frontParapet';
  frontParapet.position.set(0, 7.525, 2.63);
  root.add(frontParapet);
  const backParapet = new THREE.Mesh(new THREE.BoxGeometry(6.9, 0.6, 0.4), stoneMat);
  backParapet.name = 'backParapet';
  backParapet.position.set(0, 7.5, -2.3);
  root.add(backParapet);
  const walkway = new THREE.Mesh(new THREE.BoxGeometry(6.6, 0.05, 4.2), pavingMat);
  walkway.name = 'walkway';
  walkway.position.set(0, 7.225, 0);
  root.add(walkway);
  const merlon = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.75, 0.5), 0.012, 11), stoneMat);
  merlon.name = 'merlon';
  merlon.position.set(-3, 8.275, 2.63);
  root.add(merlon);
  const merlonCap = new THREE.Mesh(boxGeo4, trimMat);
  merlonCap.name = 'merlonCap';
  merlonCap.position.set(-3, 8.69, 2.63);
  root.add(merlonCap);
  const merlon2 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.7, 0.4), 0.012, 12), stoneMat);
  merlon2.name = 'merlon';
  merlon2.position.set(-3, 8.15, -2.3);
  root.add(merlon2);
  const merlon3 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.75, 0.5), 0.012, 13), stoneMat);
  merlon3.name = 'merlon';
  merlon3.position.set(-1, 8.275, 2.63);
  root.add(merlon3);
  const merlonCap2 = new THREE.Mesh(boxGeo4, trimMat);
  merlonCap2.name = 'merlonCap';
  merlonCap2.position.set(-1, 8.69, 2.63);
  root.add(merlonCap2);
  const merlon4 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.7, 0.4), 0.012, 14), stoneMat);
  merlon4.name = 'merlon';
  merlon4.position.set(-1, 8.15, -2.3);
  root.add(merlon4);
  const merlon5 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.75, 0.5), 0.012, 15), stoneMat);
  merlon5.name = 'merlon';
  merlon5.position.set(1, 8.275, 2.63);
  root.add(merlon5);
  const merlonCap3 = new THREE.Mesh(boxGeo4, trimMat);
  merlonCap3.name = 'merlonCap';
  merlonCap3.position.set(1, 8.69, 2.63);
  root.add(merlonCap3);
  const merlon6 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.7, 0.4), 0.012, 16), stoneMat);
  merlon6.name = 'merlon';
  merlon6.position.set(1, 8.15, -2.3);
  root.add(merlon6);
  const merlon7 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.75, 0.5), 0.012, 17), stoneMat);
  merlon7.name = 'merlon';
  merlon7.position.set(3, 8.275, 2.63);
  root.add(merlon7);
  const merlonCap4 = new THREE.Mesh(boxGeo4, trimMat);
  merlonCap4.name = 'merlonCap';
  merlonCap4.position.set(3, 8.69, 2.63);
  root.add(merlonCap4);
  const merlon8 = new THREE.Mesh(jitter(new THREE.BoxGeometry(0.96, 0.7, 0.4), 0.012, 18), stoneMat);
  merlon8.name = 'merlon';
  merlon8.position.set(3, 8.15, -2.3);
  root.add(merlon8);
  const coatOfArms = new THREE.Mesh(extrude([[-0.55, 0.45], [0.55, 0.45], [0.55, -0.1], [0.3, -0.48], [0, -0.62], [-0.3, -0.48], [-0.55, -0.1]], 0.1), bannerMat);
  coatOfArms.name = 'coatOfArms';
  coatOfArms.position.set(0, 6.45, 2.57);
  root.add(coatOfArms);
  const armsCross = new THREE.Mesh(new THREE.BoxGeometry(0.14, 0.75, 0.06), goldMat);
  armsCross.name = 'armsCross';
  armsCross.position.set(0, 6.4, 2.64);
  root.add(armsCross);
  const armsCross2 = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.14, 0.06), goldMat);
  armsCross2.name = 'armsCross';
  armsCross2.position.set(0, 6.53, 2.64);
  root.add(armsCross2);
  const leftTower = new THREE.Group();
  leftTower.name = 'leftTower';
  leftTower.position.set(-4.35, 0, 0.7);
  root.add(leftTower);
  const towerPlinth = new THREE.Mesh(cylinderGeo, trimMat);
  towerPlinth.name = 'towerPlinth';
  towerPlinth.position.set(0, 0.55, 0);
  towerPlinth.rotation.set(0, deg(15), 0);
  leftTower.add(towerPlinth);
  const towerBody = new THREE.Mesh(cylinderGeo2, stoneMat);
  towerBody.name = 'towerBody';
  towerBody.position.set(0, 5.35, 0);
  towerBody.rotation.set(0, deg(15), 0);
  leftTower.add(towerBody);
  const towerString = new THREE.Mesh(cylinderGeo3, trimMat);
  towerString.name = 'towerString';
  towerString.position.set(0, 5.45, 0);
  towerString.rotation.set(0, deg(15), 0);
  leftTower.add(towerString);
  const towerCorbel = new THREE.Group();
  towerCorbel.name = 'towerCorbel';
  towerCorbel.position.set(0.5953, 9.28, 2.2216);
  towerCorbel.rotation.set(0, deg(15), 0);
  leftTower.add(towerCorbel);
  const box75 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel.add(box75);
  const towerCorbel2 = new THREE.Group();
  towerCorbel2.name = 'towerCorbel';
  towerCorbel2.position.set(1.6263, 9.28, 1.6263);
  towerCorbel2.rotation.set(0, deg(45), 0);
  leftTower.add(towerCorbel2);
  const box77 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel2.add(box77);
  const towerCorbel3 = new THREE.Group();
  towerCorbel3.name = 'towerCorbel';
  towerCorbel3.position.set(2.2216, 9.28, 0.5953);
  towerCorbel3.rotation.set(0, deg(75), 0);
  leftTower.add(towerCorbel3);
  const box79 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel3.add(box79);
  const towerCorbel4 = new THREE.Group();
  towerCorbel4.name = 'towerCorbel';
  towerCorbel4.position.set(2.2216, 9.28, -0.5953);
  towerCorbel4.rotation.set(0, deg(105), 0);
  leftTower.add(towerCorbel4);
  const box81 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel4.add(box81);
  const towerCorbel5 = new THREE.Group();
  towerCorbel5.name = 'towerCorbel';
  towerCorbel5.position.set(1.6263, 9.28, -1.6263);
  towerCorbel5.rotation.set(0, deg(135), 0);
  leftTower.add(towerCorbel5);
  const box83 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel5.add(box83);
  const towerCorbel6 = new THREE.Group();
  towerCorbel6.name = 'towerCorbel';
  towerCorbel6.position.set(0.5953, 9.28, -2.2216);
  towerCorbel6.rotation.set(0, deg(165), 0);
  leftTower.add(towerCorbel6);
  const box85 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel6.add(box85);
  const towerCorbel7 = new THREE.Group();
  towerCorbel7.name = 'towerCorbel';
  towerCorbel7.position.set(-0.5953, 9.28, -2.2216);
  towerCorbel7.rotation.set(0, deg(195), 0);
  leftTower.add(towerCorbel7);
  const box87 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel7.add(box87);
  const towerCorbel8 = new THREE.Group();
  towerCorbel8.name = 'towerCorbel';
  towerCorbel8.position.set(-1.6263, 9.28, -1.6263);
  towerCorbel8.rotation.set(0, deg(225), 0);
  leftTower.add(towerCorbel8);
  const box89 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel8.add(box89);
  const towerCorbel9 = new THREE.Group();
  towerCorbel9.name = 'towerCorbel';
  towerCorbel9.position.set(-2.2216, 9.28, -0.5953);
  towerCorbel9.rotation.set(0, deg(255), 0);
  leftTower.add(towerCorbel9);
  const box91 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel9.add(box91);
  const towerCorbel10 = new THREE.Group();
  towerCorbel10.name = 'towerCorbel';
  towerCorbel10.position.set(-2.2216, 9.28, 0.5953);
  towerCorbel10.rotation.set(0, deg(285), 0);
  leftTower.add(towerCorbel10);
  const box93 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel10.add(box93);
  const towerCorbel11 = new THREE.Group();
  towerCorbel11.name = 'towerCorbel';
  towerCorbel11.position.set(-1.6263, 9.28, 1.6263);
  towerCorbel11.rotation.set(0, deg(315), 0);
  leftTower.add(towerCorbel11);
  const box95 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel11.add(box95);
  const towerCorbel12 = new THREE.Group();
  towerCorbel12.name = 'towerCorbel';
  towerCorbel12.position.set(-0.5953, 9.28, 2.2216);
  towerCorbel12.rotation.set(0, deg(345), 0);
  leftTower.add(towerCorbel12);
  const box97 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel12.add(box97);
  const towerParapet = new THREE.Mesh(cylinderGeo4, stoneMat);
  towerParapet.name = 'towerParapet';
  towerParapet.position.set(0, 9.9, 0);
  towerParapet.rotation.set(0, deg(15), 0);
  leftTower.add(towerParapet);
  const towerLip = new THREE.Mesh(cylinderGeo5, trimMat);
  towerLip.name = 'towerLip';
  towerLip.position.set(0, 10.2, 0);
  towerLip.rotation.set(0, deg(15), 0);
  leftTower.add(towerLip);
  const towerMerlon = new THREE.Group();
  towerMerlon.name = 'towerMerlon';
  towerMerlon.position.set(0.7355, 10.22, 2.2635);
  towerMerlon.rotation.set(0, deg(18), 0);
  leftTower.add(towerMerlon);
  const box101 = new THREE.Mesh(boxGeo6, stoneMat);
  box101.position.set(0, 0.4, 0);
  towerMerlon.add(box101);
  const box102 = new THREE.Mesh(boxGeo7, trimMat);
  box102.position.set(0, 0.84, 0);
  towerMerlon.add(box102);
  const towerMerlon2 = new THREE.Group();
  towerMerlon2.name = 'towerMerlon';
  towerMerlon2.position.set(1.9255, 10.22, 1.3989);
  towerMerlon2.rotation.set(0, deg(54), 0);
  leftTower.add(towerMerlon2);
  const box104 = new THREE.Mesh(boxGeo6, stoneMat);
  box104.position.set(0, 0.4, 0);
  towerMerlon2.add(box104);
  const box105 = new THREE.Mesh(boxGeo7, trimMat);
  box105.position.set(0, 0.84, 0);
  towerMerlon2.add(box105);
  const towerMerlon3 = new THREE.Group();
  towerMerlon3.name = 'towerMerlon';
  towerMerlon3.position.set(2.38, 10.22, 0);
  towerMerlon3.rotation.set(0, deg(90), 0);
  leftTower.add(towerMerlon3);
  const box107 = new THREE.Mesh(boxGeo6, stoneMat);
  box107.position.set(0, 0.4, 0);
  towerMerlon3.add(box107);
  const box108 = new THREE.Mesh(boxGeo7, trimMat);
  box108.position.set(0, 0.84, 0);
  towerMerlon3.add(box108);
  const towerMerlon4 = new THREE.Group();
  towerMerlon4.name = 'towerMerlon';
  towerMerlon4.position.set(1.9255, 10.22, -1.3989);
  towerMerlon4.rotation.set(0, deg(126), 0);
  leftTower.add(towerMerlon4);
  const box110 = new THREE.Mesh(boxGeo6, stoneMat);
  box110.position.set(0, 0.4, 0);
  towerMerlon4.add(box110);
  const box111 = new THREE.Mesh(boxGeo7, trimMat);
  box111.position.set(0, 0.84, 0);
  towerMerlon4.add(box111);
  const towerMerlon5 = new THREE.Group();
  towerMerlon5.name = 'towerMerlon';
  towerMerlon5.position.set(0.7355, 10.22, -2.2635);
  towerMerlon5.rotation.set(0, deg(162), 0);
  leftTower.add(towerMerlon5);
  const box113 = new THREE.Mesh(boxGeo6, stoneMat);
  box113.position.set(0, 0.4, 0);
  towerMerlon5.add(box113);
  const box114 = new THREE.Mesh(boxGeo7, trimMat);
  box114.position.set(0, 0.84, 0);
  towerMerlon5.add(box114);
  const towerMerlon6 = new THREE.Group();
  towerMerlon6.name = 'towerMerlon';
  towerMerlon6.position.set(-0.7355, 10.22, -2.2635);
  towerMerlon6.rotation.set(0, deg(198), 0);
  leftTower.add(towerMerlon6);
  const box116 = new THREE.Mesh(boxGeo6, stoneMat);
  box116.position.set(0, 0.4, 0);
  towerMerlon6.add(box116);
  const box117 = new THREE.Mesh(boxGeo7, trimMat);
  box117.position.set(0, 0.84, 0);
  towerMerlon6.add(box117);
  const towerMerlon7 = new THREE.Group();
  towerMerlon7.name = 'towerMerlon';
  towerMerlon7.position.set(-1.9255, 10.22, -1.3989);
  towerMerlon7.rotation.set(0, deg(234), 0);
  leftTower.add(towerMerlon7);
  const box119 = new THREE.Mesh(boxGeo6, stoneMat);
  box119.position.set(0, 0.4, 0);
  towerMerlon7.add(box119);
  const box120 = new THREE.Mesh(boxGeo7, trimMat);
  box120.position.set(0, 0.84, 0);
  towerMerlon7.add(box120);
  const towerMerlon8 = new THREE.Group();
  towerMerlon8.name = 'towerMerlon';
  towerMerlon8.position.set(-2.38, 10.22, 0);
  towerMerlon8.rotation.set(0, deg(270), 0);
  leftTower.add(towerMerlon8);
  const box122 = new THREE.Mesh(boxGeo6, stoneMat);
  box122.position.set(0, 0.4, 0);
  towerMerlon8.add(box122);
  const box123 = new THREE.Mesh(boxGeo7, trimMat);
  box123.position.set(0, 0.84, 0);
  towerMerlon8.add(box123);
  const towerMerlon9 = new THREE.Group();
  towerMerlon9.name = 'towerMerlon';
  towerMerlon9.position.set(-1.9255, 10.22, 1.3989);
  towerMerlon9.rotation.set(0, deg(306), 0);
  leftTower.add(towerMerlon9);
  const box125 = new THREE.Mesh(boxGeo6, stoneMat);
  box125.position.set(0, 0.4, 0);
  towerMerlon9.add(box125);
  const box126 = new THREE.Mesh(boxGeo7, trimMat);
  box126.position.set(0, 0.84, 0);
  towerMerlon9.add(box126);
  const towerMerlon10 = new THREE.Group();
  towerMerlon10.name = 'towerMerlon';
  towerMerlon10.position.set(-0.7355, 10.22, 2.2635);
  towerMerlon10.rotation.set(0, deg(342), 0);
  leftTower.add(towerMerlon10);
  const box128 = new THREE.Mesh(boxGeo6, stoneMat);
  box128.position.set(0, 0.4, 0);
  towerMerlon10.add(box128);
  const box129 = new THREE.Mesh(boxGeo7, trimMat);
  box129.position.set(0, 0.84, 0);
  towerMerlon10.add(box129);
  const arrowSlit = new THREE.Group();
  arrowSlit.name = 'arrowSlit';
  arrowSlit.position.set(-1.8403, 2.4, 1.0625);
  arrowSlit.rotation.set(0, deg(-60), 0);
  leftTower.add(arrowSlit);
  const box131 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit.add(box131);
  const box132 = new THREE.Mesh(boxGeo9, darkMat);
  box132.position.set(0, 0, 0.014);
  arrowSlit.add(box132);
  const box133 = new THREE.Mesh(boxGeo10, darkMat);
  box133.position.set(0, 0.12, 0.014);
  arrowSlit.add(box133);
  const arrowSlit2 = new THREE.Group();
  arrowSlit2.name = 'arrowSlit';
  arrowSlit2.position.set(-2.0526, 4.8, -0.55);
  arrowSlit2.rotation.set(0, deg(-105), 0);
  leftTower.add(arrowSlit2);
  const box135 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit2.add(box135);
  const box136 = new THREE.Mesh(boxGeo9, darkMat);
  box136.position.set(0, 0, 0.014);
  arrowSlit2.add(box136);
  const box137 = new THREE.Mesh(boxGeo10, darkMat);
  box137.position.set(0, 0.12, 0.014);
  arrowSlit2.add(box137);
  const arrowSlit3 = new THREE.Group();
  arrowSlit3.name = 'arrowSlit';
  arrowSlit3.position.set(-1.0625, 6, 1.8403);
  arrowSlit3.rotation.set(0, deg(-30), 0);
  leftTower.add(arrowSlit3);
  const box139 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit3.add(box139);
  const box140 = new THREE.Mesh(boxGeo9, darkMat);
  box140.position.set(0, 0, 0.014);
  arrowSlit3.add(box140);
  const box141 = new THREE.Mesh(boxGeo10, darkMat);
  box141.position.set(0, 0.12, 0.014);
  arrowSlit3.add(box141);
  const arrowSlit4 = new THREE.Group();
  arrowSlit4.name = 'arrowSlit';
  arrowSlit4.position.set(0.369, 3.4, 2.0928);
  arrowSlit4.rotation.set(0, deg(10), 0);
  leftTower.add(arrowSlit4);
  const box143 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit4.add(box143);
  const box144 = new THREE.Mesh(boxGeo9, darkMat);
  box144.position.set(0, 0, 0.014);
  arrowSlit4.add(box144);
  const box145 = new THREE.Mesh(boxGeo10, darkMat);
  box145.position.set(0, 0.12, 0.014);
  arrowSlit4.add(box145);
  const banner = new THREE.Group();
  banner.name = 'banner';
  banner.position.set(0.2957, 8.6, 2.1044);
  banner.rotation.set(0, deg(8), 0);
  leftTower.add(banner);
  const bannerRod = new THREE.Mesh(cylinderGeo6, woodMat);
  bannerRod.name = 'bannerRod';
  bannerRod.position.set(0, 0, 0.12);
  bannerRod.rotation.set(0, 0, deg(90));
  banner.add(bannerRod);
  const bannerCloth = new THREE.Mesh(extrudeGeo14, bannerMat);
  bannerCloth.name = 'bannerCloth';
  bannerCloth.position.set(0, -0.02, 0.1);
  banner.add(bannerCloth);
  const bannerStripe = new THREE.Mesh(boxGeo11, goldMat);
  bannerStripe.name = 'bannerStripe';
  bannerStripe.position.set(0, -1.1, 0.125);
  banner.add(bannerStripe);
  const rightTower = new THREE.Group();
  rightTower.name = 'rightTower';
  rightTower.position.set(4.35, 0, 0.7);
  root.add(rightTower);
  const towerPlinth2 = new THREE.Mesh(cylinderGeo, trimMat);
  towerPlinth2.name = 'towerPlinth';
  towerPlinth2.position.set(0, 0.55, 0);
  towerPlinth2.rotation.set(0, deg(15), 0);
  rightTower.add(towerPlinth2);
  const towerBody2 = new THREE.Mesh(cylinderGeo2, stoneMat);
  towerBody2.name = 'towerBody';
  towerBody2.position.set(0, 5.35, 0);
  towerBody2.rotation.set(0, deg(15), 0);
  rightTower.add(towerBody2);
  const towerString2 = new THREE.Mesh(cylinderGeo3, trimMat);
  towerString2.name = 'towerString';
  towerString2.position.set(0, 5.45, 0);
  towerString2.rotation.set(0, deg(15), 0);
  rightTower.add(towerString2);
  const towerCorbel13 = new THREE.Group();
  towerCorbel13.name = 'towerCorbel';
  towerCorbel13.position.set(0.5953, 9.28, 2.2216);
  towerCorbel13.rotation.set(0, deg(15), 0);
  rightTower.add(towerCorbel13);
  const box155 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel13.add(box155);
  const towerCorbel14 = new THREE.Group();
  towerCorbel14.name = 'towerCorbel';
  towerCorbel14.position.set(1.6263, 9.28, 1.6263);
  towerCorbel14.rotation.set(0, deg(45), 0);
  rightTower.add(towerCorbel14);
  const box157 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel14.add(box157);
  const towerCorbel15 = new THREE.Group();
  towerCorbel15.name = 'towerCorbel';
  towerCorbel15.position.set(2.2216, 9.28, 0.5953);
  towerCorbel15.rotation.set(0, deg(75), 0);
  rightTower.add(towerCorbel15);
  const box159 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel15.add(box159);
  const towerCorbel16 = new THREE.Group();
  towerCorbel16.name = 'towerCorbel';
  towerCorbel16.position.set(2.2216, 9.28, -0.5953);
  towerCorbel16.rotation.set(0, deg(105), 0);
  rightTower.add(towerCorbel16);
  const box161 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel16.add(box161);
  const towerCorbel17 = new THREE.Group();
  towerCorbel17.name = 'towerCorbel';
  towerCorbel17.position.set(1.6263, 9.28, -1.6263);
  towerCorbel17.rotation.set(0, deg(135), 0);
  rightTower.add(towerCorbel17);
  const box163 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel17.add(box163);
  const towerCorbel18 = new THREE.Group();
  towerCorbel18.name = 'towerCorbel';
  towerCorbel18.position.set(0.5953, 9.28, -2.2216);
  towerCorbel18.rotation.set(0, deg(165), 0);
  rightTower.add(towerCorbel18);
  const box165 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel18.add(box165);
  const towerCorbel19 = new THREE.Group();
  towerCorbel19.name = 'towerCorbel';
  towerCorbel19.position.set(-0.5953, 9.28, -2.2216);
  towerCorbel19.rotation.set(0, deg(195), 0);
  rightTower.add(towerCorbel19);
  const box167 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel19.add(box167);
  const towerCorbel20 = new THREE.Group();
  towerCorbel20.name = 'towerCorbel';
  towerCorbel20.position.set(-1.6263, 9.28, -1.6263);
  towerCorbel20.rotation.set(0, deg(225), 0);
  rightTower.add(towerCorbel20);
  const box169 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel20.add(box169);
  const towerCorbel21 = new THREE.Group();
  towerCorbel21.name = 'towerCorbel';
  towerCorbel21.position.set(-2.2216, 9.28, -0.5953);
  towerCorbel21.rotation.set(0, deg(255), 0);
  rightTower.add(towerCorbel21);
  const box171 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel21.add(box171);
  const towerCorbel22 = new THREE.Group();
  towerCorbel22.name = 'towerCorbel';
  towerCorbel22.position.set(-2.2216, 9.28, 0.5953);
  towerCorbel22.rotation.set(0, deg(285), 0);
  rightTower.add(towerCorbel22);
  const box173 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel22.add(box173);
  const towerCorbel23 = new THREE.Group();
  towerCorbel23.name = 'towerCorbel';
  towerCorbel23.position.set(-1.6263, 9.28, 1.6263);
  towerCorbel23.rotation.set(0, deg(315), 0);
  rightTower.add(towerCorbel23);
  const box175 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel23.add(box175);
  const towerCorbel24 = new THREE.Group();
  towerCorbel24.name = 'towerCorbel';
  towerCorbel24.position.set(-0.5953, 9.28, 2.2216);
  towerCorbel24.rotation.set(0, deg(345), 0);
  rightTower.add(towerCorbel24);
  const box177 = new THREE.Mesh(boxGeo5, trimMat);
  towerCorbel24.add(box177);
  const towerParapet2 = new THREE.Mesh(cylinderGeo4, stoneMat);
  towerParapet2.name = 'towerParapet';
  towerParapet2.position.set(0, 9.9, 0);
  towerParapet2.rotation.set(0, deg(15), 0);
  rightTower.add(towerParapet2);
  const towerLip2 = new THREE.Mesh(cylinderGeo5, trimMat);
  towerLip2.name = 'towerLip';
  towerLip2.position.set(0, 10.2, 0);
  towerLip2.rotation.set(0, deg(15), 0);
  rightTower.add(towerLip2);
  const towerMerlon11 = new THREE.Group();
  towerMerlon11.name = 'towerMerlon';
  towerMerlon11.position.set(0.7355, 10.22, 2.2635);
  towerMerlon11.rotation.set(0, deg(18), 0);
  rightTower.add(towerMerlon11);
  const box181 = new THREE.Mesh(boxGeo6, stoneMat);
  box181.position.set(0, 0.4, 0);
  towerMerlon11.add(box181);
  const box182 = new THREE.Mesh(boxGeo7, trimMat);
  box182.position.set(0, 0.84, 0);
  towerMerlon11.add(box182);
  const towerMerlon12 = new THREE.Group();
  towerMerlon12.name = 'towerMerlon';
  towerMerlon12.position.set(1.9255, 10.22, 1.3989);
  towerMerlon12.rotation.set(0, deg(54), 0);
  rightTower.add(towerMerlon12);
  const box184 = new THREE.Mesh(boxGeo6, stoneMat);
  box184.position.set(0, 0.4, 0);
  towerMerlon12.add(box184);
  const box185 = new THREE.Mesh(boxGeo7, trimMat);
  box185.position.set(0, 0.84, 0);
  towerMerlon12.add(box185);
  const towerMerlon13 = new THREE.Group();
  towerMerlon13.name = 'towerMerlon';
  towerMerlon13.position.set(2.38, 10.22, 0);
  towerMerlon13.rotation.set(0, deg(90), 0);
  rightTower.add(towerMerlon13);
  const box187 = new THREE.Mesh(boxGeo6, stoneMat);
  box187.position.set(0, 0.4, 0);
  towerMerlon13.add(box187);
  const box188 = new THREE.Mesh(boxGeo7, trimMat);
  box188.position.set(0, 0.84, 0);
  towerMerlon13.add(box188);
  const towerMerlon14 = new THREE.Group();
  towerMerlon14.name = 'towerMerlon';
  towerMerlon14.position.set(1.9255, 10.22, -1.3989);
  towerMerlon14.rotation.set(0, deg(126), 0);
  rightTower.add(towerMerlon14);
  const box190 = new THREE.Mesh(boxGeo6, stoneMat);
  box190.position.set(0, 0.4, 0);
  towerMerlon14.add(box190);
  const box191 = new THREE.Mesh(boxGeo7, trimMat);
  box191.position.set(0, 0.84, 0);
  towerMerlon14.add(box191);
  const towerMerlon15 = new THREE.Group();
  towerMerlon15.name = 'towerMerlon';
  towerMerlon15.position.set(0.7355, 10.22, -2.2635);
  towerMerlon15.rotation.set(0, deg(162), 0);
  rightTower.add(towerMerlon15);
  const box193 = new THREE.Mesh(boxGeo6, stoneMat);
  box193.position.set(0, 0.4, 0);
  towerMerlon15.add(box193);
  const box194 = new THREE.Mesh(boxGeo7, trimMat);
  box194.position.set(0, 0.84, 0);
  towerMerlon15.add(box194);
  const towerMerlon16 = new THREE.Group();
  towerMerlon16.name = 'towerMerlon';
  towerMerlon16.position.set(-0.7355, 10.22, -2.2635);
  towerMerlon16.rotation.set(0, deg(198), 0);
  rightTower.add(towerMerlon16);
  const box196 = new THREE.Mesh(boxGeo6, stoneMat);
  box196.position.set(0, 0.4, 0);
  towerMerlon16.add(box196);
  const box197 = new THREE.Mesh(boxGeo7, trimMat);
  box197.position.set(0, 0.84, 0);
  towerMerlon16.add(box197);
  const towerMerlon17 = new THREE.Group();
  towerMerlon17.name = 'towerMerlon';
  towerMerlon17.position.set(-1.9255, 10.22, -1.3989);
  towerMerlon17.rotation.set(0, deg(234), 0);
  rightTower.add(towerMerlon17);
  const box199 = new THREE.Mesh(boxGeo6, stoneMat);
  box199.position.set(0, 0.4, 0);
  towerMerlon17.add(box199);
  const box200 = new THREE.Mesh(boxGeo7, trimMat);
  box200.position.set(0, 0.84, 0);
  towerMerlon17.add(box200);
  const towerMerlon18 = new THREE.Group();
  towerMerlon18.name = 'towerMerlon';
  towerMerlon18.position.set(-2.38, 10.22, 0);
  towerMerlon18.rotation.set(0, deg(270), 0);
  rightTower.add(towerMerlon18);
  const box202 = new THREE.Mesh(boxGeo6, stoneMat);
  box202.position.set(0, 0.4, 0);
  towerMerlon18.add(box202);
  const box203 = new THREE.Mesh(boxGeo7, trimMat);
  box203.position.set(0, 0.84, 0);
  towerMerlon18.add(box203);
  const towerMerlon19 = new THREE.Group();
  towerMerlon19.name = 'towerMerlon';
  towerMerlon19.position.set(-1.9255, 10.22, 1.3989);
  towerMerlon19.rotation.set(0, deg(306), 0);
  rightTower.add(towerMerlon19);
  const box205 = new THREE.Mesh(boxGeo6, stoneMat);
  box205.position.set(0, 0.4, 0);
  towerMerlon19.add(box205);
  const box206 = new THREE.Mesh(boxGeo7, trimMat);
  box206.position.set(0, 0.84, 0);
  towerMerlon19.add(box206);
  const towerMerlon20 = new THREE.Group();
  towerMerlon20.name = 'towerMerlon';
  towerMerlon20.position.set(-0.7355, 10.22, 2.2635);
  towerMerlon20.rotation.set(0, deg(342), 0);
  rightTower.add(towerMerlon20);
  const box208 = new THREE.Mesh(boxGeo6, stoneMat);
  box208.position.set(0, 0.4, 0);
  towerMerlon20.add(box208);
  const box209 = new THREE.Mesh(boxGeo7, trimMat);
  box209.position.set(0, 0.84, 0);
  towerMerlon20.add(box209);
  const arrowSlit5 = new THREE.Group();
  arrowSlit5.name = 'arrowSlit';
  arrowSlit5.position.set(1.8403, 2.4, 1.0625);
  arrowSlit5.rotation.set(0, deg(60), 0);
  rightTower.add(arrowSlit5);
  const box211 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit5.add(box211);
  const box212 = new THREE.Mesh(boxGeo9, darkMat);
  box212.position.set(0, 0, 0.014);
  arrowSlit5.add(box212);
  const box213 = new THREE.Mesh(boxGeo10, darkMat);
  box213.position.set(0, 0.12, 0.014);
  arrowSlit5.add(box213);
  const arrowSlit6 = new THREE.Group();
  arrowSlit6.name = 'arrowSlit';
  arrowSlit6.position.set(2.0526, 4.8, -0.55);
  arrowSlit6.rotation.set(0, deg(105), 0);
  rightTower.add(arrowSlit6);
  const box215 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit6.add(box215);
  const box216 = new THREE.Mesh(boxGeo9, darkMat);
  box216.position.set(0, 0, 0.014);
  arrowSlit6.add(box216);
  const box217 = new THREE.Mesh(boxGeo10, darkMat);
  box217.position.set(0, 0.12, 0.014);
  arrowSlit6.add(box217);
  const arrowSlit7 = new THREE.Group();
  arrowSlit7.name = 'arrowSlit';
  arrowSlit7.position.set(1.0625, 6, 1.8403);
  arrowSlit7.rotation.set(0, deg(30), 0);
  rightTower.add(arrowSlit7);
  const box219 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit7.add(box219);
  const box220 = new THREE.Mesh(boxGeo9, darkMat);
  box220.position.set(0, 0, 0.014);
  arrowSlit7.add(box220);
  const box221 = new THREE.Mesh(boxGeo10, darkMat);
  box221.position.set(0, 0.12, 0.014);
  arrowSlit7.add(box221);
  const arrowSlit8 = new THREE.Group();
  arrowSlit8.name = 'arrowSlit';
  arrowSlit8.position.set(-0.369, 3.4, 2.0928);
  arrowSlit8.rotation.set(0, deg(-10), 0);
  rightTower.add(arrowSlit8);
  const box223 = new THREE.Mesh(boxGeo8, trimMat);
  arrowSlit8.add(box223);
  const box224 = new THREE.Mesh(boxGeo9, darkMat);
  box224.position.set(0, 0, 0.014);
  arrowSlit8.add(box224);
  const box225 = new THREE.Mesh(boxGeo10, darkMat);
  box225.position.set(0, 0.12, 0.014);
  arrowSlit8.add(box225);
  const banner2 = new THREE.Group();
  banner2.name = 'banner';
  banner2.position.set(-0.2957, 8.6, 2.1044);
  banner2.rotation.set(0, deg(-8), 0);
  rightTower.add(banner2);
  const bannerRod2 = new THREE.Mesh(cylinderGeo6, woodMat);
  bannerRod2.name = 'bannerRod';
  bannerRod2.position.set(0, 0, 0.12);
  bannerRod2.rotation.set(0, 0, deg(90));
  banner2.add(bannerRod2);
  const bannerCloth2 = new THREE.Mesh(extrudeGeo14, bannerMat);
  bannerCloth2.name = 'bannerCloth';
  bannerCloth2.position.set(0, -0.02, 0.1);
  banner2.add(bannerCloth2);
  const bannerStripe2 = new THREE.Mesh(boxGeo11, goldMat);
  bannerStripe2.name = 'bannerStripe';
  bannerStripe2.position.set(0, -1.1, 0.125);
  banner2.add(bannerStripe2);
  const flagPole = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.06, 3.2, 6), woodMat);
  flagPole.name = 'flagPole';
  flagPole.position.set(4.35, 11.25, 0.7);
  root.add(flagPole);
  const pennant = new THREE.Mesh(extrude([[0, 0], [1.9, 0.08], [1.4, 0.5], [1.9, 0.92], [0, 1]], 0.04), bannerMat);
  pennant.name = 'pennant';
  pennant.position.set(4.39, 11.7, 0.7);
  pennant.rotation.set(0, deg(-20), 0);
  root.add(pennant);
  const towerFloor = new THREE.Mesh(cylinderGeo7, pavingMat);
  towerFloor.name = 'towerFloor';
  towerFloor.position.set(-4.35, 10.225, 0.7);
  towerFloor.rotation.set(0, deg(15), 0);
  root.add(towerFloor);
  const towerFloor2 = new THREE.Mesh(cylinderGeo7, pavingMat);
  towerFloor2.name = 'towerFloor';
  towerFloor2.position.set(4.35, 10.225, 0.7);
  towerFloor2.rotation.set(0, deg(15), 0);
  root.add(towerFloor2);
  const portcullisBar = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar.name = 'portcullisBar';
  portcullisBar.position.set(-1.6, 4.3875, 1.75);
  root.add(portcullisBar);
  const portcullisSpike = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike.name = 'portcullisSpike';
  portcullisSpike.position.set(-1.6, 1.9375, 1.75);
  portcullisSpike.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike);
  const portcullisBar2 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar2.name = 'portcullisBar';
  portcullisBar2.position.set(-1.28, 4.3875, 1.75);
  root.add(portcullisBar2);
  const portcullisSpike2 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike2.name = 'portcullisSpike';
  portcullisSpike2.position.set(-1.28, 1.9375, 1.75);
  portcullisSpike2.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike2);
  const portcullisBar3 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar3.name = 'portcullisBar';
  portcullisBar3.position.set(-0.96, 4.3875, 1.75);
  root.add(portcullisBar3);
  const portcullisSpike3 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike3.name = 'portcullisSpike';
  portcullisSpike3.position.set(-0.96, 1.9375, 1.75);
  portcullisSpike3.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike3);
  const portcullisBar4 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar4.name = 'portcullisBar';
  portcullisBar4.position.set(-0.64, 4.3875, 1.75);
  root.add(portcullisBar4);
  const portcullisSpike4 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike4.name = 'portcullisSpike';
  portcullisSpike4.position.set(-0.64, 1.9375, 1.75);
  portcullisSpike4.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike4);
  const portcullisBar5 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar5.name = 'portcullisBar';
  portcullisBar5.position.set(-0.32, 4.3875, 1.75);
  root.add(portcullisBar5);
  const portcullisSpike5 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike5.name = 'portcullisSpike';
  portcullisSpike5.position.set(-0.32, 1.9375, 1.75);
  portcullisSpike5.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike5);
  const portcullisBar6 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar6.name = 'portcullisBar';
  portcullisBar6.position.set(0, 4.3875, 1.75);
  root.add(portcullisBar6);
  const portcullisSpike6 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike6.name = 'portcullisSpike';
  portcullisSpike6.position.set(0, 1.9375, 1.75);
  portcullisSpike6.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike6);
  const portcullisBar7 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar7.name = 'portcullisBar';
  portcullisBar7.position.set(0.32, 4.3875, 1.75);
  root.add(portcullisBar7);
  const portcullisSpike7 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike7.name = 'portcullisSpike';
  portcullisSpike7.position.set(0.32, 1.9375, 1.75);
  portcullisSpike7.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike7);
  const portcullisBar8 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar8.name = 'portcullisBar';
  portcullisBar8.position.set(0.64, 4.3875, 1.75);
  root.add(portcullisBar8);
  const portcullisSpike8 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike8.name = 'portcullisSpike';
  portcullisSpike8.position.set(0.64, 1.9375, 1.75);
  portcullisSpike8.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike8);
  const portcullisBar9 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar9.name = 'portcullisBar';
  portcullisBar9.position.set(0.96, 4.3875, 1.75);
  root.add(portcullisBar9);
  const portcullisSpike9 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike9.name = 'portcullisSpike';
  portcullisSpike9.position.set(0.96, 1.9375, 1.75);
  portcullisSpike9.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike9);
  const portcullisBar10 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar10.name = 'portcullisBar';
  portcullisBar10.position.set(1.28, 4.3875, 1.75);
  root.add(portcullisBar10);
  const portcullisSpike10 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike10.name = 'portcullisSpike';
  portcullisSpike10.position.set(1.28, 1.9375, 1.75);
  portcullisSpike10.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike10);
  const portcullisBar11 = new THREE.Mesh(boxGeo12, ironMat);
  portcullisBar11.name = 'portcullisBar';
  portcullisBar11.position.set(1.6, 4.3875, 1.75);
  root.add(portcullisBar11);
  const portcullisSpike11 = new THREE.Mesh(coneGeo, ironMat);
  portcullisSpike11.name = 'portcullisSpike';
  portcullisSpike11.position.set(1.6, 1.9375, 1.75);
  portcullisSpike11.rotation.set(deg(180), deg(45), 0);
  root.add(portcullisSpike11);
  const portcullisRail = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail.name = 'portcullisRail';
  portcullisRail.position.set(0, 2.4375, 1.8);
  root.add(portcullisRail);
  const portcullisRail2 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail2.name = 'portcullisRail';
  portcullisRail2.position.set(0, 2.9175, 1.8);
  root.add(portcullisRail2);
  const portcullisRail3 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail3.name = 'portcullisRail';
  portcullisRail3.position.set(0, 3.3975, 1.8);
  root.add(portcullisRail3);
  const portcullisRail4 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail4.name = 'portcullisRail';
  portcullisRail4.position.set(0, 3.8775, 1.8);
  root.add(portcullisRail4);
  const portcullisRail5 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail5.name = 'portcullisRail';
  portcullisRail5.position.set(0, 4.3575, 1.8);
  root.add(portcullisRail5);
  const portcullisRail6 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail6.name = 'portcullisRail';
  portcullisRail6.position.set(0, 4.8375, 1.8);
  root.add(portcullisRail6);
  const portcullisRail7 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail7.name = 'portcullisRail';
  portcullisRail7.position.set(0, 5.3175, 1.8);
  root.add(portcullisRail7);
  const portcullisRail8 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail8.name = 'portcullisRail';
  portcullisRail8.position.set(0, 5.7975, 1.8);
  root.add(portcullisRail8);
  const portcullisRail9 = new THREE.Mesh(boxGeo13, ironMat);
  portcullisRail9.name = 'portcullisRail';
  portcullisRail9.position.set(0, 6.2775, 1.8);
  root.add(portcullisRail9);
  const gateLeaf = new THREE.Group();
  gateLeaf.name = 'gateLeaf';
  gateLeaf.position.set(-1.76, 0.05, -0.6);
  gateLeaf.rotation.set(0, deg(82), 0);
  root.add(gateLeaf);
  const leaf = new THREE.Mesh(boxGeo14, woodMat);
  leaf.name = 'leaf';
  leaf.position.set(0.88, 1.625, 0);
  gateLeaf.add(leaf);
  const leafBand = new THREE.Mesh(boxGeo15, ironMat);
  leafBand.name = 'leafBand';
  leafBand.position.set(0.88, 0.5, 0.075);
  gateLeaf.add(leafBand);
  const leafBand2 = new THREE.Mesh(boxGeo15, ironMat);
  leafBand2.name = 'leafBand';
  leafBand2.position.set(0.88, 1.625, 0.075);
  gateLeaf.add(leafBand2);
  const leafBand3 = new THREE.Mesh(boxGeo15, ironMat);
  leafBand3.name = 'leafBand';
  leafBand3.position.set(0.88, 2.75, 0.075);
  gateLeaf.add(leafBand3);
  const gateLeaf2 = new THREE.Group();
  gateLeaf2.name = 'gateLeaf';
  gateLeaf2.position.set(1.76, 0.05, -0.6);
  gateLeaf2.rotation.set(0, deg(98), 0);
  root.add(gateLeaf2);
  const leaf2 = new THREE.Mesh(boxGeo14, woodMat);
  leaf2.name = 'leaf';
  leaf2.position.set(0.88, 1.625, 0);
  gateLeaf2.add(leaf2);
  const leafBand4 = new THREE.Mesh(boxGeo15, ironMat);
  leafBand4.name = 'leafBand';
  leafBand4.position.set(0.88, 0.5, 0.075);
  gateLeaf2.add(leafBand4);
  const leafBand5 = new THREE.Mesh(boxGeo15, ironMat);
  leafBand5.name = 'leafBand';
  leafBand5.position.set(0.88, 1.625, 0.075);
  gateLeaf2.add(leafBand5);
  const leafBand6 = new THREE.Mesh(boxGeo15, ironMat);
  leafBand6.name = 'leafBand';
  leafBand6.position.set(0.88, 2.75, 0.075);
  gateLeaf2.add(leafBand6);

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

export default createCastleGate;
```

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