# Spike Trap

> A floor spike trap for platformers and dungeon crawlers: a dark steel plate with a yellow-and-black hazard border and a grid of sharp metal cone spikes. Rows, columns and spike height are adjustable; each spike cell is 25 cm, so a 4 × 4 trap fills exactly one 1 m tile.

![Spike Trap preview](https://codels.download/m/spike-trap.png)

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

## Facts

- Category: Game Kit › Hazards
- Size (W × H × D): 1.12 × 0.47 × 1.12 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 792 · Meshes: 50 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: spikes, cartoon, low-poly, stylized, dungeon, adventure, party-game, platformer, roguelike, hazard, modular, obstacle, metal, game-ready, instancing-friendly, mobile-friendly, parametric, color-blue, color-gray, color-yellow, size-medium, poly-low
- Page: https://codels.download/models/spike-trap

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `rows` | int | 1 – 8 | 4 | 4 |
| `columns` | int | 1 – 8 | 4 | 4 |
| `spikeHeight` | number | 0.15 – 0.8 | 0.35 | 0.35 |

## Parts

- frame (box · hazard)
- plate (box · plate)
- hazardStripes (group)
- socket1_1 (cylinder · socket)
- spike1_1 (cone · spike)
- socket1_2 (cylinder · socket)
- spike1_2 (cone · spike)
- socket1_3 (cylinder · socket)
- spike1_3 (cone · spike)
- socket1_4 (cylinder · socket)
- spike1_4 (cone · spike)
- socket2_1 (cylinder · socket)
- spike2_1 (cone · spike)
- socket2_2 (cylinder · socket)
- spike2_2 (cone · spike)
- socket2_3 (cylinder · socket)
- spike2_3 (cone · spike)
- socket2_4 (cylinder · socket)
- spike2_4 (cone · spike)
- socket3_1 (cylinder · socket)
- spike3_1 (cone · spike)
- socket3_2 (cylinder · socket)
- spike3_2 (cone · spike)
- socket3_3 (cylinder · socket)
- spike3_3 (cone · spike)
- socket3_4 (cylinder · socket)
- spike3_4 (cone · spike)
- socket4_1 (cylinder · socket)
- spike4_1 (cone · spike)
- socket4_2 (cylinder · socket)
- spike4_2 (cone · spike)
- socket4_3 (cylinder · socket)
- spike4_3 (cone · spike)
- socket4_4 (cylinder · socket)
- spike4_4 (cone · spike)

## How to use

Save the code below as `spike-trap.js`, then:

```js
import { createSpikeTrap } from './spike-trap.js';
const model = createSpikeTrap();
scene.add(model);
```

## Code

```js
/**
 * Spike Trap — Codels 3D model library (https://codels.download/models/spike-trap)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 792 · Size (W × H × D): 1.12 × 0.47 × 1.12 m
 *
 * Usage:
 *   import { createSpikeTrap } from './spike-trap.js';
 *   
 *   const model = createSpikeTrap();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

export function createSpikeTrap() {
  const root = new THREE.Group();
  root.name = 'SpikeTrap';

  // Materials
  const plateMat = new THREE.MeshStandardMaterial({ name: 'plate', color: 0x3a3f4b, roughness: 0.7, metalness: 0.3, flatShading: true });
  const hazardMat = new THREE.MeshStandardMaterial({ name: 'hazard', color: 0xf2c12e, roughness: 0.6, flatShading: true });
  const stripeMat = new THREE.MeshStandardMaterial({ name: 'stripe', color: 0x1f2128, roughness: 0.7, flatShading: true });
  const socketMat = new THREE.MeshStandardMaterial({ name: 'socket', color: 0x262a33, roughness: 0.8, flatShading: true });
  const spikeMat = new THREE.MeshStandardMaterial({ name: 'spike', color: 0xd3d8e0, roughness: 0.3, metalness: 0.75, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.14, 0.012, 0.0588);
  const boxGeo2 = new THREE.BoxGeometry(0.0588, 0.012, 0.125);
  const cylinderGeo = new THREE.CylinderGeometry(0.0978, 0.1063, 0.03, 6);
  const coneGeo = new THREE.ConeGeometry(0.085, 0.35, 6);

  // Parts
  const frame = new THREE.Mesh(new THREE.BoxGeometry(1.12, 0.1, 1.12), hazardMat);
  frame.name = 'frame';
  frame.position.set(0, 0.05, 0);
  root.add(frame);
  const plate = new THREE.Mesh(new THREE.BoxGeometry(1, 0.02, 1), plateMat);
  plate.name = 'plate';
  plate.position.set(0, 0.105, 0);
  root.add(plate);
  const hazardStripes = new THREE.Group();
  hazardStripes.name = 'hazardStripes';
  root.add(hazardStripes);
  const box4 = new THREE.Mesh(boxGeo, stripeMat);
  box4.position.set(-0.42, 0.104, 0.53);
  hazardStripes.add(box4);
  const box5 = new THREE.Mesh(boxGeo, stripeMat);
  box5.position.set(0.42, 0.104, -0.53);
  hazardStripes.add(box5);
  const box6 = new THREE.Mesh(boxGeo, stripeMat);
  box6.position.set(-0.14, 0.104, 0.53);
  hazardStripes.add(box6);
  const box7 = new THREE.Mesh(boxGeo, stripeMat);
  box7.position.set(0.14, 0.104, -0.53);
  hazardStripes.add(box7);
  const box8 = new THREE.Mesh(boxGeo, stripeMat);
  box8.position.set(0.14, 0.104, 0.53);
  hazardStripes.add(box8);
  const box9 = new THREE.Mesh(boxGeo, stripeMat);
  box9.position.set(-0.14, 0.104, -0.53);
  hazardStripes.add(box9);
  const box10 = new THREE.Mesh(boxGeo, stripeMat);
  box10.position.set(0.42, 0.104, 0.53);
  hazardStripes.add(box10);
  const box11 = new THREE.Mesh(boxGeo, stripeMat);
  box11.position.set(-0.42, 0.104, -0.53);
  hazardStripes.add(box11);
  const box12 = new THREE.Mesh(boxGeo2, stripeMat);
  box12.position.set(0.53, 0.104, 0.375);
  hazardStripes.add(box12);
  const box13 = new THREE.Mesh(boxGeo2, stripeMat);
  box13.position.set(-0.53, 0.104, -0.375);
  hazardStripes.add(box13);
  const box14 = new THREE.Mesh(boxGeo2, stripeMat);
  box14.position.set(0.53, 0.104, 0.125);
  hazardStripes.add(box14);
  const box15 = new THREE.Mesh(boxGeo2, stripeMat);
  box15.position.set(-0.53, 0.104, -0.125);
  hazardStripes.add(box15);
  const box16 = new THREE.Mesh(boxGeo2, stripeMat);
  box16.position.set(0.53, 0.104, -0.125);
  hazardStripes.add(box16);
  const box17 = new THREE.Mesh(boxGeo2, stripeMat);
  box17.position.set(-0.53, 0.104, 0.125);
  hazardStripes.add(box17);
  const box18 = new THREE.Mesh(boxGeo2, stripeMat);
  box18.position.set(0.53, 0.104, -0.375);
  hazardStripes.add(box18);
  const box19 = new THREE.Mesh(boxGeo2, stripeMat);
  box19.position.set(-0.53, 0.104, 0.375);
  hazardStripes.add(box19);
  const socket11 = new THREE.Mesh(cylinderGeo, socketMat);
  socket11.name = 'socket1_1';
  socket11.position.set(-0.375, 0.115, -0.375);
  socket11.rotation.set(0, deg(30), 0);
  root.add(socket11);
  const spike11 = new THREE.Mesh(coneGeo, spikeMat);
  spike11.name = 'spike1_1';
  spike11.position.set(-0.375, 0.295, -0.375);
  root.add(spike11);
  const socket12 = new THREE.Mesh(cylinderGeo, socketMat);
  socket12.name = 'socket1_2';
  socket12.position.set(-0.125, 0.115, -0.375);
  socket12.rotation.set(0, deg(30), 0);
  root.add(socket12);
  const spike12 = new THREE.Mesh(coneGeo, spikeMat);
  spike12.name = 'spike1_2';
  spike12.position.set(-0.125, 0.295, -0.375);
  spike12.rotation.set(0, deg(17), 0);
  root.add(spike12);
  const socket13 = new THREE.Mesh(cylinderGeo, socketMat);
  socket13.name = 'socket1_3';
  socket13.position.set(0.125, 0.115, -0.375);
  socket13.rotation.set(0, deg(30), 0);
  root.add(socket13);
  const spike13 = new THREE.Mesh(coneGeo, spikeMat);
  spike13.name = 'spike1_3';
  spike13.position.set(0.125, 0.295, -0.375);
  spike13.rotation.set(0, deg(34), 0);
  root.add(spike13);
  const socket14 = new THREE.Mesh(cylinderGeo, socketMat);
  socket14.name = 'socket1_4';
  socket14.position.set(0.375, 0.115, -0.375);
  socket14.rotation.set(0, deg(30), 0);
  root.add(socket14);
  const spike14 = new THREE.Mesh(coneGeo, spikeMat);
  spike14.name = 'spike1_4';
  spike14.position.set(0.375, 0.295, -0.375);
  spike14.rotation.set(0, deg(51), 0);
  root.add(spike14);
  const socket21 = new THREE.Mesh(cylinderGeo, socketMat);
  socket21.name = 'socket2_1';
  socket21.position.set(-0.375, 0.115, -0.125);
  socket21.rotation.set(0, deg(30), 0);
  root.add(socket21);
  const spike21 = new THREE.Mesh(coneGeo, spikeMat);
  spike21.name = 'spike2_1';
  spike21.position.set(-0.375, 0.295, -0.125);
  spike21.rotation.set(0, deg(17), 0);
  root.add(spike21);
  const socket22 = new THREE.Mesh(cylinderGeo, socketMat);
  socket22.name = 'socket2_2';
  socket22.position.set(-0.125, 0.115, -0.125);
  socket22.rotation.set(0, deg(30), 0);
  root.add(socket22);
  const spike22 = new THREE.Mesh(coneGeo, spikeMat);
  spike22.name = 'spike2_2';
  spike22.position.set(-0.125, 0.295, -0.125);
  spike22.rotation.set(0, deg(34), 0);
  root.add(spike22);
  const socket23 = new THREE.Mesh(cylinderGeo, socketMat);
  socket23.name = 'socket2_3';
  socket23.position.set(0.125, 0.115, -0.125);
  socket23.rotation.set(0, deg(30), 0);
  root.add(socket23);
  const spike23 = new THREE.Mesh(coneGeo, spikeMat);
  spike23.name = 'spike2_3';
  spike23.position.set(0.125, 0.295, -0.125);
  spike23.rotation.set(0, deg(51), 0);
  root.add(spike23);
  const socket24 = new THREE.Mesh(cylinderGeo, socketMat);
  socket24.name = 'socket2_4';
  socket24.position.set(0.375, 0.115, -0.125);
  socket24.rotation.set(0, deg(30), 0);
  root.add(socket24);
  const spike24 = new THREE.Mesh(coneGeo, spikeMat);
  spike24.name = 'spike2_4';
  spike24.position.set(0.375, 0.295, -0.125);
  spike24.rotation.set(0, deg(68), 0);
  root.add(spike24);
  const socket31 = new THREE.Mesh(cylinderGeo, socketMat);
  socket31.name = 'socket3_1';
  socket31.position.set(-0.375, 0.115, 0.125);
  socket31.rotation.set(0, deg(30), 0);
  root.add(socket31);
  const spike31 = new THREE.Mesh(coneGeo, spikeMat);
  spike31.name = 'spike3_1';
  spike31.position.set(-0.375, 0.295, 0.125);
  spike31.rotation.set(0, deg(34), 0);
  root.add(spike31);
  const socket32 = new THREE.Mesh(cylinderGeo, socketMat);
  socket32.name = 'socket3_2';
  socket32.position.set(-0.125, 0.115, 0.125);
  socket32.rotation.set(0, deg(30), 0);
  root.add(socket32);
  const spike32 = new THREE.Mesh(coneGeo, spikeMat);
  spike32.name = 'spike3_2';
  spike32.position.set(-0.125, 0.295, 0.125);
  spike32.rotation.set(0, deg(51), 0);
  root.add(spike32);
  const socket33 = new THREE.Mesh(cylinderGeo, socketMat);
  socket33.name = 'socket3_3';
  socket33.position.set(0.125, 0.115, 0.125);
  socket33.rotation.set(0, deg(30), 0);
  root.add(socket33);
  const spike33 = new THREE.Mesh(coneGeo, spikeMat);
  spike33.name = 'spike3_3';
  spike33.position.set(0.125, 0.295, 0.125);
  spike33.rotation.set(0, deg(68), 0);
  root.add(spike33);
  const socket34 = new THREE.Mesh(cylinderGeo, socketMat);
  socket34.name = 'socket3_4';
  socket34.position.set(0.375, 0.115, 0.125);
  socket34.rotation.set(0, deg(30), 0);
  root.add(socket34);
  const spike34 = new THREE.Mesh(coneGeo, spikeMat);
  spike34.name = 'spike3_4';
  spike34.position.set(0.375, 0.295, 0.125);
  spike34.rotation.set(0, deg(85), 0);
  root.add(spike34);
  const socket41 = new THREE.Mesh(cylinderGeo, socketMat);
  socket41.name = 'socket4_1';
  socket41.position.set(-0.375, 0.115, 0.375);
  socket41.rotation.set(0, deg(30), 0);
  root.add(socket41);
  const spike41 = new THREE.Mesh(coneGeo, spikeMat);
  spike41.name = 'spike4_1';
  spike41.position.set(-0.375, 0.295, 0.375);
  spike41.rotation.set(0, deg(51), 0);
  root.add(spike41);
  const socket42 = new THREE.Mesh(cylinderGeo, socketMat);
  socket42.name = 'socket4_2';
  socket42.position.set(-0.125, 0.115, 0.375);
  socket42.rotation.set(0, deg(30), 0);
  root.add(socket42);
  const spike42 = new THREE.Mesh(coneGeo, spikeMat);
  spike42.name = 'spike4_2';
  spike42.position.set(-0.125, 0.295, 0.375);
  spike42.rotation.set(0, deg(68), 0);
  root.add(spike42);
  const socket43 = new THREE.Mesh(cylinderGeo, socketMat);
  socket43.name = 'socket4_3';
  socket43.position.set(0.125, 0.115, 0.375);
  socket43.rotation.set(0, deg(30), 0);
  root.add(socket43);
  const spike43 = new THREE.Mesh(coneGeo, spikeMat);
  spike43.name = 'spike4_3';
  spike43.position.set(0.125, 0.295, 0.375);
  spike43.rotation.set(0, deg(85), 0);
  root.add(spike43);
  const socket44 = new THREE.Mesh(cylinderGeo, socketMat);
  socket44.name = 'socket4_4';
  socket44.position.set(0.375, 0.115, 0.375);
  socket44.rotation.set(0, deg(30), 0);
  root.add(socket44);
  const spike44 = new THREE.Mesh(coneGeo, spikeMat);
  spike44.name = 'spike4_4';
  spike44.position.set(0.375, 0.295, 0.375);
  spike44.rotation.set(0, deg(102), 0);
  root.add(spike44);

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

export default createSpikeTrap;
```

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