720 tris0.97 × 1.79 × 0.10 m
Use it in code
Remix in the editorwall-banner.js · 171 lines
Self-contained ES module — only depends on three. Call the factory and add the group to your scene.
/**
* Wall Banner — Codels 3D model library
* 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;
Ratings & comments
0 comments
No comments yet. Share how you used this model or what could be better.
Related models
Same category or similar tags









