# Blaster Pistol

> A chunky, toy-like sci-fi blaster pistol (about 0.35 m long) standing on its grip with the barrel pointing +X: rounded beveled body, glowing energy coils around the barrel, emissive power cell, sight fin and rubber grip panels. Recolor body, accent and glow for space shooters, arena FPS games or loot pickups.

![Blaster Pistol preview](https://codels.download/m/blaster-pistol.png)

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

## Facts

- Category: Items & Weapons › Weapons
- Size (W × H × D): 0.42 × 0.23 × 0.07 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 988 · Meshes: 19 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: blaster, gun, raygun, cartoon, low-poly, stylized, sci-fi, space, fps, shooter, space-shooter, pickup, weapon, energy, plastic, emissive, game-ready, mobile-friendly, parametric, multicolor, color-orange, color-white, size-small, poly-low
- Page: https://codels.download/models/blaster-pistol

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `body` | color | #rrggbb | #eceae4 | #eceae4 |
| `accent` | color | #rrggbb | #ff7a3c | #ff7a3c |
| `glow` | color | #rrggbb | #3fe6ff | #3fe6ff |

## Parts

- body (extrude · body)
- gripPanelR (extrude · dark)
- stripeR (extrude · accent)
- cellR (box · glow)
- gripPanelL (extrude · dark)
- stripeL (extrude · accent)
- cellL (box · glow)
- barrel (cylinder · metal)
- coil1 (torus · glow)
- coil2 (torus · glow)
- coil3 (torus · glow)
- muzzle (cylinder · accent)
- muzzleGlow (cylinder · glow)
- fin (extrude · accent)
- powerCell (capsule · glow)
- cellCapF (cylinder · metal)
- cellCapB (cylinder · metal)
- triggerGuard (torus · dark)
- trigger (box · accent)

## How to use

Save the code below as `blaster-pistol.js`, then:

```js
import { createBlasterPistol } from './blaster-pistol.js';
const model = createBlasterPistol();
scene.add(model);
```

## Code

```js
/**
 * Blaster Pistol — Codels 3D model library (https://codels.download/models/blaster-pistol)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 988 · Size (W × H × D): 0.42 × 0.23 × 0.07 m
 *
 * Usage:
 *   import { createBlasterPistol } from './blaster-pistol.js';
 *   
 *   const model = createBlasterPistol();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

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

  // Materials
  const bodyMat = new THREE.MeshStandardMaterial({ name: 'body', color: 0xeceae4, roughness: 0.45, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xff7a3c, roughness: 0.45, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x2d333d, roughness: 0.7, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0x9aa4b0, roughness: 0.35, metalness: 0.7, flatShading: true });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x3fe6ff, roughness: 0.3, emissive: 0x3fe6ff, emissiveIntensity: 1.1, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[-0.108, 0.012], [-0.068, 0.012], [-0.047, 0.088], [-0.098, 0.088]], 0.004);
  const extrudeGeo2 = extrude([[-0.12, 0.135], [0.09, 0.135], [0.095, 0.155], [-0.115, 0.155]], 0.004);
  const boxGeo = new THREE.BoxGeometry(0.05, 0.014, 0.004);
  const torusGeo = new THREE.TorusGeometry(0.026, 0.007, 5, 12);
  const cylinderGeo = new THREE.CylinderGeometry(0.02, 0.02, 0.01, 8);

  // Parts
  const body = new THREE.Mesh(extrude([[-0.12, 0], [-0.06, 0], [-0.035, 0.1], [0.06, 0.1], [0.1, 0.112], [0.11, 0.135], [0.105, 0.17], [0.02, 0.18], [-0.09, 0.18], [-0.135, 0.165], [-0.14, 0.125], [-0.105, 0.1]], 0.036, [], [0.009, 0.008, 2]), bodyMat);
  body.name = 'body';
  body.position.set(0, 0.009, 0);
  root.add(body);
  const gripPanelR = new THREE.Mesh(extrudeGeo, darkMat);
  gripPanelR.name = 'gripPanelR';
  gripPanelR.position.set(0, 0.009, 0.028);
  root.add(gripPanelR);
  const stripeR = new THREE.Mesh(extrudeGeo2, accentMat);
  stripeR.name = 'stripeR';
  stripeR.position.set(0, 0.009, 0.028);
  root.add(stripeR);
  const cellR = new THREE.Mesh(boxGeo, glowMat);
  cellR.name = 'cellR';
  cellR.position.set(-0.035, 0.131, 0.028);
  root.add(cellR);
  const gripPanelL = new THREE.Mesh(extrudeGeo, darkMat);
  gripPanelL.name = 'gripPanelL';
  gripPanelL.position.set(0, 0.009, -0.028);
  root.add(gripPanelL);
  const stripeL = new THREE.Mesh(extrudeGeo2, accentMat);
  stripeL.name = 'stripeL';
  stripeL.position.set(0, 0.009, -0.028);
  root.add(stripeL);
  const cellL = new THREE.Mesh(boxGeo, glowMat);
  cellL.name = 'cellL';
  cellL.position.set(-0.035, 0.131, -0.028);
  root.add(cellL);
  const barrel = new THREE.Mesh(new THREE.CylinderGeometry(0.024, 0.024, 0.13, 10), metalMat);
  barrel.name = 'barrel';
  barrel.position.set(0.165, 0.157, 0);
  barrel.rotation.set(0, 0, deg(-90));
  root.add(barrel);
  const coil1 = new THREE.Mesh(torusGeo, glowMat);
  coil1.name = 'coil1';
  coil1.position.set(0.135, 0.157, 0);
  coil1.rotation.set(0, deg(90), 0);
  root.add(coil1);
  const coil2 = new THREE.Mesh(torusGeo, glowMat);
  coil2.name = 'coil2';
  coil2.position.set(0.165, 0.157, 0);
  coil2.rotation.set(0, deg(90), 0);
  root.add(coil2);
  const coil3 = new THREE.Mesh(torusGeo, glowMat);
  coil3.name = 'coil3';
  coil3.position.set(0.195, 0.157, 0);
  coil3.rotation.set(0, deg(90), 0);
  root.add(coil3);
  const muzzle = new THREE.Mesh(new THREE.CylinderGeometry(0.034, 0.03, 0.04, 10), accentMat);
  muzzle.name = 'muzzle';
  muzzle.position.set(0.245, 0.157, 0);
  muzzle.rotation.set(0, 0, deg(-90));
  root.add(muzzle);
  const muzzleGlow = new THREE.Mesh(new THREE.CylinderGeometry(0.017, 0.017, 0.01, 10), glowMat);
  muzzleGlow.name = 'muzzleGlow';
  muzzleGlow.position.set(0.263, 0.157, 0);
  muzzleGlow.rotation.set(0, 0, deg(-90));
  root.add(muzzleGlow);
  const fin = new THREE.Mesh(extrude([[-0.03, 0], [0.05, 0], [0.03, 0.035], [-0.01, 0.035]], 0.012, [], [0.003, 0.003, 1]), accentMat);
  fin.name = 'fin';
  fin.position.set(0, 0.194, 0);
  root.add(fin);
  const powerCell = new THREE.Mesh(new THREE.CapsuleGeometry(0.017, 0.05, 3, 8), glowMat);
  powerCell.name = 'powerCell';
  powerCell.position.set(-0.07, 0.213, 0);
  powerCell.rotation.set(0, 0, deg(90));
  root.add(powerCell);
  const cellCapF = new THREE.Mesh(cylinderGeo, metalMat);
  cellCapF.name = 'cellCapF';
  cellCapF.position.set(-0.035, 0.213, 0);
  cellCapF.rotation.set(0, 0, deg(90));
  root.add(cellCapF);
  const cellCapB = new THREE.Mesh(cylinderGeo, metalMat);
  cellCapB.name = 'cellCapB';
  cellCapB.position.set(-0.105, 0.213, 0);
  cellCapB.rotation.set(0, 0, deg(90));
  root.add(cellCapB);
  const triggerGuard = new THREE.Mesh(new THREE.TorusGeometry(0.032, 0.006, 4, 10, Math.PI), darkMat);
  triggerGuard.name = 'triggerGuard';
  triggerGuard.position.set(0, 0.109, 0);
  triggerGuard.rotation.set(0, 0, deg(180));
  root.add(triggerGuard);
  const trigger = new THREE.Mesh(new THREE.BoxGeometry(0.01, 0.028, 0.012), accentMat);
  trigger.name = 'trigger';
  trigger.position.set(0, 0.097, 0);
  trigger.rotation.set(0, 0, deg(-12));
  root.add(trigger);

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

export default createBlasterPistol;
```

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