# Fishing Rod

> A low-poly fishing rod with a cork grip, round crank reel, line guides along a tapered blank and a red-and-white bobber on the line. Rest it on a forked-stick stand with the bobber dangling from the tip, or lay it flat on the ground with the line looping out. Add a wooden bucket with the day’s catch for lakeside camps, docks, cozy life-sims and survival games.

![Fishing Rod preview](https://codels.download/m/fishing-rod.png)

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

## Facts

- Category: Props › Tools
- Size (W × H × D): 1.47 × 0.82 × 0.81 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 1,378 · Meshes: 43 · Materials: 8
- License: CC0-1.0 (Codels built-in)
- Tags: bobber, bucket, fish, fishing, reel, low-poly, stylized, camping, nautical, beach, river, village, adventure, farming-sim, survival, equipment, interactable, prop, tool, metal, wood, mobile-friendly, parametric, color-blue, color-brown, color-gray, size-medium, poly-low
- Page: https://codels.download/models/fishing-rod

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `pose` | select | stand \| flat | stand | stand |
| `rod` | color | #rrggbb | #2f5f8f | #2f5f8f |
| `bobber` | color | #rrggbb | #d8352b | #d8352b |
| `bucket` | boolean | true \| false | true | true |

## Parts

- setup (group)
  - rod (group)
    - buttCap (cylinder · dark)
    - grip (cylinder · cork)
    - reelSeat (cylinder · metal)
    - foreGrip (cylinder · cork)
    - windingCheck (cylinder · dark)
    - blank (cylinder · blank)
    - tipTop (torus · metal)
    - guideFoot (box · metal)
    - guide (torus · metal)
    - guideFoot (box · metal)
    - guide (torus · metal)
    - guideFoot (box · metal)
    - guide (torus · metal)
    - guideFoot (box · metal)
    - guide (torus · metal)
    - reelFoot (box · metal)
    - reelStem (box · metal)
    - reel (cylinder · metal)
    - reelPlate (cylinder · dark)
    - reelHub (cylinder · metal)
    - crankArm (box · metal)
    - crankKnob (cylinder · dark)
  - line (tube · white)
  - lineDrop (cylinder · white)
  - bobberTop (sphere · bobber)
  - bobberBottom (sphere · white)
  - bobberStick (cylinder · bobber)
  - leader (cylinder · white)
  - sinker (sphere · dark)
  - hook (torus · metal)
  - standStick (cylinder · wood)
  - standProng (cylinder · wood)
  - standProng (cylinder · wood)
  - stone (dodecahedron · dark)
- bucket (group)
  - bucketShell (cylinder · wood)
  - bucketBottom (cylinder · wood)
  - water (cylinder · water)

## How to use

Save the code below as `fishing-rod.js`, then:

```js
import { createFishingRod } from './fishing-rod.js';
const model = createFishingRod();
scene.add(model);
```

## Code

```js
/**
 * Fishing Rod — Codels 3D model library (https://codels.download/models/fishing-rod)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,378 · Size (W × H × D): 1.47 × 0.82 × 0.81 m
 *
 * Usage:
 *   import { createFishingRod } from './fishing-rod.js';
 *   
 *   const model = createFishingRod();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
  const pos = geometry.attributes.position;
  const h = (a, b, c, s) => {
    let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
    x = Math.imul(x ^ (x >>> 16), 2246822507);
    x = Math.imul(x ^ (x >>> 13), 3266489909);
    return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
  };
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
    const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
    pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
  }
  pos.needsUpdate = true;
  geometry.computeVertexNormals();
  return geometry;
}

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

  // Materials
  const blankMat = new THREE.MeshStandardMaterial({ name: 'blank', color: 0x2f5f8f, roughness: 0.35, metalness: 0.1, flatShading: true });
  const corkMat = new THREE.MeshStandardMaterial({ name: 'cork', color: 0xc99b63, roughness: 0.95, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0xb4bbc4, roughness: 0.3, metalness: 0.6, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x2b2c31, roughness: 0.6, flatShading: true });
  const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf2f0ea, roughness: 0.6, flatShading: true });
  const bobberMat = new THREE.MeshStandardMaterial({ name: 'bobber', color: 0xd8352b, roughness: 0.4, flatShading: true });
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x7d5634, roughness: 0.9, flatShading: true, side: THREE.DoubleSide });
  const waterMat = new THREE.MeshStandardMaterial({ name: 'water', color: 0x3f7fa8, roughness: 0.15, metalness: 0.1, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.012, 0.012, 0.0025);
  const sphereGeo = new THREE.SphereGeometry(0.032, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2);
  const cylinderGeo = new THREE.CylinderGeometry(0.008, 0.012, 0.1435, 5);

  // Parts
  const setup = new THREE.Group();
  setup.name = 'setup';
  setup.rotation.set(0, deg(-28), 0);
  root.add(setup);
  const rod = new THREE.Group();
  rod.name = 'rod';
  rod.position.set(-0.78, 0.018, 0);
  rod.rotation.set(0, 0, deg(26));
  setup.add(rod);
  const buttCap = new THREE.Mesh(new THREE.CylinderGeometry(0.018, 0.018, 0.02, 7), darkMat);
  buttCap.name = 'buttCap';
  buttCap.position.set(0.01, 0, 0);
  buttCap.rotation.set(0, 0, deg(-90));
  rod.add(buttCap);
  const grip = new THREE.Mesh(new THREE.CylinderGeometry(0.015, 0.0175, 0.28, 7), corkMat);
  grip.name = 'grip';
  grip.position.set(0.16, 0, 0);
  grip.rotation.set(0, 0, deg(-90));
  rod.add(grip);
  const reelSeat = new THREE.Mesh(new THREE.CylinderGeometry(0.012, 0.012, 0.08, 7), metalMat);
  reelSeat.name = 'reelSeat';
  reelSeat.position.set(0.34, 0, 0);
  reelSeat.rotation.set(0, 0, deg(-90));
  rod.add(reelSeat);
  const foreGrip = new THREE.Mesh(new THREE.CylinderGeometry(0.0115, 0.0145, 0.09, 7), corkMat);
  foreGrip.name = 'foreGrip';
  foreGrip.position.set(0.425, 0, 0);
  foreGrip.rotation.set(0, 0, deg(-90));
  rod.add(foreGrip);
  const windingCheck = new THREE.Mesh(new THREE.CylinderGeometry(0.0105, 0.011, 0.015, 7), darkMat);
  windingCheck.name = 'windingCheck';
  windingCheck.position.set(0.4775, 0, 0);
  windingCheck.rotation.set(0, 0, deg(-90));
  rod.add(windingCheck);
  const blank = new THREE.Mesh(new THREE.CylinderGeometry(0.0028, 0.0095, 1.32, 6), blankMat);
  blank.name = 'blank';
  blank.position.set(1.14, 0, 0);
  blank.rotation.set(0, 0, deg(-90));
  rod.add(blank);
  const tipTop = new THREE.Mesh(new THREE.TorusGeometry(0.004, 0.0013, 3, 6), metalMat);
  tipTop.name = 'tipTop';
  tipTop.position.set(1.803, 0, 0);
  tipTop.rotation.set(0, deg(90), 0);
  rod.add(tipTop);
  const guideFoot = new THREE.Mesh(boxGeo, metalMat);
  guideFoot.name = 'guideFoot';
  guideFoot.position.set(0.72, -0.0123, 0);
  rod.add(guideFoot);
  const guide = new THREE.Mesh(new THREE.TorusGeometry(0.013, 0.0018, 3, 7), metalMat);
  guide.name = 'guide';
  guide.position.set(0.72, -0.0293, 0);
  guide.rotation.set(0, deg(90), 0);
  rod.add(guide);
  const guideFoot2 = new THREE.Mesh(boxGeo, metalMat);
  guideFoot2.name = 'guideFoot';
  guideFoot2.position.set(0.99, -0.0109, 0);
  rod.add(guideFoot2);
  const guide2 = new THREE.Mesh(new THREE.TorusGeometry(0.0105, 0.0018, 3, 7), metalMat);
  guide2.name = 'guide';
  guide2.position.set(0.99, -0.0254, 0);
  guide2.rotation.set(0, deg(90), 0);
  rod.add(guide2);
  const guideFoot3 = new THREE.Mesh(boxGeo, metalMat);
  guideFoot3.name = 'guideFoot';
  guideFoot3.position.set(1.25, -0.0096, 0);
  rod.add(guideFoot3);
  const guide3 = new THREE.Mesh(new THREE.TorusGeometry(0.0085, 0.0018, 3, 7), metalMat);
  guide3.name = 'guide';
  guide3.position.set(1.25, -0.0221, 0);
  guide3.rotation.set(0, deg(90), 0);
  rod.add(guide3);
  const guideFoot4 = new THREE.Mesh(boxGeo, metalMat);
  guideFoot4.name = 'guideFoot';
  guideFoot4.position.set(1.5, -0.0083, 0);
  rod.add(guideFoot4);
  const guide4 = new THREE.Mesh(new THREE.TorusGeometry(0.0068, 0.0018, 3, 7), metalMat);
  guide4.name = 'guide';
  guide4.position.set(1.5, -0.0191, 0);
  guide4.rotation.set(0, deg(90), 0);
  rod.add(guide4);
  const reelFoot = new THREE.Mesh(new THREE.BoxGeometry(0.055, 0.008, 0.016), metalMat);
  reelFoot.name = 'reelFoot';
  reelFoot.position.set(0.34, -0.014, 0);
  rod.add(reelFoot);
  const reelStem = new THREE.Mesh(new THREE.BoxGeometry(0.014, 0.034, 0.012), metalMat);
  reelStem.name = 'reelStem';
  reelStem.position.set(0.34, -0.034, 0);
  rod.add(reelStem);
  const reel = new THREE.Mesh(new THREE.CylinderGeometry(0.044, 0.044, 0.03, 10), metalMat);
  reel.name = 'reel';
  reel.position.set(0.34, -0.088, 0);
  reel.rotation.set(deg(90), 0, 0);
  rod.add(reel);
  const reelPlate = new THREE.Mesh(new THREE.CylinderGeometry(0.036, 0.036, 0.034, 10), darkMat);
  reelPlate.name = 'reelPlate';
  reelPlate.position.set(0.34, -0.088, 0);
  reelPlate.rotation.set(deg(90), 0, 0);
  rod.add(reelPlate);
  const reelHub = new THREE.Mesh(new THREE.CylinderGeometry(0.009, 0.009, 0.04, 6), metalMat);
  reelHub.name = 'reelHub';
  reelHub.position.set(0.34, -0.088, 0);
  reelHub.rotation.set(deg(90), 0, 0);
  rod.add(reelHub);
  const crankArm = new THREE.Mesh(new THREE.BoxGeometry(0.052, 0.009, 0.006), metalMat);
  crankArm.name = 'crankArm';
  crankArm.position.set(0.36, -0.096, 0.021);
  crankArm.rotation.set(0, 0, deg(-20));
  rod.add(crankArm);
  const crankKnob = new THREE.Mesh(new THREE.CylinderGeometry(0.008, 0.008, 0.022, 6), darkMat);
  crankKnob.name = 'crankKnob';
  crankKnob.position.set(0.382, -0.104, 0.032);
  crankKnob.rotation.set(deg(90), 0, 0);
  rod.add(crankKnob);
  const line = new THREE.Mesh(tube([[-0.4466, 0.1328, 0], [-0.12, 0.3073, 0], [0.1209, 0.4291, 0], [0.3532, 0.5461, 0], [0.5766, 0.6584, 0], [0.8419, 0.8079, 0]], 0.0016, 28, 3), whiteMat);
  line.name = 'line';
  setup.add(line);
  const lineDrop = new THREE.Mesh(new THREE.CylinderGeometry(0.0016, 0.0016, 0.34, 3), whiteMat);
  lineDrop.name = 'lineDrop';
  lineDrop.position.set(0.8423, 0.637, 0);
  lineDrop.rotation.set(0, 0, deg(180));
  setup.add(lineDrop);
  const bobberTop = new THREE.Mesh(sphereGeo, bobberMat);
  bobberTop.name = 'bobberTop';
  bobberTop.position.set(0.8423, 0.435, 0);
  setup.add(bobberTop);
  const bobberBottom = new THREE.Mesh(sphereGeo, whiteMat);
  bobberBottom.name = 'bobberBottom';
  bobberBottom.position.set(0.8423, 0.435, 0);
  bobberBottom.rotation.set(deg(180), 0, 0);
  setup.add(bobberBottom);
  const bobberStick = new THREE.Mesh(new THREE.CylinderGeometry(0.004, 0.004, 0.04, 5), bobberMat);
  bobberStick.name = 'bobberStick';
  bobberStick.position.set(0.8423, 0.48, 0);
  setup.add(bobberStick);
  const leader = new THREE.Mesh(new THREE.CylinderGeometry(0.0013, 0.0013, 0.07, 3), whiteMat);
  leader.name = 'leader';
  leader.position.set(0.8423, 0.37, 0);
  leader.rotation.set(0, 0, deg(180));
  setup.add(leader);
  const sinker = new THREE.Mesh(new THREE.SphereGeometry(0.008, 5, 3), darkMat);
  sinker.name = 'sinker';
  sinker.position.set(0.8423, 0.335, 0);
  setup.add(sinker);
  const hook = new THREE.Mesh(new THREE.TorusGeometry(0.011, 0.0018, 3, 8, 4.3982), metalMat);
  hook.name = 'hook';
  hook.position.set(0.8423, 0.315, 0);
  hook.rotation.set(0, 0, deg(200));
  setup.add(hook);
  const standStick = new THREE.Mesh(new THREE.CylinderGeometry(0.013, 0.017, 0.3693, 6), woodMat);
  standStick.name = 'standStick';
  standStick.position.set(0.0209, 0.1844, 0);
  standStick.rotation.set(0, 0, deg(3.1044));
  setup.add(standStick);
  const standProng = new THREE.Mesh(cylinderGeo, woodMat);
  standProng.name = 'standProng';
  standProng.position.set(0.0059, 0.4238, -0.03);
  standProng.rotation.set(deg(-24.714), deg(-0.8757), deg(3.9957));
  setup.add(standProng);
  const standProng2 = new THREE.Mesh(cylinderGeo, woodMat);
  standProng2.name = 'standProng';
  standProng2.position.set(0.0059, 0.4238, 0.03);
  standProng2.rotation.set(deg(24.714), deg(0.8757), deg(3.9957));
  setup.add(standProng2);
  const stone = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.05, 0), 0.008, 2), darkMat);
  stone.name = 'stone';
  stone.position.set(0.0709, 0.02, 0.04);
  stone.scale.set(1, 0.55, 0.9);
  setup.add(stone);
  const bucket = new THREE.Group();
  bucket.name = 'bucket';
  bucket.position.set(-0.4, 0, 0.2);
  bucket.rotation.set(0, deg(15), 0);
  root.add(bucket);
  const bucketShell = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.1, 0.22, 9, 1, true), woodMat);
  bucketShell.name = 'bucketShell';
  bucketShell.position.set(0, 0.11, 0);
  bucket.add(bucketShell);
  const bucketBottom = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.012, 9), woodMat);
  bucketBottom.name = 'bucketBottom';
  bucketBottom.position.set(0, 0.006, 0);
  bucket.add(bucketBottom);
  const water = new THREE.Mesh(new THREE.CylinderGeometry(0.113, 0.113, 0.01, 9), waterMat);
  water.name = 'water';
  water.position.set(0, 0.175, 0);
  bucket.add(water);
  const hoop = new THREE.Mesh(new THREE.TorusGeometry(0.1061, 0.006, 3, 9), metalMat);
  hoop.name = 'hoop';
  hoop.position.set(0, 0.04, 0);
  hoop.rotation.set(deg(90), 0, 0);
  bucket.add(hoop);
  const hoop2 = new THREE.Mesh(new THREE.TorusGeometry(0.1169, 0.006, 3, 9), metalMat);
  hoop2.name = 'hoop';
  hoop2.position.set(0, 0.18, 0);
  hoop2.rotation.set(deg(90), 0, 0);
  bucket.add(hoop2);
  const bail = new THREE.Mesh(new THREE.TorusGeometry(0.12, 0.004, 3, 10, Math.PI), metalMat);
  bail.name = 'bail';
  bail.position.set(0, 0.22, 0);
  bail.rotation.set(0, deg(30), 0);
  bucket.add(bail);
  const fish = new THREE.Group();
  fish.name = 'fish';
  fish.position.set(0.02, 0.2, 0.01);
  fish.rotation.set(deg(14), deg(20), deg(-12));
  bucket.add(fish);
  const fishBody = new THREE.Mesh(new THREE.SphereGeometry(0.045, 7, 5), metalMat);
  fishBody.name = 'fishBody';
  fishBody.scale.set(0.55, 1.6, 1);
  fish.add(fishBody);
  const fishTail = new THREE.Mesh(extrude([[0, 0], [0.045, 0.06], [0, 0.045], [-0.045, 0.06]], 0.01), metalMat);
  fishTail.name = 'fishTail';
  fishTail.position.set(0, 0.065, 0);
  fishTail.rotation.set(0, deg(90), 0);
  fish.add(fishTail);
  const fishFin = new THREE.Mesh(new THREE.BoxGeometry(0.012, 0.03, 0.05), blankMat);
  fishFin.name = 'fishFin';
  fishFin.position.set(0, 0, 0.02);
  fish.add(fishFin);

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

export default createFishingRod;
```

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