# Tree Stump

> A low-poly cut tree stump with a flared bark base, a light sawn top showing growth rings, gnarly surface roots and an optional wood axe stuck in the cut. A classic prop for lumberjack camps, forest clearings, survival crafting and RPG woodcutting spots.

![Tree Stump preview](https://codels.download/m/tree-stump.png)

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

## Facts

- Category: Nature › Trees
- Size (W × H × D): 1.31 × 1.00 × 1.42 m — units are meters, +Y up, front faces +Z
- Origin: center of the base (y = 0)
- Triangles: 422 · Meshes: 17 · Materials: 5
- License: CC0-1.0 (Codels built-in)
- Tags: axe, log, stump, low-poly, stylized, camping, medieval, forest, village, farming-sim, rpg, survival, decoration, obstacle, prop, wood, game-ready, mobile-friendly, parametric, color-brown, size-medium, poly-low
- Page: https://codels.download/models/tree-stump

## Files

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

## Parameters

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

| Param | Type | Range / options | Default | Current |
|---|---|---|---|---|
| `radius` | number | 0.25 – 0.8 | 0.42 | 0.42 |
| `height` | number | 0.2 – 0.9 | 0.45 | 0.45 |
| `roots` | int | 0 – 6 | 4 | 4 |
| `axe` | boolean | true \| false | true | true |

## Parts

- body (cylinder · bark)
- foot (cylinder · bark)
- cut (cylinder · cut)
- ring1 (ring · ring)
- ring2 (ring · ring)
- ring3 (ring · ring)
- pith (circle · ring)
- root1 (cylinder · bark)
- rootTip1 (cylinder · bark)
- root2 (cylinder · bark)
- rootTip2 (cylinder · bark)
- root3 (cylinder · bark)
- rootTip3 (cylinder · bark)
- root4 (cylinder · bark)
- rootTip4 (cylinder · bark)
- axe (group)
  - axeHead (extrude · steel)
  - axeHandle (cylinder · handle)

## How to use

Save the code below as `tree-stump.js`, then:

```js
import { createTreeStump } from './tree-stump.js';
const model = createTreeStump();
scene.add(model);
```

## Code

```js
/**
 * Tree Stump — Codels 3D model library (https://codels.download/models/tree-stump)
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 422 · Size (W × H × D): 1.31 × 1.00 × 1.42 m
 *
 * Usage:
 *   import { createTreeStump } from './tree-stump.js';
 *   
 *   const model = createTreeStump();
 *   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 createTreeStump() {
  const root = new THREE.Group();
  root.name = 'TreeStump';

  // Materials
  const barkMat = new THREE.MeshStandardMaterial({ name: 'bark', color: 0x5f4631, roughness: 0.95, flatShading: true });
  const cutMat = new THREE.MeshStandardMaterial({ name: 'cut', color: 0xd3a262, roughness: 0.85, flatShading: true });
  const ringMat = new THREE.MeshStandardMaterial({ name: 'ring', color: 0x9c6a3a, roughness: 0.9, flatShading: true });
  const steelMat = new THREE.MeshStandardMaterial({ name: 'steel', color: 0x9aa1a8, roughness: 0.35, metalness: 0.6, flatShading: true });
  const handleMat = new THREE.MeshStandardMaterial({ name: 'handle', color: 0xa5733f, roughness: 0.8, flatShading: true });

  // Shared geometries
  const cylinderGeo = new THREE.CylinderGeometry(0.0714, 0.1176, 0.2716, 6, 1, true);

  // Parts
  const body = new THREE.Mesh(new THREE.CylinderGeometry(0.42, 0.4452, 0.45, 9), barkMat);
  body.name = 'body';
  body.position.set(0, 0.225, 0);
  root.add(body);
  const foot = new THREE.Mesh(new THREE.CylinderGeometry(0.4452, 0.5376, 0.14, 9), barkMat);
  foot.name = 'foot';
  foot.position.set(0, 0.07, 0);
  root.add(foot);
  const cut = new THREE.Mesh(new THREE.CylinderGeometry(0.3696, 0.3696, 0.02, 9), cutMat);
  cut.name = 'cut';
  cut.position.set(0, 0.448, 0);
  root.add(cut);
  const ring1 = new THREE.Mesh(new THREE.RingGeometry(0.0661, 0.0821, 18), ringMat);
  ring1.name = 'ring1';
  ring1.position.set(0.0017, 0.46, -0.0022);
  ring1.rotation.set(deg(-90), 0, 0);
  root.add(ring1);
  const ring2 = new THREE.Mesh(new THREE.RingGeometry(0.1688, 0.1848, 18), ringMat);
  ring2.name = 'ring2';
  ring2.position.set(0.0051, 0.46, -0.0029);
  ring2.rotation.set(deg(-90), 0, 0);
  root.add(ring2);
  const ring3 = new THREE.Mesh(new THREE.RingGeometry(0.2715, 0.2875, 18), ringMat);
  ring3.name = 'ring3';
  ring3.position.set(0.0035, 0.46, -0.0048);
  ring3.rotation.set(deg(-90), 0, 0);
  root.add(ring3);
  const pith = new THREE.Mesh(new THREE.CircleGeometry(0.02, 6), ringMat);
  pith.name = 'pith';
  pith.position.set(0, 0.46, 0);
  pith.rotation.set(deg(-90), 0, 0);
  root.add(pith);
  const root1 = new THREE.Mesh(cylinderGeo, barkMat);
  root1.name = 'root1';
  root1.position.set(0.3125, 0.1257, 0.1726);
  root1.rotation.set(deg(33.4409), deg(-35.534), deg(-93.695));
  root.add(root1);
  const rootTip1 = new THREE.Mesh(new THREE.CylinderGeometry(0.0357, 0.0714, 0.2884, 6), barkMat);
  rootTip1.name = 'rootTip1';
  rootTip1.position.set(0.5352, 0.0553, 0.2956);
  rootTip1.rotation.set(deg(33.1732), deg(-29.1521), deg(-82.2427));
  root.add(rootTip1);
  const root2 = new THREE.Mesh(cylinderGeo, barkMat);
  root2.name = 'root2';
  root2.position.set(-0.0713, 0.1257, 0.3498);
  root2.rotation.set(deg(109.3161), deg(15.5908), deg(11.09));
  root.add(root2);
  const rootTip2 = new THREE.Mesh(new THREE.CylinderGeometry(0.0357, 0.0714, 0.2423, 6), barkMat);
  rootTip2.name = 'rootTip2';
  rootTip2.position.set(-0.1174, 0.0553, 0.5762);
  rootTip2.rotation.set(deg(98.0673), deg(13.3943), deg(11.6427));
  root.add(rootTip2);
  const root3 = new THREE.Mesh(cylinderGeo, barkMat);
  root3.name = 'root3';
  root3.position.set(-0.2839, 0.1257, -0.2165);
  root3.rotation.set(deg(-48.6488), deg(-41.4683), deg(79.8885));
  root.add(root3);
  const rootTip3 = new THREE.Mesh(new THREE.CylinderGeometry(0.0357, 0.0714, 0.3021, 6), barkMat);
  rootTip3.name = 'rootTip3';
  rootTip3.position.set(-0.4917, 0.0553, -0.3749);
  rootTip3.rotation.set(deg(-45.9965), deg(-33.4629), deg(70.6168));
  root.add(rootTip3);
  const root4 = new THREE.Mesh(cylinderGeo, barkMat);
  root4.name = 'root4';
  root4.position.set(0.1689, 0.1257, -0.3145);
  root4.rotation.set(deg(-94.6237), deg(34.9152), deg(-32.3526));
  root.add(root4);
  const rootTip4 = new THREE.Mesh(new THREE.CylinderGeometry(0.0357, 0.0714, 0.3238, 6), barkMat);
  rootTip4.name = 'rootTip4';
  rootTip4.position.set(0.2977, 0.0553, -0.5545);
  rootTip4.rotation.set(deg(-82.143), deg(28.176), deg(-32.1295));
  root.add(rootTip4);
  const axe = new THREE.Group();
  axe.name = 'axe';
  axe.position.set(-0.063, 0.593, 0.0504);
  axe.rotation.set(0, deg(35), deg(24));
  axe.scale.setScalar(1.25);
  root.add(axe);
  const axeHead = new THREE.Mesh(extrude([[-0.035, 0.05], [-0.035, -0.04], [-0.09, -0.15], [-0.065, -0.168], [0, -0.175], [0.07, -0.168], [0.1, -0.15], [0.035, -0.04], [0.035, 0.05]], 0.03), steelMat);
  axeHead.name = 'axeHead';
  axe.add(axeHead);
  const axeHandle = new THREE.Mesh(new THREE.CylinderGeometry(0.022, 0.018, 0.78, 6), handleMat);
  axeHandle.name = 'axeHandle';
  axeHandle.position.set(0.33, 0.015, 0);
  axeHandle.rotation.set(0, 0, deg(-90));
  axe.add(axeHandle);

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

export default createTreeStump;
```

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