# Duck

> A round, toy-like low-poly duck in two flavors: a fluffy yellow duckling with a big head, or a mallard drake with a glossy green head, white neck ring, chestnut chest and blue wing flash. Swimming mode hides the webbed feet so it floats on a water plane. Head, wings and legs are pivoted groups for waddle and paddle animations.

![Duck preview](https://codels.download/m/duck.png)

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

## Facts

- Category: Characters › Animals
- Size (W × H × D): 0.16 × 0.28 × 0.30 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 668 · Meshes: 16 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: bird, duck, duckling, mallard, cartoon, low-poly, stylized, farm, grassland, river, village, farming-sim, party-game, animal, npc, game-ready, mobile-friendly, parametric, color-yellow, size-tiny, poly-low
- Page: https://codels.download/models/duck

## Files

| Format | URL |
|---|---|
| three.js ES module (`createDuck()`) | https://codels.download/m/duck.js |
| React Three Fiber component (`<Duck />`) | https://codels.download/m/duck.jsx |
| Instancing module (`createDuckInstances(count, place)`, one draw call per material) | https://codels.download/m/duck.instanced.js |
| Standalone HTML demo | https://codels.download/m/duck.html |
| glTF binary | https://codels.download/m/duck.glb |
| glTF binary, Meshopt-compressed (2–3× smaller; GLTFLoader needs `setMeshoptDecoder(MeshoptDecoder)`) | https://codels.download/m/duck.glb?compress=meshopt |
| glTF JSON | https://codels.download/m/duck.gltf |
| OBJ (vertex colors) + MTL | https://codels.download/m/duck.obj · https://codels.download/m/duck.mtl |
| STL | https://codels.download/m/duck.stl |
| CodelSpec JSON | https://codels.download/m/duck.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 | duckling \| mallard | duckling | duckling |
| `swimming` | boolean | true \| false | false | false |

## Parts

- duck (group)
  - legL (group)
    - shinL (cylinder · feet)
    - footL (extrude · feet)
  - legR (group)
    - shinR (cylinder · feet)
    - footR (extrude · feet)
  - body (group)
    - torso (sphere · down)
    - tail (cone · down)
  - wingL (group)
    - wingPanelL (sphere · down)
  - wingR (group)
    - wingPanelR (sphere · down)
  - head (group)
    - neck (cylinder · down)
    - skull (sphere · down)
    - bill (sphere · bill)
    - eyeL (sphere · eye)
    - eyeShineL (sphere · white)
    - eyeR (sphere · eye)
    - eyeShineR (sphere · white)
    - tuft (cone · down)

## How to use

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

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

## Code

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

  // Materials
  const downMat = new THREE.MeshStandardMaterial({ name: 'down', color: 0xffd23f, roughness: 0.9, flatShading: true });
  const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf4f1ea, roughness: 0.7, flatShading: true });
  const billMat = new THREE.MeshStandardMaterial({ name: 'bill', color: 0xf39a2e, roughness: 0.55, flatShading: true });
  const feetMat = new THREE.MeshStandardMaterial({ name: 'feet', color: 0xf2842a, roughness: 0.6, flatShading: true });
  const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0x171314, roughness: 0.3, flatShading: true });

  // Shared geometries
  const cylinderGeo = new THREE.CylinderGeometry(0.017, 0.017, 0.09, 6);
  const extrudeGeo = extrude([[-0.012, 0], [0.012, 0], [0.05, 0.065], [0.018, 0.055], [0, 0.078], [-0.018, 0.055], [-0.05, 0.065]], 0.012);
  const sphereGeo = new THREE.SphereGeometry(0.1, 8, 5);
  const sphereGeo2 = new THREE.SphereGeometry(0.0221, 6, 4);
  const sphereGeo3 = new THREE.SphereGeometry(0.0078, 4, 3);

  // Parts
  const duck = new THREE.Group();
  duck.name = 'duck';
  duck.scale.setScalar(0.5);
  root.add(duck);
  const legL = new THREE.Group();
  legL.name = 'legL';
  legL.position.set(0.06, 0.09, 0);
  duck.add(legL);
  const shinL = new THREE.Mesh(cylinderGeo, feetMat);
  shinL.name = 'shinL';
  shinL.position.set(0, -0.045, 0);
  legL.add(shinL);
  const footL = new THREE.Mesh(extrudeGeo, feetMat);
  footL.name = 'footL';
  footL.position.set(0, -0.084, -0.012);
  footL.rotation.set(deg(90), 0, 0);
  legL.add(footL);
  const legR = new THREE.Group();
  legR.name = 'legR';
  legR.position.set(-0.06, 0.09, 0);
  duck.add(legR);
  const shinR = new THREE.Mesh(cylinderGeo, feetMat);
  shinR.name = 'shinR';
  shinR.position.set(0, -0.045, 0);
  legR.add(shinR);
  const footR = new THREE.Mesh(extrudeGeo, feetMat);
  footR.name = 'footR';
  footR.position.set(0, -0.084, -0.012);
  footR.rotation.set(deg(90), 0, 0);
  legR.add(footR);
  const body = new THREE.Group();
  body.name = 'body';
  duck.add(body);
  const torso = new THREE.Mesh(new THREE.SphereGeometry(0.17, 10, 7), downMat);
  torso.name = 'torso';
  torso.position.set(0, 0.1974, -0.01);
  torso.scale.set(0.85, 0.82, 1.12);
  body.add(torso);
  const tail = new THREE.Mesh(new THREE.ConeGeometry(0.075, 0.13, 6), downMat);
  tail.name = 'tail';
  tail.position.set(0, 0.2674, -0.19);
  tail.rotation.set(deg(-62), 0, 0);
  body.add(tail);
  const wingL = new THREE.Group();
  wingL.name = 'wingL';
  wingL.position.set(0.119, 0.2424, -0.015);
  duck.add(wingL);
  const wingPanelL = new THREE.Mesh(sphereGeo, downMat);
  wingPanelL.name = 'wingPanelL';
  wingPanelL.position.set(0.012, -0.045, -0.04);
  wingPanelL.rotation.set(deg(-12), 0, 0);
  wingPanelL.scale.set(0.28, 0.55, 1.05);
  wingL.add(wingPanelL);
  const wingR = new THREE.Group();
  wingR.name = 'wingR';
  wingR.position.set(-0.119, 0.2424, -0.015);
  duck.add(wingR);
  const wingPanelR = new THREE.Mesh(sphereGeo, downMat);
  wingPanelR.name = 'wingPanelR';
  wingPanelR.position.set(-0.012, -0.045, -0.04);
  wingPanelR.rotation.set(deg(-12), 0, 0);
  wingPanelR.scale.set(0.28, 0.55, 1.05);
  wingR.add(wingPanelR);
  const head = new THREE.Group();
  head.name = 'head';
  head.position.set(0, 0.2741, 0.11);
  duck.add(head);
  const neck = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.065, 0.075, 8), downMat);
  neck.name = 'neck';
  neck.position.set(0, 0.0375, 0);
  head.add(neck);
  const skull = new THREE.Mesh(new THREE.SphereGeometry(0.13, 10, 7), downMat);
  skull.name = 'skull';
  skull.position.set(0, 0.1465, 0.02);
  head.add(skull);
  const bill = new THREE.Mesh(new THREE.SphereGeometry(0.0806, 8, 4), billMat);
  bill.name = 'bill';
  bill.position.set(0, 0.1244, 0.1474);
  bill.scale.set(1, 0.32, 1.15);
  head.add(bill);
  const eyeL = new THREE.Mesh(sphereGeo2, eyeMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.0806, 0.1764, 0.1136);
  head.add(eyeL);
  const eyeShineL = new THREE.Mesh(sphereGeo3, whiteMat);
  eyeShineL.name = 'eyeShineL';
  eyeShineL.position.set(0.0903, 0.1855, 0.1266);
  head.add(eyeShineL);
  const eyeR = new THREE.Mesh(sphereGeo2, eyeMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.0806, 0.1764, 0.1136);
  head.add(eyeR);
  const eyeShineR = new THREE.Mesh(sphereGeo3, whiteMat);
  eyeShineR.name = 'eyeShineR';
  eyeShineR.position.set(-0.0903, 0.1855, 0.1266);
  head.add(eyeShineR);
  const tuft = new THREE.Mesh(new THREE.ConeGeometry(0.025, 0.05, 4), downMat);
  tuft.name = 'tuft';
  tuft.position.set(0, 0.27, 0.01);
  tuft.rotation.set(deg(-20), 0, 0);
  head.add(tuft);

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

export default createDuck;
```

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