JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

HTML

<script src="https://unpkg.com/[email protected]/build/three.min.js"></script>
<script src="https://unpkg.com/[email protected]/examples/js/controls/OrbitControls.js"></script>
<div class="sketchpadContainer">
  <canvas id="sketchpad"></canvas>
  <div class="sketchpadLabel">Draw on me!</div>
</div>

CSS

body {
  margin: 0;
}

.sketchpadContainer {
  position: fixed;
  top: 10px;
  left: 10px;
}

#sketchpad {
  background: #a0a0a0;
  border-radius: 3px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.sketchpadLabel {
  color: #ccc;
  text-shadow: 0 1px 4px black;
  text-align: center;
  font-family: sans-serif;
  font-size: 14px;
}

JavaScript

const scene = new THREE.Scene();

let curve = null;
let surface = null;

function update3DCurve(points) {
	let lineSegments = [];
  for (let i = 0; i < points.length; i++) {
    const a = points[i];
    const b = points[(i + 1) % points.length];

    lineSegments.push(new THREE.LineCurve3(
      new THREE.Vector3(a[0], a[1], 0),
      new THREE.Vector3(b[0], b[1], 0)
    ));
  }

  const curvePath = new THREE.CurvePath();
  curvePath.autoClose = true;
  curvePath.curves = lineSegments;
  
  // White curve
  if (curve !== null) {
  	curve.geometry.dispose();
    curve.material.dispose();
    scene.remove(curve);
  }
  const curveGeometry = new THREE.TubeGeometry(curvePath, 200, 0.01, 10, true);
  const curveMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    side: THREE.DoubleSide,
    depthTest: false,
  });
  curve = new THREE.Mesh(curveGeometry, curveMaterial);
  curve.renderOrder = Number.MAX_SAFE_INTEGER;
  curve.position.set(0, 0, -0.25);
  scene.add(curve);
  
  // Blue 3D Surface
  if (surface !== null) {
  	surface.geometry.dispose();
    surface.material.dispose();
    scene.remove(surface);
  }
  const surfaceMaterial = new THREE.MeshStandardMaterial({
    color: 0x49ef4,
    side: THREE.DoubleSide,
    opacity: 0.5,
    transparent: true,
  });
  const surfaceGeometry = new THREE.ParametricGeometry((u, v, vec) => {
  	u = (u + v) % 1;
  
  	const point1 = curvePath.getPoint(u);
    const point2 = curvePath.getPoint(v);
    
    vec.addVectors(point1, point2).divideScalar(2);
    vec.z = point1.distanceTo(point2);
  }, 50, 50);
  surface = new THREE.Mesh(surfaceGeometry, surfaceMaterial);
  surface.position.set(0, 0, -0.25);
  scene.add(surface);
}

const sketchpadCanvas = document.querySelector("#sketchpad");
const sketchpadCtx = sketchpadCanvas.getContext("2d");

sketchpadCanvas.width = 150;
sketchpadCanvas.height = 150;

let sketchpadPoints =...