# Manhole Cover

> A cast-iron manhole cover that sits flush with the ground: only 3 cm thin, a round lid in its frame ring with raised concentric rings, radial ribs, a center boss and pick holes. Switch to a square storm drain grate with slots over a dark pit. Drop it onto road and sidewalk tiles to add street detail in city builders, driving games and urban scenes.

![Manhole Cover preview](https://codels.download/m/manhole-cover.png)

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

## Facts

- Category: Urban & Street › Street Furniture
- Size (W × H × D): 0.70 × 0.03 × 0.70 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 696 · Meshes: 16 · Materials: 3
- License: CC0-1.0 (Codels built-in)
- Tags: cover, manhole, low-poly, stylized, modern, city, road, city-builder, decoration, prop, street-furniture, metal, flat, round, game-ready, instancing-friendly, mobile-friendly, parametric, color-gray, size-small, poly-low
- Page: https://codels.download/models/manhole-cover

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `variant` | select | manhole \| drain grate | manhole | manhole |
| `size` | number | 0.5 – 1 | 0.7 | 0.7 |
| `color` | color | #rrggbb | #4a4d50 | #4a4d50 |

## Parts

- frame (cylinder · frame)
- cover (cylinder · iron)
- gap (ring · hole)
- rib (torus · iron)
- rib (torus · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- spoke (box · iron)
- boss (cylinder · iron)
- pickHole (box · hole)
- pickHole (box · hole)

## How to use

Save the code below as `manhole-cover.js`, then:

```js
import { createManholeCover } from './manhole-cover.js';
const model = createManholeCover();
scene.add(model);
```

## Code

```js
/**
 * Manhole Cover — Codels 3D model library (https://codels.download/models/manhole-cover)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 696 · Size (W × H × D): 0.70 × 0.03 × 0.70 m
 *
 * Usage:
 *   import { createManholeCover } from './manhole-cover.js';
 *   
 *   const model = createManholeCover();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

export function createManholeCover() {
  const root = new THREE.Group();
  root.name = 'ManholeCover';

  // Materials
  const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x4a4d50, roughness: 0.55, metalness: 0.55, flatShading: true });
  const frameMat = new THREE.MeshStandardMaterial({ name: 'frame', color: 0x383a3c, roughness: 0.6, metalness: 0.5, flatShading: true });
  const holeMat = new THREE.MeshStandardMaterial({ name: 'hole', color: 0x0e0f10, roughness: 1, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.016, 0.012, 0.11);
  const boxGeo2 = new THREE.BoxGeometry(0.05, 0.002, 0.018);

  // Parts
  const frame = new THREE.Mesh(new THREE.CylinderGeometry(0.35, 0.35, 0.016, 24), frameMat);
  frame.name = 'frame';
  frame.position.set(0, 0.008, 0);
  root.add(frame);
  const cover = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.3, 0.02, 24), ironMat);
  cover.name = 'cover';
  cover.position.set(0, 0.01, 0);
  root.add(cover);
  const gap = new THREE.Mesh(new THREE.RingGeometry(0.3, 0.31, 24), holeMat);
  gap.name = 'gap';
  gap.position.set(0, 0.0165, 0);
  gap.rotation.set(deg(-90), 0, 0);
  root.add(gap);
  const rib = new THREE.Mesh(new THREE.TorusGeometry(0.26, 0.011, 3, 24), ironMat);
  rib.name = 'rib';
  rib.position.set(0, 0.02, 0);
  rib.rotation.set(deg(90), 0, 0);
  rib.scale.set(1, 1, 0.6);
  root.add(rib);
  const rib2 = new THREE.Mesh(new THREE.TorusGeometry(0.15, 0.011, 3, 24), ironMat);
  rib2.name = 'rib';
  rib2.position.set(0, 0.02, 0);
  rib2.rotation.set(deg(90), 0, 0);
  rib2.scale.set(1, 1, 0.6);
  root.add(rib2);
  const spoke = new THREE.Mesh(boxGeo, ironMat);
  spoke.name = 'spoke';
  spoke.position.set(0.0785, 0.02, 0.1894);
  spoke.rotation.set(0, deg(22.5), 0);
  root.add(spoke);
  const spoke2 = new THREE.Mesh(boxGeo, ironMat);
  spoke2.name = 'spoke';
  spoke2.position.set(0.1894, 0.02, 0.0785);
  spoke2.rotation.set(0, deg(67.5), 0);
  root.add(spoke2);
  const spoke3 = new THREE.Mesh(boxGeo, ironMat);
  spoke3.name = 'spoke';
  spoke3.position.set(0.1894, 0.02, -0.0785);
  spoke3.rotation.set(0, deg(112.5), 0);
  root.add(spoke3);
  const spoke4 = new THREE.Mesh(boxGeo, ironMat);
  spoke4.name = 'spoke';
  spoke4.position.set(0.0785, 0.02, -0.1894);
  spoke4.rotation.set(0, deg(157.5), 0);
  root.add(spoke4);
  const spoke5 = new THREE.Mesh(boxGeo, ironMat);
  spoke5.name = 'spoke';
  spoke5.position.set(-0.0785, 0.02, -0.1894);
  spoke5.rotation.set(0, deg(202.5), 0);
  root.add(spoke5);
  const spoke6 = new THREE.Mesh(boxGeo, ironMat);
  spoke6.name = 'spoke';
  spoke6.position.set(-0.1894, 0.02, -0.0785);
  spoke6.rotation.set(0, deg(247.5), 0);
  root.add(spoke6);
  const spoke7 = new THREE.Mesh(boxGeo, ironMat);
  spoke7.name = 'spoke';
  spoke7.position.set(-0.1894, 0.02, 0.0785);
  spoke7.rotation.set(0, deg(292.5), 0);
  root.add(spoke7);
  const spoke8 = new THREE.Mesh(boxGeo, ironMat);
  spoke8.name = 'spoke';
  spoke8.position.set(-0.0785, 0.02, 0.1894);
  spoke8.rotation.set(0, deg(337.5), 0);
  root.add(spoke8);
  const boss = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.072, 0.008, 12), ironMat);
  boss.name = 'boss';
  boss.position.set(0, 0.024, 0);
  root.add(boss);
  const pickHole = new THREE.Mesh(boxGeo2, holeMat);
  pickHole.name = 'pickHole';
  pickHole.position.set(-0.215, 0.0205, 0);
  root.add(pickHole);
  const pickHole2 = new THREE.Mesh(boxGeo2, holeMat);
  pickHole2.name = 'pickHole';
  pickHole2.position.set(0.215, 0.0205, 0);
  root.add(pickHole2);

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

export default createManholeCover;
```

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