# Spiked Ball

> A heavy spiked iron ball for swinging traps, rolling hazards and boss arenas: a riveted dark sphere bristling with evenly spread steel cone spikes and a raised equator band. Diameter, spike count and spike length are adjustable; the origin is at the center so it can spin or swing freely.

![Spiked Ball preview](https://codels.download/m/spiked-ball.png)

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

## Facts

- Category: Game Kit › Hazards
- Size (W × H × D): 1.57 × 1.58 × 1.57 m — units are meters, +Y up, front faces +Z
- Origin: center of the model (it floats — pickups, planets)
- Triangles: 696 · Meshes: 28 · Materials: 3
- License: CC0-1.0 (Codels built-in)
- Tags: mace, morning-star, spike-ball, spikes, cartoon, low-poly, stylized, medieval, dungeon, party-game, platformer, roguelike, enemy, hazard, obstacle, metal, round, game-ready, mobile-friendly, parametric, color-blue, color-gray, size-medium, poly-low
- Page: https://codels.download/models/spiked-ball

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `size` | number | 0.4 – 3 | 1 | 1 |
| `spikes` | int | 6 – 40 | 26 | 26 |
| `spikeLength` | number | 0.15 – 0.6 | 0.35 | 0.35 |
| `color` | color | #rrggbb | #3c414d | #3c414d |

## Parts

- ball (sphere · ball)
- band (torus · band)
- spike1 (cone · spike)
- spike2 (cone · spike)
- spike3 (cone · spike)
- spike4 (cone · spike)
- spike5 (cone · spike)
- spike6 (cone · spike)
- spike7 (cone · spike)
- spike8 (cone · spike)
- spike9 (cone · spike)
- spike10 (cone · spike)
- spike11 (cone · spike)
- spike12 (cone · spike)
- spike13 (cone · spike)
- spike14 (cone · spike)
- spike15 (cone · spike)
- spike16 (cone · spike)
- spike17 (cone · spike)
- spike18 (cone · spike)
- spike19 (cone · spike)
- spike20 (cone · spike)
- spike21 (cone · spike)
- spike22 (cone · spike)
- spike23 (cone · spike)
- spike24 (cone · spike)
- spike25 (cone · spike)
- spike26 (cone · spike)

## How to use

Save the code below as `spiked-ball.js`, then:

```js
import { createSpikedBall } from './spiked-ball.js';
const model = createSpikedBall();
scene.add(model);
```

## Code

```js
/**
 * Spiked Ball — Codels 3D model library (https://codels.download/models/spiked-ball)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
 * Triangles: 696 · Size (W × H × D): 1.57 × 1.58 × 1.57 m
 *
 * Usage:
 *   import { createSpikedBall } from './spiked-ball.js';
 *   
 *   const model = createSpikedBall();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

export function createSpikedBall() {
  const root = new THREE.Group();
  root.name = 'SpikedBall';

  // Materials
  const ballMat = new THREE.MeshStandardMaterial({ name: 'ball', color: 0x3c414d, roughness: 0.55, metalness: 0.45, flatShading: true });
  const bandMat = new THREE.MeshStandardMaterial({ name: 'band', color: 0x262a32, roughness: 0.6, metalness: 0.5, flatShading: true });
  const spikeMat = new THREE.MeshStandardMaterial({ name: 'spike', color: 0xd9dde4, roughness: 0.25, metalness: 0.8, flatShading: true });

  // Shared geometries
  const coneGeo = new THREE.ConeGeometry(0.11, 0.35, 6);

  // Parts
  const ball = new THREE.Mesh(new THREE.SphereGeometry(0.5, 12, 9), ballMat);
  ball.name = 'ball';
  root.add(ball);
  const band = new THREE.Mesh(new THREE.TorusGeometry(0.495, 0.03, 4, 24), bandMat);
  band.name = 'band';
  band.rotation.set(deg(90), 0, 0);
  root.add(band);
  const spike1 = new THREE.Mesh(coneGeo, spikeMat);
  spike1.name = 'spike1';
  spike1.position.set(0.1772, 0.6202, 0);
  spike1.rotation.set(0, 0, deg(-15.9424));
  root.add(spike1);
  const spike2 = new THREE.Mesh(coneGeo, spikeMat);
  spike2.name = 'spike2';
  spike2.position.set(-0.2218, 0.5706, 0.2032);
  spike2.rotation.set(deg(19.5999), 0, deg(20.1117));
  root.add(spike2);
  const spike3 = new THREE.Mesh(coneGeo, spikeMat);
  spike3.name = 'spike3';
  spike3.position.set(0.0332, 0.521, -0.3788);
  spike3.rotation.set(deg(-36.0243), 0, deg(-2.9547));
  root.add(spike3);
  const spike4 = new THREE.Mesh(coneGeo, spikeMat);
  spike4.name = 'spike4';
  spike4.position.set(0.2679, 0.4713, 0.3494);
  spike4.rotation.set(deg(36.5502), 0, deg(-24.5404));
  root.add(spike4);
  const spike5 = new THREE.Mesh(coneGeo, spikeMat);
  spike5.name = 'spike5';
  spike5.position.set(-0.4806, 0.4217, -0.085);
  spike5.rotation.set(deg(-11.396), 0, deg(48.1644));
  root.add(spike5);
  const spike6 = new THREE.Mesh(coneGeo, spikeMat);
  spike6.name = 'spike6';
  spike6.position.set(0.4445, 0.3721, -0.2828);
  spike6.rotation.set(deg(-37.2309), 0, deg(-43.5651));
  root.add(spike6);
  const spike7 = new THREE.Mesh(coneGeo, spikeMat);
  spike7.name = 'spike7';
  spike7.position.set(-0.145, 0.3225, 0.5394);
  spike7.rotation.set(deg(59.127), 0, deg(12.9925));
  root.add(spike7);
  const spike8 = new THREE.Mesh(coneGeo, spikeMat);
  spike8.name = 'spike8';
  spike8.position.set(-0.2694, 0.2729, -0.5187);
  spike8.rotation.set(deg(-62.2493), 0, deg(24.6847));
  root.add(spike8);
  const spike9 = new THREE.Mesh(coneGeo, spikeMat);
  spike9.name = 'spike9';
  spike9.position.set(0.5684, 0.2233, 0.2076);
  spike9.rotation.set(deg(42.9147), 0, deg(-61.7936));
  root.add(spike9);
  const spike10 = new THREE.Mesh(coneGeo, spikeMat);
  spike10.name = 'spike10';
  spike10.position.set(-0.5742, 0.1737, 0.237);
  spike10.rotation.set(deg(53.7711), 0, deg(62.9002));
  root.add(spike10);
  const spike11 = new THREE.Mesh(coneGeo, spikeMat);
  spike11.name = 'spike11';
  spike11.position.set(0.2683, 0.124, -0.5733);
  spike11.rotation.set(deg(-77.7916), 0, deg(-24.5782));
  root.add(spike11);
  const spike12 = new THREE.Mesh(coneGeo, spikeMat);
  spike12.name = 'spike12';
  spike12.position.set(0.1917, 0.0744, 0.6113);
  spike12.rotation.set(deg(83.0589), 0, deg(-17.2946));
  root.add(spike12);
  const spike13 = new THREE.Mesh(coneGeo, spikeMat);
  spike13.name = 'spike13';
  spike13.position.set(-0.5576, 0.0248, -0.3232);
  spike13.rotation.set(deg(-85.6104), 0, deg(59.8338));
  root.add(spike13);
  const spike14 = new THREE.Mesh(coneGeo, spikeMat);
  spike14.name = 'spike14';
  spike14.position.set(0.6295, -0.0248, -0.1384);
  spike14.rotation.set(deg(-100.1627), 0, deg(-77.4096));
  root.add(spike14);
  const spike15 = new THREE.Mesh(coneGeo, spikeMat);
  spike15.name = 'spike15';
  spike15.position.set(-0.3685, -0.0744, 0.5241);
  spike15.rotation.set(deg(98.0817), 0, deg(34.8401));
  root.add(spike15);
  const spike16 = new THREE.Mesh(coneGeo, spikeMat);
  spike16.name = 'spike16';
  spike16.position.set(-0.0813, -0.124, -0.6277);
  spike16.rotation.set(deg(-101.1779), 0, deg(7.245));
  root.add(spike16);
  const spike17 = new THREE.Mesh(coneGeo, spikeMat);
  spike17.name = 'spike17';
  spike17.position.set(0.475, -0.1737, 0.4003);
  spike17.rotation.set(deg(113.4506), 0, deg(-47.4269));
  root.add(spike17);
  const spike18 = new THREE.Mesh(coneGeo, spikeMat);
  spike18.name = 'spike18';
  spike18.position.set(-0.6046, -0.2233, 0.025);
  spike18.rotation.set(deg(173.6104), 0, deg(69.6156));
  root.add(spike18);
  const spike19 = new THREE.Mesh(coneGeo, spikeMat);
  spike19.name = 'spike19';
  spike19.position.set(0.4143, -0.2729, -0.4122);
  spike19.rotation.set(deg(-123.5024), 0, deg(-39.961));
  root.add(spike19);
  const spike20 = new THREE.Mesh(coneGeo, spikeMat);
  spike20.name = 'spike20';
  spike20.position.set(-0.0258, -0.3225, 0.558);
  spike20.rotation.set(deg(120.0265), 0, deg(2.2926));
  root.add(spike20);
  const spike21 = new THREE.Mesh(coneGeo, spikeMat);
  spike21.name = 'spike21';
  spike21.position.set(-0.3375, -0.3721, -0.4045);
  spike21.rotation.set(deg(-132.6125), 0, deg(31.5559));
  root.add(spike21);
  const spike22 = new THREE.Mesh(coneGeo, spikeMat);
  spike22.name = 'spike22';
  spike22.position.set(0.4837, -0.4217, 0.0651);
  spike22.rotation.set(deg(171.228), 0, deg(-48.5792));
  root.add(spike22);
  const spike23 = new THREE.Mesh(coneGeo, spikeMat);
  spike23.name = 'spike23';
  spike23.position.set(-0.3614, -0.4713, 0.2515);
  spike23.rotation.set(deg(151.9199), 0, deg(34.0792));
  root.add(spike23);
  const spike24 = new THREE.Mesh(coneGeo, spikeMat);
  spike24.name = 'spike24';
  spike24.position.set(0.0835, -0.521, -0.371);
  spike24.rotation.set(deg(-144.542), 0, deg(-7.4353));
  root.add(spike24);
  const spike25 = new THREE.Mesh(coneGeo, spikeMat);
  spike25.name = 'spike25';
  spike25.position.set(0.1495, -0.5706, 0.261);
  spike25.rotation.set(deg(155.4218), 0, deg(-13.4058));
  root.add(spike25);
  const spike26 = new THREE.Mesh(coneGeo, spikeMat);
  spike26.name = 'spike26';
  spike26.position.set(-0.1688, -0.6202, -0.0538);
  spike26.rotation.set(deg(-175.038), 0, deg(15.1696));
  root.add(spike26);

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

export default createSpikedBall;
```

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