# Crab

> A cheeky, cartoon low-poly red crab with a faceted rounded shell, pale underside, googly eyes on stalks, a little smile, six jointed walking legs and two big pincers held up and ready to snap. The claws are groups clawL/clawR (each with an animatable upper pincer), and every leg is its own group (legL1–legR3) for scuttling animations — perfect as a beach enemy, a tide-pool critter or an underwater NPC.

![Crab preview](https://codels.download/m/crab.png)

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

## Facts

- Category: Characters › Animals
- Size (W × H × D): 0.34 × 0.21 × 0.28 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,060 · Meshes: 35 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: crab, sea-life, cartoon, low-poly, stylized, tropical, underwater, beach, ocean, adventure, party-game, platformer, animal, enemy, npc, game-ready, mobile-friendly, parametric, color-red, size-small, poly-low
- Page: https://codels.download/models/crab

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `shell` | color | #rrggbb | #e2482f | #e2482f |
| `size` | number | 0.2 – 3 | 0.6 | 0.6 |
| `raised` | boolean | true \| false | true | true |

## Parts

- crab (group)
  - body (group)
    - shell (sphere · shell)
    - underside (sphere · belly)
    - shellSpot (sphere · dark)
    - shellSpot (sphere · dark)
    - shellSpot (sphere · dark)
    - shellSpot (sphere · dark)
    - mouth (box · pupil)
    - eyeStalkL (cylinder · shell)
    - eyeL (sphere · eyeWhite)
    - pupilL (sphere · pupil)
    - eyeShineL (box · eyeWhite)
    - eyeStalkR (cylinder · shell)
    - eyeR (sphere · eyeWhite)
    - pupilR (sphere · pupil)
    - eyeShineR (box · eyeWhite)
  - legL1 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - legL2 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - legL3 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - legR1 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - legR2 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - legR3 (group)
    - legUpper (box · shell)
    - legLower (box · dark)
  - clawL (group)
    - clawArmL (box · shell)
    - clawForearmL (box · shell)
    - pincerL (group)
      - clawPalmL (extrude · shell)

## How to use

Save the code below as `crab.js`, then:

```js
import { createCrab } from './crab.js';
const model = createCrab();
scene.add(model);
```

## Code

```js
/**
 * Crab — Codels 3D model library (https://codels.download/models/crab)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,060 · Size (W × H × D): 0.34 × 0.21 × 0.28 m
 *
 * Usage:
 *   import { createCrab } from './crab.js';
 *   
 *   const model = createCrab();
 *   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 createCrab() {
  const root = new THREE.Group();
  root.name = 'Crab';

  // Materials
  const shellMat = new THREE.MeshStandardMaterial({ name: 'shell', color: 0xe2482f, roughness: 0.45, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0xa33422, roughness: 0.5, flatShading: true });
  const bellyMat = new THREE.MeshStandardMaterial({ name: 'belly', color: 0xf7c2ac, roughness: 0.6, flatShading: true });
  const eyeWhiteMat = new THREE.MeshStandardMaterial({ name: 'eyeWhite', color: 0xfbfaf6, roughness: 0.3, flatShading: true });
  const pupilMat = new THREE.MeshStandardMaterial({ name: 'pupil', color: 0x161317, roughness: 0.25, flatShading: true });

  // Shared geometries
  const cylinderGeo = new THREE.CylinderGeometry(0.009, 0.012, 0.08, 5);
  const sphereGeo = new THREE.SphereGeometry(0.027, 8, 6);
  const sphereGeo2 = new THREE.SphereGeometry(0.014, 6, 4);
  const boxGeo = new THREE.BoxGeometry(0.006, 0.006, 0.003);
  const boxGeo2 = new THREE.BoxGeometry(0.028, 0.1257, 0.028);
  const boxGeo3 = new THREE.BoxGeometry(0.024, 0.1526, 0.024);
  const boxGeo4 = new THREE.BoxGeometry(0.028, 0.1261, 0.028);
  const boxGeo5 = new THREE.BoxGeometry(0.024, 0.153, 0.024);
  const boxGeo6 = new THREE.BoxGeometry(0.028, 0.1275, 0.028);
  const boxGeo7 = new THREE.BoxGeometry(0.024, 0.1578, 0.024);
  const boxGeo8 = new THREE.BoxGeometry(0.036, 0.119, 0.036);
  const boxGeo9 = new THREE.BoxGeometry(0.04, 0.121, 0.04);
  const extrudeGeo = extrude([[-0.035, -0.035], [0.04, -0.05], [0.11, -0.04], [0.16, -0.008], [0.12, -0.012], [0.075, -0.005], [0.05, 0.03], [0.01, 0.048], [-0.03, 0.035]], 0.034, [], [0.008, 0.008, 1]);
  const extrudeGeo2 = extrude([[0, -0.012], [0.04, 0.012], [0.085, 0.012], [0.115, -0.012], [0.075, -0.004], [0.035, -0.014]], 0.026, [], [0.008, 0.008, 1]);

  // Parts
  const crab = new THREE.Group();
  crab.name = 'crab';
  crab.scale.setScalar(0.6);
  root.add(crab);
  const body = new THREE.Group();
  body.name = 'body';
  crab.add(body);
  const shell = new THREE.Mesh(new THREE.SphereGeometry(1, 12, 7), shellMat);
  shell.name = 'shell';
  shell.position.set(0, 0.09, 0);
  shell.scale.set(0.15, 0.068, 0.115);
  body.add(shell);
  const underside = new THREE.Mesh(new THREE.SphereGeometry(1, 12, 5), bellyMat);
  underside.name = 'underside';
  underside.position.set(0, 0.068, 0.004);
  underside.scale.set(0.145, 0.05, 0.11);
  body.add(underside);
  const shellSpot = new THREE.Mesh(new THREE.SphereGeometry(0.022, 6, 3), darkMat);
  shellSpot.name = 'shellSpot';
  shellSpot.position.set(0.06, 0.1457, -0.03);
  shellSpot.scale.set(1, 0.3, 1);
  body.add(shellSpot);
  const shellSpot2 = new THREE.Mesh(new THREE.SphereGeometry(0.018, 6, 3), darkMat);
  shellSpot2.name = 'shellSpot';
  shellSpot2.position.set(-0.07, 0.145, -0.02);
  shellSpot2.scale.set(1, 0.3, 1);
  body.add(shellSpot2);
  const shellSpot3 = new THREE.Mesh(new THREE.SphereGeometry(0.016, 6, 3), darkMat);
  shellSpot3.name = 'shellSpot';
  shellSpot3.position.set(0, 0.1421, -0.065);
  shellSpot3.scale.set(1, 0.3, 1);
  body.add(shellSpot3);
  const shellSpot4 = new THREE.Mesh(new THREE.SphereGeometry(0.014, 6, 3), darkMat);
  shellSpot4.name = 'shellSpot';
  shellSpot4.position.set(-0.02, 0.151, 0.03);
  shellSpot4.scale.set(1, 0.3, 1);
  body.add(shellSpot4);
  const mouth = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.008, 0.008), pupilMat);
  mouth.name = 'mouth';
  mouth.position.set(0, 0.086, 0.112);
  body.add(mouth);
  const eyeStalkL = new THREE.Mesh(cylinderGeo, shellMat);
  eyeStalkL.name = 'eyeStalkL';
  eyeStalkL.position.set(0.042, 0.175, 0.07);
  eyeStalkL.rotation.set(deg(10), 0, deg(-8));
  body.add(eyeStalkL);
  const eyeL = new THREE.Mesh(sphereGeo, eyeWhiteMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.048, 0.22, 0.077);
  body.add(eyeL);
  const pupilL = new THREE.Mesh(sphereGeo2, pupilMat);
  pupilL.name = 'pupilL';
  pupilL.position.set(0.046, 0.222, 0.1);
  pupilL.scale.set(1, 1.15, 0.5);
  body.add(pupilL);
  const eyeShineL = new THREE.Mesh(boxGeo, eyeWhiteMat);
  eyeShineL.name = 'eyeShineL';
  eyeShineL.position.set(0.051, 0.228, 0.107);
  body.add(eyeShineL);
  const eyeStalkR = new THREE.Mesh(cylinderGeo, shellMat);
  eyeStalkR.name = 'eyeStalkR';
  eyeStalkR.position.set(-0.042, 0.175, 0.07);
  eyeStalkR.rotation.set(deg(10), 0, deg(8));
  body.add(eyeStalkR);
  const eyeR = new THREE.Mesh(sphereGeo, eyeWhiteMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.048, 0.22, 0.077);
  body.add(eyeR);
  const pupilR = new THREE.Mesh(sphereGeo2, pupilMat);
  pupilR.name = 'pupilR';
  pupilR.position.set(-0.046, 0.222, 0.1);
  pupilR.scale.set(1, 1.15, 0.5);
  body.add(pupilR);
  const eyeShineR = new THREE.Mesh(boxGeo, eyeWhiteMat);
  eyeShineR.name = 'eyeShineR';
  eyeShineR.position.set(-0.041, 0.228, 0.107);
  body.add(eyeShineR);
  const legL1 = new THREE.Group();
  legL1.name = 'legL1';
  legL1.position.set(0.11, 0.09, 0.035);
  crab.add(legL1);
  const legUpper = new THREE.Mesh(boxGeo2, shellMat);
  legUpper.name = 'legUpper';
  legUpper.position.set(0.05, 0.0225, 0);
  legUpper.rotation.set(deg(-90), deg(-24.2277), deg(-90));
  legL1.add(legUpper);
  const legLower = new THREE.Mesh(boxGeo3, darkMat);
  legLower.name = 'legLower';
  legLower.position.set(0.1275, -0.0195, 0.005);
  legLower.rotation.set(deg(-67.5692), deg(64.5221), deg(-114.5731));
  legL1.add(legLower);
  const legL2 = new THREE.Group();
  legL2.name = 'legL2';
  legL2.position.set(0.11, 0.09, -0.02);
  crab.add(legL2);
  const legUpper2 = new THREE.Mesh(boxGeo4, shellMat);
  legUpper2.name = 'legUpper';
  legUpper2.position.set(0.05, 0.0225, -0.005);
  legUpper2.rotation.set(deg(-87.4489), deg(-23.994), deg(-83.7472));
  legL2.add(legUpper2);
  const legLower2 = new THREE.Mesh(boxGeo5, darkMat);
  legLower2.name = 'legLower';
  legLower2.position.set(0.1275, -0.0195, -0.0175);
  legLower2.rotation.set(deg(-120.7689), deg(61.9374), deg(-55.9922));
  legL2.add(legLower2);
  const legL3 = new THREE.Group();
  legL3.name = 'legL3';
  legL3.position.set(0.11, 0.09, -0.07);
  crab.add(legL3);
  const legUpper3 = new THREE.Mesh(boxGeo6, shellMat);
  legUpper3.name = 'legUpper';
  legUpper3.position.set(0.05, 0.0225, -0.01);
  legUpper3.rotation.set(deg(-85.054), deg(-23.32), deg(-77.6688));
  legL3.add(legUpper3);
  const legLower3 = new THREE.Mesh(boxGeo7, darkMat);
  legLower3.name = 'legLower';
  legLower3.position.set(0.1275, -0.0195, -0.04);
  legLower3.rotation.set(deg(-138.1296), deg(45.6766), deg(-32.6693));
  legL3.add(legLower3);
  const legR1 = new THREE.Group();
  legR1.name = 'legR1';
  legR1.position.set(-0.11, 0.09, 0.035);
  crab.add(legR1);
  const legUpper4 = new THREE.Mesh(boxGeo2, shellMat);
  legUpper4.name = 'legUpper';
  legUpper4.position.set(-0.05, 0.0225, 0);
  legUpper4.rotation.set(deg(-90), deg(24.2277), deg(90));
  legR1.add(legUpper4);
  const legLower4 = new THREE.Mesh(boxGeo3, darkMat);
  legLower4.name = 'legLower';
  legLower4.position.set(-0.1275, -0.0195, 0.005);
  legLower4.rotation.set(deg(-67.5692), deg(-64.5221), deg(114.5731));
  legR1.add(legLower4);
  const legR2 = new THREE.Group();
  legR2.name = 'legR2';
  legR2.position.set(-0.11, 0.09, -0.02);
  crab.add(legR2);
  const legUpper5 = new THREE.Mesh(boxGeo4, shellMat);
  legUpper5.name = 'legUpper';
  legUpper5.position.set(-0.05, 0.0225, -0.005);
  legUpper5.rotation.set(deg(-87.4489), deg(23.994), deg(83.7472));
  legR2.add(legUpper5);
  const legLower5 = new THREE.Mesh(boxGeo5, darkMat);
  legLower5.name = 'legLower';
  legLower5.position.set(-0.1275, -0.0195, -0.0175);
  legLower5.rotation.set(deg(-120.7689), deg(-61.9374), deg(55.9922));
  legR2.add(legLower5);
  const legR3 = new THREE.Group();
  legR3.name = 'legR3';
  legR3.position.set(-0.11, 0.09, -0.07);
  crab.add(legR3);
  const legUpper6 = new THREE.Mesh(boxGeo6, shellMat);
  legUpper6.name = 'legUpper';
  legUpper6.position.set(-0.05, 0.0225, -0.01);
  legUpper6.rotation.set(deg(-85.054), deg(23.32), deg(77.6688));
  legR3.add(legUpper6);
  const legLower6 = new THREE.Mesh(boxGeo7, darkMat);
  legLower6.name = 'legLower';
  legLower6.position.set(-0.1275, -0.0195, -0.04);
  legLower6.rotation.set(deg(-138.1296), deg(-45.6766), deg(32.6693));
  legR3.add(legLower6);
  const clawL = new THREE.Group();
  clawL.name = 'clawL';
  clawL.position.set(0.11, 0.1, 0.07);
  crab.add(clawL);
  const clawArmL = new THREE.Mesh(boxGeo8, shellMat);
  clawArmL.name = 'clawArmL';
  clawArmL.position.set(0.04, 0.015, 0.025);
  clawArmL.rotation.set(deg(-99.5667), deg(-14.8911), deg(-123.2585));
  clawL.add(clawArmL);
  const clawForearmL = new THREE.Mesh(boxGeo9, shellMat);
  clawForearmL.name = 'clawForearmL';
  clawForearmL.position.set(0.09, 0.065, 0.085);
  clawForearmL.rotation.set(deg(-132.7543), deg(-10.9767), deg(-168.3624));
  clawL.add(clawForearmL);
  const pincerL = new THREE.Group();
  pincerL.name = 'pincerL';
  pincerL.position.set(0.1, 0.1, 0.12);
  pincerL.rotation.set(deg(-38), deg(18), 0);
  clawL.add(pincerL);
  const clawPalmL = new THREE.Mesh(extrudeGeo, shellMat);
  clawPalmL.name = 'clawPalmL';
  clawPalmL.rotation.set(0, deg(-90), 0);
  pincerL.add(clawPalmL);
  const clawDactylL = new THREE.Group();
  clawDactylL.name = 'clawDactylL';
  clawDactylL.position.set(0, 0.03, 0.045);
  clawDactylL.rotation.set(deg(-26), 0, 0);
  pincerL.add(clawDactylL);
  const clawTipL = new THREE.Mesh(extrudeGeo2, darkMat);
  clawTipL.name = 'clawTipL';
  clawTipL.rotation.set(0, deg(-90), 0);
  clawDactylL.add(clawTipL);
  const clawR = new THREE.Group();
  clawR.name = 'clawR';
  clawR.position.set(-0.11, 0.1, 0.07);
  crab.add(clawR);
  const clawArmR = new THREE.Mesh(boxGeo8, shellMat);
  clawArmR.name = 'clawArmR';
  clawArmR.position.set(-0.04, 0.015, 0.025);
  clawArmR.rotation.set(deg(-99.5667), deg(14.8911), deg(123.2585));
  clawR.add(clawArmR);
  const clawForearmR = new THREE.Mesh(boxGeo9, shellMat);
  clawForearmR.name = 'clawForearmR';
  clawForearmR.position.set(-0.09, 0.065, 0.085);
  clawForearmR.rotation.set(deg(-132.7543), deg(10.9767), deg(168.3624));
  clawR.add(clawForearmR);
  const pincerR = new THREE.Group();
  pincerR.name = 'pincerR';
  pincerR.position.set(-0.1, 0.1, 0.12);
  pincerR.rotation.set(deg(-38), deg(-18), 0);
  clawR.add(pincerR);
  const clawPalmR = new THREE.Mesh(extrudeGeo, shellMat);
  clawPalmR.name = 'clawPalmR';
  clawPalmR.rotation.set(0, deg(-90), 0);
  pincerR.add(clawPalmR);
  const clawDactylR = new THREE.Group();
  clawDactylR.name = 'clawDactylR';
  clawDactylR.position.set(0, 0.03, 0.045);
  clawDactylR.rotation.set(deg(-26), 0, 0);
  pincerR.add(clawDactylR);
  const clawTipR = new THREE.Mesh(extrudeGeo2, darkMat);
  clawTipR.name = 'clawTipR';
  clawTipR.rotation.set(0, deg(-90), 0);
  clawDactylR.add(clawTipR);

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

export default createCrab;
```

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