JSFiddle - React, Tailwind, and code Playground

by Paul West

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>

CSS

body{
  overflow: hidden;
  margin: 0;
}

JavaScript

import * as THREE from "https://threejs.org/build/three.module.js";
import {
  OrbitControls
} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 0, 10);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

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

let model = new THREE.Mesh(new THREE.SphereBufferGeometry(2, 32, 16), new THREE.MeshNormalMaterial({
  wireframe: true
}));
scene.add(model);

// hotspots
let hotspots = [];
setHotspot(0xffff00);
setHotspot(0xff00ff);
setHotspot(0x00ffff);

let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let triangle = new THREE.Triangle();
let axis = new THREE.Vector3();
let camPos = new THREE.Vector3();
let intersects;

document.addEventListener("pointerup", onMouseUp);

function onMouseUp(event) {

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);

  intersects = raycaster.intersectObjects(hotspots);
  if (intersects.length > 0) {

    let obj = intersects[0].object;
		
    triangle.set(obj.position, scene.position, camera.position);
    triangle.getNormal(axis);
    
    let angle = camera.position.angleTo(obj.position);
    let a = {
      angle: 0
    };
    let duration = angle / Math.PI * 2;
    
    camPos.copy(camera.position);
    
    gsap.to(a, {
      angle: angle,
      duration: duration,
      onStart: function() {
        controls.enabled = false;
      },
      onUpdate: function(value) {
        camera.position.copy(camPos).applyAxisAngle(axis, value.angle);
        controls.update();
      },
      onUpdateParams:[a],
      onComplete: function() {
        controls.enabled = true;
      }
    }).play();
    
 ...