JSFiddle - React, Tailwind, and code Playground

by Paul West

HTML

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
    }
  }
</script>

CSS

body{
  overflow: hidden;
  margin: 0;
}

JavaScript

import * as THREE from "three";
import {
  OrbitControls
} from "three/addons/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(10, 10, 10);
let renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

let grid = new THREE.GridHelper();
grid.rotation.z = Math.PI * 0.5;
scene.add(grid);

let woodLength = 4;
let cutAngle = THREE.MathUtils.degToRad(42);
let cutTan = Math.tan(cutAngle);

let profile = new THREE.Shape()
	.moveTo(1, 0)
  .lineTo(1, 1)
  .splineThru([
    [0.5, 1.5],
    [1, 2], 
    [0, 2.5],
    [-1, 2],
    [-0.5, 1.5],
    [-1, 1]
  ].map(p => {return new THREE.Vector2(p[0], p[1])}))
  .lineTo(-1, 0)
  .lineTo(-1, 0)
  .lineTo(1, 0)
  
let g = new THREE.ExtrudeGeometry(profile, {
	steps: 1,
	depth: 1,
	bevelEnabled: false
})

// shift verts
let pos = g.attributes.position;
for(let i = 0; i < pos.count; i++){
	let z = pos.getZ(i);
	let sign = z > 0.5 ? 1 : -1;
  let y = pos.getY(i);
  pos.setZ(i, (woodLength * 0.5 + y * Math.tan(cutTan)) * sign);
}
g.computeVertexNormals();

let m = new THREE.MeshNormalMaterial();

let o = new THREE.Mesh(g, m);
scene.add(o);


renderer.setAnimationLoop(() => {
  controls.update();
  renderer.render(scene, camera);
});