# Speed Bump

> A modular rubber speed bump laid across a lane: a low rounded hump built from alternating yellow and black segments with rounded end caps, bolt heads and reflective cat-eyes on the slopes. Default length spans the 2.7 m road of the road tiles; set the length, hump height and warning color for parking lots, school zones, garages and driving games.

![Speed Bump preview](https://codels.download/m/speed-bump.png)

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

## Facts

- Category: Urban & Street › Traffic
- Size (W × H × D): 2.70 × 0.06 × 0.44 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 528 · Meshes: 23 · Materials: 4
- License: CC0-1.0 (Codels built-in)
- Tags: speed-bump, low-poly, stylized, modern, city, road, city-builder, racing-game, obstacle, prop, street-furniture, rubber, flat, game-ready, instancing-friendly, mobile-friendly, parametric, color-gray, color-yellow, size-medium, poly-low
- Page: https://codels.download/models/speed-bump

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `length` | number | 1 – 4 | 2.7 | 2.7 |
| `height` | number | 0.04 – 0.08 | 0.06 | 0.06 |
| `color` | color | #rrggbb | #f0c01c | #f0c01c |

## Parts

- segment (extrude · yellow)
- bolt (cylinder · bolt)
- bolt (cylinder · bolt)
- catEye (box · eye)
- catEye (box · eye)
- segment (extrude · black)
- bolt (cylinder · bolt)
- bolt (cylinder · bolt)
- segment (extrude · yellow)
- bolt (cylinder · bolt)
- bolt (cylinder · bolt)
- catEye (box · eye)
- catEye (box · eye)
- segment (extrude · black)
- bolt (cylinder · bolt)
- bolt (cylinder · bolt)
- segment (extrude · yellow)
- bolt (cylinder · bolt)
- bolt (cylinder · bolt)
- catEye (box · eye)
- catEye (box · eye)
- endCap (lathe · yellow)
- endCap (lathe · yellow)

## How to use

Save the code below as `speed-bump.js`, then:

```js
import { createSpeedBump } from './speed-bump.js';
const model = createSpeedBump();
scene.add(model);
```

## Code

```js
/**
 * Speed Bump — Codels 3D model library (https://codels.download/models/speed-bump)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 528 · Size (W × H × D): 2.70 × 0.06 × 0.44 m
 *
 * Usage:
 *   import { createSpeedBump } from './speed-bump.js';
 *   
 *   const model = createSpeedBump();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Revolve a 2D profile [[radius, y], ...] around the Y axis.
function lathe(points, segments, phiStart = 0, phiLength = Math.PI * 2) {
  return new THREE.LatheGeometry(points.map(([x, y]) => new THREE.Vector2(x, y)), segments, phiStart, phiLength);
}

// 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 createSpeedBump() {
  const root = new THREE.Group();
  root.name = 'SpeedBump';

  // Materials
  const yellowMat = new THREE.MeshStandardMaterial({ name: 'yellow', color: 0xf0c01c, roughness: 0.75, flatShading: true });
  const blackMat = new THREE.MeshStandardMaterial({ name: 'black', color: 0x26282b, roughness: 0.9, flatShading: true });
  const boltMat = new THREE.MeshStandardMaterial({ name: 'bolt', color: 0x8b9096, roughness: 0.4, metalness: 0.7, flatShading: true });
  const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0xf4f1e6, roughness: 0.2, metalness: 0.3, emissive: 0xfff4d6, emissiveIntensity: 0.6, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[-0.22, 0], [-0.165, 0.027], [-0.088, 0.0528], [0, 0.06], [0.088, 0.0528], [0.165, 0.027], [0.22, 0]], 0.446);
  const cylinderGeo = new THREE.CylinderGeometry(0.014, 0.016, 0.008, 6);
  const boxGeo = new THREE.BoxGeometry(0.09, 0.012, 0.03);

  // Parts
  const segment = new THREE.Mesh(extrudeGeo, yellowMat);
  segment.name = 'segment';
  segment.position.set(-0.904, 0, 0);
  segment.rotation.set(0, deg(90), 0);
  root.add(segment);
  const bolt = new THREE.Mesh(cylinderGeo, boltMat);
  bolt.name = 'bolt';
  bolt.position.set(-1.017, 0.06, 0);
  root.add(bolt);
  const bolt2 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt2.name = 'bolt';
  bolt2.position.set(-0.791, 0.06, 0);
  root.add(bolt2);
  const catEye = new THREE.Mesh(boxGeo, eyeMat);
  catEye.name = 'catEye';
  catEye.position.set(-0.904, 0.0439, -0.1265);
  catEye.rotation.set(deg(-18.5242), 0, 0);
  root.add(catEye);
  const catEye2 = new THREE.Mesh(boxGeo, eyeMat);
  catEye2.name = 'catEye';
  catEye2.position.set(-0.904, 0.0439, 0.1265);
  catEye2.rotation.set(deg(18.5242), 0, 0);
  root.add(catEye2);
  const segment2 = new THREE.Mesh(extrudeGeo, blackMat);
  segment2.name = 'segment';
  segment2.position.set(-0.452, 0, 0);
  segment2.rotation.set(0, deg(90), 0);
  root.add(segment2);
  const bolt3 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt3.name = 'bolt';
  bolt3.position.set(-0.565, 0.06, 0);
  root.add(bolt3);
  const bolt4 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt4.name = 'bolt';
  bolt4.position.set(-0.339, 0.06, 0);
  root.add(bolt4);
  const segment3 = new THREE.Mesh(extrudeGeo, yellowMat);
  segment3.name = 'segment';
  segment3.rotation.set(0, deg(90), 0);
  root.add(segment3);
  const bolt5 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt5.name = 'bolt';
  bolt5.position.set(-0.113, 0.06, 0);
  root.add(bolt5);
  const bolt6 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt6.name = 'bolt';
  bolt6.position.set(0.113, 0.06, 0);
  root.add(bolt6);
  const catEye3 = new THREE.Mesh(boxGeo, eyeMat);
  catEye3.name = 'catEye';
  catEye3.position.set(0, 0.0439, -0.1265);
  catEye3.rotation.set(deg(-18.5242), 0, 0);
  root.add(catEye3);
  const catEye4 = new THREE.Mesh(boxGeo, eyeMat);
  catEye4.name = 'catEye';
  catEye4.position.set(0, 0.0439, 0.1265);
  catEye4.rotation.set(deg(18.5242), 0, 0);
  root.add(catEye4);
  const segment4 = new THREE.Mesh(extrudeGeo, blackMat);
  segment4.name = 'segment';
  segment4.position.set(0.452, 0, 0);
  segment4.rotation.set(0, deg(90), 0);
  root.add(segment4);
  const bolt7 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt7.name = 'bolt';
  bolt7.position.set(0.339, 0.06, 0);
  root.add(bolt7);
  const bolt8 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt8.name = 'bolt';
  bolt8.position.set(0.565, 0.06, 0);
  root.add(bolt8);
  const segment5 = new THREE.Mesh(extrudeGeo, yellowMat);
  segment5.name = 'segment';
  segment5.position.set(0.904, 0, 0);
  segment5.rotation.set(0, deg(90), 0);
  root.add(segment5);
  const bolt9 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt9.name = 'bolt';
  bolt9.position.set(0.791, 0.06, 0);
  root.add(bolt9);
  const bolt10 = new THREE.Mesh(cylinderGeo, boltMat);
  bolt10.name = 'bolt';
  bolt10.position.set(1.017, 0.06, 0);
  root.add(bolt10);
  const catEye5 = new THREE.Mesh(boxGeo, eyeMat);
  catEye5.name = 'catEye';
  catEye5.position.set(0.904, 0.0439, -0.1265);
  catEye5.rotation.set(deg(-18.5242), 0, 0);
  root.add(catEye5);
  const catEye6 = new THREE.Mesh(boxGeo, eyeMat);
  catEye6.name = 'catEye';
  catEye6.position.set(0.904, 0.0439, 0.1265);
  catEye6.rotation.set(deg(18.5242), 0, 0);
  root.add(catEye6);
  const endCap = new THREE.Mesh(lathe([[0.22, 0], [0.165, 0.027], [0.088, 0.0528], [0, 0.06]], 8, 0, Math.PI), yellowMat);
  endCap.name = 'endCap';
  endCap.position.set(1.13, 0, 0);
  root.add(endCap);
  const endCap2 = new THREE.Mesh(lathe([[0.22, 0], [0.165, 0.027], [0.088, 0.0528], [0, 0.06]], 8, Math.PI, Math.PI), yellowMat);
  endCap2.name = 'endCap';
  endCap2.position.set(-1.13, 0, 0);
  root.add(endCap2);

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

export default createSpeedBump;
```

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