# Wall Banner

> A heraldic cloth banner hanging from a wooden rod on two iron wall brackets, with a contrasting border, a bold emblem (crown, cross, eight-pointed star or chevron with roundels) and gold tassels on a pointed, swallowtail or fringed square hem. Recolor the field and trim for rival houses and factions. The brackets touch the wall plane at the top so it hangs straight down — ideal for throne rooms, castle halls, taverns and guild houses.

![Wall Banner preview](https://codels.download/m/wall-banner.png)

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

## Facts

- Category: Props › Decor
- Size (W × H × D): 0.97 × 1.79 × 0.10 m — units are meters, +Y up, front faces +Z
- Origin: wall mount point (back of the model on the wall plane z = 0)
- Triangles: 720 · Meshes: 25 · Materials: 6
- License: CC0-1.0 (Codels built-in)
- Tags: flag, heraldry, tapestry, tavern, wall-decor, low-poly, stylized, fantasy, medieval, castle, interior, rpg, strategy, decoration, prop, fabric, metal, wood, flat, symmetric, tall, mobile-friendly, parametric, color-red, size-medium, poly-low
- Page: https://codels.download/models/wall-banner

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `field` | color | #rrggbb | #8e1f27 | #8e1f27 |
| `trim` | color | #rrggbb | #e2b64c | #e2b64c |
| `emblem` | select | crown \| cross \| star \| chevron | crown | crown |
| `shape` | select | point \| swallowtail \| square | point | point |
| `length` | number | 1 – 2.4 | 1.6 | 1.6 |

## Parts

- wallPlate (box · iron)
- rivet (cylinder · iron)
- rivet (cylinder · iron)
- bracketArm (box · iron)
- bracketRing (torus · iron)
- finialBall (sphere · gold)
- finialTip (cone · gold)
- wallPlate (box · iron)
- rivet (cylinder · iron)
- rivet (cylinder · iron)
- bracketArm (box · iron)
- bracketRing (torus · iron)
- finialBall (sphere · gold)
- finialTip (cone · gold)
- rod (cylinder · wood)
- sleeve (cylinder · sleeve)
- banner (extrude · field)
- border (extrude · trim)
- crown (extrude · trim)
- crownBand (box · sleeve)
- crownPearl (sphere · trim)
- crownPearl (sphere · trim)
- crownPearl (sphere · trim)
- tasselKnot (sphere · gold)
- tassel (cone · gold)

## How to use

Save the code below as `wall-banner.js`, then:

```js
import { createWallBanner } from './wall-banner.js';
const model = createWallBanner();
scene.add(model);
```

## Code

```js
/**
 * Wall Banner — Codels 3D model library (https://codels.download/models/wall-banner)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: wall mount point (back of the model on the wall plane z = 0)
 * Triangles: 720 · Size (W × H × D): 0.97 × 1.79 × 0.10 m
 *
 * Usage:
 *   import { createWallBanner } from './wall-banner.js';
 *   
 *   const model = createWallBanner();
 *   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 createWallBanner() {
  const root = new THREE.Group();
  root.name = 'WallBanner';

  // Materials
  const fieldMat = new THREE.MeshStandardMaterial({ name: 'field', color: 0x8e1f27, roughness: 0.95, flatShading: true });
  const sleeveMat = new THREE.MeshStandardMaterial({ name: 'sleeve', color: 0x6b171d, roughness: 0.95, flatShading: true });
  const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0xe2b64c, roughness: 0.75, flatShading: true });
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x5e3b22, roughness: 0.85, flatShading: true });
  const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x3d3f45, roughness: 0.5, metalness: 0.55, flatShading: true });
  const goldMat = new THREE.MeshStandardMaterial({ name: 'gold', color: 0xc99b3c, roughness: 0.35, metalness: 0.7, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.05, 0.12, 0.012);
  const cylinderGeo = new THREE.CylinderGeometry(0.007, 0.007, 0.006, 6);
  const boxGeo2 = new THREE.BoxGeometry(0.018, 0.018, 0.063);
  const torusGeo = new THREE.TorusGeometry(0.021, 0.006, 4, 8);
  const sphereGeo = new THREE.SphereGeometry(0.026, 7, 5);
  const coneGeo = new THREE.ConeGeometry(0.016, 0.05, 6);
  const sphereGeo2 = new THREE.SphereGeometry(0.0192, 6, 4);

  // Parts
  const wallPlate = new THREE.Mesh(boxGeo, ironMat);
  wallPlate.name = 'wallPlate';
  wallPlate.position.set(0.35, 0.02, 0.006);
  root.add(wallPlate);
  const rivet = new THREE.Mesh(cylinderGeo, ironMat);
  rivet.name = 'rivet';
  rivet.position.set(0.35, 0.06, 0.014);
  rivet.rotation.set(deg(90), 0, 0);
  root.add(rivet);
  const rivet2 = new THREE.Mesh(cylinderGeo, ironMat);
  rivet2.name = 'rivet';
  rivet2.position.set(0.35, -0.02, 0.014);
  rivet2.rotation.set(deg(90), 0, 0);
  root.add(rivet2);
  const bracketArm = new THREE.Mesh(boxGeo2, ironMat);
  bracketArm.name = 'bracketArm';
  bracketArm.position.set(0.35, 0, 0.0435);
  root.add(bracketArm);
  const bracketRing = new THREE.Mesh(torusGeo, ironMat);
  bracketRing.name = 'bracketRing';
  bracketRing.position.set(0.35, 0, 0.075);
  bracketRing.rotation.set(0, deg(90), 0);
  root.add(bracketRing);
  const finialBall = new THREE.Mesh(sphereGeo, goldMat);
  finialBall.name = 'finialBall';
  finialBall.position.set(0.415, 0, 0.075);
  root.add(finialBall);
  const finialTip = new THREE.Mesh(coneGeo, goldMat);
  finialTip.name = 'finialTip';
  finialTip.position.set(0.46, 0, 0.075);
  finialTip.rotation.set(0, 0, deg(-90));
  root.add(finialTip);
  const wallPlate2 = new THREE.Mesh(boxGeo, ironMat);
  wallPlate2.name = 'wallPlate';
  wallPlate2.position.set(-0.35, 0.02, 0.006);
  root.add(wallPlate2);
  const rivet3 = new THREE.Mesh(cylinderGeo, ironMat);
  rivet3.name = 'rivet';
  rivet3.position.set(-0.35, 0.06, 0.014);
  rivet3.rotation.set(deg(90), 0, 0);
  root.add(rivet3);
  const rivet4 = new THREE.Mesh(cylinderGeo, ironMat);
  rivet4.name = 'rivet';
  rivet4.position.set(-0.35, -0.02, 0.014);
  rivet4.rotation.set(deg(90), 0, 0);
  root.add(rivet4);
  const bracketArm2 = new THREE.Mesh(boxGeo2, ironMat);
  bracketArm2.name = 'bracketArm';
  bracketArm2.position.set(-0.35, 0, 0.0435);
  root.add(bracketArm2);
  const bracketRing2 = new THREE.Mesh(torusGeo, ironMat);
  bracketRing2.name = 'bracketRing';
  bracketRing2.position.set(-0.35, 0, 0.075);
  bracketRing2.rotation.set(0, deg(90), 0);
  root.add(bracketRing2);
  const finialBall2 = new THREE.Mesh(sphereGeo, goldMat);
  finialBall2.name = 'finialBall';
  finialBall2.position.set(-0.415, 0, 0.075);
  root.add(finialBall2);
  const finialTip2 = new THREE.Mesh(coneGeo, goldMat);
  finialTip2.name = 'finialTip';
  finialTip2.position.set(-0.46, 0, 0.075);
  finialTip2.rotation.set(0, 0, deg(90));
  root.add(finialTip2);
  const rod = new THREE.Mesh(new THREE.CylinderGeometry(0.014, 0.014, 0.82, 8), woodMat);
  rod.name = 'rod';
  rod.position.set(0, 0, 0.075);
  rod.rotation.set(0, 0, deg(90));
  root.add(rod);
  const sleeve = new THREE.Mesh(new THREE.CylinderGeometry(0.026, 0.026, 0.61, 8), sleeveMat);
  sleeve.name = 'sleeve';
  sleeve.position.set(0, 0, 0.075);
  sleeve.rotation.set(0, 0, deg(90));
  root.add(sleeve);
  const banner = new THREE.Mesh(extrude([[-0.3, -0.02], [-0.3, -1.432], [0, -1.6], [0.3, -1.432], [0.3, -0.02]], 0.012), fieldMat);
  banner.name = 'banner';
  banner.position.set(0, 0, 0.075);
  root.add(banner);
  const border = new THREE.Mesh(extrude([[-0.3, -0.02], [-0.3, -1.432], [0, -1.6], [0.3, -1.432], [0.3, -0.02]], 0.004, [[[-0.265, -0.055], [-0.265, -1.4044], [0, -1.565], [0.265, -1.4044], [0.265, -0.055]]]), trimMat);
  border.name = 'border';
  border.position.set(0, 0, 0.083);
  root.add(border);
  const crown = new THREE.Mesh(extrude([[-0.126, -0.078], [0.126, -0.078], [0.15, 0.09], [0.072, 0.018], [0, 0.114], [-0.072, 0.018], [-0.15, 0.09]], 0.006), trimMat);
  crown.name = 'crown';
  crown.position.set(0, -0.5355, 0.084);
  root.add(crown);
  const crownBand = new THREE.Mesh(new THREE.BoxGeometry(0.258, 0.03, 0.004), sleeveMat);
  crownBand.name = 'crownBand';
  crownBand.position.set(0, -0.5805, 0.088);
  root.add(crownBand);
  const crownPearl = new THREE.Mesh(sphereGeo2, trimMat);
  crownPearl.name = 'crownPearl';
  crownPearl.position.set(-0.15, -0.4255, 0.085);
  root.add(crownPearl);
  const crownPearl2 = new THREE.Mesh(sphereGeo2, trimMat);
  crownPearl2.name = 'crownPearl';
  crownPearl2.position.set(0, -0.4015, 0.085);
  root.add(crownPearl2);
  const crownPearl3 = new THREE.Mesh(sphereGeo2, trimMat);
  crownPearl3.name = 'crownPearl';
  crownPearl3.position.set(0.15, -0.4255, 0.085);
  root.add(crownPearl3);
  const tasselKnot = new THREE.Mesh(new THREE.SphereGeometry(0.022, 6, 4), goldMat);
  tasselKnot.name = 'tasselKnot';
  tasselKnot.position.set(0, -1.612, 0.075);
  root.add(tasselKnot);
  const tassel = new THREE.Mesh(new THREE.ConeGeometry(0.024, 0.09, 6), goldMat);
  tassel.name = 'tassel';
  tassel.position.set(0, -1.665, 0.075);
  tassel.rotation.set(deg(180), 0, 0);
  root.add(tassel);

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

export default createWallBanner;
```

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