# Brazier

> A wrought-iron fire brazier: a deep riveted bowl with a spiked rim on three curved tripod legs with scrolled feet and braces, heaped with glowing coals and topped by layered emissive flames and sparks. Adjust the height and flame size, recolor the iron, or put it out for a cold bowl of ash and charcoal. Lights up temples, throne rooms, camps, arenas and dungeon corridors.

![Brazier preview](https://codels.download/m/brazier.png)

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

## Facts

- Category: Props › Lighting
- Size (W × H × D): 0.76 × 1.48 × 0.77 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,168 · Meshes: 47 · Materials: 7
- License: CC0-1.0 (Codels built-in)
- Tags: brazier, coal, fire, low-poly, stylized, ancient, fantasy, medieval, castle, dungeon, interior, adventure, roguelike, rpg, decoration, hazard, light-source, metal, round, emissive, mobile-friendly, parametric, color-gray, multicolor, color-orange, size-medium, poly-low
- Page: https://codels.download/models/brazier

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `lit` | boolean | true \| false | true | true |
| `flame` | number | 0.5 – 1.5 | 1 | 1 |
| `height` | number | 0.6 – 1.2 | 0.9 | 0.9 |
| `iron` | color | #rrggbb | #4a4645 | #4a4645 |

## Parts

- bowl (lathe · iron)
- bowlBand (lathe · ironDark)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- rimSpike (cone · iron)
- leg (tube · iron)
- foot (sphere · iron)
- leg (tube · iron)
- foot (sphere · iron)
- leg (tube · iron)
- foot (sphere · iron)
- brace (box · ironDark)
- brace (box · ironDark)
- brace (box · ironDark)
- coalBed (sphere · coal)
- coal (octahedron · coal)
- ember (icosahedron · ember)
- ember (octahedron · ember)
- coal (icosahedron · coal)
- ember (octahedron · ember)
- ember (icosahedron · ember)
- coal (octahedron · coal)
- ember (icosahedron · ember)
- ember (octahedron · ember)
- coal (icosahedron · coal)
- ember (octahedron · ember)
- ember (icosahedron · ember)
- coal (octahedron · coal)
- ember (icosahedron · ember)
- flames (group)
  - flameMain (cone · orange)
  - flameBackL (cone · red)
  - flameBackR (cone · red)
  - flameSideL (cone · orange)
  - flameSideR (cone · red)

## How to use

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

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

## Code

```js
/**
 * Brazier — Codels 3D model library (https://codels.download/models/brazier)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,168 · Size (W × H × D): 0.76 × 1.48 × 0.77 m
 *
 * Usage:
 *   import { createBrazier } from './brazier.js';
 *   
 *   const model = createBrazier();
 *   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;
}

// Revolve a 2D profile [[radius, y], ...] around the Y axis.
function lathe(points, segments, phiStart = 0, phiLength = Math.PI * 2) {
  return new THREE.LatheGeometry(points.map(([x, y]) => new THREE.Vector2(x, y)), segments, phiStart, phiLength);
}

// Tube along a smooth curve through the given points.
function tube(path, radius, tubularSegments, radialSegments, closed = false) {
  const curve = new THREE.CatmullRomCurve3(path.map(([x, y, z]) => new THREE.Vector3(x, y, z)), closed);
  return new THREE.TubeGeometry(curve, tubularSegments, radius, radialSegments, closed);
}

export function createBrazier() {
  const root = new THREE.Group();
  root.name = 'Brazier';

  // Materials
  const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x4a4645, roughness: 0.55, metalness: 0.5, flatShading: true });
  const ironDarkMat = new THREE.MeshStandardMaterial({ name: 'ironDark', color: 0x292726, roughness: 0.8, metalness: 0.3, flatShading: true });
  const coalMat = new THREE.MeshStandardMaterial({ name: 'coal', color: 0x2a1d18, roughness: 1, flatShading: true });
  const emberMat = new THREE.MeshStandardMaterial({ name: 'ember', color: 0xff6a1a, roughness: 1, emissive: 0xff4a00, emissiveIntensity: 1.2, flatShading: true });
  const redMat = new THREE.MeshStandardMaterial({ name: 'red', color: 0xe8401c, roughness: 1, emissive: 0xd42c08, emissiveIntensity: 1.1, flatShading: true });
  const orangeMat = new THREE.MeshStandardMaterial({ name: 'orange', color: 0xff7a1a, roughness: 1, emissive: 0xf05a00, emissiveIntensity: 1.25, flatShading: true });
  const yellowMat = new THREE.MeshStandardMaterial({ name: 'yellow', color: 0xffd760, roughness: 1, emissive: 0xffb830, emissiveIntensity: 1.4, flatShading: true });

  // Shared geometries
  const coneGeo = new THREE.ConeGeometry(0.022, 0.08, 4);
  const sphereGeo = new THREE.SphereGeometry(0.04, 6, 4);
  const boxGeo = new THREE.BoxGeometry(0.022, 0.5934, 0.03);

  // Parts
  const bowl = new THREE.Mesh(lathe([[0, 0], [0.12, 0], [0.22, 0.06], [0.29, 0.14], [0.32, 0.2], [0.345, 0.222], [0.335, 0.237], [0.305, 0.215], [0.27, 0.15], [0.19, 0.085], [0, 0.075]], 12), ironMat);
  bowl.name = 'bowl';
  bowl.position.set(0, 0.665, 0);
  root.add(bowl);
  const bowlBand = new THREE.Mesh(lathe([[0.287, 0.128], [0.3, 0.13], [0.312, 0.152], [0.299, 0.152]], 12), ironDarkMat);
  bowlBand.name = 'bowlBand';
  bowlBand.position.set(0, 0.665, 0);
  root.add(bowlBand);
  const rimSpike = new THREE.Mesh(coneGeo, ironMat);
  rimSpike.name = 'rimSpike';
  rimSpike.position.set(0.3095, 0.925, 0.1282);
  rimSpike.rotation.set(deg(7.2642), deg(-1.1373), deg(-17.7741));
  root.add(rimSpike);
  const rimSpike2 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike2.name = 'rimSpike';
  rimSpike2.position.set(0.1282, 0.925, 0.3095);
  rimSpike2.rotation.set(deg(17.7741), deg(-1.1373), deg(-7.2642));
  root.add(rimSpike2);
  const rimSpike3 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike3.name = 'rimSpike';
  rimSpike3.position.set(-0.1282, 0.925, 0.3095);
  rimSpike3.rotation.set(deg(17.7741), deg(1.1373), deg(7.2642));
  root.add(rimSpike3);
  const rimSpike4 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike4.name = 'rimSpike';
  rimSpike4.position.set(-0.3095, 0.925, 0.1282);
  rimSpike4.rotation.set(deg(7.2642), deg(1.1373), deg(17.7741));
  root.add(rimSpike4);
  const rimSpike5 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike5.name = 'rimSpike';
  rimSpike5.position.set(-0.3095, 0.925, -0.1282);
  rimSpike5.rotation.set(deg(-7.2642), deg(-1.1373), deg(17.7741));
  root.add(rimSpike5);
  const rimSpike6 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike6.name = 'rimSpike';
  rimSpike6.position.set(-0.1282, 0.925, -0.3095);
  rimSpike6.rotation.set(deg(-17.7741), deg(-1.1373), deg(7.2642));
  root.add(rimSpike6);
  const rimSpike7 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike7.name = 'rimSpike';
  rimSpike7.position.set(0.1282, 0.925, -0.3095);
  rimSpike7.rotation.set(deg(-17.7741), deg(1.1373), deg(-7.2642));
  root.add(rimSpike7);
  const rimSpike8 = new THREE.Mesh(coneGeo, ironMat);
  rimSpike8.name = 'rimSpike';
  rimSpike8.position.set(0.3095, 0.925, -0.1282);
  rimSpike8.rotation.set(deg(-7.2642), deg(1.1373), deg(-17.7741));
  root.add(rimSpike8);
  const leg = new THREE.Mesh(tube([[0, 0.03, 0.37], [0, 0.2328, 0.35], [0, 0.4788, 0.28], [0, 0.725, 0.2]], 0.022, 10, 5), ironMat);
  leg.name = 'leg';
  root.add(leg);
  const foot = new THREE.Mesh(sphereGeo, ironMat);
  foot.name = 'foot';
  foot.position.set(0, 0.026, 0.38);
  foot.scale.set(1.25, 0.65, 1.25);
  root.add(foot);
  const leg2 = new THREE.Mesh(tube([[-0.3204, 0.03, -0.185], [-0.3031, 0.2328, -0.175], [-0.2425, 0.4788, -0.14], [-0.1732, 0.725, -0.1]], 0.022, 10, 5), ironMat);
  leg2.name = 'leg';
  root.add(leg2);
  const foot2 = new THREE.Mesh(sphereGeo, ironMat);
  foot2.name = 'foot';
  foot2.position.set(-0.3291, 0.026, -0.19);
  foot2.scale.set(1.25, 0.65, 1.25);
  root.add(foot2);
  const leg3 = new THREE.Mesh(tube([[0.3204, 0.03, -0.185], [0.3031, 0.2328, -0.175], [0.2425, 0.4788, -0.14], [0.1732, 0.725, -0.1]], 0.022, 10, 5), ironMat);
  leg3.name = 'leg';
  root.add(leg3);
  const foot3 = new THREE.Mesh(sphereGeo, ironMat);
  foot3.name = 'foot';
  foot3.position.set(0.3291, 0.026, -0.19);
  foot3.scale.set(1.25, 0.65, 1.25);
  root.add(foot3);
  const brace = new THREE.Mesh(boxGeo, ironDarkMat);
  brace.name = 'brace';
  brace.position.set(-0.1434, 0.2993, 0.0828);
  brace.rotation.set(deg(-90), 0, deg(30));
  root.add(brace);
  const brace2 = new THREE.Mesh(boxGeo, ironDarkMat);
  brace2.name = 'brace';
  brace2.position.set(0, 0.2993, -0.1655);
  brace2.rotation.set(deg(-90), 0, deg(-90));
  root.add(brace2);
  const brace3 = new THREE.Mesh(boxGeo, ironDarkMat);
  brace3.name = 'brace';
  brace3.position.set(0.1434, 0.2993, 0.0828);
  brace3.rotation.set(deg(-90), 0, deg(150));
  root.add(brace3);
  const coalBed = new THREE.Mesh(jitter(new THREE.SphereGeometry(0.27, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), 0.012, 4), coalMat);
  coalBed.name = 'coalBed';
  coalBed.position.set(0, 0.815, 0);
  coalBed.scale.set(1, 0.36, 1);
  root.add(coalBed);
  const coal = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0406, 0), 0.0061, 0), coalMat);
  coal.name = 'coal';
  coal.position.set(0.1465, 0.9064, 0.0156);
  coal.rotation.set(deg(14.8925), deg(7.9007), 0);
  root.add(coal);
  const ember = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0409, 0), 0.0061, 1), emberMat);
  ember.name = 'ember';
  ember.position.set(0.1278, 0.9046, 0.0884);
  ember.rotation.set(deg(23.1084), deg(61.5041), 0);
  root.add(ember);
  const ember2 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0347, 0), 0.0052, 2), emberMat);
  ember2.name = 'ember';
  ember2.position.set(0.0748, 0.9025, 0.1385);
  ember2.rotation.set(deg(17.8695), deg(56.7548), 0);
  root.add(ember2);
  const coal2 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0397, 0), 0.006, 3), coalMat);
  coal2.name = 'coal';
  coal2.position.set(0.0127, 0.904, 0.1559);
  coal2.rotation.set(deg(62.2034), deg(60.2945), 0);
  root.add(coal2);
  const ember3 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0413, 0), 0.0062, 4), emberMat);
  ember3.name = 'ember';
  ember3.position.set(-0.0472, 0.8961, 0.1787);
  ember3.rotation.set(deg(36.5282), deg(5.7446), 0);
  root.add(ember3);
  const ember4 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0364, 0), 0.0055, 5), emberMat);
  ember4.name = 'ember';
  ember4.position.set(-0.0836, 0.8856, 0.1914);
  ember4.rotation.set(deg(38.1989), deg(57.1465), 0);
  root.add(ember4);
  const coal3 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0346, 0), 0.0052, 6), coalMat);
  coal3.name = 'coal';
  coal3.position.set(-0.1243, 0.9078, 0.0505);
  coal3.rotation.set(deg(72.2731), deg(9.4593), 0);
  root.add(coal3);
  const ember5 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0322, 0), 0.0048, 7), emberMat);
  ember5.name = 'ember';
  ember5.position.set(-0.1529, 0.9015, -0.043);
  ember5.rotation.set(deg(64.6398), deg(17.726), 0);
  root.add(ember5);
  const ember6 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0317, 0), 0.0048, 8), emberMat);
  ember6.name = 'ember';
  ember6.position.set(-0.1812, 0.8899, -0.0731);
  ember6.rotation.set(deg(68.7352), deg(22.308), 0);
  root.add(ember6);
  const coal4 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0371, 0), 0.0056, 9), coalMat);
  coal4.name = 'coal';
  coal4.position.set(-0.0485, 0.9138, -0.0918);
  coal4.rotation.set(deg(16.7985), deg(20.3714), 0);
  root.add(coal4);
  const ember7 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.044, 0), 0.0066, 10), emberMat);
  ember7.name = 'ember';
  ember7.position.set(-0.0032, 0.9192, -0.0748);
  ember7.rotation.set(deg(11.2841), deg(42.8681), 0);
  root.add(ember7);
  const ember8 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0467, 0), 0.007, 11), emberMat);
  ember8.name = 'ember';
  ember8.position.set(0.0354, 0.9197, -0.0684);
  ember8.rotation.set(deg(7.4681), deg(69.8295), 0);
  root.add(ember8);
  const coal5 = new THREE.Mesh(jitter(new THREE.OctahedronGeometry(0.0315, 0), 0.0047, 12), coalMat);
  coal5.name = 'coal';
  coal5.position.set(0.0418, 0.9181, -0.0303);
  coal5.rotation.set(deg(61.2706), deg(12.8874), 0);
  root.add(coal5);
  const ember9 = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.0432, 0), 0.0065, 13), emberMat);
  ember9.name = 'ember';
  ember9.position.set(0.0777, 0.9172, -0.0467);
  ember9.rotation.set(deg(49.8613), deg(60.0203), 0);
  root.add(ember9);
  const flames = new THREE.Group();
  flames.name = 'flames';
  flames.position.set(0, 0.865, 0);
  root.add(flames);
  const flameMain = new THREE.Mesh(jitter(new THREE.ConeGeometry(0.13, 0.5, 6), 0.014, 3), orangeMat);
  flameMain.name = 'flameMain';
  flameMain.position.set(0, 0.25, -0.01);
  flameMain.rotation.set(0, deg(15), deg(3));
  flames.add(flameMain);
  const flameBackL = new THREE.Mesh(jitter(new THREE.ConeGeometry(0.1, 0.4, 6), 0.01, 4), redMat);
  flameBackL.name = 'flameBackL';
  flameBackL.position.set(-0.09, 0.2, -0.07);
  flameBackL.rotation.set(deg(-8), 0, deg(14));
  flames.add(flameBackL);
  const flameBackR = new THREE.Mesh(jitter(new THREE.ConeGeometry(0.09, 0.34, 6), 0.01, 5), redMat);
  flameBackR.name = 'flameBackR';
  flameBackR.position.set(0.1, 0.17, -0.05);
  flameBackR.rotation.set(deg(-6), 0, deg(-16));
  flames.add(flameBackR);
  const flameSideL = new THREE.Mesh(jitter(new THREE.ConeGeometry(0.08, 0.28, 6), 0.008, 7), orangeMat);
  flameSideL.name = 'flameSideL';
  flameSideL.position.set(-0.13, 0.14, 0.05);
  flameSideL.rotation.set(deg(10), 0, deg(22));
  flames.add(flameSideL);
  const flameSideR = new THREE.Mesh(new THREE.ConeGeometry(0.075, 0.25, 6), redMat);
  flameSideR.name = 'flameSideR';
  flameSideR.position.set(0.13, 0.125, 0.04);
  flameSideR.rotation.set(deg(8), 0, deg(-24));
  flames.add(flameSideR);
  const flameFront = new THREE.Mesh(jitter(new THREE.ConeGeometry(0.085, 0.3, 6), 0.008, 6), yellowMat);
  flameFront.name = 'flameFront';
  flameFront.position.set(0.01, 0.15, 0.09);
  flameFront.rotation.set(deg(14), 0, deg(-4));
  flames.add(flameFront);
  const flameFrontR = new THREE.Mesh(new THREE.ConeGeometry(0.05, 0.17, 5), yellowMat);
  flameFrontR.name = 'flameFrontR';
  flameFrontR.position.set(0.09, 0.085, 0.1);
  flameFrontR.rotation.set(deg(18), 0, deg(-20));
  flames.add(flameFrontR);
  const flameFrontL = new THREE.Mesh(new THREE.ConeGeometry(0.045, 0.15, 5), orangeMat);
  flameFrontL.name = 'flameFrontL';
  flameFrontL.position.set(-0.08, 0.075, 0.11);
  flameFrontL.rotation.set(deg(20), 0, deg(18));
  flames.add(flameFrontL);
  const spark = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0129, 0), orangeMat);
  spark.name = 'spark';
  spark.position.set(0.0775, 0.5071, -0.1058);
  spark.rotation.set(deg(59.3976), deg(46.2127), 0);
  flames.add(spark);
  const spark2 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0118, 0), yellowMat);
  spark2.name = 'spark';
  spark2.position.set(-0.1475, 0.6091, -0.1076);
  spark2.rotation.set(deg(49.6722), deg(10.2049), 0);
  flames.add(spark2);
  const spark3 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0099, 0), orangeMat);
  spark3.name = 'spark';
  spark3.position.set(-0.0062, 0.5313, -0.0856);
  spark3.rotation.set(deg(42.6723), deg(71.0909), 0);
  flames.add(spark3);
  const spark4 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0081, 0), yellowMat);
  spark4.name = 'spark';
  spark4.position.set(0.0858, 0.6057, -0.0217);
  spark4.rotation.set(deg(81.4709), deg(27.8737), 0);
  flames.add(spark4);
  const spark5 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0097, 0), orangeMat);
  spark5.name = 'spark';
  spark5.position.set(0.0178, 0.4829, -0.092);
  spark5.rotation.set(deg(54.2315), deg(71.3583), 0);
  flames.add(spark5);

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

export default createBrazier;
```

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