JSFiddle - React, Tailwind, and code Playground

CSS

body {
	  margin: 0;
}

JavaScript

import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';

import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js';

let camera, controls, scene, renderer;

let offscreen = false;

init();
animate();

function init() {

	scene = new THREE.Scene();
	scene.background = new THREE.Color( 0xcccccc );
	scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );

	renderer = new THREE.WebGLRenderer( { antialias: true } );
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	document.body.appendChild( renderer.domElement );

	camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
	camera.position.set( 400, 200, 0 );

	// controls

	controls = new OrbitControls( camera, renderer.domElement );
	controls.listenToKeyEvents( window ); // optional

	controls.enableDamping = true;
	controls.dampingFactor = 0.05;

	controls.screenSpacePanning = false;

	controls.minDistance = 100;
	controls.maxDistance = 500;

	controls.maxPolarAngle = Math.PI / 2;
	
	document.addEventListener( 'pointerleave', function() {
	
		offscreen = true;
	
	} );
	
	document.addEventListener( 'pointerenter', function() {
	
		offscreen = false;
	
	} );

	// world

	const geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 );
	const material = new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } );

	for ( let i = 0; i < 500; i ++ ) {

		const mesh = new THREE.Mesh( geometry, material );
		mesh.position.x = Math.random() * 1600 - 800;
		mesh.position.y = 0;
		mesh.position.z = Math.random() * 1600 - 800;
		mesh.updateMatrix();
		mesh.matrixAutoUpdate = false;
		scene.add( mesh );

	}

	// lights

	const dirLight1 = new THREE.DirectionalLight( 0xffffff );
	dirLight1.position.set( 1, 1, 1 );
	scene.add( dirLight1 );

	const dirLight2 = new THREE.DirectionalLight( 0x002288 );
	dirLight2.position.set( - 1, - 1, - 1...