# Penguin

> A chubby, egg-shaped low-poly penguin with a white belly and face, orange beak and feet, rosy cheeks and little flippers. Dress it up with a cozy scarf or a pom-pom beanie for winter and Christmas levels. Flippers and feet are pivoted groups for waddle animations in snow, ice and arctic games.

![Penguin preview](https://codels.download/m/penguin.png)

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

## Facts

- Category: Characters › Animals
- Size (W × H × D): 0.56 × 0.56 × 0.51 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,072 · Meshes: 17 · Materials: 8
- License: CC0-1.0 (Codels built-in)
- Tags: bird, penguin, cartoon, low-poly, stylized, christmas, ocean, snow, adventure, party-game, platformer, animal, npc, game-ready, mobile-friendly, parametric, color-blue, color-white, size-small, poly-low
- Page: https://codels.download/models/penguin

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `back` | color | #rrggbb | #2c3550 | #2c3550 |
| `accessory` | select | none \| scarf \| beanie | scarf | scarf |
| `accent` | color | #rrggbb | #e2473f | #e2473f |

## Parts

- footL (group)
  - footPadL (sphere · beak)
- footR (group)
  - footPadR (sphere · beak)
- body (group)
  - torso (lathe · back)
  - belly (lathe · belly)
  - crownPeak (sphere · back)
- face (group)
  - eyeL (sphere · eye)
  - eyeShineL (sphere · shine)
  - cheekL (sphere · blush)
  - eyeR (sphere · eye)
  - eyeShineR (sphere · shine)
  - cheekR (sphere · blush)
  - beak (cone · beak)
- flipperL (group)
  - flipperPanelL (sphere · back)
- flipperR (group)
  - flipperPanelR (sphere · back)
- scarf (group)
  - scarfWrap (torus · accent)
  - scarfTail (group)
    - scarfEnd (box · accent)
    - scarfStripe (box · accent2)

## How to use

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

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

## Code

```js
/**
 * Penguin — Codels 3D model library (https://codels.download/models/penguin)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,072 · Size (W × H × D): 0.56 × 0.56 × 0.51 m
 *
 * Usage:
 *   import { createPenguin } from './penguin.js';
 *   
 *   const model = createPenguin();
 *   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);
}

export function createPenguin() {
  const root = new THREE.Group();
  root.name = 'Penguin';

  // Materials
  const backMat = new THREE.MeshStandardMaterial({ name: 'back', color: 0x2c3550, roughness: 0.6, flatShading: true });
  const bellyMat = new THREE.MeshStandardMaterial({ name: 'belly', color: 0xf5f3ee, roughness: 0.7, flatShading: true });
  const beakMat = new THREE.MeshStandardMaterial({ name: 'beak', color: 0xf5a131, roughness: 0.5, flatShading: true });
  const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0x151318, roughness: 0.25, flatShading: true });
  const shineMat = new THREE.MeshStandardMaterial({ name: 'shine', color: 0xffffff, roughness: 0.3, flatShading: true });
  const blushMat = new THREE.MeshStandardMaterial({ name: 'blush', color: 0xf2a2a8, roughness: 0.7, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xe2473f, roughness: 0.9, flatShading: true });
  const accent2Mat = new THREE.MeshStandardMaterial({ name: 'accent2', color: 0xf6f2ea, roughness: 0.95, flatShading: true });

  // Shared geometries
  const sphereGeo = new THREE.SphereGeometry(0.06, 8, 4);
  const latheGeo = lathe([[0, 0], [0.13, 0.012], [0.195, 0.07], [0.215, 0.17], [0.205, 0.28], [0.175, 0.38], [0.13, 0.46], [0.065, 0.51], [0, 0.525]], 12);
  const sphereGeo2 = new THREE.SphereGeometry(0.03, 6, 6);
  const sphereGeo3 = new THREE.SphereGeometry(0.009, 4, 3);
  const sphereGeo4 = new THREE.SphereGeometry(0.028, 6, 4);
  const sphereGeo5 = new THREE.SphereGeometry(0.1, 8, 5);

  // Parts
  const footL = new THREE.Group();
  footL.name = 'footL';
  footL.position.set(0.08, 0.03, 0.06);
  root.add(footL);
  const footPadL = new THREE.Mesh(sphereGeo, beakMat);
  footPadL.name = 'footPadL';
  footPadL.position.set(0, 0, 0.05);
  footPadL.scale.set(0.9, 0.5, 1.3);
  footL.add(footPadL);
  const footR = new THREE.Group();
  footR.name = 'footR';
  footR.position.set(-0.08, 0.03, 0.06);
  root.add(footR);
  const footPadR = new THREE.Mesh(sphereGeo, beakMat);
  footPadR.name = 'footPadR';
  footPadR.position.set(0, 0, 0.05);
  footPadR.scale.set(0.9, 0.5, 1.3);
  footR.add(footPadR);
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const torso = new THREE.Mesh(latheGeo, backMat);
  torso.name = 'torso';
  torso.position.set(0, 0.03, 0);
  body.add(torso);
  const belly = new THREE.Mesh(latheGeo, bellyMat);
  belly.name = 'belly';
  belly.position.set(0, 0.03, 0.042);
  belly.scale.set(0.8, 0.86, 1);
  body.add(belly);
  const crownPeak = new THREE.Mesh(new THREE.SphereGeometry(0.06, 6, 4), backMat);
  crownPeak.name = 'crownPeak';
  crownPeak.position.set(0, 0.46, 0.0901);
  crownPeak.scale.set(1, 1.1, 0.8);
  body.add(crownPeak);
  const face = new THREE.Group();
  face.name = 'face';
  root.add(face);
  const eyeL = new THREE.Mesh(sphereGeo2, eyeMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.058, 0.39, 0.1733);
  eyeL.rotation.set(0, deg(18), 0);
  eyeL.scale.set(0.85, 1.15, 0.5);
  face.add(eyeL);
  const eyeShineL = new THREE.Mesh(sphereGeo3, shineMat);
  eyeShineL.name = 'eyeShineL';
  eyeShineL.position.set(0.062, 0.406, 0.1863);
  face.add(eyeShineL);
  const cheekL = new THREE.Mesh(sphereGeo4, blushMat);
  cheekL.name = 'cheekL';
  cheekL.position.set(0.088, 0.358, 0.1749);
  cheekL.rotation.set(0, deg(38), 0);
  cheekL.scale.set(1, 0.55, 0.4);
  face.add(cheekL);
  const eyeR = new THREE.Mesh(sphereGeo2, eyeMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.058, 0.39, 0.1733);
  eyeR.rotation.set(0, deg(-18), 0);
  eyeR.scale.set(0.85, 1.15, 0.5);
  face.add(eyeR);
  const eyeShineR = new THREE.Mesh(sphereGeo3, shineMat);
  eyeShineR.name = 'eyeShineR';
  eyeShineR.position.set(-0.062, 0.406, 0.1863);
  face.add(eyeShineR);
  const cheekR = new THREE.Mesh(sphereGeo4, blushMat);
  cheekR.name = 'cheekR';
  cheekR.position.set(-0.088, 0.358, 0.1749);
  cheekR.rotation.set(0, deg(-38), 0);
  cheekR.scale.set(1, 0.55, 0.4);
  face.add(cheekR);
  const beak = new THREE.Mesh(new THREE.ConeGeometry(0.042, 0.085, 6), beakMat);
  beak.name = 'beak';
  beak.position.set(0, 0.345, 0.2411);
  beak.rotation.set(deg(90), 0, 0);
  beak.scale.set(1.25, 1, 0.7);
  face.add(beak);
  const flipperL = new THREE.Group();
  flipperL.name = 'flipperL';
  flipperL.position.set(0.189, 0.33, -0.01);
  flipperL.rotation.set(0, 0, deg(22));
  root.add(flipperL);
  const flipperPanelL = new THREE.Mesh(sphereGeo5, backMat);
  flipperPanelL.name = 'flipperPanelL';
  flipperPanelL.position.set(0.01, -0.09, 0);
  flipperPanelL.scale.set(0.28, 1, 0.55);
  flipperL.add(flipperPanelL);
  const flipperR = new THREE.Group();
  flipperR.name = 'flipperR';
  flipperR.position.set(-0.189, 0.33, -0.01);
  flipperR.rotation.set(0, 0, deg(-22));
  root.add(flipperR);
  const flipperPanelR = new THREE.Mesh(sphereGeo5, backMat);
  flipperPanelR.name = 'flipperPanelR';
  flipperPanelR.position.set(-0.01, -0.09, 0);
  flipperPanelR.scale.set(0.28, 1, 0.55);
  flipperR.add(flipperPanelR);
  const scarf = new THREE.Group();
  scarf.name = 'scarf';
  scarf.position.set(0, 0.28, 0);
  root.add(scarf);
  const scarfWrap = new THREE.Mesh(new THREE.TorusGeometry(0.2037, 0.03, 6, 14), accentMat);
  scarfWrap.name = 'scarfWrap';
  scarfWrap.position.set(0, 0, 0.02);
  scarfWrap.rotation.set(deg(90), 0, 0);
  scarfWrap.scale.set(1, 1.1, 1);
  scarf.add(scarfWrap);
  const scarfTail = new THREE.Group();
  scarfTail.name = 'scarfTail';
  scarfTail.position.set(0.1, -0.01, 0.2028);
  scarfTail.rotation.set(deg(10), deg(28), deg(8));
  scarf.add(scarfTail);
  const scarfEnd = new THREE.Mesh(new THREE.BoxGeometry(0.065, 0.15, 0.026), accentMat);
  scarfEnd.name = 'scarfEnd';
  scarfEnd.position.set(0, -0.075, 0);
  scarfTail.add(scarfEnd);
  const scarfStripe = new THREE.Mesh(new THREE.BoxGeometry(0.067, 0.022, 0.028), accent2Mat);
  scarfStripe.name = 'scarfStripe';
  scarfStripe.position.set(0, -0.12, 0);
  scarfTail.add(scarfStripe);

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

export default createPenguin;
```

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