# Skateboard

> A stylized street skateboard with a popsicle-shaped deck, kicked nose and tail, inset griptape, mounting bolts, two metal trucks with hangers, kingpins and bushings, and four urethane wheels — groups wheelFL, wheelFR, wheelRL, wheelRR with axles along X so they can spin. Pick the deck and wheel colors and toggle the griptape; great for skate parks, sports games and city props.

![Skateboard preview](https://codels.download/m/skateboard.png)

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

## Facts

- Category: Vehicles › Other Vehicles
- Size (W × H × D): 0.21 × 0.15 × 0.80 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,700 · Meshes: 43 · Materials: 7
- License: CC0-1.0 (Codels built-in)
- Tags: skateboard, skatepark, low-poly, stylized, modern, sports, city, party-game, sports-game, equipment, prop, vehicle, wood, game-ready, parametric, color-gray, color-orange, color-red, size-small, poly-medium
- Page: https://codels.download/models/skateboard

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `deckColor` | color | #rrggbb | #e0533d | #e0533d |
| `wheelColor` | color | #rrggbb | #f2ead2 | #f2ead2 |
| `griptape` | boolean | true \| false | true | true |

## Parts

- body (group)
  - deck (box · deck)
  - plyEdge (box · ply)
  - nose (group)
    - noseDeck (extrude · deck)
    - noseGrip (extrude · grip)
  - tail (group)
    - tailDeck (extrude · deck)
    - tailGrip (extrude · grip)
  - griptapeL (box · grip)
  - griptapeR (box · grip)
  - truckFront (group)
    - baseplate (box · metal)
    - kingpin (cylinder · metal)
    - bushing (cylinder · bushing)
    - pivot (cylinder · dark)
    - hanger (extrude · metal)
    - axle (cylinder · metal)
  - truckRear (group)
    - baseplate (box · metal)
    - kingpin (cylinder · metal)
    - bushing (cylinder · bushing)
    - pivot (cylinder · dark)
    - hanger (extrude · metal)
    - axle (cylinder · metal)
- wheels (group)
  - wheelFL (group)
    - urethane (lathe · wheel)
    - bearing (cylinder · metal)
    - axleNut (cylinder · metal)
  - wheelFR (group)
    - urethane (lathe · wheel)
    - bearing (cylinder · metal)
    - axleNut (cylinder · metal)
  - wheelRL (group)
    - urethane (lathe · wheel)
    - bearing (cylinder · metal)
    - axleNut (cylinder · metal)
  - wheelRR (group)
    - urethane (lathe · wheel)

## How to use

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

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

## Code

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

  // Materials
  const deckMat = new THREE.MeshStandardMaterial({ name: 'deck', color: 0xe0533d, roughness: 0.6, flatShading: true });
  const plyMat = new THREE.MeshStandardMaterial({ name: 'ply', color: 0xd8b98a, roughness: 0.8, flatShading: true });
  const gripMat = new THREE.MeshStandardMaterial({ name: 'grip', color: 0x1f2023, roughness: 1, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0xb4b9bf, roughness: 0.35, metalness: 0.7, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x3a3c40, roughness: 0.6, metalness: 0.3, flatShading: true });
  const bushingMat = new THREE.MeshStandardMaterial({ name: 'bushing', color: 0xf2c21b, roughness: 0.7, flatShading: true });
  const wheelMat = new THREE.MeshStandardMaterial({ name: 'wheel', color: 0xf2ead2, roughness: 0.55, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.0785, 0.002, 0.472);
  const boxGeo2 = new THREE.BoxGeometry(0.175, 0.001, 0.025);
  const boxGeo3 = new THREE.BoxGeometry(0.058, 0.01, 0.088);
  const boxGeo4 = new THREE.BoxGeometry(0.007, 0.002, 0.007);
  const cylinderGeo = new THREE.CylinderGeometry(0.004, 0.004, 0.045, 6);
  const cylinderGeo2 = new THREE.CylinderGeometry(0.011, 0.012, 0.012, 8);
  const cylinderGeo3 = new THREE.CylinderGeometry(0.006, 0.006, 0.02, 6);
  const extrudeGeo = extrude([[-0.066, -0.008], [0.066, -0.008], [0.03, 0.026], [-0.03, 0.026]], 0.024, [], [0.002, 0.002, 1]);
  const cylinderGeo4 = new THREE.CylinderGeometry(0.004, 0.004, 0.2, 6);
  const latheGeo = lathe([[0.0135, -0.012], [0.0135, -0.016], [0.02, -0.016], [0.027, -0.009], [0.027, 0.009], [0.02, 0.016], [0.0135, 0.016], [0.0135, 0.012]], 14);
  const cylinderGeo5 = new THREE.CylinderGeometry(0.0135, 0.0135, 0.024, 10);
  const cylinderGeo6 = new THREE.CylinderGeometry(0.006, 0.006, 0.01, 6);

  // Parts
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const deck = new THREE.Mesh(new THREE.BoxGeometry(0.205, 0.012, 0.47), deckMat);
  deck.name = 'deck';
  deck.position.set(0, 0.089, 0);
  body.add(deck);
  const plyEdge = new THREE.Mesh(new THREE.BoxGeometry(0.207, 0.003, 0.47), plyMat);
  plyEdge.name = 'plyEdge';
  plyEdge.position.set(0, 0.0845, 0);
  body.add(plyEdge);
  const nose = new THREE.Group();
  nose.name = 'nose';
  nose.position.set(0, 0.089, 0.235);
  nose.rotation.set(deg(-19), 0, 0);
  body.add(nose);
  const noseDeck = new THREE.Mesh(extrude([[-0.1025, 0], [0.1025, 0], [0.1025, 0.07], [0.0975, 0.1017], [0.0829, 0.1302], [0.0602, 0.1529], [0.0317, 0.1675], [0, 0.1725], [-0.0317, 0.1675], [-0.0602, 0.1529], [-0.0829, 0.1302], [-0.0975, 0.1017], [-0.1025, 0.07]], 0.012), deckMat);
  noseDeck.name = 'noseDeck';
  noseDeck.rotation.set(deg(90), 0, 0);
  nose.add(noseDeck);
  const noseGrip = new THREE.Mesh(extrude([[-0.0945, 0], [0.0945, 0], [0.0945, 0.07], [0.0899, 0.0992], [0.0765, 0.1255], [0.0555, 0.1465], [0.0292, 0.1599], [0, 0.1645], [-0.0292, 0.1599], [-0.0555, 0.1465], [-0.0765, 0.1255], [-0.0899, 0.0992], [-0.0945, 0.07]], 0.002), gripMat);
  noseGrip.name = 'noseGrip';
  noseGrip.position.set(0, 0.007, 0.002);
  noseGrip.rotation.set(deg(90), 0, 0);
  nose.add(noseGrip);
  const tail = new THREE.Group();
  tail.name = 'tail';
  tail.position.set(0, 0.089, -0.235);
  tail.rotation.set(deg(19), 0, 0);
  body.add(tail);
  const tailDeck = new THREE.Mesh(extrude([[-0.1025, 0], [0.1025, 0], [0.1025, -0.07], [0.0975, -0.1017], [0.0829, -0.1302], [0.0602, -0.1529], [0.0317, -0.1675], [0, -0.1725], [-0.0317, -0.1675], [-0.0602, -0.1529], [-0.0829, -0.1302], [-0.0975, -0.1017], [-0.1025, -0.07]], 0.012), deckMat);
  tailDeck.name = 'tailDeck';
  tailDeck.rotation.set(deg(90), 0, 0);
  tail.add(tailDeck);
  const tailGrip = new THREE.Mesh(extrude([[-0.0945, 0], [0.0945, 0], [0.0945, -0.07], [0.0899, -0.0992], [0.0765, -0.1255], [0.0555, -0.1465], [0.0292, -0.1599], [0, -0.1645], [-0.0292, -0.1599], [-0.0555, -0.1465], [-0.0765, -0.1255], [-0.0899, -0.0992], [-0.0945, -0.07]], 0.002), gripMat);
  tailGrip.name = 'tailGrip';
  tailGrip.position.set(0, 0.007, -0.002);
  tailGrip.rotation.set(deg(90), 0, 0);
  tail.add(tailGrip);
  const griptapeL = new THREE.Mesh(boxGeo, gripMat);
  griptapeL.name = 'griptapeL';
  griptapeL.position.set(0.0553, 0.096, 0);
  body.add(griptapeL);
  const griptapeR = new THREE.Mesh(boxGeo, gripMat);
  griptapeR.name = 'griptapeR';
  griptapeR.position.set(-0.0552, 0.096, 0);
  body.add(griptapeR);
  const box12 = new THREE.Mesh(boxGeo2, plyMat);
  box12.position.set(0, 0.0825, -0.06);
  body.add(box12);
  const box13 = new THREE.Mesh(boxGeo2, plyMat);
  box13.position.set(0, 0.0825, 0);
  body.add(box13);
  const box14 = new THREE.Mesh(boxGeo2, plyMat);
  box14.position.set(0, 0.0825, 0.06);
  body.add(box14);
  const truckFront = new THREE.Group();
  truckFront.name = 'truckFront';
  truckFront.position.set(0, 0, 0.2);
  body.add(truckFront);
  const baseplate = new THREE.Mesh(boxGeo3, metalMat);
  baseplate.name = 'baseplate';
  baseplate.position.set(0, 0.078, 0);
  truckFront.add(baseplate);
  const box17 = new THREE.Mesh(boxGeo4, metalMat);
  box17.position.set(0.02, 0.098, 0.03);
  truckFront.add(box17);
  const box18 = new THREE.Mesh(boxGeo4, metalMat);
  box18.position.set(0.02, 0.098, -0.03);
  truckFront.add(box18);
  const box19 = new THREE.Mesh(boxGeo4, metalMat);
  box19.position.set(-0.02, 0.098, 0.03);
  truckFront.add(box19);
  const box20 = new THREE.Mesh(boxGeo4, metalMat);
  box20.position.set(-0.02, 0.098, -0.03);
  truckFront.add(box20);
  const kingpin = new THREE.Mesh(cylinderGeo, metalMat);
  kingpin.name = 'kingpin';
  kingpin.position.set(0, 0.057, -0.012);
  kingpin.rotation.set(deg(35), 0, 0);
  truckFront.add(kingpin);
  const bushing = new THREE.Mesh(cylinderGeo2, bushingMat);
  bushing.name = 'bushing';
  bushing.position.set(0, 0.063, -0.009);
  bushing.rotation.set(deg(35), 0, 0);
  truckFront.add(bushing);
  const pivot = new THREE.Mesh(cylinderGeo3, darkMat);
  pivot.name = 'pivot';
  pivot.position.set(0, 0.065, 0.022);
  pivot.rotation.set(deg(-50), 0, 0);
  truckFront.add(pivot);
  const hanger = new THREE.Mesh(extrudeGeo, metalMat);
  hanger.name = 'hanger';
  hanger.position.set(0, 0.027, 0);
  truckFront.add(hanger);
  const axle = new THREE.Mesh(cylinderGeo4, metalMat);
  axle.name = 'axle';
  axle.position.set(0, 0.027, 0);
  axle.rotation.set(0, 0, deg(90));
  truckFront.add(axle);
  const truckRear = new THREE.Group();
  truckRear.name = 'truckRear';
  truckRear.position.set(0, 0, -0.2);
  body.add(truckRear);
  const baseplate2 = new THREE.Mesh(boxGeo3, metalMat);
  baseplate2.name = 'baseplate';
  baseplate2.position.set(0, 0.078, 0);
  truckRear.add(baseplate2);
  const box28 = new THREE.Mesh(boxGeo4, metalMat);
  box28.position.set(0.02, 0.098, 0.03);
  truckRear.add(box28);
  const box29 = new THREE.Mesh(boxGeo4, metalMat);
  box29.position.set(0.02, 0.098, -0.03);
  truckRear.add(box29);
  const box30 = new THREE.Mesh(boxGeo4, metalMat);
  box30.position.set(-0.02, 0.098, 0.03);
  truckRear.add(box30);
  const box31 = new THREE.Mesh(boxGeo4, metalMat);
  box31.position.set(-0.02, 0.098, -0.03);
  truckRear.add(box31);
  const kingpin2 = new THREE.Mesh(cylinderGeo, metalMat);
  kingpin2.name = 'kingpin';
  kingpin2.position.set(0, 0.057, 0.012);
  kingpin2.rotation.set(deg(-35), 0, 0);
  truckRear.add(kingpin2);
  const bushing2 = new THREE.Mesh(cylinderGeo2, bushingMat);
  bushing2.name = 'bushing';
  bushing2.position.set(0, 0.063, 0.009);
  bushing2.rotation.set(deg(-35), 0, 0);
  truckRear.add(bushing2);
  const pivot2 = new THREE.Mesh(cylinderGeo3, darkMat);
  pivot2.name = 'pivot';
  pivot2.position.set(0, 0.065, -0.022);
  pivot2.rotation.set(deg(50), 0, 0);
  truckRear.add(pivot2);
  const hanger2 = new THREE.Mesh(extrudeGeo, metalMat);
  hanger2.name = 'hanger';
  hanger2.position.set(0, 0.027, 0);
  truckRear.add(hanger2);
  const axle2 = new THREE.Mesh(cylinderGeo4, metalMat);
  axle2.name = 'axle';
  axle2.position.set(0, 0.027, 0);
  axle2.rotation.set(0, 0, deg(90));
  truckRear.add(axle2);
  const wheels = new THREE.Group();
  wheels.name = 'wheels';
  root.add(wheels);
  const wheelFL = new THREE.Group();
  wheelFL.name = 'wheelFL';
  wheelFL.position.set(0.084, 0.027, 0.2);
  wheels.add(wheelFL);
  const urethane = new THREE.Mesh(latheGeo, wheelMat);
  urethane.name = 'urethane';
  urethane.rotation.set(0, 0, deg(90));
  wheelFL.add(urethane);
  const bearing = new THREE.Mesh(cylinderGeo5, metalMat);
  bearing.name = 'bearing';
  bearing.rotation.set(0, 0, deg(90));
  wheelFL.add(bearing);
  const axleNut = new THREE.Mesh(cylinderGeo6, metalMat);
  axleNut.name = 'axleNut';
  axleNut.position.set(0.016, 0, 0);
  axleNut.rotation.set(0, 0, deg(90));
  wheelFL.add(axleNut);
  const wheelFR = new THREE.Group();
  wheelFR.name = 'wheelFR';
  wheelFR.position.set(-0.084, 0.027, 0.2);
  wheels.add(wheelFR);
  const urethane2 = new THREE.Mesh(latheGeo, wheelMat);
  urethane2.name = 'urethane';
  urethane2.rotation.set(0, 0, deg(90));
  wheelFR.add(urethane2);
  const bearing2 = new THREE.Mesh(cylinderGeo5, metalMat);
  bearing2.name = 'bearing';
  bearing2.rotation.set(0, 0, deg(90));
  wheelFR.add(bearing2);
  const axleNut2 = new THREE.Mesh(cylinderGeo6, metalMat);
  axleNut2.name = 'axleNut';
  axleNut2.position.set(-0.016, 0, 0);
  axleNut2.rotation.set(0, 0, deg(90));
  wheelFR.add(axleNut2);
  const wheelRL = new THREE.Group();
  wheelRL.name = 'wheelRL';
  wheelRL.position.set(0.084, 0.027, -0.2);
  wheels.add(wheelRL);
  const urethane3 = new THREE.Mesh(latheGeo, wheelMat);
  urethane3.name = 'urethane';
  urethane3.rotation.set(0, 0, deg(90));
  wheelRL.add(urethane3);
  const bearing3 = new THREE.Mesh(cylinderGeo5, metalMat);
  bearing3.name = 'bearing';
  bearing3.rotation.set(0, 0, deg(90));
  wheelRL.add(bearing3);
  const axleNut3 = new THREE.Mesh(cylinderGeo6, metalMat);
  axleNut3.name = 'axleNut';
  axleNut3.position.set(0.016, 0, 0);
  axleNut3.rotation.set(0, 0, deg(90));
  wheelRL.add(axleNut3);
  const wheelRR = new THREE.Group();
  wheelRR.name = 'wheelRR';
  wheelRR.position.set(-0.084, 0.027, -0.2);
  wheels.add(wheelRR);
  const urethane4 = new THREE.Mesh(latheGeo, wheelMat);
  urethane4.name = 'urethane';
  urethane4.rotation.set(0, 0, deg(90));
  wheelRR.add(urethane4);
  const bearing4 = new THREE.Mesh(cylinderGeo5, metalMat);
  bearing4.name = 'bearing';
  bearing4.rotation.set(0, 0, deg(90));
  wheelRR.add(bearing4);
  const axleNut4 = new THREE.Mesh(cylinderGeo6, metalMat);
  axleNut4.name = 'axleNut';
  axleNut4.position.set(-0.016, 0, 0);
  axleNut4.rotation.set(0, 0, deg(90));
  wheelRR.add(axleNut4);

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

export default createSkateboard;
```

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