# Knight

> A chunky, chibi-proportioned armored knight with a great helm and T-visor, plume, shoulder pauldrons, a heraldic tabard, a heater shield on the left arm and a sword raised in the right hand. Recolor the armor and team colors for rival factions. Head, arms (with elbow pivots) and legs are separate groups for walk and attack animations in RPGs and medieval games.

![Knight preview](https://codels.download/m/knight.png)

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

## Facts

- Category: Characters › Humanoids
- Size (W × H × D): 1.12 × 1.94 × 1.02 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 648 · Meshes: 48 · Materials: 7
- License: CC0-1.0 (Codels built-in)
- Tags: armor, helmet, knight, shield, sword, warrior, blocky, cartoon, low-poly, fantasy, medieval, castle, adventure, rpg, character, enemy, npc, game-ready, mobile-friendly, parametric, color-blue, multicolor, size-medium, poly-low
- Page: https://codels.download/models/knight

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `armor` | color | #rrggbb | #b9c2cc | #b9c2cc |
| `team` | color | #rrggbb | #2f5fb3 | #2f5fb3 |
| `trim` | color | #rrggbb | #e8b53f | #e8b53f |
| `plume` | boolean | true \| false | true | true |
| `shield` | boolean | true \| false | true | true |

## Parts

- legL (group)
  - thighL (box · armorDark)
  - kneeCapL (box · armor)
  - greaveL (box · armor)
  - bootL (box · leather)
- legR (group)
  - thighR (box · armorDark)
  - kneeCapR (box · armor)
  - greaveR (box · armor)
  - bootR (box · leather)
- body (group)
  - breastplate (box · armor)
  - tabardFront (box · team)
  - tabardBack (box · team)
  - crestV (box · trim)
  - crestH (box · trim)
  - belt (box · leather)
  - buckle (box · trim)
  - tassets (box · armorDark)
  - tabardSkirt (box · team)
  - gorget (box · armorDark)
- armL (group)
  - pauldronL (box · armor)
  - pauldronTrimL (box · trim)
  - upperArmL (box · armorDark)
  - forearmL (group)
    - vambraceL (box · armor)
    - gauntletL (box · leather)
    - shield (group)
      - shieldRim (extrude · armor)
      - shieldFace (extrude · team)
      - shieldCrossV (box · trim)
      - shieldCrossH (box · trim)
- armR (group)
  - pauldronR (box · armor)
  - pauldronTrimR (box · trim)
  - upperArmR (box · armorDark)
  - forearmR (group)
    - vambraceR (box · armor)
    - gauntletR (box · leather)

## How to use

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

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

## Code

```js
/**
 * Knight — Codels 3D model library (https://codels.download/models/knight)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 648 · Size (W × H × D): 1.12 × 1.94 × 1.02 m
 *
 * Usage:
 *   import { createKnight } from './knight.js';
 *   
 *   const model = createKnight();
 *   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 createKnight() {
  const root = new THREE.Group();
  root.name = 'Knight';

  // Materials
  const armorMat = new THREE.MeshStandardMaterial({ name: 'armor', color: 0xb9c2cc, roughness: 0.35, metalness: 0.6, flatShading: true });
  const armorDarkMat = new THREE.MeshStandardMaterial({ name: 'armorDark', color: 0x73787e, roughness: 0.45, metalness: 0.55, flatShading: true });
  const teamMat = new THREE.MeshStandardMaterial({ name: 'team', color: 0x2f5fb3, roughness: 0.85, flatShading: true });
  const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0xe8b53f, roughness: 0.35, metalness: 0.6, flatShading: true });
  const leatherMat = new THREE.MeshStandardMaterial({ name: 'leather', color: 0x5b3b29, roughness: 0.8, flatShading: true });
  const slitMat = new THREE.MeshStandardMaterial({ name: 'slit', color: 0x15131a, roughness: 0.9, flatShading: true });
  const bladeMat = new THREE.MeshStandardMaterial({ name: 'blade', color: 0xe3e8ee, roughness: 0.2, metalness: 0.8, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.19, 0.26, 0.2);
  const boxGeo2 = new THREE.BoxGeometry(0.15, 0.08, 0.06);
  const boxGeo3 = new THREE.BoxGeometry(0.2, 0.26, 0.21);
  const boxGeo4 = new THREE.BoxGeometry(0.22, 0.09, 0.29);
  const boxGeo5 = new THREE.BoxGeometry(0.34, 0.5, 0.02);
  const boxGeo6 = new THREE.BoxGeometry(0.22, 0.12, 0.28);
  const boxGeo7 = new THREE.BoxGeometry(0.23, 0.035, 0.29);
  const boxGeo8 = new THREE.BoxGeometry(0.15, 0.22, 0.17);
  const boxGeo9 = new THREE.BoxGeometry(0.16, 0.2, 0.18);
  const boxGeo10 = new THREE.BoxGeometry(0.15, 0.1, 0.15);
  const boxGeo11 = new THREE.BoxGeometry(0.03, 0.03, 0.02);

  // Parts
  const legL = new THREE.Group();
  legL.name = 'legL';
  legL.position.set(0.12, 0.6, 0);
  root.add(legL);
  const thighL = new THREE.Mesh(boxGeo, armorDarkMat);
  thighL.name = 'thighL';
  thighL.position.set(0, -0.13, 0);
  legL.add(thighL);
  const kneeCapL = new THREE.Mesh(boxGeo2, armorMat);
  kneeCapL.name = 'kneeCapL';
  kneeCapL.position.set(0, -0.29, 0.09);
  legL.add(kneeCapL);
  const greaveL = new THREE.Mesh(boxGeo3, armorMat);
  greaveL.name = 'greaveL';
  greaveL.position.set(0, -0.4, 0);
  legL.add(greaveL);
  const bootL = new THREE.Mesh(boxGeo4, leatherMat);
  bootL.name = 'bootL';
  bootL.position.set(0, -0.555, 0.03);
  legL.add(bootL);
  const legR = new THREE.Group();
  legR.name = 'legR';
  legR.position.set(-0.12, 0.6, 0);
  root.add(legR);
  const thighR = new THREE.Mesh(boxGeo, armorDarkMat);
  thighR.name = 'thighR';
  thighR.position.set(0, -0.13, 0);
  legR.add(thighR);
  const kneeCapR = new THREE.Mesh(boxGeo2, armorMat);
  kneeCapR.name = 'kneeCapR';
  kneeCapR.position.set(0, -0.29, 0.09);
  legR.add(kneeCapR);
  const greaveR = new THREE.Mesh(boxGeo3, armorMat);
  greaveR.name = 'greaveR';
  greaveR.position.set(0, -0.4, 0);
  legR.add(greaveR);
  const bootR = new THREE.Mesh(boxGeo4, leatherMat);
  bootR.name = 'bootR';
  bootR.position.set(0, -0.555, 0.03);
  legR.add(bootR);
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const breastplate = new THREE.Mesh(new THREE.BoxGeometry(0.52, 0.56, 0.32), armorMat);
  breastplate.name = 'breastplate';
  breastplate.position.set(0, 0.88, 0);
  body.add(breastplate);
  const tabardFront = new THREE.Mesh(boxGeo5, teamMat);
  tabardFront.name = 'tabardFront';
  tabardFront.position.set(0, 0.83, 0.163);
  body.add(tabardFront);
  const tabardBack = new THREE.Mesh(boxGeo5, teamMat);
  tabardBack.name = 'tabardBack';
  tabardBack.position.set(0, 0.83, -0.163);
  body.add(tabardBack);
  const crestV = new THREE.Mesh(new THREE.BoxGeometry(0.06, 0.24, 0.01), trimMat);
  crestV.name = 'crestV';
  crestV.position.set(0, 0.91, 0.172);
  body.add(crestV);
  const crestH = new THREE.Mesh(new THREE.BoxGeometry(0.18, 0.06, 0.01), trimMat);
  crestH.name = 'crestH';
  crestH.position.set(0, 0.95, 0.172);
  body.add(crestH);
  const belt = new THREE.Mesh(new THREE.BoxGeometry(0.55, 0.07, 0.35), leatherMat);
  belt.name = 'belt';
  belt.position.set(0, 0.65, 0);
  body.add(belt);
  const buckle = new THREE.Mesh(new THREE.BoxGeometry(0.08, 0.07, 0.02), trimMat);
  buckle.name = 'buckle';
  buckle.position.set(0, 0.65, 0.18);
  body.add(buckle);
  const tassets = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.14, 0.3), armorDarkMat);
  tassets.name = 'tassets';
  tassets.position.set(0, 0.56, 0);
  body.add(tassets);
  const tabardSkirt = new THREE.Mesh(new THREE.BoxGeometry(0.28, 0.2, 0.02), teamMat);
  tabardSkirt.name = 'tabardSkirt';
  tabardSkirt.position.set(0, 0.54, 0.166);
  body.add(tabardSkirt);
  const gorget = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.07, 0.24), armorDarkMat);
  gorget.name = 'gorget';
  gorget.position.set(0, 1.18, 0);
  body.add(gorget);
  const armL = new THREE.Group();
  armL.name = 'armL';
  armL.position.set(0.34, 1.08, 0);
  armL.rotation.set(deg(4), 0, deg(6));
  root.add(armL);
  const pauldronL = new THREE.Mesh(boxGeo6, armorMat);
  pauldronL.name = 'pauldronL';
  pauldronL.position.set(0.03, 0.03, 0);
  armL.add(pauldronL);
  const pauldronTrimL = new THREE.Mesh(boxGeo7, trimMat);
  pauldronTrimL.name = 'pauldronTrimL';
  pauldronTrimL.position.set(0.03, -0.04, 0);
  armL.add(pauldronTrimL);
  const upperArmL = new THREE.Mesh(boxGeo8, armorDarkMat);
  upperArmL.name = 'upperArmL';
  upperArmL.position.set(0, -0.15, 0);
  armL.add(upperArmL);
  const forearmL = new THREE.Group();
  forearmL.name = 'forearmL';
  forearmL.position.set(0, -0.26, 0);
  forearmL.rotation.set(deg(-50), 0, 0);
  armL.add(forearmL);
  const vambraceL = new THREE.Mesh(boxGeo9, armorMat);
  vambraceL.name = 'vambraceL';
  vambraceL.position.set(0, -0.1, 0);
  forearmL.add(vambraceL);
  const gauntletL = new THREE.Mesh(boxGeo10, leatherMat);
  gauntletL.name = 'gauntletL';
  gauntletL.position.set(0, -0.24, 0);
  forearmL.add(gauntletL);
  const shield = new THREE.Group();
  shield.name = 'shield';
  shield.position.set(0.13, -0.12, 0.02);
  shield.rotation.set(deg(50), deg(70), 0);
  forearmL.add(shield);
  const shieldRim = new THREE.Mesh(extrude([[-0.21, 0.24], [0.21, 0.24], [0.21, 0.02], [0.16, -0.14], [0.08, -0.25], [0, -0.3], [-0.08, -0.25], [-0.16, -0.14], [-0.21, 0.02]], 0.05), armorMat);
  shieldRim.name = 'shieldRim';
  shield.add(shieldRim);
  const shieldFace = new THREE.Mesh(extrude([[-0.1806, 0.2162], [0.1806, 0.2162], [0.1806, 0.0226], [0.1376, -0.1182], [0.0688, -0.215], [0, -0.259], [-0.0688, -0.215], [-0.1376, -0.1182], [-0.1806, 0.0226]], 0.02), teamMat);
  shieldFace.name = 'shieldFace';
  shieldFace.position.set(0, 0, 0.029);
  shield.add(shieldFace);
  const shieldCrossV = new THREE.Mesh(new THREE.BoxGeometry(0.07, 0.38, 0.012), trimMat);
  shieldCrossV.name = 'shieldCrossV';
  shieldCrossV.position.set(0, -0.03, 0.04);
  shield.add(shieldCrossV);
  const shieldCrossH = new THREE.Mesh(new THREE.BoxGeometry(0.28, 0.07, 0.012), trimMat);
  shieldCrossH.name = 'shieldCrossH';
  shieldCrossH.position.set(0, 0.07, 0.04);
  shield.add(shieldCrossH);
  const armR = new THREE.Group();
  armR.name = 'armR';
  armR.position.set(-0.34, 1.08, 0);
  armR.rotation.set(deg(8), 0, deg(-6));
  root.add(armR);
  const pauldronR = new THREE.Mesh(boxGeo6, armorMat);
  pauldronR.name = 'pauldronR';
  pauldronR.position.set(-0.03, 0.03, 0);
  armR.add(pauldronR);
  const pauldronTrimR = new THREE.Mesh(boxGeo7, trimMat);
  pauldronTrimR.name = 'pauldronTrimR';
  pauldronTrimR.position.set(-0.03, -0.04, 0);
  armR.add(pauldronTrimR);
  const upperArmR = new THREE.Mesh(boxGeo8, armorDarkMat);
  upperArmR.name = 'upperArmR';
  upperArmR.position.set(0, -0.15, 0);
  armR.add(upperArmR);
  const forearmR = new THREE.Group();
  forearmR.name = 'forearmR';
  forearmR.position.set(0, -0.26, 0);
  forearmR.rotation.set(deg(-75), 0, 0);
  armR.add(forearmR);
  const vambraceR = new THREE.Mesh(boxGeo9, armorMat);
  vambraceR.name = 'vambraceR';
  vambraceR.position.set(0, -0.1, 0);
  forearmR.add(vambraceR);
  const gauntletR = new THREE.Mesh(boxGeo10, leatherMat);
  gauntletR.name = 'gauntletR';
  gauntletR.position.set(0, -0.24, 0);
  forearmR.add(gauntletR);
  const sword = new THREE.Group();
  sword.name = 'sword';
  sword.position.set(0, -0.24, 0);
  sword.rotation.set(deg(100), 0, 0);
  forearmR.add(sword);
  const grip = new THREE.Mesh(new THREE.BoxGeometry(0.045, 0.16, 0.045), leatherMat);
  grip.name = 'grip';
  sword.add(grip);
  const pommel = new THREE.Mesh(new THREE.BoxGeometry(0.07, 0.06, 0.07), trimMat);
  pommel.name = 'pommel';
  pommel.position.set(0, -0.11, 0);
  sword.add(pommel);
  const crossguard = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.05, 0.07), trimMat);
  crossguard.name = 'crossguard';
  crossguard.position.set(0, 0.1, 0);
  sword.add(crossguard);
  const blade = new THREE.Mesh(extrude([[-0.045, 0], [0.045, 0], [0.04, 0.62], [0, 0.72], [-0.04, 0.62]], 0.022), bladeMat);
  blade.name = 'blade';
  blade.position.set(0, 0.125, 0);
  sword.add(blade);
  const fuller = new THREE.Mesh(new THREE.BoxGeometry(0.014, 0.52, 0.028), armorDarkMat);
  fuller.name = 'fuller';
  fuller.position.set(0, 0.42, 0);
  sword.add(fuller);
  const head = new THREE.Group();
  head.name = 'head';
  head.position.set(0, 1.18, 0);
  root.add(head);
  const helm = new THREE.Mesh(new THREE.BoxGeometry(0.48, 0.5, 0.46), armorMat);
  helm.name = 'helm';
  helm.position.set(0, 0.29, 0);
  head.add(helm);
  const helmBand = new THREE.Mesh(new THREE.BoxGeometry(0.492, 0.05, 0.472), trimMat);
  helmBand.name = 'helmBand';
  helmBand.position.set(0, 0.19, 0);
  head.add(helmBand);
  const visorSlit = new THREE.Mesh(new THREE.BoxGeometry(0.36, 0.06, 0.02), slitMat);
  visorSlit.name = 'visorSlit';
  visorSlit.position.set(0, 0.33, 0.232);
  head.add(visorSlit);
  const visorNoseSlit = new THREE.Mesh(new THREE.BoxGeometry(0.07, 0.2, 0.02), slitMat);
  visorNoseSlit.name = 'visorNoseSlit';
  visorNoseSlit.position.set(0, 0.23, 0.232);
  head.add(visorNoseSlit);
  const helmRidge = new THREE.Mesh(new THREE.BoxGeometry(0.03, 0.12, 0.03), armorDarkMat);
  helmRidge.name = 'helmRidge';
  helmRidge.position.set(0, 0.46, 0.236);
  head.add(helmRidge);
  const breath = new THREE.Mesh(boxGeo11, slitMat);
  breath.name = 'breath';
  breath.position.set(0.12, 0.16, 0.232);
  head.add(breath);
  const breath2 = new THREE.Mesh(boxGeo11, slitMat);
  breath2.name = 'breath';
  breath2.position.set(0.17, 0.16, 0.232);
  head.add(breath2);
  const breath3 = new THREE.Mesh(boxGeo11, slitMat);
  breath3.name = 'breath';
  breath3.position.set(-0.12, 0.16, 0.232);
  head.add(breath3);
  const breath4 = new THREE.Mesh(boxGeo11, slitMat);
  breath4.name = 'breath';
  breath4.position.set(-0.17, 0.16, 0.232);
  head.add(breath4);
  const plume = new THREE.Group();
  plume.name = 'plume';
  plume.position.set(0, 0.54, -0.02);
  head.add(plume);
  const plumeHolder = new THREE.Mesh(new THREE.BoxGeometry(0.08, 0.06, 0.08), trimMat);
  plumeHolder.name = 'plumeHolder';
  plumeHolder.position.set(0, 0.03, 0);
  plume.add(plumeHolder);
  const plumeCrest = new THREE.Mesh(extrude([[-0.19, -0.02], [-0.17, 0.07], [-0.1, 0.14], [0, 0.17], [0.1, 0.16], [0.19, 0.1], [0.25, 0], [0.27, -0.12], [0.235, -0.2], [0.21, -0.1], [0.19, -0.02]], 0.075), teamMat);
  plumeCrest.name = 'plumeCrest';
  plumeCrest.rotation.set(0, deg(90), 0);
  plumeCrest.scale.set(1.3, 1.3, 1);
  plume.add(plumeCrest);

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

export default createKnight;
```

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