1.1K tris0.56 × 0.56 × 0.51 m
Use it in code
Remix in the editorpenguin.js · 175 lines
Self-contained ES module — only depends on three. Call the factory and add the group to your scene.
/**
* Penguin — Codels 3D model library
* 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;
Ratings & comments
0 comments
No comments yet. Share how you used this model or what could be better.
Related models
Same category or similar tags









