# Stone Golem

> A hulking, chunky low-poly stone golem assembled from jittered faceted boulders — massive shoulders, a tiny head with a heavy brow and glowing eyes, long arms ending in huge rock fists and stumpy legs — with glowing runes carved into its chest and forearms. Recolor the stone and the magic glow, and toggle moss patches and glowing back crystals. Head, arms and legs are pivoted groups for lumbering walk, smash and wake-up animations; a great boss or guardian for dungeons, caves, ruins and fantasy RPGs.

![Stone Golem preview](https://codels.download/m/golem.png)

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

## Facts

- Category: Characters › Creatures & Monsters
- Size (W × H × D): 2.52 × 2.32 × 1.06 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 912 · Meshes: 43 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: boss, boulder, golem, ruins, chunky, low-poly, stylized, fantasy, cave, dungeon, mountain, roguelike, rpg, enemy, stone, emissive, game-ready, mobile-friendly, parametric, color-gray, size-medium, poly-low
- Page: https://codels.download/models/golem

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `stone` | color | #rrggbb | #858a93 | #858a93 |
| `glow` | color | #rrggbb | #46dcff | #46dcff |
| `moss` | boolean | true \| false | true | true |
| `crystals` | boolean | true \| false | true | true |

## Parts

- legL (group)
  - thighL (dodecahedron · stoneDark)
  - footL (dodecahedron · stone)
- legR (group)
  - thighR (dodecahedron · stoneDark)
  - footR (dodecahedron · stone)
- body (group)
  - pelvis (dodecahedron · stoneDark)
  - torso (dodecahedron · stone)
  - chestRune (group)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeStroke (box · glow)
    - runeBar (box · glow)
  - mossBack (icosahedron · moss)
  - backCrystal1 (octahedron · glow)
  - backCrystal2 (octahedron · glow)
  - backCrystal3 (octahedron · glow)
- armL (group)
  - shoulderL (dodecahedron · stoneLight)
  - upperArmL (dodecahedron · stoneDark)
  - forearmL (dodecahedron · stone)
  - fistL (dodecahedron · stoneLight)
  - forearmRuneL (group)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeEdge (box · glow)
    - runeStroke (box · glow)
    - runeBar (box · glow)
  - mossShoulder (icosahedron · moss)
- armR (group)
  - shoulderR (dodecahedron · stoneLight)
  - upperArmR (dodecahedron · stoneDark)
  - forearmR (dodecahedron · stone)
  - fistR (dodecahedron · stoneLight)
  - forearmRuneR (group)
    - runeEdge (box · glow)

## How to use

Save the code below as `golem.js`, then:

```js
import { createGolem } from './golem.js';
const model = createGolem();
scene.add(model);
```

## Code

```js
/**
 * Stone Golem — Codels 3D model library (https://codels.download/models/golem)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 912 · Size (W × H × D): 2.52 × 2.32 × 1.06 m
 *
 * Usage:
 *   import { createGolem } from './golem.js';
 *   
 *   const model = createGolem();
 *   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;
}

export function createGolem() {
  const root = new THREE.Group();
  root.name = 'Golem';

  // Materials
  const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0x858a93, roughness: 0.95, flatShading: true });
  const stoneDarkMat = new THREE.MeshStandardMaterial({ name: 'stoneDark', color: 0x686c73, roughness: 0.95, flatShading: true });
  const stoneLightMat = new THREE.MeshStandardMaterial({ name: 'stoneLight', color: 0x9498a0, roughness: 0.95, flatShading: true });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x46dcff, roughness: 0.3, emissive: 0x46dcff, emissiveIntensity: 1.1, flatShading: true });
  const mossMat = new THREE.MeshStandardMaterial({ name: 'moss', color: 0x6b9a3e, roughness: 1, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.2016, 0.0364, 0.02);
  const octahedronGeo = new THREE.OctahedronGeometry(0.085, 0);
  const boxGeo2 = new THREE.BoxGeometry(0.0648, 0.018, 0.02);
  const boxGeo3 = new THREE.BoxGeometry(0.018, 0.135, 0.02);
  const boxGeo4 = new THREE.BoxGeometry(0.045, 0.018, 0.02);
  const boxGeo5 = new THREE.BoxGeometry(0.11, 0.055, 0.03);

  // Parts
  const legL = new THREE.Group();
  legL.name = 'legL';
  legL.position.set(0.3, 0.72, 0);
  root.add(legL);
  const thighL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.035, 3), stoneDarkMat);
  thighL.name = 'thighL';
  thighL.position.set(0, -0.14, 0);
  legL.add(thighL);
  const footL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3, 0), 0.03, 5), stoneMat);
  footL.name = 'footL';
  footL.position.set(0, -0.5313, 0.06);
  footL.scale.set(1.05, 0.62, 1.25);
  legL.add(footL);
  const legR = new THREE.Group();
  legR.name = 'legR';
  legR.position.set(-0.3, 0.72, 0);
  root.add(legR);
  const thighR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.035, 4), stoneDarkMat);
  thighR.name = 'thighR';
  thighR.position.set(0, -0.14, 0);
  legR.add(thighR);
  const footR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3, 0), 0.03, 6), stoneMat);
  footR.name = 'footR';
  footR.position.set(0, -0.5445, 0.06);
  footR.scale.set(1.05, 0.62, 1.25);
  legR.add(footR);
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const pelvis = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.4, 0), 0.04, 8), stoneDarkMat);
  pelvis.name = 'pelvis';
  pelvis.position.set(0, 0.84, 0);
  pelvis.scale.set(1.25, 0.7, 0.9);
  body.add(pelvis);
  const torso = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.62, 0), 0.06, 2), stoneMat);
  torso.name = 'torso';
  torso.position.set(0, 1.4, 0);
  torso.scale.set(1.2, 0.95, 0.85);
  body.add(torso);
  const chestRune = new THREE.Group();
  chestRune.name = 'chestRune';
  chestRune.position.set(-0.0045, 1.4814, 0.4943);
  chestRune.rotation.set(deg(-7.2582), deg(-22.2077), deg(-1.4263));
  body.add(chestRune);
  const runeEdge = new THREE.Mesh(boxGeo, glowMat);
  runeEdge.name = 'runeEdge';
  runeEdge.position.set(-0.07, 0.07, 0);
  runeEdge.rotation.set(0, 0, deg(45));
  chestRune.add(runeEdge);
  const runeEdge2 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge2.name = 'runeEdge';
  runeEdge2.position.set(0.07, 0.07, 0);
  runeEdge2.rotation.set(0, 0, deg(-45));
  chestRune.add(runeEdge2);
  const runeEdge3 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge3.name = 'runeEdge';
  runeEdge3.position.set(-0.07, -0.07, 0);
  runeEdge3.rotation.set(0, 0, deg(-45));
  chestRune.add(runeEdge3);
  const runeEdge4 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge4.name = 'runeEdge';
  runeEdge4.position.set(0.07, -0.07, 0);
  runeEdge4.rotation.set(0, 0, deg(45));
  chestRune.add(runeEdge4);
  const runeStroke = new THREE.Mesh(new THREE.BoxGeometry(0.0364, 0.42, 0.02), glowMat);
  runeStroke.name = 'runeStroke';
  chestRune.add(runeStroke);
  const runeBar = new THREE.Mesh(new THREE.BoxGeometry(0.14, 0.0364, 0.02), glowMat);
  runeBar.name = 'runeBar';
  runeBar.position.set(0, -0.07, 0);
  chestRune.add(runeBar);
  const mossBack = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.26, 0), 0.03, 21), mossMat);
  mossBack.name = 'mossBack';
  mossBack.position.set(-0.22, 1.9532, -0.05);
  mossBack.scale.set(1.1, 0.28, 0.9);
  body.add(mossBack);
  const backCrystal1 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal1.name = 'backCrystal1';
  backCrystal1.position.set(-0.25, 1.62, -0.3526);
  backCrystal1.rotation.set(deg(-43.8302), deg(-10.4646), deg(25.6471));
  backCrystal1.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal1);
  const backCrystal2 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal2.name = 'backCrystal2';
  backCrystal2.position.set(0.05, 1.72, -0.2488);
  backCrystal2.rotation.set(deg(-38.5378), deg(1.5622), deg(-4.4667));
  backCrystal2.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal2);
  const backCrystal3 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal3.name = 'backCrystal3';
  backCrystal3.position.set(0.3, 1.55, -0.2999);
  backCrystal3.rotation.set(deg(-44.8632), deg(13.4762), deg(-31.9421));
  backCrystal3.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal3);
  const armL = new THREE.Group();
  armL.name = 'armL';
  armL.position.set(0.74, 1.74, 0);
  armL.rotation.set(deg(-6), 0, deg(9));
  root.add(armL);
  const shoulderL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.35, 0), 0.04, 31), stoneLightMat);
  shoulderL.name = 'shoulderL';
  armL.add(shoulderL);
  const upperArmL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.21, 0), 0.025, 33), stoneDarkMat);
  upperArmL.name = 'upperArmL';
  upperArmL.position.set(0, -0.4, 0);
  armL.add(upperArmL);
  const forearmL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.03, 35), stoneMat);
  forearmL.name = 'forearmL';
  forearmL.position.set(0, -0.76, 0.04);
  forearmL.scale.set(1, 1.25, 1);
  armL.add(forearmL);
  const fistL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.33, 0), 0.04, 37), stoneLightMat);
  fistL.name = 'fistL';
  fistL.position.set(0, -1.18, 0.07);
  armL.add(fistL);
  const forearmRuneL = new THREE.Group();
  forearmRuneL.name = 'forearmRuneL';
  forearmRuneL.position.set(0.0579, -0.7793, 0.2378);
  forearmRuneL.rotation.set(deg(-4.3648), deg(41.2508), deg(1.6435));
  armL.add(forearmRuneL);
  const runeEdge5 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge5.name = 'runeEdge';
  runeEdge5.position.set(-0.0225, 0.0225, 0);
  runeEdge5.rotation.set(0, 0, deg(45));
  forearmRuneL.add(runeEdge5);
  const runeEdge6 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge6.name = 'runeEdge';
  runeEdge6.position.set(0.0225, 0.0225, 0);
  runeEdge6.rotation.set(0, 0, deg(-45));
  forearmRuneL.add(runeEdge6);
  const runeEdge7 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge7.name = 'runeEdge';
  runeEdge7.position.set(-0.0225, -0.0225, 0);
  runeEdge7.rotation.set(0, 0, deg(-45));
  forearmRuneL.add(runeEdge7);
  const runeEdge8 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge8.name = 'runeEdge';
  runeEdge8.position.set(0.0225, -0.0225, 0);
  runeEdge8.rotation.set(0, 0, deg(45));
  forearmRuneL.add(runeEdge8);
  const runeStroke2 = new THREE.Mesh(boxGeo3, glowMat);
  runeStroke2.name = 'runeStroke';
  forearmRuneL.add(runeStroke2);
  const runeBar2 = new THREE.Mesh(boxGeo4, glowMat);
  runeBar2.name = 'runeBar';
  runeBar2.position.set(0, -0.0225, 0);
  forearmRuneL.add(runeBar2);
  const mossShoulder = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.2, 0), 0.025, 41), mossMat);
  mossShoulder.name = 'mossShoulder';
  mossShoulder.position.set(0.02, 0.31, -0.02);
  mossShoulder.scale.set(1, 0.3, 1);
  armL.add(mossShoulder);
  const armR = new THREE.Group();
  armR.name = 'armR';
  armR.position.set(-0.74, 1.74, 0);
  armR.rotation.set(deg(-6), 0, deg(-9));
  root.add(armR);
  const shoulderR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.35, 0), 0.04, 32), stoneLightMat);
  shoulderR.name = 'shoulderR';
  armR.add(shoulderR);
  const upperArmR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.21, 0), 0.025, 34), stoneDarkMat);
  upperArmR.name = 'upperArmR';
  upperArmR.position.set(0, -0.4, 0);
  armR.add(upperArmR);
  const forearmR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.03, 36), stoneMat);
  forearmR.name = 'forearmR';
  forearmR.position.set(0, -0.76, 0.04);
  forearmR.scale.set(1, 1.25, 1);
  armR.add(forearmR);
  const fistR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.33, 0), 0.04, 38), stoneLightMat);
  fistR.name = 'fistR';
  fistR.position.set(0, -1.18, 0.07);
  armR.add(fistR);
  const forearmRuneR = new THREE.Group();
  forearmRuneR.name = 'forearmRuneR';
  forearmRuneR.position.set(-0.0569, -0.7806, 0.2372);
  forearmRuneR.rotation.set(deg(3.4854), deg(-35.3884), deg(1.1123));
  armR.add(forearmRuneR);
  const runeEdge9 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge9.name = 'runeEdge';
  runeEdge9.position.set(-0.0225, 0.0225, 0);
  runeEdge9.rotation.set(0, 0, deg(45));
  forearmRuneR.add(runeEdge9);
  const runeEdge10 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge10.name = 'runeEdge';
  runeEdge10.position.set(0.0225, 0.0225, 0);
  runeEdge10.rotation.set(0, 0, deg(-45));
  forearmRuneR.add(runeEdge10);
  const runeEdge11 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge11.name = 'runeEdge';
  runeEdge11.position.set(-0.0225, -0.0225, 0);
  runeEdge11.rotation.set(0, 0, deg(-45));
  forearmRuneR.add(runeEdge11);
  const runeEdge12 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge12.name = 'runeEdge';
  runeEdge12.position.set(0.0225, -0.0225, 0);
  runeEdge12.rotation.set(0, 0, deg(45));
  forearmRuneR.add(runeEdge12);
  const runeStroke3 = new THREE.Mesh(boxGeo3, glowMat);
  runeStroke3.name = 'runeStroke';
  forearmRuneR.add(runeStroke3);
  const runeBar3 = new THREE.Mesh(boxGeo4, glowMat);
  runeBar3.name = 'runeBar';
  runeBar3.position.set(0, -0.0225, 0);
  forearmRuneR.add(runeBar3);
  const head = new THREE.Group();
  head.name = 'head';
  head.position.set(0, 1.92, 0.12);
  root.add(head);
  const skull = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.31, 0), 0.03, 51), stoneMat);
  skull.name = 'skull';
  skull.position.set(0, 0.15, 0.06);
  skull.scale.set(1.12, 0.85, 1);
  head.add(skull);
  const brow = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.17, 0), 0.015, 52), stoneDarkMat);
  brow.name = 'brow';
  brow.position.set(0, 0.25, 0.2);
  brow.scale.set(1.75, 0.42, 0.7);
  head.add(brow);
  const eyeL = new THREE.Mesh(boxGeo5, glowMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.11, 0.15, 0.2711);
  eyeL.rotation.set(deg(8.2871), deg(18.1187), deg(-13.3236));
  head.add(eyeL);
  const eyeR = new THREE.Mesh(boxGeo5, glowMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.11, 0.15, 0.2782);
  eyeR.rotation.set(deg(4.8602), deg(-28.7519), deg(13.2464));
  head.add(eyeR);
  const mouth = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.035, 0.03), stoneDarkMat);
  mouth.name = 'mouth';
  mouth.position.set(0, 0.03, 0.2563);
  mouth.rotation.set(deg(53.6954), deg(-1.8448), deg(0.9339));
  head.add(mouth);
  const mossHead = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.17, 0), 0.02, 61), mossMat);
  mossHead.name = 'mossHead';
  mossHead.position.set(-0.05, 0.35, 0);
  mossHead.scale.set(1, 0.3, 1);
  head.add(mossHead);

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

export default createGolem;
```

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