# Formula Race Car

> A stylized open-wheel formula race car with a slim nose, sidepods, airbox, front and rear wings, exposed suspension arms, a helmeted driver and fat racing slicks. Set the livery, accent and number colors plus a parametric 1–99 racing number. Wheels are named groups for spinning — perfect for racing and arcade games.

![Formula Race Car preview](https://codels.download/m/race-car.png)

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

## Facts

- Category: Vehicles › Cars & Trucks
- Size (W × H × D): 1.98 × 1.06 × 4.48 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 2,304 · Meshes: 61 · Materials: 6
- License: CC0-1.0 (Codels built-in)
- Tags: car, fast, race-car, low-poly, stylized, racing, sports, road, racing-game, sports-game, hero-asset, vehicle, game-ready, parametric, color-blue, color-gray, color-orange, size-large, poly-medium
- Page: https://codels.download/models/race-car

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `bodyColor` | color | #rrggbb | #2456b5 | #2456b5 |
| `accentColor` | color | #rrggbb | #ffc933 | #ffc933 |
| `numberColor` | color | #rrggbb | #1d1f24 | #1d1f24 |
| `number` | int | 1 – 99 | 7 | 7 |

## Parts

- body (group)
  - tub (extrude · paint)
  - airboxIntake (box · trim)
  - nose (extrude · paint)
  - noseTip (box · accent)
  - sidepodL (extrude · paint)
  - intakeL (box · trim)
  - roundelL (cylinder · white)
  - sidepodR (extrude · paint)
  - intakeR (box · trim)
  - roundelR (cylinder · white)
  - floor (box · trim)
  - helmet (sphere · accent)
  - visor (box · trim)
  - windscreen (box · trim)
  - frontWing (group)
  - rearWing (group)
    - diffuser (box · trim)
    - rainLight (box · rainLight)
- wheels (group)
  - wheelFL (group)
    - tire (lathe · trim)
    - rim (cylinder · accent)
    - wheelNut (cylinder · trim)
  - wheelFR (group)
    - tire (lathe · trim)
    - rim (cylinder · accent)
    - wheelNut (cylinder · trim)
  - wheelRL (group)
    - tire (lathe · trim)
    - rim (cylinder · accent)
    - wheelNut (cylinder · trim)
  - wheelRR (group)
    - tire (lathe · trim)
    - rim (cylinder · accent)
    - wheelNut (cylinder · trim)

## How to use

Save the code below as `race-car.js`, then:

```js
import { createRaceCar } from './race-car.js';
const model = createRaceCar();
scene.add(model);
```

## Code

```js
/**
 * Formula Race Car — Codels 3D model library (https://codels.download/models/race-car)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 2,304 · Size (W × H × D): 1.98 × 1.06 × 4.48 m
 *
 * Usage:
 *   import { createRaceCar } from './race-car.js';
 *   
 *   const model = createRaceCar();
 *   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);
}

// Tube along a smooth curve through the given points.
function tube(path, radius, tubularSegments, radialSegments, closed = false) {
  const curve = new THREE.CatmullRomCurve3(path.map(([x, y, z]) => new THREE.Vector3(x, y, z)), closed);
  return new THREE.TubeGeometry(curve, tubularSegments, radius, radialSegments, closed);
}

export function createRaceCar() {
  const root = new THREE.Group();
  root.name = 'RaceCar';

  // Materials
  const paintMat = new THREE.MeshStandardMaterial({ name: 'paint', color: 0x2456b5, roughness: 0.35, metalness: 0.15, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xffc933, roughness: 0.4, metalness: 0.1, flatShading: true });
  const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf3f3ef, roughness: 0.5, flatShading: true });
  const numberMat = new THREE.MeshStandardMaterial({ name: 'number', color: 0x1d1f24, roughness: 0.5, flatShading: true });
  const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0x222327, roughness: 0.8, flatShading: true });
  const rainLightMat = new THREE.MeshStandardMaterial({ name: 'rainLight', color: 0xe0202a, roughness: 0.3, emissive: 0xff2020, emissiveIntensity: 0.9, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[0.3, 0.18], [0.3, 0.5], [0.05, 0.55], [-0.4, 0.52], [-0.84, 0.3], [-0.84, 0.18]], 0.3, [], [0.04, 0.04, 2]);
  const boxGeo = new THREE.BoxGeometry(0.26, 0.2, 0.02);
  const cylinderGeo = new THREE.CylinderGeometry(0.15, 0.15, 0.01, 14);
  const boxGeo2 = new THREE.BoxGeometry(0.01, 0.026, 0.09);
  const boxGeo3 = new THREE.BoxGeometry(0.01, 0.085, 0.026);
  const boxGeo4 = new THREE.BoxGeometry(0.012, 0.03, 0.62);
  const boxGeo5 = new THREE.BoxGeometry(0.03, 0.2, 0.5);
  const boxGeo6 = new THREE.BoxGeometry(0.03, 0.18, 0.12);
  const boxGeo7 = new THREE.BoxGeometry(0.03, 0.46, 0.62);
  const latheGeo = lathe([[0.2112, -0.12], [0.2112, -0.15], [0.25, -0.15], [0.3, -0.12], [0.32, -0.07], [0.32, 0.07], [0.3, 0.12], [0.25, 0.15], [0.2112, 0.15], [0.2112, 0.12]], 14);
  const cylinderGeo2 = new THREE.CylinderGeometry(0.2112, 0.2112, 0.24, 14);
  const cylinderGeo3 = new THREE.CylinderGeometry(0.0634, 0.076, 0.06, 6);
  const latheGeo2 = lathe([[0.231, -0.16], [0.231, -0.19], [0.28, -0.19], [0.33, -0.16], [0.35, -0.11], [0.35, 0.11], [0.33, 0.16], [0.28, 0.19], [0.231, 0.19], [0.231, 0.16]], 14);
  const cylinderGeo4 = new THREE.CylinderGeometry(0.231, 0.231, 0.32, 14);
  const cylinderGeo5 = new THREE.CylinderGeometry(0.0693, 0.0832, 0.06, 6);

  // Parts
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const tub = new THREE.Mesh(extrude([[0.8, 0.17], [0.8, 0.55], [0.32, 0.62], [0.24, 0.5], [-0.24, 0.5], [-0.32, 0.92], [-0.6, 0.96], [-1.05, 0.7], [-1.8, 0.48], [-1.86, 0.17]], 0.5, [], [0.06, 0.05, 2]), paintMat);
  tub.name = 'tub';
  tub.rotation.set(0, deg(-90), 0);
  body.add(tub);
  const airboxIntake = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.12, 0.3), trimMat);
  airboxIntake.name = 'airboxIntake';
  airboxIntake.position.set(0, 0.88, -0.4);
  body.add(airboxIntake);
  const nose = new THREE.Mesh(extrude([[2.12, 0.2], [2.14, 0.3], [0.7, 0.58], [0.7, 0.2]], 0.22, [], [0.04, 0.035, 2]), paintMat);
  nose.name = 'nose';
  nose.rotation.set(0, deg(-90), 0);
  body.add(nose);
  const noseTip = new THREE.Mesh(new THREE.BoxGeometry(0.26, 0.05, 0.36), accentMat);
  noseTip.name = 'noseTip';
  noseTip.position.set(0, 0.3, 1.98);
  noseTip.rotation.set(deg(-11), 0, 0);
  body.add(noseTip);
  const sidepodL = new THREE.Mesh(extrudeGeo, paintMat);
  sidepodL.name = 'sidepodL';
  sidepodL.position.set(0.47, 0, 0);
  sidepodL.rotation.set(0, deg(-90), 0);
  body.add(sidepodL);
  const intakeL = new THREE.Mesh(boxGeo, trimMat);
  intakeL.name = 'intakeL';
  intakeL.position.set(0.47, 0.38, 0.35);
  body.add(intakeL);
  const roundelL = new THREE.Mesh(cylinderGeo, whiteMat);
  roundelL.name = 'roundelL';
  roundelL.position.set(0.665, 0.36, -0.2);
  roundelL.rotation.set(0, 0, deg(90));
  body.add(roundelL);
  const box9 = new THREE.Mesh(boxGeo2, numberMat);
  box9.position.set(0.673, 0.432, -0.2);
  body.add(box9);
  const box10 = new THREE.Mesh(boxGeo3, numberMat);
  box10.position.set(0.673, 0.4025, -0.232);
  body.add(box10);
  const box11 = new THREE.Mesh(boxGeo3, numberMat);
  box11.position.set(0.673, 0.3175, -0.232);
  body.add(box11);
  const box12 = new THREE.Mesh(boxGeo4, accentMat);
  box12.position.set(0.666, 0.47, 0);
  body.add(box12);
  const sidepodR = new THREE.Mesh(extrudeGeo, paintMat);
  sidepodR.name = 'sidepodR';
  sidepodR.position.set(-0.47, 0, 0);
  sidepodR.rotation.set(0, deg(-90), 0);
  body.add(sidepodR);
  const intakeR = new THREE.Mesh(boxGeo, trimMat);
  intakeR.name = 'intakeR';
  intakeR.position.set(-0.47, 0.38, 0.35);
  body.add(intakeR);
  const roundelR = new THREE.Mesh(cylinderGeo, whiteMat);
  roundelR.name = 'roundelR';
  roundelR.position.set(-0.665, 0.36, -0.2);
  roundelR.rotation.set(0, 0, deg(90));
  body.add(roundelR);
  const box16 = new THREE.Mesh(boxGeo2, numberMat);
  box16.position.set(-0.673, 0.432, -0.2);
  body.add(box16);
  const box17 = new THREE.Mesh(boxGeo3, numberMat);
  box17.position.set(-0.673, 0.4025, -0.168);
  body.add(box17);
  const box18 = new THREE.Mesh(boxGeo3, numberMat);
  box18.position.set(-0.673, 0.3175, -0.168);
  body.add(box18);
  const box19 = new THREE.Mesh(boxGeo4, accentMat);
  box19.position.set(-0.666, 0.47, 0);
  body.add(box19);
  const floor = new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.04, 2.3), trimMat);
  floor.name = 'floor';
  floor.position.set(0, 0.11, -0.2);
  body.add(floor);
  const helmet = new THREE.Mesh(new THREE.SphereGeometry(0.135, 10, 7), accentMat);
  helmet.name = 'helmet';
  helmet.position.set(0, 0.72, 0.02);
  body.add(helmet);
  const visor = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.06, 0.06), trimMat);
  visor.name = 'visor';
  visor.position.set(0, 0.74, 0.135);
  body.add(visor);
  const windscreen = new THREE.Mesh(new THREE.BoxGeometry(0.26, 0.04, 0.12), trimMat);
  windscreen.name = 'windscreen';
  windscreen.position.set(0, 0.66, 0.36);
  windscreen.rotation.set(deg(-20), 0, 0);
  body.add(windscreen);
  const frontWing = new THREE.Group();
  frontWing.name = 'frontWing';
  body.add(frontWing);
  const box25 = new THREE.Mesh(new THREE.BoxGeometry(1.78, 0.035, 0.42), paintMat);
  box25.position.set(0, 0.11, 2);
  frontWing.add(box25);
  const box26 = new THREE.Mesh(new THREE.BoxGeometry(1.62, 0.03, 0.18), accentMat);
  box26.position.set(0, 0.17, 1.92);
  box26.rotation.set(deg(-14), 0, 0);
  frontWing.add(box26);
  const box27 = new THREE.Mesh(boxGeo5, accentMat);
  box27.position.set(0.9, 0.17, 1.98);
  frontWing.add(box27);
  const box28 = new THREE.Mesh(boxGeo5, accentMat);
  box28.position.set(-0.9, 0.17, 1.98);
  frontWing.add(box28);
  const box29 = new THREE.Mesh(boxGeo6, trimMat);
  box29.position.set(0.12, 0.2, 2);
  frontWing.add(box29);
  const box30 = new THREE.Mesh(boxGeo6, trimMat);
  box30.position.set(-0.12, 0.2, 2);
  frontWing.add(box30);
  const rearWing = new THREE.Group();
  rearWing.name = 'rearWing';
  body.add(rearWing);
  const box32 = new THREE.Mesh(new THREE.BoxGeometry(1, 0.04, 0.38), paintMat);
  box32.position.set(0, 0.92, -1.92);
  rearWing.add(box32);
  const box33 = new THREE.Mesh(new THREE.BoxGeometry(1, 0.03, 0.2), accentMat);
  box33.position.set(0, 1.02, -2);
  box33.rotation.set(deg(16), 0, 0);
  rearWing.add(box33);
  const box34 = new THREE.Mesh(boxGeo7, accentMat);
  box34.position.set(0.515, 0.84, -1.94);
  rearWing.add(box34);
  const box35 = new THREE.Mesh(boxGeo7, accentMat);
  box35.position.set(-0.515, 0.84, -1.94);
  rearWing.add(box35);
  const box36 = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.4, 0.1), trimMat);
  box36.position.set(0, 0.7, -1.86);
  rearWing.add(box36);
  const diffuser = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.18, 0.3), trimMat);
  diffuser.name = 'diffuser';
  diffuser.position.set(0, 0.22, -1.95);
  rearWing.add(diffuser);
  const rainLight = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.07, 0.03), rainLightMat);
  rainLight.name = 'rainLight';
  rainLight.position.set(0, 0.4, -2);
  rearWing.add(rainLight);
  const tube39 = new THREE.Mesh(tube([[0.12, 0.46, 1.44], [0.68, 0.38, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube39);
  const tube40 = new THREE.Mesh(tube([[0.12, 0.46, 1.18], [0.68, 0.38, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube40);
  const tube41 = new THREE.Mesh(tube([[0.12, 0.24, 1.44], [0.68, 0.24, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube41);
  const tube42 = new THREE.Mesh(tube([[0.12, 0.24, 1.18], [0.68, 0.24, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube42);
  const tube43 = new THREE.Mesh(tube([[0.26, 0.5, -1.12], [0.62, 0.42, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube43);
  const tube44 = new THREE.Mesh(tube([[0.26, 0.26, -1.12], [0.62, 0.27, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube44);
  const tube45 = new THREE.Mesh(tube([[0.26, 0.38, -1.6], [0.62, 0.35, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube45);
  const tube46 = new THREE.Mesh(tube([[-0.12, 0.46, 1.44], [-0.68, 0.38, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube46);
  const tube47 = new THREE.Mesh(tube([[-0.12, 0.46, 1.18], [-0.68, 0.38, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube47);
  const tube48 = new THREE.Mesh(tube([[-0.12, 0.24, 1.44], [-0.68, 0.24, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube48);
  const tube49 = new THREE.Mesh(tube([[-0.12, 0.24, 1.18], [-0.68, 0.24, 1.32]], 0.017, 1, 4), trimMat);
  body.add(tube49);
  const tube50 = new THREE.Mesh(tube([[-0.26, 0.5, -1.12], [-0.62, 0.42, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube50);
  const tube51 = new THREE.Mesh(tube([[-0.26, 0.26, -1.12], [-0.62, 0.27, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube51);
  const tube52 = new THREE.Mesh(tube([[-0.26, 0.38, -1.6], [-0.62, 0.35, -1.32]], 0.017, 1, 4), trimMat);
  body.add(tube52);
  const wheels = new THREE.Group();
  wheels.name = 'wheels';
  root.add(wheels);
  const wheelFL = new THREE.Group();
  wheelFL.name = 'wheelFL';
  wheelFL.position.set(0.8, 0.32, 1.32);
  wheels.add(wheelFL);
  const tire = new THREE.Mesh(latheGeo, trimMat);
  tire.name = 'tire';
  tire.rotation.set(0, 0, deg(90));
  wheelFL.add(tire);
  const rim = new THREE.Mesh(cylinderGeo2, accentMat);
  rim.name = 'rim';
  rim.rotation.set(0, 0, deg(90));
  wheelFL.add(rim);
  const wheelNut = new THREE.Mesh(cylinderGeo3, trimMat);
  wheelNut.name = 'wheelNut';
  wheelNut.position.set(0.14, 0, 0);
  wheelNut.rotation.set(0, 0, deg(-90));
  wheelFL.add(wheelNut);
  const wheelFR = new THREE.Group();
  wheelFR.name = 'wheelFR';
  wheelFR.position.set(-0.8, 0.32, 1.32);
  wheels.add(wheelFR);
  const tire2 = new THREE.Mesh(latheGeo, trimMat);
  tire2.name = 'tire';
  tire2.rotation.set(0, 0, deg(90));
  wheelFR.add(tire2);
  const rim2 = new THREE.Mesh(cylinderGeo2, accentMat);
  rim2.name = 'rim';
  rim2.rotation.set(0, 0, deg(90));
  wheelFR.add(rim2);
  const wheelNut2 = new THREE.Mesh(cylinderGeo3, trimMat);
  wheelNut2.name = 'wheelNut';
  wheelNut2.position.set(-0.14, 0, 0);
  wheelNut2.rotation.set(0, 0, deg(90));
  wheelFR.add(wheelNut2);
  const wheelRL = new THREE.Group();
  wheelRL.name = 'wheelRL';
  wheelRL.position.set(0.78, 0.35, -1.32);
  wheels.add(wheelRL);
  const tire3 = new THREE.Mesh(latheGeo2, trimMat);
  tire3.name = 'tire';
  tire3.rotation.set(0, 0, deg(90));
  wheelRL.add(tire3);
  const rim3 = new THREE.Mesh(cylinderGeo4, accentMat);
  rim3.name = 'rim';
  rim3.rotation.set(0, 0, deg(90));
  wheelRL.add(rim3);
  const wheelNut3 = new THREE.Mesh(cylinderGeo5, trimMat);
  wheelNut3.name = 'wheelNut';
  wheelNut3.position.set(0.18, 0, 0);
  wheelNut3.rotation.set(0, 0, deg(-90));
  wheelRL.add(wheelNut3);
  const wheelRR = new THREE.Group();
  wheelRR.name = 'wheelRR';
  wheelRR.position.set(-0.78, 0.35, -1.32);
  wheels.add(wheelRR);
  const tire4 = new THREE.Mesh(latheGeo2, trimMat);
  tire4.name = 'tire';
  tire4.rotation.set(0, 0, deg(90));
  wheelRR.add(tire4);
  const rim4 = new THREE.Mesh(cylinderGeo4, accentMat);
  rim4.name = 'rim';
  rim4.rotation.set(0, 0, deg(90));
  wheelRR.add(rim4);
  const wheelNut4 = new THREE.Mesh(cylinderGeo5, trimMat);
  wheelNut4.name = 'wheelNut';
  wheelNut4.position.set(-0.18, 0, 0);
  wheelNut4.rotation.set(0, 0, deg(90));
  wheelRR.add(wheelNut4);

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

export default createRaceCar;
```

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