# Soda Can

> A glossy aluminum soda can (12 oz, about 12 cm tall): lathe-turned body with a domed bottom, a necked shoulder and rolled rim, a painted color body wrapped by a dynamic tilted accent stripe, a front logo panel with a star and a pull tab on the recessed lid. Toggle it open to lift the tab and show the dark drinking hole. Great for vending machines, kitchens, picnics, energy-drink pickups and city litter.

![Soda Can preview](https://codels.download/m/soda-can.png)

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

## Facts

- Category: Food & Drink › Drinks
- Size (W × H × D): 0.07 × 0.12 × 0.07 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 944 · Meshes: 11 · Materials: 4
- License: CC0-1.0 (Codels built-in)
- Tags: aluminum-can, beverage-can, drink, soda, cartoon, low-poly, stylized, kitchen, modern, summer, city, party-game, collectible, food, pickup, prop, metal, round, game-ready, mobile-friendly, parametric, color-red, color-white, size-tiny, poly-low
- Page: https://codels.download/models/soda-can

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `color` | color | #rrggbb | #d62f35 | #d62f35 |
| `accent` | color | #rrggbb | #ffffff | #ffffff |
| `opened` | boolean | true \| false | false | false |

## Parts

- bottom (lathe · alu)
- body (lathe · paint)
- top (lathe · alu)
- stripe (group)
  - stripeBand (cylinder · accent)
- stripeThin (group)
  - stripeThinBand (cylinder · accent)
- logoPanel (cylinder · accent)
- logoStar (extrude · logo)
- logoLine (cylinder · logo)
- tearPanel (extrude · alu)
- rivet (cylinder · alu)
- tabHinge (group)
  - tab (extrude · alu)

## How to use

Save the code below as `soda-can.js`, then:

```js
import { createSodaCan } from './soda-can.js';
const model = createSodaCan();
scene.add(model);
```

## Code

```js
/**
 * Soda Can — Codels 3D model library (https://codels.download/models/soda-can)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 944 · Size (W × H × D): 0.07 × 0.12 × 0.07 m
 *
 * Usage:
 *   import { createSodaCan } from './soda-can.js';
 *   
 *   const model = createSodaCan();
 *   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);
}

// 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 createSodaCan() {
  const root = new THREE.Group();
  root.name = 'SodaCan';

  // Materials
  const aluMat = new THREE.MeshStandardMaterial({ name: 'alu', color: 0xc9ced6, roughness: 0.3, metalness: 0.85, flatShading: true });
  const paintMat = new THREE.MeshStandardMaterial({ name: 'paint', color: 0xd62f35, roughness: 0.3, metalness: 0.35 });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xffffff, roughness: 0.35, metalness: 0.2 });
  const logoMat = new THREE.MeshStandardMaterial({ name: 'logo', color: 0xf5a93d, roughness: 0.35, metalness: 0.2, flatShading: true });

  // Parts
  const bottom = new THREE.Mesh(lathe([[0, 0.006], [0.018, 0.0035], [0.025, 0], [0.029, 0.0015], [0.0325, 0.007], [0.033, 0.012]], 24), aluMat);
  bottom.name = 'bottom';
  root.add(bottom);
  const body = new THREE.Mesh(lathe([[0.033, 0.012], [0.033, 0.104]], 24), paintMat);
  body.name = 'body';
  root.add(body);
  const top = new THREE.Mesh(lathe([[0.033, 0.104], [0.0325, 0.108], [0.0295, 0.1135], [0.0272, 0.1185], [0.0276, 0.1215], [0.026, 0.1225], [0.0252, 0.1195], [0.0245, 0.1175], [0, 0.1175]], 24), aluMat);
  top.name = 'top';
  root.add(top);
  const stripe = new THREE.Group();
  stripe.name = 'stripe';
  stripe.position.set(0, 0.052, 0);
  stripe.rotation.set(deg(49.0795), 0, 0);
  stripe.scale.set(1, 0.8669, 1.1536);
  root.add(stripe);
  const stripeBand = new THREE.Mesh(new THREE.CylinderGeometry(0.0335, 0.0335, 0.012, 24, 1, true), accentMat);
  stripeBand.name = 'stripeBand';
  stripeBand.rotation.set(deg(-40.9205), 0, 0);
  stripe.add(stripeBand);
  const stripeThin = new THREE.Group();
  stripeThin.name = 'stripeThin';
  stripeThin.position.set(0, 0.068, 0);
  stripeThin.rotation.set(deg(49.0795), 0, 0);
  stripeThin.scale.set(1, 0.8669, 1.1536);
  root.add(stripeThin);
  const stripeThinBand = new THREE.Mesh(new THREE.CylinderGeometry(0.0335, 0.0335, 0.0035, 24, 1, true), accentMat);
  stripeThinBand.name = 'stripeThinBand';
  stripeThinBand.rotation.set(deg(-40.9205), 0, 0);
  stripeThin.add(stripeThinBand);
  const logoPanel = new THREE.Mesh(new THREE.CylinderGeometry(0.0339, 0.0339, 0.03, 8, 1, true, -0.42, 0.84), accentMat);
  logoPanel.name = 'logoPanel';
  logoPanel.position.set(0, 0.083, 0);
  root.add(logoPanel);
  const logoStar = new THREE.Mesh(extrude([[0, 0.0085], [-0.0022, 0.0031], [-0.0081, 0.0026], [-0.0036, -0.0012], [-0.005, -0.0069], [0, -0.0038], [0.005, -0.0069], [0.0036, -0.0012], [0.0081, 0.0026], [0.0022, 0.0031]], 0.002), logoMat);
  logoStar.name = 'logoStar';
  logoStar.position.set(0, 0.083, 0.0338);
  root.add(logoStar);
  const logoLine = new THREE.Mesh(new THREE.CylinderGeometry(0.0339, 0.0339, 0.004, 8, 1, true, -0.42, 0.84), logoMat);
  logoLine.name = 'logoLine';
  logoLine.position.set(0, 0.029, 0);
  root.add(logoLine);
  const tearPanel = new THREE.Mesh(extrude([[-0.008, 0.004], [0.008, 0.004], [0.0095, 0.012], [0.006, 0.018], [-0.006, 0.018], [-0.0095, 0.012]], 0.0008), aluMat);
  tearPanel.name = 'tearPanel';
  tearPanel.position.set(0, 0.1179, 0);
  tearPanel.rotation.set(deg(-90), 0, deg(180));
  root.add(tearPanel);
  const rivet = new THREE.Mesh(new THREE.CylinderGeometry(0.0022, 0.0022, 0.0016, 8), aluMat);
  rivet.name = 'rivet';
  rivet.position.set(0, 0.1183, 0);
  root.add(rivet);
  const tabHinge = new THREE.Group();
  tabHinge.name = 'tabHinge';
  tabHinge.position.set(0, 0.1193, 0);
  tabHinge.rotation.set(deg(2), 0, 0);
  root.add(tabHinge);
  const tab = new THREE.Mesh(extrude([[-0.006, -0.004], [0.006, -0.004], [0.0075, 0.006], [0.0072, 0.012], [0.004, 0.016], [-0.004, 0.016], [-0.0072, 0.012], [-0.0075, 0.006]], 0.0012, [[[-0.0042, 0.006], [0.0042, 0.006], [0.0045, 0.0105], [0.0025, 0.013], [-0.0025, 0.013], [-0.0045, 0.0105]]]), aluMat);
  tab.name = 'tab';
  tab.rotation.set(deg(-90), 0, 0);
  tabHinge.add(tab);

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

export default createSodaCan;
```

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