Explorar o código

Manual: Honor latest changes. (#26355)

Michael Herzog %!s(int64=2) %!d(string=hai) anos
pai
achega
4e07037493
Modificáronse 64 ficheiros con 8114 adicións e 6374 borrados
  1. 19 8
      manual/en/textures.html
  2. 1 0
      manual/en/voxel-geometry.html
  3. 91 70
      manual/examples/render-on-demand-w-damping.html
  4. 122 93
      manual/examples/render-on-demand-w-gui.html
  5. 93 72
      manual/examples/render-on-demand.html
  6. 119 99
      manual/examples/render-target.html
  7. 18 14
      manual/examples/responsive-editor.html
  8. 82 64
      manual/examples/responsive-hd-dpi.html
  9. 58 47
      manual/examples/responsive-no-resize.html
  10. 61 50
      manual/examples/responsive-update-camera.html
  11. 81 63
      manual/examples/responsive.html
  12. 102 81
      manual/examples/scenegraph-car.html
  13. 151 125
      manual/examples/scenegraph-sun-earth-moon-axes-grids.html
  14. 108 90
      manual/examples/scenegraph-sun-earth-moon-axes.html
  15. 98 82
      manual/examples/scenegraph-sun-earth-moon.html
  16. 84 68
      manual/examples/scenegraph-sun-earth-orbit-fixed.html
  17. 80 64
      manual/examples/scenegraph-sun-earth-orbit.html
  18. 80 64
      manual/examples/scenegraph-sun-earth.html
  19. 75 59
      manual/examples/scenegraph-sun.html
  20. 259 234
      manual/examples/scenegraph-tank.html
  21. 91 75
      manual/examples/shadertoy-as-texture.html
  22. 56 46
      manual/examples/shadertoy-basic-x40.html
  23. 56 46
      manual/examples/shadertoy-basic.html
  24. 63 53
      manual/examples/shadertoy-bleepy-blocks.html
  25. 45 35
      manual/examples/shadertoy-prep.html
  26. 244 188
      manual/examples/shadows-directional-light-shadow-acne.html
  27. 243 186
      manual/examples/shadows-directional-light-with-camera-gui.html
  28. 167 132
      manual/examples/shadows-directional-light-with-camera-helper.html
  29. 164 129
      manual/examples/shadows-directional-light.html
  30. 162 137
      manual/examples/shadows-fake.html
  31. 211 162
      manual/examples/shadows-point-light.html
  32. 235 178
      manual/examples/shadows-spot-light-with-camera-gui.html
  33. 238 181
      manual/examples/shadows-spot-light-with-shadow-radius.html
  34. 81 59
      manual/examples/textured-cube-6-textures.html
  35. 137 104
      manual/examples/textured-cube-adjust.html
  36. 98 72
      manual/examples/textured-cube-wait-for-all-textures.html
  37. 73 55
      manual/examples/textured-cube-wait-for-texture.html
  38. 71 54
      manual/examples/textured-cube.html
  39. 2 1
      manual/examples/threejs-responsive.js
  40. 112 89
      manual/examples/tips-preservedrawingbuffer.html
  41. 108 82
      manual/examples/tips-screenshot-bad.html
  42. 121 92
      manual/examples/tips-screenshot-good.html
  43. 34 23
      manual/examples/tips-tabindex.html
  44. 89 71
      manual/examples/tips-transparent-canvas.html
  45. 119 91
      manual/examples/transparency-doubleside-hack.html
  46. 112 86
      manual/examples/transparency-doubleside.html
  47. 148 109
      manual/examples/transparency-intersecting-planes-alphatest.html
  48. 113 88
      manual/examples/transparency-intersecting-planes-fixed.html
  49. 98 75
      manual/examples/transparency-intersecting-planes.html
  50. 111 85
      manual/examples/transparency.html
  51. 615 478
      manual/examples/voxel-geometry-culled-faces-ui.html
  52. 337 268
      manual/examples/voxel-geometry-culled-faces-with-textures.html
  53. 292 226
      manual/examples/voxel-geometry-culled-faces.html
  54. 104 77
      manual/examples/voxel-geometry-merged.html
  55. 119 84
      manual/examples/voxel-geometry-separate-cubes.html
  56. 114 90
      manual/examples/webxr-basic-vr-optional.html
  57. 98 78
      manual/examples/webxr-basic-w-background.html
  58. 85 67
      manual/examples/webxr-basic.html
  59. 109 95
      manual/examples/webxr-look-to-select-selector.html
  60. 238 196
      manual/examples/webxr-look-to-select-w-cursor.html
  61. 138 108
      manual/examples/webxr-look-to-select.html
  62. 257 201
      manual/examples/webxr-point-to-select-w-move.html
  63. 223 175
      manual/examples/webxr-point-to-select.html
  64. 1 0
      manual/ko/voxel-geometry.html

+ 19 - 8
manual/en/textures.html

@@ -66,10 +66,12 @@ put this image on cube.</p>
 <a href="/docs/#api/en/loaders/TextureLoader#load"><code class="notranslate" translate="no">load</code></a> method with the URL of an
 image and set the material's <code class="notranslate" translate="no">map</code> property to the result instead of setting its <code class="notranslate" translate="no">color</code>.</p>
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader();
++const texture = loader.load( 'resources/images/wall.jpg' );
++texture.colorSpace = THREE.SRGBColorSpace;
 
 const material = new THREE.MeshBasicMaterial({
 -  color: 0xFF8844,
-+  map: loader.load('resources/images/wall.jpg'),
++  map: texture,
 });
 </pre>
 <p>Note that we're using <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a> so no need for any lights.</p>
@@ -96,20 +98,28 @@ const material = new THREE.MeshBasicMaterial({
 
 <p>We just make 6 materials and pass them as an array when we create the <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a></p>
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
+-const texture = loader.load( 'resources/images/wall.jpg' );
+-texture.colorSpace = THREE.SRGBColorSpace;
 
 -const material = new THREE.MeshBasicMaterial({
--  map: loader.load('resources/images/wall.jpg'),
+-  map: texture,
 -});
 +const materials = [
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
-+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-1.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-2.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-3.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-4.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-5.jpg')}),
++  new THREE.MeshBasicMaterial({map: loadColorTexture('resources/images/flower-6.jpg')}),
 +];
 -const cube = new THREE.Mesh(geometry, material);
 +const cube = new THREE.Mesh(geometry, materials);
+
++function loadColorTexture( path ) {
++  const texture = loader.load( path );
++  texture.colorSpace = THREE.SRGBColorSpace;
++  return texture;
++}
 </pre>
 <p>It works!</p>
 <p></p><div translate="no" class="threejs_example_container notranslate">
@@ -152,6 +162,7 @@ we can wait for the texture to load before creating our <a href="/docs/#api/en/o
 like this</p>
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
 loader.load('resources/images/wall.jpg', (texture) =&gt; {
+  texture.colorSpace = THREE.SRGBColorSpace;
   const material = new THREE.MeshBasicMaterial({
     map: texture,
   });

+ 1 - 0
manual/en/voxel-geometry.html

@@ -691,6 +691,7 @@ of the texture.</p>
 const texture = loader.load('resources/images/minecraft/flourish-cc-by-nc-sa.png', render);
 texture.magFilter = THREE.NearestFilter;
 texture.minFilter = THREE.NearestFilter;
+texture.colorSpace = THREE.SRGBColorSpace;
 </pre>
 <p>and pass the settings to the <code class="notranslate" translate="no">VoxelWorld</code> class</p>
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const tileSize = 16;

+ 91 - 70
manual/examples/render-on-demand-w-damping.html

@@ -35,90 +35,111 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.enableDamping = true;
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const controls = new OrbitControls( camera, canvas );
+	controls.enableDamping = true;
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    cube.position.x = x;
+	const scene = new THREE.Scene();
 
-    return cube;
-  }
+	{
 
-  makeInstance(geometry, 0x44aa88,  0);
-  makeInstance(geometry, 0x8844aa, -2);
-  makeInstance(geometry, 0xaa8844,  2);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  let renderRequested = false;
+	}
 
-  function render() {
-    renderRequested = undefined;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	makeInstance( geometry, 0x44aa88, 0 );
+	makeInstance( geometry, 0x8844aa, - 2 );
+	makeInstance( geometry, 0xaa8844, 2 );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 122 - 93
manual/examples/render-on-demand-w-gui.html

@@ -35,115 +35,144 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.enableDamping = true;
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const gui = new GUI();
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const controls = new OrbitControls( camera, canvas );
+	controls.enableDamping = true;
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const gui = new GUI();
 
-    cube.position.x = x;
+	const scene = new THREE.Scene();
 
-    const folder = gui.addFolder(`Cube${x}`);
-    folder.addColor(new ColorGUIHelper(material, 'color'), 'value')
-        .name('color')
-        .onChange(requestRenderIfNotRequested);
-    folder.add(cube.scale, 'x', .1, 1.5)
-        .name('scale x')
-        .onChange(requestRenderIfNotRequested);
-    folder.open();
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  makeInstance(geometry, 0x44aa88,  0);
-  makeInstance(geometry, 0x8844aa, -2);
-  makeInstance(geometry, 0xaa8844,  2);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  let renderRequested = false;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function render() {
-    renderRequested = undefined;
+	class ColorGUIHelper {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		constructor( object, prop ) {
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+			this.object = object;
+			this.prop = prop;
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeInstance( geometry, color, x ) {
+
+		const material = new THREE.MeshPhongMaterial( { color } );
+
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+
+		const folder = gui.addFolder( `Cube${x}` );
+		folder.addColor( new ColorGUIHelper( material, 'color' ), 'value' )
+			.name( 'color' )
+			.onChange( requestRenderIfNotRequested );
+		folder.add( cube.scale, 'x', .1, 1.5 )
+			.name( 'scale x' )
+			.onChange( requestRenderIfNotRequested );
+		folder.open();
+
+		return cube;
+
+	}
+
+	makeInstance( geometry, 0x44aa88, 0 );
+	makeInstance( geometry, 0x8844aa, - 2 );
+	makeInstance( geometry, 0xaa8844, 2 );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 93 - 72
manual/examples/render-on-demand.html

@@ -35,88 +35,109 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    cube.position.x = x;
+	const scene = new THREE.Scene();
 
-    return cube;
-  }
+	{
 
-  makeInstance(geometry, 0x44aa88,  0);
-  makeInstance(geometry, 0x8844aa, -2);
-  makeInstance(geometry, 0xaa8844,  2);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  function render() {
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	}
+
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
+
+	function makeInstance( geometry, color, x ) {
+
+		const material = new THREE.MeshPhongMaterial( { color } );
+
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	makeInstance( geometry, 0x44aa88, 0 );
+	makeInstance( geometry, 0x8844aa, - 2 );
+	makeInstance( geometry, 0xaa8844, 2 );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	controls.addEventListener( 'change', render );
+	window.addEventListener( 'resize', render );
+
+	// note: this is a workaround for an OrbitControls issue
+	// in an iframe. Will remove once the issue is fixed in
+	// three.js
+	window.addEventListener( 'mousedown', ( e ) => {
+
+		e.preventDefault();
+		window.focus();
+
+	} );
+	window.addEventListener( 'keydown', ( e ) => {
+
+		e.preventDefault();
+
+	} );
 
-    renderer.render(scene, camera);
-  }
-  render();
-
-  controls.addEventListener('change', render);
-  window.addEventListener('resize', render);
-
-  // note: this is a workaround for an OrbitControls issue
-  // in an iframe. Will remove once the issue is fixed in
-  // three.js
-  window.addEventListener('mousedown', (e) => {
-    e.preventDefault();
-    window.focus();
-  });
-  window.addEventListener('keydown', (e) => {
-    e.preventDefault();
-  });
 }
 
 main();

+ 119 - 99
manual/examples/render-target.html

@@ -36,120 +36,140 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const rtWidth = 512;
-  const rtHeight = 512;
-  const renderTarget = new THREE.WebGLRenderTarget(rtWidth, rtHeight);
-
-  const rtFov = 75;
-  const rtAspect = rtWidth / rtHeight;
-  const rtNear = 0.1;
-  const rtFar = 5;
-  const rtCamera = new THREE.PerspectiveCamera(rtFov, rtAspect, rtNear, rtFar);
-  rtCamera.position.z = 2;
-
-  const rtScene = new THREE.Scene();
-  rtScene.background = new THREE.Color('red');
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    rtScene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const rtWidth = 512;
+	const rtHeight = 512;
+	const renderTarget = new THREE.WebGLRenderTarget( rtWidth, rtHeight );
 
-    const cube = new THREE.Mesh(geometry, material);
-    rtScene.add(cube);
+	const rtFov = 75;
+	const rtAspect = rtWidth / rtHeight;
+	const rtNear = 0.1;
+	const rtFar = 5;
+	const rtCamera = new THREE.PerspectiveCamera( rtFov, rtAspect, rtNear, rtFar );
+	rtCamera.position.z = 2;
 
-    cube.position.x = x;
+	const rtScene = new THREE.Scene();
+	rtScene.background = new THREE.Color( 'red' );
 
-    return cube;
-  }
+	{
 
-  const rtCubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		rtScene.add( light );
 
-  const material = new THREE.MeshPhongMaterial({
-    map: renderTarget.texture,
-  });
-  const cube = new THREE.Mesh(geometry, material);
-  scene.add(cube);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    // rotate all the cubes in the render target scene
-    rtCubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    // draw render target scene to render target
-    renderer.setRenderTarget(renderTarget);
-    renderer.render(rtScene, rtCamera);
-    renderer.setRenderTarget(null);
+		const cube = new THREE.Mesh( geometry, material );
+		rtScene.add( cube );
 
-    // rotate the cube in the scene
-    cube.rotation.x = time;
-    cube.rotation.y = time * 1.1;
+		cube.position.x = x;
 
-    // render the scene to the canvas
-    renderer.render(scene, camera);
+		return cube;
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const rtCubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
+
+	const scene = new THREE.Scene();
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 1;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	const material = new THREE.MeshPhongMaterial( {
+		map: renderTarget.texture,
+	} );
+	const cube = new THREE.Mesh( geometry, material );
+	scene.add( cube );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		// rotate all the cubes in the render target scene
+		rtCubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		// draw render target scene to render target
+		renderer.setRenderTarget( renderTarget );
+		renderer.render( rtScene, rtCamera );
+		renderer.setRenderTarget( null );
+
+		// rotate the cube in the scene
+		cube.rotation.x = time;
+		cube.rotation.y = time * 1.1;
+
+		// render the scene to the canvas
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 18 - 14
manual/examples/responsive-editor.html

@@ -63,19 +63,23 @@
 
 // This code is only related to handling the split.
 // Our three.js code has not changed
-Split(['#view', '#controls'], {  // eslint-disable-line new-cap
-  sizes: [75, 25],
-  minSize: 100,
-  elementStyle: (dimension, size, gutterSize) => {
-    return {
-      'flex-basis': `calc(${size}% - ${gutterSize}px)`,
-    };
-  },
-  gutterStyle: (dimension, gutterSize) => {
-    return {
-      'flex-basis': `${gutterSize}px`,
-    };
-  },
-});
+Split( [ '#view', '#controls' ], { // eslint-disable-line new-cap
+	sizes: [ 75, 25 ],
+	minSize: 100,
+	elementStyle: ( dimension, size, gutterSize ) => {
+
+		return {
+			'flex-basis': `calc(${size}% - ${gutterSize}px)`,
+		};
+
+	},
+	gutterStyle: ( dimension, gutterSize ) => {
+
+		return {
+			'flex-basis': `${gutterSize}px`,
+		};
+
+	},
+} );
 </script>
 </html>

+ 82 - 64
manual/examples/responsive-hd-dpi.html

@@ -36,82 +36,100 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const pixelRatio = window.devicePixelRatio;
-    const width  = canvas.clientWidth  * pixelRatio | 0;
-    const height = canvas.clientHeight * pixelRatio | 0;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    requestAnimationFrame(render);
-  }
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const pixelRatio = window.devicePixelRatio;
+		const width = canvas.clientWidth * pixelRatio | 0;
+		const height = canvas.clientHeight * pixelRatio | 0;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 58 - 47
manual/examples/responsive-no-resize.html

@@ -36,64 +36,75 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	function makeInstance( geometry, color, x ) {
 
-    renderer.render(scene, camera);
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    requestAnimationFrame(render);
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 61 - 50
manual/examples/responsive-update-camera.html

@@ -36,68 +36,79 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    const canvas = renderer.domElement;
-    camera.aspect = canvas.clientWidth / canvas.clientHeight;
-    camera.updateProjectionMatrix();
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    requestAnimationFrame(render);
-  }
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		const canvas = renderer.domElement;
+		camera.aspect = canvas.clientWidth / canvas.clientHeight;
+		camera.updateProjectionMatrix();
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 81 - 63
manual/examples/responsive.html

@@ -36,81 +36,99 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    requestAnimationFrame(render);
-  }
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 102 - 81
manual/examples/scenegraph-car.html

@@ -37,95 +37,116 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.setClearColor(0xAAAAAA);
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(8, 4, 10);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const light = new THREE.DirectionalLight(0xffffff, 1);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
-  {
-    const light = new THREE.DirectionalLight(0xffffff, 1);
-    light.position.set(1, -2, -4);
-    scene.add(light);
-  }
 
-  const carWidth = 4;
-  const carHeight = 1;
-  const carLength = 8;
-
-  const bodyGeometry = new THREE.BoxGeometry(carWidth, carHeight, carLength);
-  const bodyMaterial = new THREE.MeshPhongMaterial({color: 0x6688AA});
-  const bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
-  scene.add(bodyMesh);
-
-  const wheelRadius = 1;
-  const wheelThickness = .5;
-  const wheelSegments = 6;
-  const wheelGeometry = new THREE.CylinderGeometry(
-      wheelRadius,     // top radius
-      wheelRadius,     // bottom radius
-      wheelThickness,  // height of cylinder
-      wheelSegments);
-  const wheelMaterial = new THREE.MeshPhongMaterial({color: 0x888888});
-  const wheelPositions = [
-    [-carWidth / 2 + wheelThickness / 2, -carHeight / 2,  carLength / 3],
-    [ carWidth / 2 + wheelThickness / 2, -carHeight / 2,  carLength / 3],
-    [-carWidth / 2 + wheelThickness / 2, -carHeight / 2, -carLength / 3],
-    [ carWidth / 2 + wheelThickness / 2, -carHeight / 2, -carLength / 3],
-  ];
-  const wheelMeshes = wheelPositions.map((position) => {
-    const mesh = new THREE.Mesh(wheelGeometry, wheelMaterial);
-    mesh.position.set(...position);
-    mesh.rotation.z = Math.PI * .5;
-    scene.add(mesh);
-    return mesh;
-  });
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.setClearColor( 0xAAAAAA );
 
-  // const carPosition = [0, 0, 0];
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 8, 4, 10 );
+	camera.lookAt( 0, 0, 0 );
 
-  function render(time) {
-    time *= 0.001;
+	const scene = new THREE.Scene();
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	{
 
-    wheelMeshes.forEach((obj) => {
-      obj.rotation.x = time;
-    });
+		const light = new THREE.DirectionalLight( 0xffffff, 3 );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-    renderer.render(scene, camera);
+	}
 
-    requestAnimationFrame(render);
-  }
+	{
+
+		const light = new THREE.DirectionalLight( 0xffffff, 3 );
+		light.position.set( 1, - 2, - 4 );
+		scene.add( light );
+
+	}
+
+	const carWidth = 4;
+	const carHeight = 1;
+	const carLength = 8;
+
+	const bodyGeometry = new THREE.BoxGeometry( carWidth, carHeight, carLength );
+	const bodyMaterial = new THREE.MeshPhongMaterial( { color: 0x6688AA } );
+	const bodyMesh = new THREE.Mesh( bodyGeometry, bodyMaterial );
+	scene.add( bodyMesh );
+
+	const wheelRadius = 1;
+	const wheelThickness = .5;
+	const wheelSegments = 6;
+	const wheelGeometry = new THREE.CylinderGeometry(
+		wheelRadius, // top radius
+		wheelRadius, // bottom radius
+		wheelThickness, // height of cylinder
+		wheelSegments );
+	const wheelMaterial = new THREE.MeshPhongMaterial( { color: 0x888888 } );
+	const wheelPositions = [
+		[ - carWidth / 2 + wheelThickness / 2, - carHeight / 2, carLength / 3 ],
+		[ carWidth / 2 + wheelThickness / 2, - carHeight / 2, carLength / 3 ],
+		[ - carWidth / 2 + wheelThickness / 2, - carHeight / 2, - carLength / 3 ],
+		[ carWidth / 2 + wheelThickness / 2, - carHeight / 2, - carLength / 3 ],
+	];
+	const wheelMeshes = wheelPositions.map( ( position ) => {
+
+		const mesh = new THREE.Mesh( wheelGeometry, wheelMaterial );
+		mesh.position.set( ...position );
+		mesh.rotation.z = Math.PI * .5;
+		scene.add( mesh );
+		return mesh;
+
+	} );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	// const carPosition = [0, 0, 0];
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		wheelMeshes.forEach( ( obj ) => {
+
+			obj.rotation.x = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 151 - 125
manual/examples/scenegraph-sun-earth-moon-axes-grids.html

@@ -61,142 +61,168 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  const gui = new GUI();
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const solarSystem = new THREE.Object3D();
-  scene.add(solarSystem);
-  objects.push(solarSystem);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  solarSystem.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthOrbit = new THREE.Object3D();
-  earthOrbit.position.x = 10;
-  solarSystem.add(earthOrbit);
-  objects.push(earthOrbit);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthOrbit.add(earthMesh);
-  objects.push(earthMesh);
-
-  const moonOrbit = new THREE.Object3D();
-  moonOrbit.position.x = 2;
-  earthOrbit.add(moonOrbit);
-
-  const moonMaterial = new THREE.MeshPhongMaterial({color: 0x888888, emissive: 0x222222});
-  const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
-  moonMesh.scale.set(.5, .5, .5);
-  moonOrbit.add(moonMesh);
-  objects.push(moonMesh);
-
-  // Turns both axes and grid visible on/off
-  // GUI requires a property that returns a bool
-  // to decide to make a checkbox so we make a setter
-  // can getter for `visible` which we can tell GUI
-  // to look at.
-  class AxisGridHelper {
-    constructor(node, units = 10) {
-      const axes = new THREE.AxesHelper();
-      axes.material.depthTest = false;
-      axes.renderOrder = 2;  // after the grid
-      node.add(axes);
-
-      const grid = new THREE.GridHelper(units, units);
-      grid.material.depthTest = false;
-      grid.renderOrder = 1;
-      node.add(grid);
-
-      this.grid = grid;
-      this.axes = axes;
-      this.visible = false;
-    }
-    get visible() {
-      return this._visible;
-    }
-    set visible(v) {
-      this._visible = v;
-      this.grid.visible = v;
-      this.axes.visible = v;
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	const gui = new GUI();
 
-  function makeAxisGrid(node, label, units) {
-    const helper = new AxisGridHelper(node, units);
-    gui.add(helper, 'visible').name(label);
-  }
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-  makeAxisGrid(solarSystem, 'solarSystem', 26);
-  makeAxisGrid(sunMesh, 'sunMesh');
-  makeAxisGrid(earthOrbit, 'earthOrbit');
-  makeAxisGrid(earthMesh, 'earthMesh');
-  makeAxisGrid(moonOrbit, 'moonOrbit');
-  makeAxisGrid(moonMesh, 'moonMesh');
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const scene = new THREE.Scene();
 
-  function render(time) {
-    time *= 0.001;
+	{
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	}
 
-    renderer.render(scene, camera);
+	const objects = [];
 
-    requestAnimationFrame(render);
-  }
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const solarSystem = new THREE.Object3D();
+	scene.add( solarSystem );
+	objects.push( solarSystem );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	solarSystem.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthOrbit = new THREE.Object3D();
+	earthOrbit.position.x = 10;
+	solarSystem.add( earthOrbit );
+	objects.push( earthOrbit );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthOrbit.add( earthMesh );
+	objects.push( earthMesh );
+
+	const moonOrbit = new THREE.Object3D();
+	moonOrbit.position.x = 2;
+	earthOrbit.add( moonOrbit );
+
+	const moonMaterial = new THREE.MeshPhongMaterial( { color: 0x888888, emissive: 0x222222 } );
+	const moonMesh = new THREE.Mesh( sphereGeometry, moonMaterial );
+	moonMesh.scale.set( .5, .5, .5 );
+	moonOrbit.add( moonMesh );
+	objects.push( moonMesh );
+
+	// Turns both axes and grid visible on/off
+	// GUI requires a property that returns a bool
+	// to decide to make a checkbox so we make a setter
+	// can getter for `visible` which we can tell GUI
+	// to look at.
+	class AxisGridHelper {
+
+		constructor( node, units = 10 ) {
+
+			const axes = new THREE.AxesHelper();
+			axes.material.depthTest = false;
+			axes.renderOrder = 2; // after the grid
+			node.add( axes );
+
+			const grid = new THREE.GridHelper( units, units );
+			grid.material.depthTest = false;
+			grid.renderOrder = 1;
+			node.add( grid );
+
+			this.grid = grid;
+			this.axes = axes;
+			this.visible = false;
+
+		}
+		get visible() {
+
+			return this._visible;
+
+		}
+		set visible( v ) {
+
+			this._visible = v;
+			this.grid.visible = v;
+			this.axes.visible = v;
+
+		}
+
+	}
+
+	function makeAxisGrid( node, label, units ) {
+
+		const helper = new AxisGridHelper( node, units );
+		gui.add( helper, 'visible' ).name( label );
+
+	}
+
+	makeAxisGrid( solarSystem, 'solarSystem', 26 );
+	makeAxisGrid( sunMesh, 'sunMesh' );
+	makeAxisGrid( earthOrbit, 'earthOrbit' );
+	makeAxisGrid( earthMesh, 'earthMesh' );
+	makeAxisGrid( moonOrbit, 'moonOrbit' );
+	makeAxisGrid( moonMesh, 'moonMesh' );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 108 - 90
manual/examples/scenegraph-sun-earth-moon-axes.html

@@ -36,103 +36,121 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const solarSystem = new THREE.Object3D();
-  scene.add(solarSystem);
-  objects.push(solarSystem);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  solarSystem.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthOrbit = new THREE.Object3D();
-  earthOrbit.position.x = 10;
-  solarSystem.add(earthOrbit);
-  objects.push(earthOrbit);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthOrbit.add(earthMesh);
-  objects.push(earthMesh);
-
-  const moonOrbit = new THREE.Object3D();
-  moonOrbit.position.x = 2;
-  earthOrbit.add(moonOrbit);
-
-  const moonMaterial = new THREE.MeshPhongMaterial({color: 0x888888, emissive: 0x222222});
-  const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
-  moonMesh.scale.set(.5, .5, .5);
-  moonOrbit.add(moonMesh);
-  objects.push(moonMesh);
-
-  // add an AxesHelper to each node
-  objects.forEach((node) => {
-    const axes = new THREE.AxesHelper();
-    axes.material.depthTest = false;
-    axes.renderOrder = 1;
-    node.add(axes);
-  });
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const solarSystem = new THREE.Object3D();
+	scene.add( solarSystem );
+	objects.push( solarSystem );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	solarSystem.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthOrbit = new THREE.Object3D();
+	earthOrbit.position.x = 10;
+	solarSystem.add( earthOrbit );
+	objects.push( earthOrbit );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthOrbit.add( earthMesh );
+	objects.push( earthMesh );
+
+	const moonOrbit = new THREE.Object3D();
+	moonOrbit.position.x = 2;
+	earthOrbit.add( moonOrbit );
+
+	const moonMaterial = new THREE.MeshPhongMaterial( { color: 0x888888, emissive: 0x222222 } );
+	const moonMesh = new THREE.Mesh( sphereGeometry, moonMaterial );
+	moonMesh.scale.set( .5, .5, .5 );
+	moonOrbit.add( moonMesh );
+	objects.push( moonMesh );
+
+	// add an AxesHelper to each node
+	objects.forEach( ( node ) => {
+
+		const axes = new THREE.AxesHelper();
+		axes.material.depthTest = false;
+		axes.renderOrder = 1;
+		node.add( axes );
+
+	} );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 98 - 82
manual/examples/scenegraph-sun-earth-moon.html

@@ -36,95 +36,111 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const solarSystem = new THREE.Object3D();
-  scene.add(solarSystem);
-  objects.push(solarSystem);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  solarSystem.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthOrbit = new THREE.Object3D();
-  earthOrbit.position.x = 10;
-  solarSystem.add(earthOrbit);
-  objects.push(earthOrbit);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthOrbit.add(earthMesh);
-  objects.push(earthMesh);
-
-  const moonOrbit = new THREE.Object3D();
-  moonOrbit.position.x = 2;
-  earthOrbit.add(moonOrbit);
-
-  const moonMaterial = new THREE.MeshPhongMaterial({color: 0x888888, emissive: 0x222222});
-  const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
-  moonMesh.scale.set(.5, .5, .5);
-  moonOrbit.add(moonMesh);
-  objects.push(moonMesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const solarSystem = new THREE.Object3D();
+	scene.add( solarSystem );
+	objects.push( solarSystem );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	solarSystem.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthOrbit = new THREE.Object3D();
+	earthOrbit.position.x = 10;
+	solarSystem.add( earthOrbit );
+	objects.push( earthOrbit );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthOrbit.add( earthMesh );
+	objects.push( earthMesh );
+
+	const moonOrbit = new THREE.Object3D();
+	moonOrbit.position.x = 2;
+	earthOrbit.add( moonOrbit );
+
+	const moonMaterial = new THREE.MeshPhongMaterial( { color: 0x888888, emissive: 0x222222 } );
+	const moonMesh = new THREE.Mesh( sphereGeometry, moonMaterial );
+	moonMesh.scale.set( .5, .5, .5 );
+	moonOrbit.add( moonMesh );
+	objects.push( moonMesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 84 - 68
manual/examples/scenegraph-sun-earth-orbit-fixed.html

@@ -36,81 +36,97 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const solarSystem = new THREE.Object3D();
-  scene.add(solarSystem);
-  objects.push(solarSystem);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  solarSystem.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthMesh.position.x = 10;
-  solarSystem.add(earthMesh);
-  objects.push(earthMesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const solarSystem = new THREE.Object3D();
+	scene.add( solarSystem );
+	objects.push( solarSystem );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	solarSystem.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthMesh.position.x = 10;
+	solarSystem.add( earthMesh );
+	objects.push( earthMesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 80 - 64
manual/examples/scenegraph-sun-earth-orbit.html

@@ -36,77 +36,93 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 150, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  scene.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthMesh.position.x = 10;
-  sunMesh.add(earthMesh);
-  objects.push(earthMesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 150, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	scene.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthMesh.position.x = 10;
+	sunMesh.add( earthMesh );
+	objects.push( earthMesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 80 - 64
manual/examples/scenegraph-sun-earth.html

@@ -36,77 +36,93 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  scene.add(sunMesh);
-  objects.push(sunMesh);
-
-  const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
-  const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
-  earthMesh.position.x = 10;
-  scene.add(earthMesh);
-  objects.push(earthMesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	scene.add( sunMesh );
+	objects.push( sunMesh );
+
+	const earthMaterial = new THREE.MeshPhongMaterial( { color: 0x2233FF, emissive: 0x112244 } );
+	const earthMesh = new THREE.Mesh( sphereGeometry, earthMaterial );
+	earthMesh.position.x = 10;
+	scene.add( earthMesh );
+	objects.push( earthMesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 75 - 59
manual/examples/scenegraph-sun.html

@@ -36,72 +36,88 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 40;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 50, 0);
-  camera.up.set(0, 0, 1);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 3;
-    const light = new THREE.PointLight(color, intensity);
-    scene.add(light);
-  }
 
-  // an array of objects who's rotation to update
-  const objects = [];
-
-  const radius = 1;
-  const widthSegments = 6;
-  const heightSegments = 6;
-  const sphereGeometry = new THREE.SphereGeometry(
-      radius, widthSegments, heightSegments);
-
-  const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
-  const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
-  sunMesh.scale.set(5, 5, 5);
-  scene.add(sunMesh);
-  objects.push(sunMesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function render(time) {
-    time *= 0.001;
+	const fov = 40;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 50, 0 );
+	camera.up.set( 0, 0, 1 );
+	camera.lookAt( 0, 0, 0 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
 
-    objects.forEach((obj) => {
-      obj.rotation.y = time;
-    });
+	{
 
-    renderer.render(scene, camera);
+		const color = 0xFFFFFF;
+		const intensity = 500;
+		const light = new THREE.PointLight( color, intensity );
+		scene.add( light );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	// an array of objects who's rotation to update
+	const objects = [];
+
+	const radius = 1;
+	const widthSegments = 6;
+	const heightSegments = 6;
+	const sphereGeometry = new THREE.SphereGeometry(
+		radius, widthSegments, heightSegments );
+
+	const sunMaterial = new THREE.MeshPhongMaterial( { emissive: 0xFFFF00 } );
+	const sunMesh = new THREE.Mesh( sphereGeometry, sunMaterial );
+	sunMesh.scale.set( 5, 5, 5 );
+	scene.add( sunMesh );
+	objects.push( sunMesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		objects.forEach( ( obj ) => {
+
+			obj.rotation.y = time;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 259 - 234
manual/examples/scenegraph-tank.html

@@ -46,253 +46,278 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas: canvas});
-  renderer.setClearColor(0xAAAAAA);
-  renderer.shadowMap.enabled = true;
-
-  function makeCamera(fov = 40) {
-    const aspect = 2;  // the canvas default
-    const zNear = 0.1;
-    const zFar = 1000;
-    return new THREE.PerspectiveCamera(fov, aspect, zNear, zFar);
-  }
-  const camera = makeCamera();
-  camera.position.set(8, 4, 10).multiplyScalar(3);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const light = new THREE.DirectionalLight(0xffffff, 1);
-    light.position.set(0, 20, 0);
-    scene.add(light);
-    light.castShadow = true;
-    light.shadow.mapSize.width = 2048;
-    light.shadow.mapSize.height = 2048;
-
-    const d = 50;
-    light.shadow.camera.left = -d;
-    light.shadow.camera.right = d;
-    light.shadow.camera.top = d;
-    light.shadow.camera.bottom = -d;
-    light.shadow.camera.near = 1;
-    light.shadow.camera.far = 50;
-    light.shadow.bias = 0.001;
-  }
 
-  {
-    const light = new THREE.DirectionalLight(0xffffff, 1);
-    light.position.set(1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas: canvas } );
+	renderer.useLegacyLights = false;
+	renderer.setClearColor( 0xAAAAAA );
+	renderer.shadowMap.enabled = true;
+
+	function makeCamera( fov = 40 ) {
+
+		const aspect = 2; // the canvas default
+		const zNear = 0.1;
+		const zFar = 1000;
+		return new THREE.PerspectiveCamera( fov, aspect, zNear, zFar );
+
+	}
+
+	const camera = makeCamera();
+	camera.position.set( 8, 4, 10 ).multiplyScalar( 3 );
+	camera.lookAt( 0, 0, 0 );
+
+	const scene = new THREE.Scene();
+
+	{
+
+		const light = new THREE.DirectionalLight( 0xffffff, 3 );
+		light.position.set( 0, 20, 0 );
+		scene.add( light );
+		light.castShadow = true;
+		light.shadow.mapSize.width = 2048;
+		light.shadow.mapSize.height = 2048;
+
+		const d = 50;
+		light.shadow.camera.left = - d;
+		light.shadow.camera.right = d;
+		light.shadow.camera.top = d;
+		light.shadow.camera.bottom = - d;
+		light.shadow.camera.near = 1;
+		light.shadow.camera.far = 50;
+		light.shadow.bias = 0.001;
+
+	}
+
+	{
+
+		const light = new THREE.DirectionalLight( 0xffffff, 3 );
+		light.position.set( 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	const groundGeometry = new THREE.PlaneGeometry( 50, 50 );
+	const groundMaterial = new THREE.MeshPhongMaterial( { color: 0xCC8866 } );
+	const groundMesh = new THREE.Mesh( groundGeometry, groundMaterial );
+	groundMesh.rotation.x = Math.PI * - .5;
+	groundMesh.receiveShadow = true;
+	scene.add( groundMesh );
+
+	const carWidth = 4;
+	const carHeight = 1;
+	const carLength = 8;
+
+	const tank = new THREE.Object3D();
+	scene.add( tank );
+
+	const bodyGeometry = new THREE.BoxGeometry( carWidth, carHeight, carLength );
+	const bodyMaterial = new THREE.MeshPhongMaterial( { color: 0x6688AA } );
+	const bodyMesh = new THREE.Mesh( bodyGeometry, bodyMaterial );
+	bodyMesh.position.y = 1.4;
+	bodyMesh.castShadow = true;
+	tank.add( bodyMesh );
+
+	const tankCameraFov = 75;
+	const tankCamera = makeCamera( tankCameraFov );
+	tankCamera.position.y = 3;
+	tankCamera.position.z = - 6;
+	tankCamera.rotation.y = Math.PI;
+	bodyMesh.add( tankCamera );
+
+	const wheelRadius = 1;
+	const wheelThickness = .5;
+	const wheelSegments = 6;
+	const wheelGeometry = new THREE.CylinderGeometry(
+		wheelRadius, // top radius
+		wheelRadius, // bottom radius
+		wheelThickness, // height of cylinder
+		wheelSegments );
+	const wheelMaterial = new THREE.MeshPhongMaterial( { color: 0x888888 } );
+	const wheelPositions = [
+		[ - carWidth / 2 - wheelThickness / 2, - carHeight / 2, carLength / 3 ],
+		[ carWidth / 2 + wheelThickness / 2, - carHeight / 2, carLength / 3 ],
+		[ - carWidth / 2 - wheelThickness / 2, - carHeight / 2, 0 ],
+		[ carWidth / 2 + wheelThickness / 2, - carHeight / 2, 0 ],
+		[ - carWidth / 2 - wheelThickness / 2, - carHeight / 2, - carLength / 3 ],
+		[ carWidth / 2 + wheelThickness / 2, - carHeight / 2, - carLength / 3 ],
+	];
+	const wheelMeshes = wheelPositions.map( ( position ) => {
+
+		const mesh = new THREE.Mesh( wheelGeometry, wheelMaterial );
+		mesh.position.set( ...position );
+		mesh.rotation.z = Math.PI * .5;
+		mesh.castShadow = true;
+		bodyMesh.add( mesh );
+		return mesh;
+
+	} );
+
+	const domeRadius = 2;
+	const domeWidthSubdivisions = 12;
+	const domeHeightSubdivisions = 12;
+	const domePhiStart = 0;
+	const domePhiEnd = Math.PI * 2;
+	const domeThetaStart = 0;
+	const domeThetaEnd = Math.PI * .5;
+	const domeGeometry = new THREE.SphereGeometry(
+		domeRadius, domeWidthSubdivisions, domeHeightSubdivisions,
+		domePhiStart, domePhiEnd, domeThetaStart, domeThetaEnd );
+	const domeMesh = new THREE.Mesh( domeGeometry, bodyMaterial );
+	domeMesh.castShadow = true;
+	bodyMesh.add( domeMesh );
+	domeMesh.position.y = .5;
+
+	const turretWidth = .1;
+	const turretHeight = .1;
+	const turretLength = carLength * .75 * .2;
+	const turretGeometry = new THREE.BoxGeometry(
+		turretWidth, turretHeight, turretLength );
+	const turretMesh = new THREE.Mesh( turretGeometry, bodyMaterial );
+	const turretPivot = new THREE.Object3D();
+	turretMesh.castShadow = true;
+	turretPivot.scale.set( 5, 5, 5 );
+	turretPivot.position.y = .5;
+	turretMesh.position.z = turretLength * .5;
+	turretPivot.add( turretMesh );
+	bodyMesh.add( turretPivot );
+
+	const turretCamera = makeCamera();
+	turretCamera.position.y = .75 * .2;
+	turretMesh.add( turretCamera );
+
+	const targetGeometry = new THREE.SphereGeometry( .5, 6, 3 );
+	const targetMaterial = new THREE.MeshPhongMaterial( { color: 0x00FF00, flatShading: true } );
+	const targetMesh = new THREE.Mesh( targetGeometry, targetMaterial );
+	const targetOrbit = new THREE.Object3D();
+	const targetElevation = new THREE.Object3D();
+	const targetBob = new THREE.Object3D();
+	targetMesh.castShadow = true;
+	scene.add( targetOrbit );
+	targetOrbit.add( targetElevation );
+	targetElevation.position.z = carLength * 2;
+	targetElevation.position.y = 8;
+	targetElevation.add( targetBob );
+	targetBob.add( targetMesh );
+
+	const targetCamera = makeCamera();
+	const targetCameraPivot = new THREE.Object3D();
+	targetCamera.position.y = 1;
+	targetCamera.position.z = - 2;
+	targetCamera.rotation.y = Math.PI;
+	targetBob.add( targetCameraPivot );
+	targetCameraPivot.add( targetCamera );
+
+	// Create a sine-like wave
+	const curve = new THREE.SplineCurve( [
+		new THREE.Vector2( - 10, 0 ),
+		new THREE.Vector2( - 5, 5 ),
+		new THREE.Vector2( 0, 0 ),
+		new THREE.Vector2( 5, - 5 ),
+		new THREE.Vector2( 10, 0 ),
+		new THREE.Vector2( 5, 10 ),
+		new THREE.Vector2( - 5, 10 ),
+		new THREE.Vector2( - 10, - 10 ),
+		new THREE.Vector2( - 15, - 8 ),
+		new THREE.Vector2( - 10, 0 ),
+	] );
+
+	const points = curve.getPoints( 50 );
+	const geometry = new THREE.BufferGeometry().setFromPoints( points );
+	const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
+	const splineObject = new THREE.Line( geometry, material );
+	splineObject.rotation.x = Math.PI * .5;
+	splineObject.position.y = 0.05;
+	scene.add( splineObject );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	const targetPosition = new THREE.Vector3();
+	const tankPosition = new THREE.Vector2();
+	const tankTarget = new THREE.Vector2();
+
+	const cameras = [
+		{ cam: camera, desc: 'detached camera', },
+		{ cam: turretCamera, desc: 'on turret looking at target', },
+		{ cam: targetCamera, desc: 'near target looking at tank', },
+		{ cam: tankCamera, desc: 'above back of tank', },
+	];
+
+	const infoElem = document.querySelector( '#info' );
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			cameras.forEach( ( cameraInfo ) => {
+
+				const camera = cameraInfo.cam;
+				camera.aspect = canvas.clientWidth / canvas.clientHeight;
+				camera.updateProjectionMatrix();
+
+			} );
+
+		}
+
+		// move target
+		targetOrbit.rotation.y = time * .27;
+		targetBob.position.y = Math.sin( time * 2 ) * 4;
+		targetMesh.rotation.x = time * 7;
+		targetMesh.rotation.y = time * 13;
+		targetMaterial.emissive.setHSL( time * 10 % 1, 1, .25 );
+		targetMaterial.color.setHSL( time * 10 % 1, 1, .25 );
 
-  const groundGeometry = new THREE.PlaneGeometry(50, 50);
-  const groundMaterial = new THREE.MeshPhongMaterial({color: 0xCC8866});
-  const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
-  groundMesh.rotation.x = Math.PI * -.5;
-  groundMesh.receiveShadow = true;
-  scene.add(groundMesh);
-
-  const carWidth = 4;
-  const carHeight = 1;
-  const carLength = 8;
-
-  const tank = new THREE.Object3D();
-  scene.add(tank);
-
-  const bodyGeometry = new THREE.BoxGeometry(carWidth, carHeight, carLength);
-  const bodyMaterial = new THREE.MeshPhongMaterial({color: 0x6688AA});
-  const bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
-  bodyMesh.position.y = 1.4;
-  bodyMesh.castShadow = true;
-  tank.add(bodyMesh);
-
-  const tankCameraFov = 75;
-  const tankCamera = makeCamera(tankCameraFov);
-  tankCamera.position.y = 3;
-  tankCamera.position.z = -6;
-  tankCamera.rotation.y = Math.PI;
-  bodyMesh.add(tankCamera);
-
-  const wheelRadius = 1;
-  const wheelThickness = .5;
-  const wheelSegments = 6;
-  const wheelGeometry = new THREE.CylinderGeometry(
-      wheelRadius,     // top radius
-      wheelRadius,     // bottom radius
-      wheelThickness,  // height of cylinder
-      wheelSegments);
-  const wheelMaterial = new THREE.MeshPhongMaterial({color: 0x888888});
-  const wheelPositions = [
-    [-carWidth / 2 - wheelThickness / 2, -carHeight / 2,  carLength / 3],
-    [ carWidth / 2 + wheelThickness / 2, -carHeight / 2,  carLength / 3],
-    [-carWidth / 2 - wheelThickness / 2, -carHeight / 2, 0],
-    [ carWidth / 2 + wheelThickness / 2, -carHeight / 2, 0],
-    [-carWidth / 2 - wheelThickness / 2, -carHeight / 2, -carLength / 3],
-    [ carWidth / 2 + wheelThickness / 2, -carHeight / 2, -carLength / 3],
-  ];
-  const wheelMeshes = wheelPositions.map((position) => {
-    const mesh = new THREE.Mesh(wheelGeometry, wheelMaterial);
-    mesh.position.set(...position);
-    mesh.rotation.z = Math.PI * .5;
-    mesh.castShadow = true;
-    bodyMesh.add(mesh);
-    return mesh;
-  });
-
-  const domeRadius = 2;
-  const domeWidthSubdivisions = 12;
-  const domeHeightSubdivisions = 12;
-  const domePhiStart = 0;
-  const domePhiEnd = Math.PI * 2;
-  const domeThetaStart = 0;
-  const domeThetaEnd = Math.PI * .5;
-  const domeGeometry = new THREE.SphereGeometry(
-    domeRadius, domeWidthSubdivisions, domeHeightSubdivisions,
-    domePhiStart, domePhiEnd, domeThetaStart, domeThetaEnd);
-  const domeMesh = new THREE.Mesh(domeGeometry, bodyMaterial);
-  domeMesh.castShadow = true;
-  bodyMesh.add(domeMesh);
-  domeMesh.position.y = .5;
-
-  const turretWidth = .1;
-  const turretHeight = .1;
-  const turretLength = carLength * .75 * .2;
-  const turretGeometry = new THREE.BoxGeometry(
-      turretWidth, turretHeight, turretLength);
-  const turretMesh = new THREE.Mesh(turretGeometry, bodyMaterial);
-  const turretPivot = new THREE.Object3D();
-  turretMesh.castShadow = true;
-  turretPivot.scale.set(5, 5, 5);
-  turretPivot.position.y = .5;
-  turretMesh.position.z = turretLength * .5;
-  turretPivot.add(turretMesh);
-  bodyMesh.add(turretPivot);
-
-  const turretCamera = makeCamera();
-  turretCamera.position.y = .75 * .2;
-  turretMesh.add(turretCamera);
-
-  const targetGeometry = new THREE.SphereGeometry(.5, 6, 3);
-  const targetMaterial = new THREE.MeshPhongMaterial({color: 0x00FF00, flatShading: true});
-  const targetMesh = new THREE.Mesh(targetGeometry, targetMaterial);
-  const targetOrbit = new THREE.Object3D();
-  const targetElevation = new THREE.Object3D();
-  const targetBob = new THREE.Object3D();
-  targetMesh.castShadow = true;
-  scene.add(targetOrbit);
-  targetOrbit.add(targetElevation);
-  targetElevation.position.z = carLength * 2;
-  targetElevation.position.y = 8;
-  targetElevation.add(targetBob);
-  targetBob.add(targetMesh);
-
-  const targetCamera = makeCamera();
-  const targetCameraPivot = new THREE.Object3D();
-  targetCamera.position.y = 1;
-  targetCamera.position.z = -2;
-  targetCamera.rotation.y = Math.PI;
-  targetBob.add(targetCameraPivot);
-  targetCameraPivot.add(targetCamera);
-
-  // Create a sine-like wave
-  const curve = new THREE.SplineCurve( [
-    new THREE.Vector2( -10, 0 ),
-    new THREE.Vector2( -5, 5 ),
-    new THREE.Vector2( 0, 0 ),
-    new THREE.Vector2( 5, -5 ),
-    new THREE.Vector2( 10, 0 ),
-    new THREE.Vector2( 5, 10 ),
-    new THREE.Vector2( -5, 10 ),
-    new THREE.Vector2( -10, -10 ),
-    new THREE.Vector2( -15, -8 ),
-    new THREE.Vector2( -10, 0 ),
-  ] );
-
-  const points = curve.getPoints( 50 );
-  const geometry = new THREE.BufferGeometry().setFromPoints( points );
-  const material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
-  const splineObject = new THREE.Line( geometry, material );
-  splineObject.rotation.x = Math.PI * .5;
-  splineObject.position.y = 0.05;
-  scene.add(splineObject);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		// move tank
+		const tankTime = time * .05;
+		curve.getPointAt( tankTime % 1, tankPosition );
+		curve.getPointAt( ( tankTime + 0.01 ) % 1, tankTarget );
+		tank.position.set( tankPosition.x, 0, tankPosition.y );
+		tank.lookAt( tankTarget.x, 0, tankTarget.y );
 
-  const targetPosition = new THREE.Vector3();
-  const tankPosition = new THREE.Vector2();
-  const tankTarget = new THREE.Vector2();
-
-  const cameras = [
-    { cam: camera, desc: 'detached camera', },
-    { cam: turretCamera, desc: 'on turret looking at target', },
-    { cam: targetCamera, desc: 'near target looking at tank', },
-    { cam: tankCamera, desc: 'above back of tank', },
-  ];
-
-  const infoElem = document.querySelector('#info');
-
-  function render(time) {
-    time *= 0.001;
-
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      cameras.forEach((cameraInfo) => {
-        const camera = cameraInfo.cam;
-        camera.aspect = canvas.clientWidth / canvas.clientHeight;
-        camera.updateProjectionMatrix();
-      });
-    }
+		// face turret at target
+		targetMesh.getWorldPosition( targetPosition );
+		turretPivot.lookAt( targetPosition );
 
-    // move target
-    targetOrbit.rotation.y = time * .27;
-    targetBob.position.y = Math.sin(time * 2) * 4;
-    targetMesh.rotation.x = time * 7;
-    targetMesh.rotation.y = time * 13;
-    targetMaterial.emissive.setHSL(time * 10 % 1, 1, .25);
-    targetMaterial.color.setHSL(time * 10 % 1, 1, .25);
+		// make the turretCamera look at target
+		turretCamera.lookAt( targetPosition );
 
-    // move tank
-    const tankTime = time * .05;
-    curve.getPointAt(tankTime % 1, tankPosition);
-    curve.getPointAt((tankTime + 0.01) % 1, tankTarget);
-    tank.position.set(tankPosition.x, 0, tankPosition.y);
-    tank.lookAt(tankTarget.x, 0, tankTarget.y);
+		// make the targetCameraPivot look at the at the tank
+		tank.getWorldPosition( targetPosition );
+		targetCameraPivot.lookAt( targetPosition );
 
-    // face turret at target
-    targetMesh.getWorldPosition(targetPosition);
-    turretPivot.lookAt(targetPosition);
+		wheelMeshes.forEach( ( obj ) => {
 
-    // make the turretCamera look at target
-    turretCamera.lookAt(targetPosition);
+			obj.rotation.x = time * 3;
 
-    // make the targetCameraPivot look at the at the tank
-    tank.getWorldPosition(targetPosition);
-    targetCameraPivot.lookAt(targetPosition);
+		} );
 
-    wheelMeshes.forEach((obj) => {
-      obj.rotation.x = time * 3;
-    });
+		const camera = cameras[ time * .25 % cameras.length | 0 ];
+		infoElem.textContent = camera.desc;
 
-    const camera = cameras[time * .25 % cameras.length | 0];
-    infoElem.textContent = camera.desc;
+		renderer.render( scene, camera.cam );
 
-    renderer.render(scene, camera.cam);
+		requestAnimationFrame( render );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 91 - 75
manual/examples/shadertoy-as-texture.html

@@ -36,22 +36,24 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-  const fragmentShader = `
+
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
+
+	const scene = new THREE.Scene();
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
+	const fragmentShader = `
   #include <common>
 
   uniform vec3 iResolution;
@@ -86,7 +88,7 @@ function main() {
     mainImage(gl_FragColor, vUv * iResolution.xy);
   }
   `;
-  const vertexShader = `
+	const vertexShader = `
     varying vec2 vUv;
     void main() {
       vUv = uv;
@@ -94,72 +96,86 @@ function main() {
     }
   `;
 
-  const loader = new THREE.TextureLoader();
-  const texture = loader.load('resources/images/bayer.png');
-  texture.minFilter = THREE.NearestFilter;
-  texture.magFilter = THREE.NearestFilter;
-  texture.wrapS = THREE.RepeatWrapping;
-  texture.wrapT = THREE.RepeatWrapping;
-  const uniforms = {
-    iTime: { value: 0 },
-    iResolution:  { value: new THREE.Vector3(1, 1, 1) },
-    iChannel0: { value: texture },
-  };
-  const material = new THREE.ShaderMaterial({
-    vertexShader,
-    fragmentShader,
-    uniforms,
-  });
-  function makeInstance(geometry, x) {
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
-
-    cube.position.x = x;
-
-    return cube;
-  }
+	const loader = new THREE.TextureLoader();
+	const texture = loader.load( 'resources/images/bayer.png' );
+	texture.minFilter = THREE.NearestFilter;
+	texture.magFilter = THREE.NearestFilter;
+	texture.wrapS = THREE.RepeatWrapping;
+	texture.wrapT = THREE.RepeatWrapping;
+	const uniforms = {
+		iTime: { value: 0 },
+		iResolution: { value: new THREE.Vector3( 1, 1, 1 ) },
+		iChannel0: { value: texture },
+	};
+	const material = new THREE.ShaderMaterial( {
+		vertexShader,
+		fragmentShader,
+		uniforms,
+	} );
+	function makeInstance( geometry, x ) {
 
-  const cubes = [
-    makeInstance(geometry,  0),
-    makeInstance(geometry, -2),
-    makeInstance(geometry,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+		cube.position.x = x;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		return cube;
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	}
 
-    uniforms.iTime.value = time;
+	const cubes = [
+		makeInstance( geometry, 0 ),
+		makeInstance( geometry, - 2 ),
+		makeInstance( geometry, 2 ),
+	];
 
-    renderer.render(scene, camera);
+	function resizeRendererToDisplaySize( renderer ) {
 
-    requestAnimationFrame(render);
-  }
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		uniforms.iTime.value = time;
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 56 - 46
manual/examples/shadertoy-basic-x40.html

@@ -36,22 +36,24 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.autoClearColor = false;
-
-  const camera = new THREE.OrthographicCamera(
-    -1, // left
-     1, // right
-     1, // top
-    -1, // bottom
-    -1, // near,
-     1, // far
-  );
-  const scene = new THREE.Scene();
-  const plane = new THREE.PlaneGeometry(2, 2);
-
-  const fragmentShader = `
+
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.autoClearColor = false;
+
+	const camera = new THREE.OrthographicCamera(
+		- 1, // left
+		1, // right
+		1, // top
+		- 1, // bottom
+		- 1, // near,
+		1, // far
+	);
+	const scene = new THREE.Scene();
+	const plane = new THREE.PlaneGeometry( 2, 2 );
+
+	const fragmentShader = `
   #include <common>
 
   uniform vec3 iResolution;
@@ -75,42 +77,50 @@ function main() {
     mainImage(gl_FragColor, gl_FragCoord.xy);
   }
   `;
-  const uniforms = {
-    iTime: { value: 0 },
-    iResolution:  { value: new THREE.Vector3() },
-  };
-  const material = new THREE.ShaderMaterial({
-    fragmentShader,
-    uniforms,
-  });
-  scene.add(new THREE.Mesh(plane, material));
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const uniforms = {
+		iTime: { value: 0 },
+		iResolution: { value: new THREE.Vector3() },
+	};
+	const material = new THREE.ShaderMaterial( {
+		fragmentShader,
+		uniforms,
+	} );
+	scene.add( new THREE.Mesh( plane, material ) );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+	function resizeRendererToDisplaySize( renderer ) {
 
-    resizeRendererToDisplaySize(renderer);
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
 
-    const canvas = renderer.domElement;
-    uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
-    uniforms.iTime.value = time;
+			renderer.setSize( width, height, false );
 
-    renderer.render(scene, camera);
+		}
 
-    requestAnimationFrame(render);
-  }
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		resizeRendererToDisplaySize( renderer );
+
+		const canvas = renderer.domElement;
+		uniforms.iResolution.value.set( canvas.width, canvas.height, 1 );
+		uniforms.iTime.value = time;
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 56 - 46
manual/examples/shadertoy-basic.html

@@ -36,22 +36,24 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.autoClearColor = false;
-
-  const camera = new THREE.OrthographicCamera(
-    -1, // left
-     1, // right
-     1, // top
-    -1, // bottom
-    -1, // near,
-     1, // far
-  );
-  const scene = new THREE.Scene();
-  const plane = new THREE.PlaneGeometry(2, 2);
-
-  const fragmentShader = `
+
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.autoClearColor = false;
+
+	const camera = new THREE.OrthographicCamera(
+		- 1, // left
+		1, // right
+		1, // top
+		- 1, // bottom
+		- 1, // near,
+		1, // far
+	);
+	const scene = new THREE.Scene();
+	const plane = new THREE.PlaneGeometry( 2, 2 );
+
+	const fragmentShader = `
   #include <common>
 
   uniform vec3 iResolution;
@@ -75,42 +77,50 @@ function main() {
     mainImage(gl_FragColor, gl_FragCoord.xy);
   }
   `;
-  const uniforms = {
-    iTime: { value: 0 },
-    iResolution:  { value: new THREE.Vector3() },
-  };
-  const material = new THREE.ShaderMaterial({
-    fragmentShader,
-    uniforms,
-  });
-  scene.add(new THREE.Mesh(plane, material));
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const uniforms = {
+		iTime: { value: 0 },
+		iResolution: { value: new THREE.Vector3() },
+	};
+	const material = new THREE.ShaderMaterial( {
+		fragmentShader,
+		uniforms,
+	} );
+	scene.add( new THREE.Mesh( plane, material ) );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+	function resizeRendererToDisplaySize( renderer ) {
 
-    resizeRendererToDisplaySize(renderer);
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
 
-    const canvas = renderer.domElement;
-    uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
-    uniforms.iTime.value = time;
+			renderer.setSize( width, height, false );
 
-    renderer.render(scene, camera);
+		}
 
-    requestAnimationFrame(render);
-  }
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		resizeRendererToDisplaySize( renderer );
+
+		const canvas = renderer.domElement;
+		uniforms.iResolution.value.set( canvas.width, canvas.height, 1 );
+		uniforms.iTime.value = time;
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 63 - 53
manual/examples/shadertoy-bleepy-blocks.html

@@ -36,22 +36,24 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.autoClearColor = false;
-
-  const camera = new THREE.OrthographicCamera(
-    -1, // left
-     1, // right
-     1, // top
-    -1, // bottom
-    -1, // near,
-     1, // far
-  );
-  const scene = new THREE.Scene();
-  const plane = new THREE.PlaneGeometry(2, 2);
-
-  const fragmentShader = `
+
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.autoClearColor = false;
+
+	const camera = new THREE.OrthographicCamera(
+		- 1, // left
+		1, // right
+		1, // top
+		- 1, // bottom
+		- 1, // near,
+		1, // far
+	);
+	const scene = new THREE.Scene();
+	const plane = new THREE.PlaneGeometry( 2, 2 );
+
+	const fragmentShader = `
   #include <common>
 
   uniform vec3 iResolution;
@@ -84,49 +86,57 @@ function main() {
     mainImage(gl_FragColor, gl_FragCoord.xy);
   }
   `;
-  const loader = new THREE.TextureLoader();
-  const texture = loader.load('resources/images/bayer.png');
-  texture.minFilter = THREE.NearestFilter;
-  texture.magFilter = THREE.NearestFilter;
-  texture.wrapS = THREE.RepeatWrapping;
-  texture.wrapT = THREE.RepeatWrapping;
-  const uniforms = {
-    iTime: { value: 0 },
-    iResolution:  { value: new THREE.Vector3() },
-    iChannel0: { value: texture },
-  };
-  const material = new THREE.ShaderMaterial({
-    fragmentShader,
-    uniforms,
-  });
-  scene.add(new THREE.Mesh(plane, material));
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const loader = new THREE.TextureLoader();
+	const texture = loader.load( 'resources/images/bayer.png' );
+	texture.minFilter = THREE.NearestFilter;
+	texture.magFilter = THREE.NearestFilter;
+	texture.wrapS = THREE.RepeatWrapping;
+	texture.wrapT = THREE.RepeatWrapping;
+	const uniforms = {
+		iTime: { value: 0 },
+		iResolution: { value: new THREE.Vector3() },
+		iChannel0: { value: texture },
+	};
+	const material = new THREE.ShaderMaterial( {
+		fragmentShader,
+		uniforms,
+	} );
+	scene.add( new THREE.Mesh( plane, material ) );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+	function resizeRendererToDisplaySize( renderer ) {
 
-    resizeRendererToDisplaySize(renderer);
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
 
-    const canvas = renderer.domElement;
-    uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
-    uniforms.iTime.value = time;
+			renderer.setSize( width, height, false );
 
-    renderer.render(scene, camera);
+		}
 
-    requestAnimationFrame(render);
-  }
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		resizeRendererToDisplaySize( renderer );
+
+		const canvas = renderer.domElement;
+		uniforms.iResolution.value.set( canvas.width, canvas.height, 1 );
+		uniforms.iTime.value = time;
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 45 - 35
manual/examples/shadertoy-prep.html

@@ -36,45 +36,55 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.autoClearColor = false;
-
-  const camera = new THREE.OrthographicCamera(
-    -1, // left
-     1, // right
-     1, // top
-    -1, // bottom
-    -1, // near,
-     1, // far
-  );
-  const scene = new THREE.Scene();
-  const plane = new THREE.PlaneGeometry(2, 2);
-  const material = new THREE.MeshBasicMaterial({
-      color: 'red',
-  });
-  scene.add(new THREE.Mesh(plane, material));
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render() {
-    resizeRendererToDisplaySize(renderer);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.autoClearColor = false;
 
-    renderer.render(scene, camera);
+	const camera = new THREE.OrthographicCamera(
+		- 1, // left
+		1, // right
+		1, // top
+		- 1, // bottom
+		- 1, // near,
+		1, // far
+	);
+	const scene = new THREE.Scene();
+	const plane = new THREE.PlaneGeometry( 2, 2 );
+	const material = new THREE.MeshBasicMaterial( {
+		color: 'red',
+	} );
+	scene.add( new THREE.Mesh( plane, material ) );
 
-    requestAnimationFrame(render);
-  }
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 244 - 188
manual/examples/shadows-directional-light-shadow-acne.html

@@ -35,57 +35,66 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
 
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(-1.4, 14, 12);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( - 1.4, 14, 12 );
 
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize, planeSize, planeSize);
-    const positionAttribute = planeGeo.attributes.position;
-    for (let i = 0; i < positionAttribute.count; ++i) {
-      positionAttribute.setZ(i, Math.random() * .2);
-    }
-    planeGeo.computeVertexNormals();
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      flatShading: true,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  /*
+	{
+
+		const planeSize = 40;
+
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
+
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize, planeSize, planeSize );
+		const positionAttribute = planeGeo.attributes.position;
+		for ( let i = 0; i < positionAttribute.count; ++ i ) {
+
+			positionAttribute.setZ( i, Math.random() * .2 );
+
+		}
+
+		planeGeo.computeVertexNormals();
+
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			flatShading: true,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
+
+	}
+
+	/*
   {
     const sphereRadius = 4;
     const sphereWidthDivisions = 32;
@@ -114,164 +123,211 @@ function main() {
     scene.add(mesh);
   }
   */
-  {
-    const sphereRadius = 4;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(
-      sphereRadius,
-      sphereWidthDivisions,
-      sphereHeightDivisions,
-    );
-    const sphereMat = new THREE.MeshPhongMaterial({
-      color: '#AC8',
-    });
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(0, 0, 0);
-    scene.add(mesh);
+	{
 
-  }
+		const sphereRadius = 4;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry(
+			sphereRadius,
+			sphereWidthDivisions,
+			sphereHeightDivisions,
+		);
+		const sphereMat = new THREE.MeshPhongMaterial( {
+			color: '#AC8',
+		} );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( 0, 0, 0 );
+		scene.add( mesh );
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	}
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    // folder.open();
-  }
+	class ColorGUIHelper {
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(4, 10, 5);
-    light.target.position.set(-4, 1, -4);
-    scene.add(light);
-    scene.add(light.target);
-    //light.shadow.bias = -0.001;
-    light.shadow.camera.near = 0.000001;
-    light.shadow.camera.far = 1000000;
-
-    const cameraHelper = new THREE.CameraHelper(light.shadow.camera);
-    scene.add(cameraHelper);
-
-    const helper = new THREE.DirectionalLightHelper(light);
-    scene.add(helper);
-
-    function updateCamera() {
-      // update the light target's matrixWorld because it's needed by the helper
-      light.target.updateMatrixWorld();
-      helper.update();
-      // update the light's shadow camera's projection matrix
-      light.shadow.camera.updateProjectionMatrix();
-      // and now update the camera helper we're using to show the light's shadow camera
-      cameraHelper.update();
-    }
-    updateCamera();
-
-    class DimensionGUIHelper {
-      constructor(obj, minProp, maxProp) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-      }
-      get value() {
-        return this.obj[this.maxProp] * 2;
-      }
-      set value(v) {
-        this.obj[this.maxProp] = v /  2;
-        this.obj[this.minProp] = v / -2;
-      }
-    }
+		constructor( object, prop ) {
 
-    class MinMaxGUIHelper {
-      constructor(obj, minProp, maxProp, minDif) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-        this.minDif = minDif;
-      }
-      get min() {
-        return this.obj[this.minProp];
-      }
-      set min(v) {
-        this.obj[this.minProp] = v;
-        this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
-      }
-      get max() {
-        return this.obj[this.maxProp];
-      }
-      set max(v) {
-        this.obj[this.maxProp] = v;
-        this.min = this.min;  // this will call the min setter
-      }
-    }
+			this.object = object;
+			this.prop = prop;
 
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2);
-    {
-      const folder = gui.addFolder('Shadow Camera');
-      folder.open();
-      folder.add(new DimensionGUIHelper(light.shadow.camera, 'left', 'right'), 'value', 1, 100)
-        .name('width')
-        .onChange(updateCamera);
-      folder.add(new DimensionGUIHelper(light.shadow.camera, 'bottom', 'top'), 'value', 1, 100)
-        .name('height')
-        .onChange(updateCamera);
-      const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
-      folder.add(minMaxGUIHelper, 'min', 0.1, 50, 0.1).name('near').onChange(updateCamera);
-      folder.add(minMaxGUIHelper, 'max', 0.1, 50, 0.1).name('far').onChange(updateCamera);
-      folder.add(light.shadow.camera, 'zoom', 0.01, 1.5, 0.01).onChange(updateCamera);
-    }
+		}
+		get value() {
 
-    makeXYZGUI(gui, light.position, 'position', updateCamera);
-    makeXYZGUI(gui, light.target.position, 'target', updateCamera);
-  }
+			return `#${this.object[ this.prop ].getHexString()}`;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		}
+		set value( hexString ) {
 
-  function render() {
+			this.object[ this.prop ].set( hexString );
 
-    resizeRendererToDisplaySize(renderer);
+		}
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	}
 
-    renderer.render(scene, camera);
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
 
-    requestAnimationFrame(render);
-  }
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		// folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 4, 10, 5 );
+		light.target.position.set( - 4, 1, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+		//light.shadow.bias = -0.001;
+		light.shadow.camera.near = 0.000001;
+		light.shadow.camera.far = 1000000;
+
+		const cameraHelper = new THREE.CameraHelper( light.shadow.camera );
+		scene.add( cameraHelper );
+
+		const helper = new THREE.DirectionalLightHelper( light );
+		scene.add( helper );
+
+		function updateCamera() {
+
+			// update the light target's matrixWorld because it's needed by the helper
+			light.target.updateMatrixWorld();
+			helper.update();
+			// update the light's shadow camera's projection matrix
+			light.shadow.camera.updateProjectionMatrix();
+			// and now update the camera helper we're using to show the light's shadow camera
+			cameraHelper.update();
+
+		}
+
+		updateCamera();
+
+		class DimensionGUIHelper {
+
+			constructor( obj, minProp, maxProp ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+
+			}
+			get value() {
+
+				return this.obj[ this.maxProp ] * 2;
+
+			}
+			set value( v ) {
+
+				this.obj[ this.maxProp ] = v / 2;
+				this.obj[ this.minProp ] = v / - 2;
+
+			}
+
+		}
+
+		class MinMaxGUIHelper {
+
+			constructor( obj, minProp, maxProp, minDif ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+				this.minDif = minDif;
+
+			}
+			get min() {
+
+				return this.obj[ this.minProp ];
+
+			}
+			set min( v ) {
+
+				this.obj[ this.minProp ] = v;
+				this.obj[ this.maxProp ] = Math.max( this.obj[ this.maxProp ], v + this.minDif );
+
+			}
+			get max() {
+
+				return this.obj[ this.maxProp ];
+
+			}
+			set max( v ) {
+
+				this.obj[ this.maxProp ] = v;
+				this.min = this.min; // this will call the min setter
+
+			}
+
+		}
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 10 );
+		{
+
+			const folder = gui.addFolder( 'Shadow Camera' );
+			folder.open();
+			folder.add( new DimensionGUIHelper( light.shadow.camera, 'left', 'right' ), 'value', 1, 100 )
+				.name( 'width' )
+				.onChange( updateCamera );
+			folder.add( new DimensionGUIHelper( light.shadow.camera, 'bottom', 'top' ), 'value', 1, 100 )
+				.name( 'height' )
+				.onChange( updateCamera );
+			const minMaxGUIHelper = new MinMaxGUIHelper( light.shadow.camera, 'near', 'far', 0.1 );
+			folder.add( minMaxGUIHelper, 'min', 0.1, 50, 0.1 ).name( 'near' ).onChange( updateCamera );
+			folder.add( minMaxGUIHelper, 'max', 0.1, 50, 0.1 ).name( 'far' ).onChange( updateCamera );
+			folder.add( light.shadow.camera, 'zoom', 0.01, 1.5, 0.01 ).onChange( updateCamera );
+
+		}
+
+		makeXYZGUI( gui, light.position, 'position', updateCamera );
+		makeXYZGUI( gui, light.target.position, 'target', updateCamera );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 243 - 186
manual/examples/shadows-directional-light-with-camera-gui.html

@@ -35,207 +35,264 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    // folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    light.target.position.set(-4, 0, -4);
-    scene.add(light);
-    scene.add(light.target);
-
-    const cameraHelper = new THREE.CameraHelper(light.shadow.camera);
-    scene.add(cameraHelper);
-
-    const helper = new THREE.DirectionalLightHelper(light);
-    scene.add(helper);
-
-    function updateCamera() {
-      // update the light target's matrixWorld because it's needed by the helper
-      light.target.updateMatrixWorld();
-      helper.update();
-      // update the light's shadow camera's projection matrix
-      light.shadow.camera.updateProjectionMatrix();
-      // and now update the camera helper we're using to show the light's shadow camera
-      cameraHelper.update();
-    }
-    updateCamera();
-
-    class DimensionGUIHelper {
-      constructor(obj, minProp, maxProp) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-      }
-      get value() {
-        return this.obj[this.maxProp] * 2;
-      }
-      set value(v) {
-        this.obj[this.maxProp] = v /  2;
-        this.obj[this.minProp] = v / -2;
-      }
-    }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-    class MinMaxGUIHelper {
-      constructor(obj, minProp, maxProp, minDif) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-        this.minDif = minDif;
-      }
-      get min() {
-        return this.obj[this.minProp];
-      }
-      set min(v) {
-        this.obj[this.minProp] = v;
-        this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
-      }
-      get max() {
-        return this.obj[this.maxProp];
-      }
-      set max(v) {
-        this.obj[this.maxProp] = v;
-        this.min = this.min;  // this will call the min setter
-      }
-    }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-    {
-      const folder = gui.addFolder('Shadow Camera');
-      folder.open();
-      folder.add(new DimensionGUIHelper(light.shadow.camera, 'left', 'right'), 'value', 1, 100)
-        .name('width')
-        .onChange(updateCamera);
-      folder.add(new DimensionGUIHelper(light.shadow.camera, 'bottom', 'top'), 'value', 1, 100)
-        .name('height')
-        .onChange(updateCamera);
-      const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
-      folder.add(minMaxGUIHelper, 'min', 0.1, 50, 0.1).name('near').onChange(updateCamera);
-      folder.add(minMaxGUIHelper, 'max', 0.1, 50, 0.1).name('far').onChange(updateCamera);
-      folder.add(light.shadow.camera, 'zoom', 0.01, 1.5, 0.01).onChange(updateCamera);
-    }
+	{
 
-    makeXYZGUI(gui, light.position, 'position', updateCamera);
-    makeXYZGUI(gui, light.target.position, 'target', updateCamera);
-  }
+		const planeSize = 40;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-  function render() {
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-    resizeRendererToDisplaySize(renderer);
+	}
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	{
 
-    renderer.render(scene, camera);
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		// folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		light.target.position.set( - 4, 0, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+
+		const cameraHelper = new THREE.CameraHelper( light.shadow.camera );
+		scene.add( cameraHelper );
+
+		const helper = new THREE.DirectionalLightHelper( light );
+		scene.add( helper );
+
+		function updateCamera() {
+
+			// update the light target's matrixWorld because it's needed by the helper
+			light.target.updateMatrixWorld();
+			helper.update();
+			// update the light's shadow camera's projection matrix
+			light.shadow.camera.updateProjectionMatrix();
+			// and now update the camera helper we're using to show the light's shadow camera
+			cameraHelper.update();
+
+		}
+
+		updateCamera();
+
+		class DimensionGUIHelper {
+
+			constructor( obj, minProp, maxProp ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+
+			}
+			get value() {
+
+				return this.obj[ this.maxProp ] * 2;
+
+			}
+			set value( v ) {
+
+				this.obj[ this.maxProp ] = v / 2;
+				this.obj[ this.minProp ] = v / - 2;
+
+			}
+
+		}
+
+		class MinMaxGUIHelper {
+
+			constructor( obj, minProp, maxProp, minDif ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+				this.minDif = minDif;
+
+			}
+			get min() {
+
+				return this.obj[ this.minProp ];
+
+			}
+			set min( v ) {
+
+				this.obj[ this.minProp ] = v;
+				this.obj[ this.maxProp ] = Math.max( this.obj[ this.maxProp ], v + this.minDif );
+
+			}
+			get max() {
+
+				return this.obj[ this.maxProp ];
+
+			}
+			set max( v ) {
+
+				this.obj[ this.maxProp ] = v;
+				this.min = this.min; // this will call the min setter
+
+			}
+
+		}
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 10, 0.01 );
+		{
+
+			const folder = gui.addFolder( 'Shadow Camera' );
+			folder.open();
+			folder.add( new DimensionGUIHelper( light.shadow.camera, 'left', 'right' ), 'value', 1, 100 )
+				.name( 'width' )
+				.onChange( updateCamera );
+			folder.add( new DimensionGUIHelper( light.shadow.camera, 'bottom', 'top' ), 'value', 1, 100 )
+				.name( 'height' )
+				.onChange( updateCamera );
+			const minMaxGUIHelper = new MinMaxGUIHelper( light.shadow.camera, 'near', 'far', 0.1 );
+			folder.add( minMaxGUIHelper, 'min', 0.1, 50, 0.1 ).name( 'near' ).onChange( updateCamera );
+			folder.add( minMaxGUIHelper, 'max', 0.1, 50, 0.1 ).name( 'far' ).onChange( updateCamera );
+			folder.add( light.shadow.camera, 'zoom', 0.01, 1.5, 0.01 ).onChange( updateCamera );
+
+		}
+
+		makeXYZGUI( gui, light.position, 'position', updateCamera );
+		makeXYZGUI( gui, light.target.position, 'target', updateCamera );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 167 - 132
manual/examples/shadows-directional-light-with-camera-helper.html

@@ -35,150 +35,185 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    light.target.position.set(-4, 0, -4);
-    scene.add(light);
-    scene.add(light.target);
-
-    const cameraHelper = new THREE.CameraHelper(light.shadow.camera);
-    scene.add(cameraHelper);
-
-    const helper = new THREE.DirectionalLightHelper(light);
-    scene.add(helper);
-
-    const onChange = () => {
-      light.target.updateMatrixWorld();
-      helper.update();
-    };
-    onChange();
-
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-
-    makeXYZGUI(gui, light.position, 'position', onChange);
-    makeXYZGUI(gui, light.target.position, 'target', onChange);
-  }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-  function render() {
+	{
 
-    resizeRendererToDisplaySize(renderer);
+		const planeSize = 40;
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-    renderer.render(scene, camera);
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	{
+
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		light.target.position.set( - 4, 0, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+
+		const cameraHelper = new THREE.CameraHelper( light.shadow.camera );
+		scene.add( cameraHelper );
+
+		const helper = new THREE.DirectionalLightHelper( light );
+		scene.add( helper );
+
+		const onChange = () => {
+
+			light.target.updateMatrixWorld();
+			helper.update();
+
+		};
+
+		onChange();
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 10, 0.01 );
+
+		makeXYZGUI( gui, light.position, 'position', onChange );
+		makeXYZGUI( gui, light.target.position, 'target', onChange );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 164 - 129
manual/examples/shadows-directional-light.html

@@ -35,147 +35,182 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    light.target.position.set(-4, 0, -4);
-    scene.add(light);
-    scene.add(light.target);
-
-    const helper = new THREE.DirectionalLightHelper(light);
-    scene.add(helper);
-
-    const onChange = () => {
-      light.target.updateMatrixWorld();
-      helper.update();
-    };
-    onChange();
-
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-
-    makeXYZGUI(gui, light.position, 'position', onChange);
-    makeXYZGUI(gui, light.target.position, 'target', onChange);
-  }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-  function render() {
+	{
 
-    resizeRendererToDisplaySize(renderer);
+		const planeSize = 40;
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-    renderer.render(scene, camera);
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	{
+
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		light.target.position.set( - 4, 0, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+
+		const helper = new THREE.DirectionalLightHelper( light );
+		scene.add( helper );
+
+		const onChange = () => {
+
+			light.target.updateMatrixWorld();
+			helper.update();
+
+		};
+
+		onChange();
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 10, 0.01 );
+
+		makeXYZGUI( gui, light.position, 'position', onChange );
+		makeXYZGUI( gui, light.target.position, 'target', onChange );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 162 - 137
manual/examples/shadows-fake.html

@@ -36,157 +36,182 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-  camera.lookAt(0, 0, 0);
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  const loader = new THREE.TextureLoader();
-
-  {
-    const planeSize = 40;
-
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshBasicMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    planeMat.color.setRGB(1.5, 1.5, 1.5);
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
 
-  const shadowTexture = loader.load('resources/images/roundshadow.png');
-  const sphereShadowBases = [];
-  {
-    const sphereRadius = 1;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-
-    const planeSize = 1;
-    const shadowGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-
-    const numSpheres = 15;
-    for (let i = 0; i < numSpheres; ++i) {
-      // make a base for the shadow and the sphere.
-      // so they move together.
-      const base = new THREE.Object3D();
-      scene.add(base);
-
-      // add the shadow to the base
-      // note: we make a new material for each sphere
-      // so we can set that sphere's material transparency
-      // separately.
-      const shadowMat = new THREE.MeshBasicMaterial({
-        map: shadowTexture,
-        transparent: true,    // so we can see the ground
-        depthWrite: false,    // so we don't have to sort
-      });
-      const shadowMesh = new THREE.Mesh(shadowGeo, shadowMat);
-      shadowMesh.position.y = 0.001;  // so we're above the ground slightly
-      shadowMesh.rotation.x = Math.PI * -.5;
-      const shadowSize = sphereRadius * 4;
-      shadowMesh.scale.set(shadowSize, shadowSize, shadowSize);
-      base.add(shadowMesh);
-
-      // add the sphere to the base
-      const u = i / numSpheres;
-      const sphereMat = new THREE.MeshPhongMaterial();
-      sphereMat.color.setHSL(u, 1, .75);
-      const sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);
-      sphereMesh.position.set(0, sphereRadius + 2, 0);
-      base.add(sphereMesh);
-
-      // remember all 3 plus the y position
-      sphereShadowBases.push({base, sphereMesh, shadowMesh, y: sphereMesh.position.y});
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
+	camera.lookAt( 0, 0, 0 );
+
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
+
+	const loader = new THREE.TextureLoader();
+
+	{
+
+		const planeSize = 40;
+
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
+
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshBasicMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		planeMat.color.setRGB( 1.5, 1.5, 1.5 );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-  {
-    const skyColor = 0xB1E1FF;  // light blue
-    const groundColor = 0xB97A20;  // brownish orange
-    const intensity = 0.25;
-    const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
-    scene.add(light);
-  }
+	}
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 0.75;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(0, 10, 5);
-    light.target.position.set(-5, 0, 0);
-    scene.add(light);
-    scene.add(light.target);
-  }
+	const shadowTexture = loader.load( 'resources/images/roundshadow.png' );
+	const sphereShadowBases = [];
+	{
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const sphereRadius = 1;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+		const planeSize = 1;
+		const shadowGeo = new THREE.PlaneGeometry( planeSize, planeSize );
 
-    resizeRendererToDisplaySize(renderer);
+		const numSpheres = 15;
+		for ( let i = 0; i < numSpheres; ++ i ) {
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+			// make a base for the shadow and the sphere.
+			// so they move together.
+			const base = new THREE.Object3D();
+			scene.add( base );
 
-    sphereShadowBases.forEach((sphereShadowBase, ndx) => {
-      const {base, sphereMesh, shadowMesh, y} = sphereShadowBase;
+			// add the shadow to the base
+			// note: we make a new material for each sphere
+			// so we can set that sphere's material transparency
+			// separately.
+			const shadowMat = new THREE.MeshBasicMaterial( {
+				map: shadowTexture,
+				transparent: true, // so we can see the ground
+				depthWrite: false, // so we don't have to sort
+			} );
+			const shadowMesh = new THREE.Mesh( shadowGeo, shadowMat );
+			shadowMesh.position.y = 0.001; // so we're above the ground slightly
+			shadowMesh.rotation.x = Math.PI * - .5;
+			const shadowSize = sphereRadius * 4;
+			shadowMesh.scale.set( shadowSize, shadowSize, shadowSize );
+			base.add( shadowMesh );
 
-      // u is a value that goes from 0 to 1 as we iterate the spheres
-      const u = ndx / sphereShadowBases.length;
+			// add the sphere to the base
+			const u = i / numSpheres;
+			const sphereMat = new THREE.MeshPhongMaterial();
+			sphereMat.color.setHSL( u, 1, .75 );
+			const sphereMesh = new THREE.Mesh( sphereGeo, sphereMat );
+			sphereMesh.position.set( 0, sphereRadius + 2, 0 );
+			base.add( sphereMesh );
 
-      // compute a position for there base. This will move
-      // both the sphere and its shadow
-      const speed = time * .2;
-      const angle = speed + u * Math.PI * 2 * (ndx % 1 ? 1 : -1);
-      const radius = Math.sin(speed - ndx) * 10;
-      base.position.set(Math.cos(angle) * radius, 0, Math.sin(angle) * radius);
+			// remember all 3 plus the y position
+			sphereShadowBases.push( { base, sphereMesh, shadowMesh, y: sphereMesh.position.y } );
 
-      // yOff is a value that goes from 0 to 1
-      const yOff = Math.abs(Math.sin(time * 2 + ndx));
-      // move the sphere up and down
-      sphereMesh.position.y = y + THREE.MathUtils.lerp(-2, 2, yOff);
-      // fade the shadow as the sphere goes up
-      shadowMesh.material.opacity = THREE.MathUtils.lerp(1, .25, yOff);
-    });
+		}
 
-    renderer.render(scene, camera);
+	}
 
-    requestAnimationFrame(render);
-  }
+	{
+
+		const skyColor = 0xB1E1FF; // light blue
+		const groundColor = 0xB97A20; // brownish orange
+		const intensity = 0.75;
+		const light = new THREE.HemisphereLight( skyColor, groundColor, intensity );
+		scene.add( light );
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 2.5;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( 0, 10, 5 );
+		light.target.position.set( - 5, 0, 0 );
+		scene.add( light );
+		scene.add( light.target );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		sphereShadowBases.forEach( ( sphereShadowBase, ndx ) => {
+
+			const { base, sphereMesh, shadowMesh, y } = sphereShadowBase;
+
+			// u is a value that goes from 0 to 1 as we iterate the spheres
+			const u = ndx / sphereShadowBases.length;
+
+			// compute a position for there base. This will move
+			// both the sphere and its shadow
+			const speed = time * .2;
+			const angle = speed + u * Math.PI * 2 * ( ndx % 1 ? 1 : - 1 );
+			const radius = Math.sin( speed - ndx ) * 10;
+			base.position.set( Math.cos( angle ) * radius, 0, Math.sin( angle ) * radius );
+
+			// yOff is a value that goes from 0 to 1
+			const yOff = Math.abs( Math.sin( time * 2 + ndx ) );
+			// move the sphere up and down
+			sphereMesh.position.y = y + THREE.MathUtils.lerp( - 2, 2, yOff );
+			// fade the shadow as the sphere goes up
+			shadowMesh.material.opacity = THREE.MathUtils.lerp( 1, .25, yOff );
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 211 - 162
manual/examples/shadows-point-light.html

@@ -35,185 +35,234 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 30;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({
-      color: '#CCC',
-      side: THREE.BackSide,
-    });
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.receiveShadow = true;
-    mesh.position.set(0, cubeSize / 2 - 0.1, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    // folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.PointLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    scene.add(light);
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-    const helper = new THREE.PointLightHelper(light);
-    scene.add(helper);
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-    function updateCamera() {
-    }
+	{
 
-    class MinMaxGUIHelper {
-      constructor(obj, minProp, maxProp, minDif) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-        this.minDif = minDif;
-      }
-      get min() {
-        return this.obj[this.minProp];
-      }
-      set min(v) {
-        this.obj[this.minProp] = v;
-        this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
-      }
-      get max() {
-        return this.obj[this.maxProp];
-      }
-      set max(v) {
-        this.obj[this.maxProp] = v;
-        this.min = this.min;  // this will call the min setter
-      }
-    }
+		const planeSize = 40;
 
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-    gui.add(light, 'distance', 0, 40).onChange(updateCamera);
-
-    {
-      const folder = gui.addFolder('Shadow Camera');
-      folder.open();
-      const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
-      folder.add(minMaxGUIHelper, 'min', 0.1, 50, 0.1).name('near').onChange(updateCamera);
-      folder.add(minMaxGUIHelper, 'max', 0.1, 50, 0.1).name('far').onChange(updateCamera);
-    }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-    makeXYZGUI(gui, light.position, 'position', updateCamera);
-  }
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render() {
+	{
 
-    resizeRendererToDisplaySize(renderer);
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	}
 
-    renderer.render(scene, camera);
+	{
 
-    requestAnimationFrame(render);
-  }
+		const cubeSize = 30;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( {
+			color: '#CCC',
+			side: THREE.BackSide,
+		} );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.receiveShadow = true;
+		mesh.position.set( 0, cubeSize / 2 - 0.1, 0 );
+		scene.add( mesh );
+
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		// folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 100;
+		const light = new THREE.PointLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		scene.add( light );
+
+		const helper = new THREE.PointLightHelper( light );
+		scene.add( helper );
+
+		function updateCamera() {
+		}
+
+		class MinMaxGUIHelper {
+
+			constructor( obj, minProp, maxProp, minDif ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+				this.minDif = minDif;
+
+			}
+			get min() {
+
+				return this.obj[ this.minProp ];
+
+			}
+			set min( v ) {
+
+				this.obj[ this.minProp ] = v;
+				this.obj[ this.maxProp ] = Math.max( this.obj[ this.maxProp ], v + this.minDif );
+
+			}
+			get max() {
+
+				return this.obj[ this.maxProp ];
+
+			}
+			set max( v ) {
+
+				this.obj[ this.maxProp ] = v;
+				this.min = this.min; // this will call the min setter
+
+			}
+
+		}
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 200 );
+		gui.add( light, 'distance', 0, 40 ).onChange( updateCamera );
+
+		{
+
+			const folder = gui.addFolder( 'Shadow Camera' );
+			folder.open();
+			const minMaxGUIHelper = new MinMaxGUIHelper( light.shadow.camera, 'near', 'far', 0.1 );
+			folder.add( minMaxGUIHelper, 'min', 0.1, 50, 0.1 ).name( 'near' ).onChange( updateCamera );
+			folder.add( minMaxGUIHelper, 'max', 0.1, 50, 0.1 ).name( 'far' ).onChange( updateCamera );
+
+		}
+
+		makeXYZGUI( gui, light.position, 'position', updateCamera );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 235 - 178
manual/examples/shadows-spot-light-with-camera-gui.html

@@ -35,199 +35,256 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    // folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.SpotLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    light.target.position.set(-4, 0, -4);
-    scene.add(light);
-    scene.add(light.target);
-
-    const cameraHelper = new THREE.CameraHelper(light.shadow.camera);
-    scene.add(cameraHelper);
-
-    function updateCamera() {
-      // update the light target's matrixWorld because it's needed by the helper
-      light.target.updateMatrixWorld();
-      // update the light's shadow camera's projection matrix
-      light.shadow.camera.updateProjectionMatrix();
-      // and now update the camera helper we're using to show the light's shadow camera
-      cameraHelper.update();
-    }
-    updateCamera();
-    setTimeout(updateCamera);
-
-    class MinMaxGUIHelper {
-      constructor(obj, minProp, maxProp, minDif) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-        this.minDif = minDif;
-      }
-      get min() {
-        return this.obj[this.minProp];
-      }
-      set min(v) {
-        this.obj[this.minProp] = v;
-        this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
-      }
-      get max() {
-        return this.obj[this.maxProp];
-      }
-      set max(v) {
-        this.obj[this.maxProp] = v;
-        this.min = this.min;  // this will call the min setter
-      }
-    }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-  class DegRadHelper {
-    constructor(obj, prop) {
-      this.obj = obj;
-      this.prop = prop;
-    }
-    get value() {
-      return THREE.MathUtils.radToDeg(this.obj[this.prop]);
-    }
-    set value(v) {
-      this.obj[this.prop] = THREE.MathUtils.degToRad(v);
-    }
-  }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-    gui.add(light, 'distance', 0, 40).onChange(updateCamera);
-    gui.add(new DegRadHelper(light, 'angle'), 'value', 0, 90).name('angle').onChange(updateCamera);
-    gui.add(light, 'penumbra', 0, 1, 0.01);
-
-    {
-      const folder = gui.addFolder('Shadow Camera');
-      folder.open();
-      const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
-      folder.add(minMaxGUIHelper, 'min', 0.1, 50, 0.1).name('near').onChange(updateCamera);
-      folder.add(minMaxGUIHelper, 'max', 0.1, 50, 0.1).name('far').onChange(updateCamera);
-    }
+	{
 
-    makeXYZGUI(gui, light.position, 'position', updateCamera);
-    makeXYZGUI(gui, light.target.position, 'target', updateCamera);
-  }
+		const planeSize = 40;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-  function render() {
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-    resizeRendererToDisplaySize(renderer);
+	}
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	{
 
-    renderer.render(scene, camera);
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		// folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 100;
+		const light = new THREE.SpotLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		light.target.position.set( - 4, 0, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+
+		const cameraHelper = new THREE.CameraHelper( light.shadow.camera );
+		scene.add( cameraHelper );
+
+		function updateCamera() {
+
+			// update the light target's matrixWorld because it's needed by the helper
+			light.target.updateMatrixWorld();
+			// update the light's shadow camera's projection matrix
+			light.shadow.camera.updateProjectionMatrix();
+			// and now update the camera helper we're using to show the light's shadow camera
+			cameraHelper.update();
+
+		}
+
+		updateCamera();
+		setTimeout( updateCamera );
+
+		class MinMaxGUIHelper {
+
+			constructor( obj, minProp, maxProp, minDif ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+				this.minDif = minDif;
+
+			}
+			get min() {
+
+				return this.obj[ this.minProp ];
+
+			}
+			set min( v ) {
+
+				this.obj[ this.minProp ] = v;
+				this.obj[ this.maxProp ] = Math.max( this.obj[ this.maxProp ], v + this.minDif );
+
+			}
+			get max() {
+
+				return this.obj[ this.maxProp ];
+
+			}
+			set max( v ) {
+
+				this.obj[ this.maxProp ] = v;
+				this.min = this.min; // this will call the min setter
+
+			}
+
+		}
+
+		class DegRadHelper {
+
+			constructor( obj, prop ) {
+
+				this.obj = obj;
+				this.prop = prop;
+
+			}
+			get value() {
+
+				return THREE.MathUtils.radToDeg( this.obj[ this.prop ] );
+
+			}
+			set value( v ) {
+
+				this.obj[ this.prop ] = THREE.MathUtils.degToRad( v );
+
+			}
+
+		}
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 200 );
+		gui.add( light, 'distance', 0, 40 ).onChange( updateCamera );
+		gui.add( new DegRadHelper( light, 'angle' ), 'value', 0, 90 ).name( 'angle' ).onChange( updateCamera );
+		gui.add( light, 'penumbra', 0, 1, 0.01 );
+
+		{
+
+			const folder = gui.addFolder( 'Shadow Camera' );
+			folder.open();
+			const minMaxGUIHelper = new MinMaxGUIHelper( light.shadow.camera, 'near', 'far', 0.1 );
+			folder.add( minMaxGUIHelper, 'min', 0.1, 50, 0.1 ).name( 'near' ).onChange( updateCamera );
+			folder.add( minMaxGUIHelper, 'max', 0.1, 50, 0.1 ).name( 'far' ).onChange( updateCamera );
+
+		}
+
+		makeXYZGUI( gui, light.position, 'position', updateCamera );
+		makeXYZGUI( gui, light.target.position, 'target', updateCamera );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 238 - 181
manual/examples/shadows-spot-light-with-shadow-radius.html

@@ -35,202 +35,259 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.shadowMap.enabled = true;
-renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
-
-  const fov = 45;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 100;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 10, 20);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 5, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('black');
-
-  {
-    const planeSize = 40;
-
-    const loader = new THREE.TextureLoader();
-    const texture = loader.load('resources/images/checker.png');
-    texture.wrapS = THREE.RepeatWrapping;
-    texture.wrapT = THREE.RepeatWrapping;
-    texture.magFilter = THREE.NearestFilter;
-    const repeats = planeSize / 2;
-    texture.repeat.set(repeats, repeats);
-
-    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
-    const planeMat = new THREE.MeshPhongMaterial({
-      map: texture,
-      side: THREE.DoubleSide,
-    });
-    const mesh = new THREE.Mesh(planeGeo, planeMat);
-    mesh.receiveShadow = true;
-    mesh.rotation.x = Math.PI * -.5;
-    scene.add(mesh);
-  }
-  {
-    const cubeSize = 4;
-    const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
-    const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
-    const mesh = new THREE.Mesh(cubeGeo, cubeMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(cubeSize + 1, cubeSize / 2, 0);
-    scene.add(mesh);
-  }
-  {
-    const sphereRadius = 3;
-    const sphereWidthDivisions = 32;
-    const sphereHeightDivisions = 16;
-    const sphereGeo = new THREE.SphereGeometry(sphereRadius, sphereWidthDivisions, sphereHeightDivisions);
-    const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
-    const mesh = new THREE.Mesh(sphereGeo, sphereMat);
-    mesh.castShadow = true;
-    mesh.receiveShadow = true;
-    mesh.position.set(-sphereRadius - 1, sphereRadius + 2, 0);
-    scene.add(mesh);
-  }
 
-  class ColorGUIHelper {
-    constructor(object, prop) {
-      this.object = object;
-      this.prop = prop;
-    }
-    get value() {
-      return `#${this.object[this.prop].getHexString()}`;
-    }
-    set value(hexString) {
-      this.object[this.prop].set(hexString);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.shadowMap.enabled = true;
+	renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
 
-  function makeXYZGUI(gui, vector3, name, onChangeFn) {
-    const folder = gui.addFolder(name);
-    folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
-    folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
-    folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
-    // folder.open();
-  }
+	const fov = 45;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 100;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 10, 20 );
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.SpotLight(color, intensity);
-    light.castShadow = true;
-    light.position.set(0, 10, 0);
-    light.target.position.set(-4, 0, -4);
-    scene.add(light);
-    scene.add(light.target);
-
-    const cameraHelper = new THREE.CameraHelper(light.shadow.camera);
-    scene.add(cameraHelper);
-
-    function updateCamera() {
-      // update the light target's matrixWorld because it's needed by the helper
-      light.target.updateMatrixWorld();
-      // update the light's shadow camera's projection matrix
-      light.shadow.camera.updateProjectionMatrix();
-      // and now update the camera helper we're using to show the light's shadow camera
-      cameraHelper.update();
-    }
-    updateCamera();
-    setTimeout(updateCamera);
-
-    class MinMaxGUIHelper {
-      constructor(obj, minProp, maxProp, minDif) {
-        this.obj = obj;
-        this.minProp = minProp;
-        this.maxProp = maxProp;
-        this.minDif = minDif;
-      }
-      get min() {
-        return this.obj[this.minProp];
-      }
-      set min(v) {
-        this.obj[this.minProp] = v;
-        this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
-      }
-      get max() {
-        return this.obj[this.maxProp];
-      }
-      set max(v) {
-        this.obj[this.maxProp] = v;
-        this.min = this.min;  // this will call the min setter
-      }
-    }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 5, 0 );
+	controls.update();
 
-  class DegRadHelper {
-    constructor(obj, prop) {
-      this.obj = obj;
-      this.prop = prop;
-    }
-    get value() {
-      return THREE.MathUtils.radToDeg(this.obj[this.prop]);
-    }
-    set value(v) {
-      this.obj[this.prop] = THREE.MathUtils.degToRad(v);
-    }
-  }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'black' );
 
-    const gui = new GUI();
-    gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-    gui.add(light, 'intensity', 0, 2, 0.01);
-    gui.add(light, 'distance', 0, 40).onChange(updateCamera);
-    gui.add(new DegRadHelper(light, 'angle'), 'value', 0, 90).name('angle').onChange(updateCamera);
-    gui.add(light, 'penumbra', 0, 1, 0.01);
-
-    gui.add(light.shadow, 'radius', 0, 50, 0.01);
-
-    {
-      const folder = gui.addFolder('Shadow Camera');
-      folder.open();
-      const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
-      folder.add(minMaxGUIHelper, 'min', 0.1, 50, 0.1).name('near').onChange(updateCamera);
-      folder.add(minMaxGUIHelper, 'max', 0.1, 50, 0.1).name('far').onChange(updateCamera);
-    }
+	{
 
-    makeXYZGUI(gui, light.position, 'position', updateCamera);
-    makeXYZGUI(gui, light.target.position, 'target', updateCamera);
-  }
+		const planeSize = 40;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const loader = new THREE.TextureLoader();
+		const texture = loader.load( 'resources/images/checker.png' );
+		texture.wrapS = THREE.RepeatWrapping;
+		texture.wrapT = THREE.RepeatWrapping;
+		texture.magFilter = THREE.NearestFilter;
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const repeats = planeSize / 2;
+		texture.repeat.set( repeats, repeats );
 
-  function render() {
+		const planeGeo = new THREE.PlaneGeometry( planeSize, planeSize );
+		const planeMat = new THREE.MeshPhongMaterial( {
+			map: texture,
+			side: THREE.DoubleSide,
+		} );
+		const mesh = new THREE.Mesh( planeGeo, planeMat );
+		mesh.receiveShadow = true;
+		mesh.rotation.x = Math.PI * - .5;
+		scene.add( mesh );
 
-    resizeRendererToDisplaySize(renderer);
+	}
 
-    {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	{
 
-    renderer.render(scene, camera);
+		const cubeSize = 4;
+		const cubeGeo = new THREE.BoxGeometry( cubeSize, cubeSize, cubeSize );
+		const cubeMat = new THREE.MeshPhongMaterial( { color: '#8AC' } );
+		const mesh = new THREE.Mesh( cubeGeo, cubeMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( cubeSize + 1, cubeSize / 2, 0 );
+		scene.add( mesh );
 
-    requestAnimationFrame(render);
-  }
+	}
+
+	{
+
+		const sphereRadius = 3;
+		const sphereWidthDivisions = 32;
+		const sphereHeightDivisions = 16;
+		const sphereGeo = new THREE.SphereGeometry( sphereRadius, sphereWidthDivisions, sphereHeightDivisions );
+		const sphereMat = new THREE.MeshPhongMaterial( { color: '#CA8' } );
+		const mesh = new THREE.Mesh( sphereGeo, sphereMat );
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+		mesh.position.set( - sphereRadius - 1, sphereRadius + 2, 0 );
+		scene.add( mesh );
+
+	}
+
+	class ColorGUIHelper {
+
+		constructor( object, prop ) {
+
+			this.object = object;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return `#${this.object[ this.prop ].getHexString()}`;
+
+		}
+		set value( hexString ) {
+
+			this.object[ this.prop ].set( hexString );
+
+		}
+
+	}
+
+	function makeXYZGUI( gui, vector3, name, onChangeFn ) {
+
+		const folder = gui.addFolder( name );
+		folder.add( vector3, 'x', - 10, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'y', 0, 10 ).onChange( onChangeFn );
+		folder.add( vector3, 'z', - 10, 10 ).onChange( onChangeFn );
+		// folder.open();
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 100;
+		const light = new THREE.SpotLight( color, intensity );
+		light.castShadow = true;
+		light.position.set( 0, 10, 0 );
+		light.target.position.set( - 4, 0, - 4 );
+		scene.add( light );
+		scene.add( light.target );
+
+		const cameraHelper = new THREE.CameraHelper( light.shadow.camera );
+		scene.add( cameraHelper );
+
+		function updateCamera() {
+
+			// update the light target's matrixWorld because it's needed by the helper
+			light.target.updateMatrixWorld();
+			// update the light's shadow camera's projection matrix
+			light.shadow.camera.updateProjectionMatrix();
+			// and now update the camera helper we're using to show the light's shadow camera
+			cameraHelper.update();
+
+		}
+
+		updateCamera();
+		setTimeout( updateCamera );
+
+		class MinMaxGUIHelper {
+
+			constructor( obj, minProp, maxProp, minDif ) {
+
+				this.obj = obj;
+				this.minProp = minProp;
+				this.maxProp = maxProp;
+				this.minDif = minDif;
+
+			}
+			get min() {
+
+				return this.obj[ this.minProp ];
+
+			}
+			set min( v ) {
+
+				this.obj[ this.minProp ] = v;
+				this.obj[ this.maxProp ] = Math.max( this.obj[ this.maxProp ], v + this.minDif );
+
+			}
+			get max() {
+
+				return this.obj[ this.maxProp ];
+
+			}
+			set max( v ) {
+
+				this.obj[ this.maxProp ] = v;
+				this.min = this.min; // this will call the min setter
+
+			}
+
+		}
+
+		class DegRadHelper {
+
+			constructor( obj, prop ) {
+
+				this.obj = obj;
+				this.prop = prop;
+
+			}
+			get value() {
+
+				return THREE.MathUtils.radToDeg( this.obj[ this.prop ] );
+
+			}
+			set value( v ) {
+
+				this.obj[ this.prop ] = THREE.MathUtils.degToRad( v );
+
+			}
+
+		}
+
+		const gui = new GUI();
+		gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
+		gui.add( light, 'intensity', 0, 200 );
+		gui.add( light, 'distance', 0, 40 ).onChange( updateCamera );
+		gui.add( new DegRadHelper( light, 'angle' ), 'value', 0, 90 ).name( 'angle' ).onChange( updateCamera );
+		gui.add( light, 'penumbra', 0, 1, 0.01 );
+
+		gui.add( light.shadow, 'radius', 0, 50, 0.01 );
+
+		{
+
+			const folder = gui.addFolder( 'Shadow Camera' );
+			folder.open();
+			const minMaxGUIHelper = new MinMaxGUIHelper( light.shadow.camera, 'near', 'far', 0.1 );
+			folder.add( minMaxGUIHelper, 'min', 0.1, 50, 0.1 ).name( 'near' ).onChange( updateCamera );
+			folder.add( minMaxGUIHelper, 'max', 0.1, 50, 0.1 ).name( 'far' ).onChange( updateCamera );
+
+		}
+
+		makeXYZGUI( gui, light.position, 'position', updateCamera );
+		makeXYZGUI( gui, light.target.position, 'target', updateCamera );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render() {
+
+		resizeRendererToDisplaySize( renderer );
+
+		{
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 81 - 59
manual/examples/textured-cube-6-textures.html

@@ -36,71 +36,93 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  const cubes = [];  // just an array we can use to rotate the cubes
-  const loader = new THREE.TextureLoader();
-
-  const materials = [
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
-  ];
-  const cube = new THREE.Mesh(geometry, materials);
-  scene.add(cube);
-  cubes.push(cube);  // add to our list of cubes to rotate
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render(time) {
-    time *= 0.001;
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    cubes.forEach((cube, ndx) => {
-      const speed = .2 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	const scene = new THREE.Scene();
 
-    renderer.render(scene, camera);
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    requestAnimationFrame(render);
-  }
+	const cubes = []; // just an array we can use to rotate the cubes
+	const loader = new THREE.TextureLoader();
+
+	const materials = [
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-1.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-2.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-3.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-4.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-5.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-6.jpg' ) } ),
+	];
+	const cube = new THREE.Mesh( geometry, materials );
+	scene.add( cube );
+	cubes.push( cube ); // add to our list of cubes to rotate
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function loadColorTexture( path ) {
+
+		const texture = loader.load( path );
+		texture.colorSpace = THREE.SRGBColorSpace;
+		return texture;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = .2 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 137 - 104
manual/examples/textured-cube-adjust.html

@@ -35,122 +35,155 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  const cubes = [];  // just an array we can use to rotate the cubes
-  const loader = new THREE.TextureLoader();
-
-  const texture = loader.load('resources/images/wall.jpg');
-  const material = new THREE.MeshBasicMaterial({
-    map: texture,
-  });
-  const cube = new THREE.Mesh(geometry, material);
-  scene.add(cube);
-  cubes.push(cube);  // add to our list of cubes to rotate
-
-  class DegRadHelper {
-    constructor(obj, prop) {
-      this.obj = obj;
-      this.prop = prop;
-    }
-    get value() {
-      return THREE.MathUtils.radToDeg(this.obj[this.prop]);
-    }
-    set value(v) {
-      this.obj[this.prop] = THREE.MathUtils.degToRad(v);
-    }
-  }
 
-  class StringToNumberHelper {
-    constructor(obj, prop) {
-      this.obj = obj;
-      this.prop = prop;
-    }
-    get value() {
-      return this.obj[this.prop];
-    }
-    set value(v) {
-      this.obj[this.prop] = parseFloat(v);
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  const wrapModes = {
-    'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
-    'RepeatWrapping': THREE.RepeatWrapping,
-    'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
-  };
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-  function updateTexture() {
-    texture.needsUpdate = true;
-  }
+	const scene = new THREE.Scene();
 
-  const gui = new GUI();
-  gui.add(new StringToNumberHelper(texture, 'wrapS'), 'value', wrapModes)
-    .name('texture.wrapS')
-    .onChange(updateTexture);
-  gui.add(new StringToNumberHelper(texture, 'wrapT'), 'value', wrapModes)
-    .name('texture.wrapT')
-    .onChange(updateTexture);
-  gui.add(texture.repeat, 'x', 0, 5, .01).name('texture.repeat.x');
-  gui.add(texture.repeat, 'y', 0, 5, .01).name('texture.repeat.y');
-  gui.add(texture.offset, 'x', -2, 2, .01).name('texture.offset.x');
-  gui.add(texture.offset, 'y', -2, 2, .01).name('texture.offset.y');
-  gui.add(texture.center, 'x', -.5, 1.5, .01).name('texture.center.x');
-  gui.add(texture.center, 'y', -.5, 1.5, .01).name('texture.center.y');
-  gui.add(new DegRadHelper(texture, 'rotation'), 'value', -360, 360)
-    .name('texture.rotation');
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function render(time) {
-    time *= 0.001;
+	const cubes = []; // just an array we can use to rotate the cubes
+	const loader = new THREE.TextureLoader();
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const texture = loader.load( 'resources/images/wall.jpg' );
+	texture.colorSpace = THREE.SRGBColorSpace;
+	const material = new THREE.MeshBasicMaterial( {
+		map: texture,
+	} );
+	const cube = new THREE.Mesh( geometry, material );
+	scene.add( cube );
+	cubes.push( cube ); // add to our list of cubes to rotate
 
-    cubes.forEach((cube, ndx) => {
-      const speed = .2 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	class DegRadHelper {
 
-    renderer.render(scene, camera);
+		constructor( obj, prop ) {
 
-    requestAnimationFrame(render);
-  }
+			this.obj = obj;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return THREE.MathUtils.radToDeg( this.obj[ this.prop ] );
+
+		}
+		set value( v ) {
+
+			this.obj[ this.prop ] = THREE.MathUtils.degToRad( v );
+
+		}
+
+	}
+
+	class StringToNumberHelper {
+
+		constructor( obj, prop ) {
+
+			this.obj = obj;
+			this.prop = prop;
+
+		}
+		get value() {
+
+			return this.obj[ this.prop ];
+
+		}
+		set value( v ) {
+
+			this.obj[ this.prop ] = parseFloat( v );
+
+		}
+
+	}
+
+	const wrapModes = {
+		'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
+		'RepeatWrapping': THREE.RepeatWrapping,
+		'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
+	};
+
+	function updateTexture() {
+
+		texture.needsUpdate = true;
+
+	}
+
+	const gui = new GUI();
+	gui.add( new StringToNumberHelper( texture, 'wrapS' ), 'value', wrapModes )
+		.name( 'texture.wrapS' )
+		.onChange( updateTexture );
+	gui.add( new StringToNumberHelper( texture, 'wrapT' ), 'value', wrapModes )
+		.name( 'texture.wrapT' )
+		.onChange( updateTexture );
+	gui.add( texture.repeat, 'x', 0, 5, .01 ).name( 'texture.repeat.x' );
+	gui.add( texture.repeat, 'y', 0, 5, .01 ).name( 'texture.repeat.y' );
+	gui.add( texture.offset, 'x', - 2, 2, .01 ).name( 'texture.offset.x' );
+	gui.add( texture.offset, 'y', - 2, 2, .01 ).name( 'texture.offset.y' );
+	gui.add( texture.center, 'x', - .5, 1.5, .01 ).name( 'texture.center.x' );
+	gui.add( texture.center, 'y', - .5, 1.5, .01 ).name( 'texture.center.y' );
+	gui.add( new DegRadHelper( texture, 'rotation' ), 'value', - 360, 360 )
+		.name( 'texture.rotation' );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = .2 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 98 - 72
manual/examples/textured-cube-wait-for-all-textures.html

@@ -61,84 +61,110 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  const cubes = [];  // just an array we can use to rotate the cubes
-  const loadManager = new THREE.LoadingManager();
-  const loader = new THREE.TextureLoader(loadManager);
-
-  const materials = [
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
-    new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
-  ];
-
-  const loadingElem = document.querySelector('#loading');
-  const progressBarElem = loadingElem.querySelector('.progressbar');
-
-  loadManager.onLoad = () => {
-    loadingElem.style.display = 'none';
-    const cube = new THREE.Mesh(geometry, materials);
-    scene.add(cube);
-    cubes.push(cube);  // add to our list of cubes to rotate
-  };
-
-  loadManager.onProgress = (urlOfLastItemLoaded, itemsLoaded, itemsTotal) => {
-    const progress = itemsLoaded / itemsTotal;
-    progressBarElem.style.transform = `scaleX(${progress})`;
-  };
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render(time) {
-    time *= 0.001;
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    cubes.forEach((cube, ndx) => {
-      const speed = .2 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	const scene = new THREE.Scene();
 
-    renderer.render(scene, camera);
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    requestAnimationFrame(render);
-  }
+	const cubes = []; // just an array we can use to rotate the cubes
+	const loadManager = new THREE.LoadingManager();
+	const loader = new THREE.TextureLoader( loadManager );
+
+	const materials = [
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-1.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-2.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-3.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-4.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-5.jpg' ) } ),
+		new THREE.MeshBasicMaterial( { map: loadColorTexture( 'resources/images/flower-6.jpg' ) } ),
+	];
+
+	const loadingElem = document.querySelector( '#loading' );
+	const progressBarElem = loadingElem.querySelector( '.progressbar' );
+
+	loadManager.onLoad = () => {
+
+		loadingElem.style.display = 'none';
+		const cube = new THREE.Mesh( geometry, materials );
+		scene.add( cube );
+		cubes.push( cube ); // add to our list of cubes to rotate
+
+	};
+
+	loadManager.onProgress = ( urlOfLastItemLoaded, itemsLoaded, itemsTotal ) => {
+
+		const progress = itemsLoaded / itemsTotal;
+		progressBarElem.style.transform = `scaleX(${progress})`;
+
+	};
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function loadColorTexture( path ) {
+
+		const texture = loader.load( path );
+		texture.colorSpace = THREE.SRGBColorSpace;
+		return texture;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = .2 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 73 - 55
manual/examples/textured-cube-wait-for-texture.html

@@ -36,67 +36,85 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  const cubes = [];  // just an array we can use to rotate the cubes
-  const loader = new THREE.TextureLoader();
-  loader.load('resources/images/wall.jpg', (texture) => {
-    const material = new THREE.MeshBasicMaterial({
-      map: texture,
-    });
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
-    cubes.push(cube);  // add to our list of cubes to rotate
-  });
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render(time) {
-    time *= 0.001;
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    cubes.forEach((cube, ndx) => {
-      const speed = .2 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	const scene = new THREE.Scene();
 
-    renderer.render(scene, camera);
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    requestAnimationFrame(render);
-  }
+	const cubes = []; // just an array we can use to rotate the cubes
+	const loader = new THREE.TextureLoader();
+	loader.load( 'resources/images/wall.jpg', ( texture ) => {
+
+		texture.colorSpace = THREE.SRGBColorSpace;
+
+		const material = new THREE.MeshBasicMaterial( {
+			map: texture,
+		} );
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+		cubes.push( cube ); // add to our list of cubes to rotate
+
+	} );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = .2 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 71 - 54
manual/examples/textured-cube.html

@@ -36,66 +36,83 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  const cubes = [];  // just an array we can use to rotate the cubes
-  const loader = new THREE.TextureLoader();
-
-  const material = new THREE.MeshBasicMaterial({
-    map: loader.load('resources/images/wall.jpg'),
-  });
-  const cube = new THREE.Mesh(geometry, material);
-  scene.add(cube);
-  cubes.push(cube);  // add to our list of cubes to rotate
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render(time) {
-    time *= 0.001;
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    cubes.forEach((cube, ndx) => {
-      const speed = .2 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	const scene = new THREE.Scene();
 
-    renderer.render(scene, camera);
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    requestAnimationFrame(render);
-  }
+	const cubes = []; // just an array we can use to rotate the cubes
+	const loader = new THREE.TextureLoader();
+
+	const texture = loader.load( 'resources/images/wall.jpg' );
+	texture.colorSpace = THREE.SRGBColorSpace;
+
+	const material = new THREE.MeshBasicMaterial( {
+		map: texture
+	} );
+	const cube = new THREE.Mesh( geometry, material );
+	scene.add( cube );
+	cubes.push( cube ); // add to our list of cubes to rotate
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = .2 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 2 - 1
manual/examples/threejs-responsive.js

@@ -4,6 +4,7 @@ function main() {
 
 	const canvas = document.querySelector( '#c' );
 	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
 	const fov = 75;
 	const aspect = 2; // the canvas default
@@ -17,7 +18,7 @@ function main() {
 	{
 
 		const color = 0xFFFFFF;
-		const intensity = 1;
+		const intensity = 3;
 		const light = new THREE.DirectionalLight( color, intensity );
 		light.position.set( - 1, 2, 4 );
 		scene.add( light );

+ 112 - 89
manual/examples/tips-preservedrawingbuffer.html

@@ -36,110 +36,133 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({
-    canvas,
-    preserveDrawingBuffer: true,
-    alpha: true,
-    antialias: true
-  });
-  renderer.autoClearColor = false;
-
-  const camera = new THREE.OrthographicCamera(-2, 2, 1, -1, -1, 1);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( {
+		canvas,
+		preserveDrawingBuffer: true,
+		alpha: true,
+		antialias: true
+	} );
+	renderer.useLegacyLights = false;
+	renderer.autoClearColor = false;
 
-  const base = new THREE.Object3D();
-  scene.add(base);
-  base.scale.set(0.1, 0.1, 0.1);
+	const camera = new THREE.OrthographicCamera( - 2, 2, 1, - 1, - 1, 1 );
 
-  function makeInstance(geometry, color, x, y, z) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const scene = new THREE.Scene();
 
-    const cube = new THREE.Mesh(geometry, material);
-    base.add(cube);
+	{
 
-    cube.position.set(x, y, z);
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-    return cube;
-  }
+	}
 
-  makeInstance(geometry, '#F00', -2,  0,  0);
-  makeInstance(geometry, '#FF0',  2,  0,  0);
-  makeInstance(geometry, '#0F0',  0, -2,  0);
-  makeInstance(geometry, '#0FF',  0,  2,  0);
-  makeInstance(geometry, '#00F',  0,  0, -2);
-  makeInstance(geometry, '#F0F',  0,  0,  2);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  const state = { x: 0, y: 0 };
+	const base = new THREE.Object3D();
+	scene.add( base );
+	base.scale.set( 0.1, 0.1, 0.1 );
 
-  function render(time) {
-    time *= 0.001;  // convert to seconds
+	function makeInstance( geometry, color, x, y, z ) {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-        const canvas = renderer.domElement;
-        camera.right = canvas.clientWidth / canvas.clientHeight;
-        camera.left = -camera.right;
-        camera.updateProjectionMatrix();
-      }
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-      base.position.set(state.x, state.y, 0);
-      base.rotation.x = time;
-      base.rotation.y = time * 1.11;
+		const cube = new THREE.Mesh( geometry, material );
+		base.add( cube );
 
-      renderer.render(scene, camera);
+		cube.position.set( x, y, z );
 
-      requestAnimationFrame(render);
-  }
-  requestAnimationFrame(render);
-
-  function getCanvasRelativePosition(event) {
-    const rect = canvas.getBoundingClientRect();
-    return {
-      x: (event.clientX - rect.left) * canvas.width  / rect.width,
-      y: (event.clientY - rect.top ) * canvas.height / rect.height,
-    };
-  }
+		return cube;
 
-  const temp = new THREE.Vector3();
-  function setPosition(e) {
-    const pos = getCanvasRelativePosition(e);
-    const x = pos.x / canvas.width * 2 - 1;
-    const y = pos.y / canvas.height * -2 + 1;
-    temp.set(x, y, 0).unproject(camera);
-    state.x = temp.x;
-    state.y = temp.y;
-  }
+	}
+
+	makeInstance( geometry, '#F00', - 2, 0, 0 );
+	makeInstance( geometry, '#FF0', 2, 0, 0 );
+	makeInstance( geometry, '#0F0', 0, - 2, 0 );
+	makeInstance( geometry, '#0FF', 0, 2, 0 );
+	makeInstance( geometry, '#00F', 0, 0, - 2 );
+	makeInstance( geometry, '#F0F', 0, 0, 2 );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	const state = { x: 0, y: 0 };
+
+	function render( time ) {
+
+		time *= 0.001; // convert to seconds
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.right = canvas.clientWidth / canvas.clientHeight;
+			camera.left = - camera.right;
+			camera.updateProjectionMatrix();
+
+		}
+
+		base.position.set( state.x, state.y, 0 );
+		base.rotation.x = time;
+		base.rotation.y = time * 1.11;
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
+
+	function getCanvasRelativePosition( event ) {
+
+		const rect = canvas.getBoundingClientRect();
+		return {
+			x: ( event.clientX - rect.left ) * canvas.width / rect.width,
+			y: ( event.clientY - rect.top ) * canvas.height / rect.height,
+		};
+
+	}
+
+	const temp = new THREE.Vector3();
+	function setPosition( e ) {
+
+		const pos = getCanvasRelativePosition( e );
+		const x = pos.x / canvas.width * 2 - 1;
+		const y = pos.y / canvas.height * - 2 + 1;
+		temp.set( x, y, 0 ).unproject( camera );
+		state.x = temp.x;
+		state.y = temp.y;
+
+	}
+
+	canvas.addEventListener( 'mousemove', setPosition );
+	canvas.addEventListener( 'touchmove', ( e ) => {
+
+		e.preventDefault();
+		setPosition( e.touches[ 0 ] );
+
+	}, { passive: false } );
 
-  canvas.addEventListener('mousemove', setPosition);
-  canvas.addEventListener('touchmove', (e) => {
-    e.preventDefault();
-    setPosition(e.touches[0]);
-  }, {passive: false});
 }
 
 main();

+ 108 - 82
manual/examples/tips-screenshot-bad.html

@@ -53,100 +53,126 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    requestAnimationFrame(render);
-  }
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
+
+	const elem = document.querySelector( '#screenshot' );
+	elem.addEventListener( 'click', () => {
+
+		canvas.toBlob( ( blob ) => {
+
+			saveBlob( blob, `screencapture-${canvas.width}x${canvas.height}.png` );
+
+		} );
+
+	} );
+
+	const saveBlob = ( function () {
+
+		const a = document.createElement( 'a' );
+		document.body.appendChild( a );
+		a.style.display = 'none';
+		return function saveData( blob, fileName ) {
+
+			const url = window.URL.createObjectURL( blob );
+			a.href = url;
+			a.download = fileName;
+			a.click();
+
+		};
+
+	}() );
 
-  requestAnimationFrame(render);
-
-  const elem = document.querySelector('#screenshot');
-  elem.addEventListener('click', () => {
-    canvas.toBlob((blob) => {
-      saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
-    });
-  });
-
-  const saveBlob = (function() {
-    const a = document.createElement('a');
-    document.body.appendChild(a);
-    a.style.display = 'none';
-    return function saveData(blob, fileName) {
-       const url = window.URL.createObjectURL(blob);
-       a.href = url;
-       a.download = fileName;
-       a.click();
-    };
-  }());
 }
 
 main();

+ 121 - 92
manual/examples/tips-screenshot-good.html

@@ -53,108 +53,137 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  const state = {
-    time: 0,
-  };
-
-  function render() {
-    if (resizeRendererToDisplaySize(renderer)) {
-        const canvas = renderer.domElement;
-        camera.aspect = canvas.clientWidth / canvas.clientHeight;
-        camera.updateProjectionMatrix();
-      }
-
-      cubes.forEach((cube, ndx) => {
-        const speed = 1 + ndx * .1;
-        const rot = state.time * speed;
-        cube.rotation.x = rot;
-        cube.rotation.y = rot;
-      });
-
-      renderer.render(scene, camera);
-  }
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function animate(time) {
-    state.time = time * 0.001;
+	function makeInstance( geometry, color, x ) {
 
-    render();
+		const material = new THREE.MeshPhongMaterial( { color } );
+
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	const state = {
+		time: 0,
+	};
+
+	function render() {
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = state.time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+	}
+
+	function animate( time ) {
+
+		state.time = time * 0.001;
+
+		render();
+
+		requestAnimationFrame( animate );
+
+	}
+
+	requestAnimationFrame( animate );
+
+	const elem = document.querySelector( '#screenshot' );
+	elem.addEventListener( 'click', () => {
+
+		render();
+		canvas.toBlob( ( blob ) => {
+
+			saveBlob( blob, `screencapture-${canvas.width}x${canvas.height}.png` );
+
+		} );
+
+	} );
+
+	const saveBlob = ( function () {
+
+		const a = document.createElement( 'a' );
+		document.body.appendChild( a );
+		a.style.display = 'none';
+		return function saveData( blob, fileName ) {
+
+			const url = window.URL.createObjectURL( blob );
+			a.href = url;
+			a.download = fileName;
+			a.click();
+
+		};
+
+	}() );
 
-    requestAnimationFrame(animate);
-  }
-  requestAnimationFrame(animate);
-
-  const elem = document.querySelector('#screenshot');
-  elem.addEventListener('click', () => {
-    render();
-    canvas.toBlob((blob) => {
-      saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
-    });
-  });
-
-  const saveBlob = (function() {
-    const a = document.createElement('a');
-    document.body.appendChild(a);
-    a.style.display = 'none';
-    return function saveData(blob, fileName) {
-       const url = window.URL.createObjectURL(blob);
-       a.href = url;
-       a.download = fileName;
-       a.click();
-    };
-  }());
 }
 
 main();

+ 34 - 23
manual/examples/tips-tabindex.html

@@ -38,29 +38,40 @@
   </body>
 <script type="module">
 
-document.querySelectorAll('canvas').forEach((canvas) => {
-  const ctx = canvas.getContext('2d');
-
-  function draw(str) {
-    ctx.clearRect(0, 0, canvas.width, canvas.height);
-    ctx.textAlign = 'center';
-    ctx.textBaseline = 'middle';
-    ctx.fillText(str, canvas.width / 2, canvas.height / 2);
-  }
-  draw(canvas.id);
-
-  canvas.addEventListener('focus', () => {
-    draw('has focus press a key');
-  });
-
-  canvas.addEventListener('blur', () => {
-    draw('lost focus');
-  });
-
-  canvas.addEventListener('keydown', (e) => {
-    draw(`keyCode: ${e.keyCode}`);
-  });
-});
+document.querySelectorAll( 'canvas' ).forEach( ( canvas ) => {
+
+	const ctx = canvas.getContext( '2d' );
+
+	function draw( str ) {
+
+		ctx.clearRect( 0, 0, canvas.width, canvas.height );
+		ctx.textAlign = 'center';
+		ctx.textBaseline = 'middle';
+		ctx.fillText( str, canvas.width / 2, canvas.height / 2 );
+
+	}
+
+	draw( canvas.id );
+
+	canvas.addEventListener( 'focus', () => {
+
+		draw( 'has focus press a key' );
+
+	} );
+
+	canvas.addEventListener( 'blur', () => {
+
+		draw( 'lost focus' );
+
+	} );
+
+	canvas.addEventListener( 'keydown', ( e ) => {
+
+		draw( `keyCode: ${e.keyCode}` );
+
+	} );
+
+} );
 
 </script>
 </html>

+ 89 - 71
manual/examples/tips-transparent-canvas.html

@@ -63,89 +63,107 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({
-    canvas,
-    alpha: true,
-    premultipliedAlpha: false,
-    antialias: true
-  });
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 2;
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( {
+		canvas,
+		alpha: true,
+		premultipliedAlpha: false,
+		antialias: true
+	} );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({
-      color,
-      opacity: 0.5,
-    });
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 2;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( {
+			color,
+			opacity: 0.5,
+		} );
 
-    renderer.render(scene, camera);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    requestAnimationFrame(render);
-  }
+		cube.position.x = x;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+		requestAnimationFrame( render );
+
+	}
+
+	requestAnimationFrame( render );
 
-  requestAnimationFrame(render);
 }
 
 main();

+ 119 - 91
manual/examples/transparency-doubleside-hack.html

@@ -35,108 +35,136 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 4;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
-
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
-
-  function makeInstance(geometry, color, x, y, z) {
-    [THREE.BackSide, THREE.FrontSide].forEach((side) => {
-      const material = new THREE.MeshPhongMaterial({
-        color,
-        opacity: 0.5,
-        transparent: true,
-        side,
-      });
-
-      const cube = new THREE.Mesh(geometry, material);
-      scene.add(cube);
-
-      cube.position.set(x, y, z);
-    });
-  }
 
-  function hsl(h, s, l) {
-    return (new THREE.Color()).setHSL(h, s, l);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  {
-    const d = 0.8;
-    makeInstance(geometry, hsl(0 / 8, 1, .5), -d, -d, -d);
-    makeInstance(geometry, hsl(1 / 8, 1, .5),  d, -d, -d);
-    makeInstance(geometry, hsl(2 / 8, 1, .5), -d,  d, -d);
-    makeInstance(geometry, hsl(3 / 8, 1, .5),  d,  d, -d);
-    makeInstance(geometry, hsl(4 / 8, 1, .5), -d, -d,  d);
-    makeInstance(geometry, hsl(5 / 8, 1, .5),  d, -d,  d);
-    makeInstance(geometry, hsl(6 / 8, 1, .5), -d,  d,  d);
-    makeInstance(geometry, hsl(7 / 8, 1, .5),  d,  d,  d);
-  }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 4;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-  let renderRequested = false;
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-  function render() {
-    renderRequested = undefined;
+	function addLight( x, y, z ) {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
 
-    renderer.render(scene, camera);
-  }
-  render();
+	}
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
+
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
+
+	function makeInstance( geometry, color, x, y, z ) {
+
+		[ THREE.BackSide, THREE.FrontSide ].forEach( ( side ) => {
+
+			const material = new THREE.MeshPhongMaterial( {
+				color,
+				opacity: 0.5,
+				transparent: true,
+				side,
+			} );
+
+			const cube = new THREE.Mesh( geometry, material );
+			scene.add( cube );
+
+			cube.position.set( x, y, z );
+
+		} );
+
+	}
+
+	function hsl( h, s, l ) {
+
+		return ( new THREE.Color() ).setHSL( h, s, l );
+
+	}
+
+	{
+
+		const d = 0.8;
+		makeInstance( geometry, hsl( 0 / 8, 1, .5 ), - d, - d, - d );
+		makeInstance( geometry, hsl( 1 / 8, 1, .5 ), d, - d, - d );
+		makeInstance( geometry, hsl( 2 / 8, 1, .5 ), - d, d, - d );
+		makeInstance( geometry, hsl( 3 / 8, 1, .5 ), d, d, - d );
+		makeInstance( geometry, hsl( 4 / 8, 1, .5 ), - d, - d, d );
+		makeInstance( geometry, hsl( 5 / 8, 1, .5 ), d, - d, d );
+		makeInstance( geometry, hsl( 6 / 8, 1, .5 ), - d, d, d );
+		makeInstance( geometry, hsl( 7 / 8, 1, .5 ), d, d, d );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 112 - 86
manual/examples/transparency-doubleside.html

@@ -35,108 +35,134 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 4;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(...pos) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(...pos);
-    scene.add(light);
-  }
-  addLight(-1, 2, 4);
-  addLight( 1, -1, -2);
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x, y, z) {
-    const material = new THREE.MeshPhongMaterial({
-      color,
-      opacity: 0.5,
-      transparent: true,
-      side: THREE.DoubleSide,
-    });
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 4;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    cube.position.set(x, y, z);
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-    return cube;
-  }
+	function addLight( ...pos ) {
 
-  function hsl(h, s, l) {
-    return (new THREE.Color()).setHSL(h, s, l);
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( ...pos );
+		scene.add( light );
 
-  {
-    const d = 0.8;
-    makeInstance(geometry, hsl(0 / 8, 1, .5), -d, -d, -d);
-    makeInstance(geometry, hsl(1 / 8, 1, .5),  d, -d, -d);
-    makeInstance(geometry, hsl(2 / 8, 1, .5), -d,  d, -d);
-    makeInstance(geometry, hsl(3 / 8, 1, .5),  d,  d, -d);
-    makeInstance(geometry, hsl(4 / 8, 1, .5), -d, -d,  d);
-    makeInstance(geometry, hsl(5 / 8, 1, .5),  d, -d,  d);
-    makeInstance(geometry, hsl(6 / 8, 1, .5), -d,  d,  d);
-    makeInstance(geometry, hsl(7 / 8, 1, .5),  d,  d,  d);
-  }
+	}
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
 
-  let renderRequested = false;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function render() {
-    renderRequested = undefined;
+	function makeInstance( geometry, color, x, y, z ) {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const material = new THREE.MeshPhongMaterial( {
+			color,
+			opacity: 0.5,
+			transparent: true,
+			side: THREE.DoubleSide,
+		} );
 
-    renderer.render(scene, camera);
-  }
-  render();
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		cube.position.set( x, y, z );
+
+		return cube;
+
+	}
+
+	function hsl( h, s, l ) {
+
+		return ( new THREE.Color() ).setHSL( h, s, l );
+
+	}
+
+	{
+
+		const d = 0.8;
+		makeInstance( geometry, hsl( 0 / 8, 1, .5 ), - d, - d, - d );
+		makeInstance( geometry, hsl( 1 / 8, 1, .5 ), d, - d, - d );
+		makeInstance( geometry, hsl( 2 / 8, 1, .5 ), - d, d, - d );
+		makeInstance( geometry, hsl( 3 / 8, 1, .5 ), d, d, - d );
+		makeInstance( geometry, hsl( 4 / 8, 1, .5 ), - d, - d, d );
+		makeInstance( geometry, hsl( 5 / 8, 1, .5 ), d, - d, d );
+		makeInstance( geometry, hsl( 6 / 8, 1, .5 ), - d, d, d );
+		makeInstance( geometry, hsl( 7 / 8, 1, .5 ), d, d, d );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 148 - 109
manual/examples/transparency-intersecting-planes-alphatest.html

@@ -35,131 +35,170 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
-import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0.5, 1, 0.5);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
 
-  const planeWidth = 1;
-  const planeHeight = 1;
-  const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  const loader = new THREE.TextureLoader();
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0.5, 1, 0.5 );
 
-  function makeInstance(geometry, color, rotY, url) {
-    const texture = loader.load(url, render);
-    const material = new THREE.MeshPhongMaterial({
-      color,
-      map: texture,
-      alphaTest: 0.5,
-      transparent: true,
-      side: THREE.DoubleSide,
-    });
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    const mesh = new THREE.Mesh(geometry, material);
-    scene.add(mesh);
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-    mesh.rotation.y = rotY;
-  }
+	function addLight( x, y, z ) {
 
-  makeInstance(geometry, 'white', 0,             'resources/images/tree-01.png');  /* threejs.org: url */
-  makeInstance(geometry, 'white', Math.PI * 0.5, 'resources/images/tree-02.png');  /* threejs.org: url */
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
 
-  class AllMaterialPropertyGUIHelper {
-    constructor(prop, scene) {
-      this.prop = prop;
-      this.scene = scene;
-    }
-    get value() {
-      const {scene, prop} = this;
-      let v;
-      scene.traverse((obj) => {
-        if (obj.material && obj.material[prop] !== undefined) {
-          v = obj.material[prop];
-        }
-      });
-      return v;
-    }
-    set value(v) {
-      const {scene, prop} = this;
-      scene.traverse((obj) => {
-        if (obj.material && obj.material[prop] !== undefined) {
-          obj.material[prop] = v;
-          obj.material.needsUpdate = true;
-        }
-      });
-    }
-  }
+	}
 
-  const gui = new GUI();
-  gui.add(new AllMaterialPropertyGUIHelper('alphaTest', scene), 'value', 0, 1)
-      .name('alphaTest')
-      .onChange(requestRenderIfNotRequested);
-  gui.add(new AllMaterialPropertyGUIHelper('transparent', scene), 'value')
-      .name('transparent')
-      .onChange(requestRenderIfNotRequested);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
 
-  let renderRequested = false;
+	const planeWidth = 1;
+	const planeHeight = 1;
+	const geometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
 
-  function render() {
-    renderRequested = undefined;
+	const loader = new THREE.TextureLoader();
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, rotY, url ) {
 
-    renderer.render(scene, camera);
-  }
-  render();
+		const texture = loader.load( url, render );
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const material = new THREE.MeshPhongMaterial( {
+			color,
+			map: texture,
+			alphaTest: 0.5,
+			transparent: true,
+			side: THREE.DoubleSide,
+		} );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+
+		mesh.rotation.y = rotY;
+
+	}
+
+	makeInstance( geometry, 'white', 0, 'resources/images/tree-01.png' ); /* threejs.org: url */
+	makeInstance( geometry, 'white', Math.PI * 0.5, 'resources/images/tree-02.png' ); /* threejs.org: url */
+
+	class AllMaterialPropertyGUIHelper {
+
+		constructor( prop, scene ) {
+
+			this.prop = prop;
+			this.scene = scene;
+
+		}
+		get value() {
+
+			const { scene, prop } = this;
+			let v;
+			scene.traverse( ( obj ) => {
+
+				if ( obj.material && obj.material[ prop ] !== undefined ) {
+
+					v = obj.material[ prop ];
+
+				}
+
+			} );
+			return v;
+
+		}
+		set value( v ) {
+
+			const { scene, prop } = this;
+			scene.traverse( ( obj ) => {
+
+				if ( obj.material && obj.material[ prop ] !== undefined ) {
+
+					obj.material[ prop ] = v;
+					obj.material.needsUpdate = true;
+
+				}
+
+			} );
+
+		}
+
+	}
+
+	const gui = new GUI();
+	gui.add( new AllMaterialPropertyGUIHelper( 'alphaTest', scene ), 'value', 0, 1 )
+		.name( 'alphaTest' )
+		.onChange( requestRenderIfNotRequested );
+	gui.add( new AllMaterialPropertyGUIHelper( 'transparent', scene ), 'value' )
+		.name( 'transparent' )
+		.onChange( requestRenderIfNotRequested );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 113 - 88
manual/examples/transparency-intersecting-planes-fixed.html

@@ -35,104 +35,129 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0.5, 1, 0.5);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
-
-  const planeWidth = 0.5;
-  const planeHeight = 1;
-  const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight);
-
-  const loader = new THREE.TextureLoader();
-
-  function makeInstance(geometry, color, rotY, url) {
-    const base = new THREE.Object3D();
-    scene.add(base);
-    base.rotation.y = rotY;
-
-    [-1, 1].forEach((x) => {
-      const texture = loader.load(url, render);
-      texture.offset.x = x < 0 ? 0 : 0.5;
-      texture.repeat.x = .5;
-      const material = new THREE.MeshPhongMaterial({
-        color,
-        map: texture,
-        opacity: 0.5,
-        transparent: true,
-        side: THREE.DoubleSide,
-      });
-
-      const mesh = new THREE.Mesh(geometry, material);
-      base.add(mesh);
-
-      mesh.position.x = x * .25;
-    });
-  }
 
-  makeInstance(geometry, 'pink',       0,             'resources/images/happyface.png');  /* threejs.org: url */
-  makeInstance(geometry, 'lightblue',  Math.PI * 0.5, 'resources/images/hmmmface.png');   /* threejs.org: url */
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0.5, 1, 0.5 );
 
-  let renderRequested = false;
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-  function render() {
-    renderRequested = undefined;
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function addLight( x, y, z ) {
 
-    renderer.render(scene, camera);
-  }
-  render();
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+	}
+
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
+
+	const planeWidth = 0.5;
+	const planeHeight = 1;
+	const geometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
+
+	const loader = new THREE.TextureLoader();
+
+	function makeInstance( geometry, color, rotY, url ) {
+
+		const base = new THREE.Object3D();
+		scene.add( base );
+		base.rotation.y = rotY;
+
+		[ - 1, 1 ].forEach( ( x ) => {
+
+			const texture = loader.load( url, render );
+			texture.offset.x = x < 0 ? 0 : 0.5;
+			texture.repeat.x = .5;
+			texture.colorSpace = THREE.SRGBColorSpace;
+			const material = new THREE.MeshPhongMaterial( {
+				color,
+				map: texture,
+				opacity: 0.5,
+				transparent: true,
+				side: THREE.DoubleSide,
+			} );
+
+			const mesh = new THREE.Mesh( geometry, material );
+			base.add( mesh );
+
+			mesh.position.x = x * .25;
+
+		} );
+
+	}
+
+	makeInstance( geometry, 'pink', 0, 'resources/images/happyface.png' ); /* threejs.org: url */
+	makeInstance( geometry, 'lightblue', Math.PI * 0.5, 'resources/images/hmmmface.png' ); /* threejs.org: url */
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 98 - 75
manual/examples/transparency-intersecting-planes.html

@@ -35,96 +35,119 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0.5, 1, 0.5);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
 
-  const planeWidth = 1;
-  const planeHeight = 1;
-  const geometry = new THREE.PlaneGeometry(planeWidth, planeHeight);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  const loader = new THREE.TextureLoader();
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0.5, 1, 0.5 );
 
-  function makeInstance(geometry, color, rotY, url) {
-    const texture = loader.load(url, render);
-    const material = new THREE.MeshPhongMaterial({
-      color,
-      map: texture,
-      opacity: 0.5,
-      transparent: true,
-      side: THREE.DoubleSide,
-    });
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    const mesh = new THREE.Mesh(geometry, material);
-    scene.add(mesh);
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-    mesh.rotation.y = rotY;
-  }
+	function addLight( x, y, z ) {
 
-  makeInstance(geometry, 'pink',       0,             'resources/images/happyface.png');  /* threejs.org: url */
-  makeInstance(geometry, 'lightblue',  Math.PI * 0.5, 'resources/images/hmmmface.png');   /* threejs.org: url */
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  let renderRequested = false;
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
 
-  function render() {
-    renderRequested = undefined;
+	const planeWidth = 1;
+	const planeHeight = 1;
+	const geometry = new THREE.PlaneGeometry( planeWidth, planeHeight );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const loader = new THREE.TextureLoader();
 
-    renderer.render(scene, camera);
-  }
-  render();
+	function makeInstance( geometry, color, rotY, url ) {
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const texture = loader.load( url, render );
+		texture.colorSpace = THREE.SRGBColorSpace;
+		const material = new THREE.MeshPhongMaterial( {
+			color,
+			map: texture,
+			opacity: 0.5,
+			transparent: true,
+			side: THREE.DoubleSide,
+		} );
+
+		const mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+
+		mesh.rotation.y = rotY;
+
+	}
+
+	makeInstance( geometry, 'pink', 0, 'resources/images/happyface.png' ); /* threejs.org: url */
+	makeInstance( geometry, 'lightblue', Math.PI * 0.5, 'resources/images/hmmmface.png' ); /* threejs.org: url */
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 111 - 85
manual/examples/transparency.html

@@ -35,107 +35,133 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 25;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.z = 4;
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(0, 0, 0);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('white');
-
-  function addLight(...pos) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(...pos);
-    scene.add(light);
-  }
-  addLight(-1, 2, 4);
-  addLight( 1, -1, -2);
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  function makeInstance(geometry, color, x, y, z) {
-    const material = new THREE.MeshPhongMaterial({
-      color,
-      opacity: 0.5,
-      transparent: true,
-    });
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 25;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.z = 4;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( 0, 0, 0 );
+	controls.update();
 
-    cube.position.set(x, y, z);
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'white' );
 
-    return cube;
-  }
+	function addLight( ...pos ) {
 
-  function hsl(h, s, l) {
-    return (new THREE.Color()).setHSL(h, s, l);
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( ...pos );
+		scene.add( light );
 
-  {
-    const d = 0.8;
-    makeInstance(geometry, hsl(0 / 8, 1, .5), -d, -d, -d);
-    makeInstance(geometry, hsl(1 / 8, 1, .5),  d, -d, -d);
-    makeInstance(geometry, hsl(2 / 8, 1, .5), -d,  d, -d);
-    makeInstance(geometry, hsl(3 / 8, 1, .5),  d,  d, -d);
-    makeInstance(geometry, hsl(4 / 8, 1, .5), -d, -d,  d);
-    makeInstance(geometry, hsl(5 / 8, 1, .5),  d, -d,  d);
-    makeInstance(geometry, hsl(6 / 8, 1, .5), -d,  d,  d);
-    makeInstance(geometry, hsl(7 / 8, 1, .5),  d,  d,  d);
-  }
+	}
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
 
-  let renderRequested = false;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function render() {
-    renderRequested = undefined;
+	function makeInstance( geometry, color, x, y, z ) {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const material = new THREE.MeshPhongMaterial( {
+			color,
+			opacity: 0.5,
+			transparent: true,
+		} );
 
-    renderer.render(scene, camera);
-  }
-  render();
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		cube.position.set( x, y, z );
+
+		return cube;
+
+	}
+
+	function hsl( h, s, l ) {
+
+		return ( new THREE.Color() ).setHSL( h, s, l );
+
+	}
+
+	{
+
+		const d = 0.8;
+		makeInstance( geometry, hsl( 0 / 8, 1, .5 ), - d, - d, - d );
+		makeInstance( geometry, hsl( 1 / 8, 1, .5 ), d, - d, - d );
+		makeInstance( geometry, hsl( 2 / 8, 1, .5 ), - d, d, - d );
+		makeInstance( geometry, hsl( 3 / 8, 1, .5 ), d, d, - d );
+		makeInstance( geometry, hsl( 4 / 8, 1, .5 ), - d, - d, d );
+		makeInstance( geometry, hsl( 5 / 8, 1, .5 ), d, - d, d );
+		makeInstance( geometry, hsl( 6 / 8, 1, .5 ), - d, d, d );
+		makeInstance( geometry, hsl( 7 / 8, 1, .5 ), d, d, d );
+
+	}
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 615 - 478
manual/examples/voxel-geometry-culled-faces-ui.html

@@ -86,512 +86,649 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 class VoxelWorld {
-  constructor(options) {
-    this.cellSize = options.cellSize;
-    this.tileSize = options.tileSize;
-    this.tileTextureWidth = options.tileTextureWidth;
-    this.tileTextureHeight = options.tileTextureHeight;
-    const {cellSize} = this;
-    this.cellSliceSize = cellSize * cellSize;
-    this.cells = {};
-  }
-  computeVoxelOffset(x, y, z) {
-    const {cellSize, cellSliceSize} = this;
-    const voxelX = THREE.MathUtils.euclideanModulo(x, cellSize) | 0;
-    const voxelY = THREE.MathUtils.euclideanModulo(y, cellSize) | 0;
-    const voxelZ = THREE.MathUtils.euclideanModulo(z, cellSize) | 0;
-    return voxelY * cellSliceSize +
+
+	constructor( options ) {
+
+		this.cellSize = options.cellSize;
+		this.tileSize = options.tileSize;
+		this.tileTextureWidth = options.tileTextureWidth;
+		this.tileTextureHeight = options.tileTextureHeight;
+		const { cellSize } = this;
+		this.cellSliceSize = cellSize * cellSize;
+		this.cells = {};
+
+	}
+	computeVoxelOffset( x, y, z ) {
+
+		const { cellSize, cellSliceSize } = this;
+		const voxelX = THREE.MathUtils.euclideanModulo( x, cellSize ) | 0;
+		const voxelY = THREE.MathUtils.euclideanModulo( y, cellSize ) | 0;
+		const voxelZ = THREE.MathUtils.euclideanModulo( z, cellSize ) | 0;
+		return voxelY * cellSliceSize +
            voxelZ * cellSize +
            voxelX;
-  }
-  computeCellId(x, y, z) {
-    const {cellSize} = this;
-    const cellX = Math.floor(x / cellSize);
-    const cellY = Math.floor(y / cellSize);
-    const cellZ = Math.floor(z / cellSize);
-    return `${cellX},${cellY},${cellZ}`;
-  }
-  addCellForVoxel(x, y, z) {
-    const cellId = this.computeCellId(x, y, z);
-    let cell = this.cells[cellId];
-    if (!cell) {
-      const {cellSize} = this;
-      cell = new Uint8Array(cellSize * cellSize * cellSize);
-      this.cells[cellId] = cell;
-    }
-    return cell;
-  }
-  getCellForVoxel(x, y, z) {
-    return this.cells[this.computeCellId(x, y, z)];
-  }
-  setVoxel(x, y, z, v, addCell = true) {
-    let cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      if (!addCell) {
-        return;
-      }
-      cell = this.addCellForVoxel(x, y, z);
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    cell[voxelOffset] = v;
-  }
-  getVoxel(x, y, z) {
-    const cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      return 0;
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    return cell[voxelOffset];
-  }
-  generateGeometryDataForCell(cellX, cellY, cellZ) {
-    const {cellSize, tileSize, tileTextureWidth, tileTextureHeight} = this;
-    const positions = [];
-    const normals = [];
-    const uvs = [];
-    const indices = [];
-    const startX = cellX * cellSize;
-    const startY = cellY * cellSize;
-    const startZ = cellZ * cellSize;
-
-    for (let y = 0; y < cellSize; ++y) {
-      const voxelY = startY + y;
-      for (let z = 0; z < cellSize; ++z) {
-        const voxelZ = startZ + z;
-        for (let x = 0; x < cellSize; ++x) {
-          const voxelX = startX + x;
-          const voxel = this.getVoxel(voxelX, voxelY, voxelZ);
-          if (voxel) {
-            // voxel 0 is sky (empty) so for UVs we start at 0
-            const uvVoxel = voxel - 1;
-            // There is a voxel here but do we need faces for it?
-            for (const {dir, corners, uvRow} of VoxelWorld.faces) {
-              const neighbor = this.getVoxel(
-                  voxelX + dir[0],
-                  voxelY + dir[1],
-                  voxelZ + dir[2]);
-              if (!neighbor) {
-                // this voxel has no neighbor in this direction so we need a face.
-                const ndx = positions.length / 3;
-                for (const {pos, uv} of corners) {
-                  positions.push(pos[0] + x, pos[1] + y, pos[2] + z);
-                  normals.push(...dir);
-                  uvs.push(
-                        (uvVoxel +   uv[0]) * tileSize / tileTextureWidth,
-                    1 - (uvRow + 1 - uv[1]) * tileSize / tileTextureHeight);
-                }
-                indices.push(
-                  ndx, ndx + 1, ndx + 2,
-                  ndx + 2, ndx + 1, ndx + 3,
-                );
-              }
-            }
-          }
-        }
-      }
-    }
 
-    return {
-      positions,
-      normals,
-      uvs,
-      indices,
-    };
-  }
+	}
+	computeCellId( x, y, z ) {
 
-    // from
-    // https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.42.3443&rep=rep1&type=pdf
-    intersectRay(start, end) {
-    let dx = end.x - start.x;
-    let dy = end.y - start.y;
-    let dz = end.z - start.z;
-    const lenSq = dx * dx + dy * dy + dz * dz;
-    const len = Math.sqrt(lenSq);
-
-    dx /= len;
-    dy /= len;
-    dz /= len;
-
-    let t = 0.0;
-    let ix = Math.floor(start.x);
-    let iy = Math.floor(start.y);
-    let iz = Math.floor(start.z);
-
-    const stepX = (dx > 0) ? 1 : -1;
-    const stepY = (dy > 0) ? 1 : -1;
-    const stepZ = (dz > 0) ? 1 : -1;
-
-    const txDelta = Math.abs(1 / dx);
-    const tyDelta = Math.abs(1 / dy);
-    const tzDelta = Math.abs(1 / dz);
-
-    const xDist = (stepX > 0) ? (ix + 1 - start.x) : (start.x - ix);
-    const yDist = (stepY > 0) ? (iy + 1 - start.y) : (start.y - iy);
-    const zDist = (stepZ > 0) ? (iz + 1 - start.z) : (start.z - iz);
-
-    // location of nearest voxel boundary, in units of t
-    let txMax = (txDelta < Infinity) ? txDelta * xDist : Infinity;
-    let tyMax = (tyDelta < Infinity) ? tyDelta * yDist : Infinity;
-    let tzMax = (tzDelta < Infinity) ? tzDelta * zDist : Infinity;
-
-    let steppedIndex = -1;
-
-    // main loop along raycast vector
-    while (t <= len) {
-      const voxel = this.getVoxel(ix, iy, iz);
-      if (voxel) {
-        return {
-          position: [
-            start.x + t * dx,
-            start.y + t * dy,
-            start.z + t * dz,
-          ],
-          normal: [
-            steppedIndex === 0 ? -stepX : 0,
-            steppedIndex === 1 ? -stepY : 0,
-            steppedIndex === 2 ? -stepZ : 0,
-          ],
-          voxel,
-        };
-      }
+		const { cellSize } = this;
+		const cellX = Math.floor( x / cellSize );
+		const cellY = Math.floor( y / cellSize );
+		const cellZ = Math.floor( z / cellSize );
+		return `${cellX},${cellY},${cellZ}`;
+
+	}
+	addCellForVoxel( x, y, z ) {
+
+		const cellId = this.computeCellId( x, y, z );
+		let cell = this.cells[ cellId ];
+		if ( ! cell ) {
+
+			const { cellSize } = this;
+			cell = new Uint8Array( cellSize * cellSize * cellSize );
+			this.cells[ cellId ] = cell;
+
+		}
+
+		return cell;
+
+	}
+	getCellForVoxel( x, y, z ) {
+
+		return this.cells[ this.computeCellId( x, y, z ) ];
+
+	}
+	setVoxel( x, y, z, v, addCell = true ) {
+
+		let cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			if ( ! addCell ) {
+
+				return;
+
+			}
+
+			cell = this.addCellForVoxel( x, y, z );
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		cell[ voxelOffset ] = v;
+
+	}
+	getVoxel( x, y, z ) {
+
+		const cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			return 0;
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		return cell[ voxelOffset ];
+
+	}
+	generateGeometryDataForCell( cellX, cellY, cellZ ) {
+
+		const { cellSize, tileSize, tileTextureWidth, tileTextureHeight } = this;
+		const positions = [];
+		const normals = [];
+		const uvs = [];
+		const indices = [];
+		const startX = cellX * cellSize;
+		const startY = cellY * cellSize;
+		const startZ = cellZ * cellSize;
+
+		for ( let y = 0; y < cellSize; ++ y ) {
+
+			const voxelY = startY + y;
+			for ( let z = 0; z < cellSize; ++ z ) {
+
+				const voxelZ = startZ + z;
+				for ( let x = 0; x < cellSize; ++ x ) {
+
+					const voxelX = startX + x;
+					const voxel = this.getVoxel( voxelX, voxelY, voxelZ );
+					if ( voxel ) {
+
+						// voxel 0 is sky (empty) so for UVs we start at 0
+						const uvVoxel = voxel - 1;
+						// There is a voxel here but do we need faces for it?
+						for ( const { dir, corners, uvRow } of VoxelWorld.faces ) {
+
+							const neighbor = this.getVoxel(
+								voxelX + dir[ 0 ],
+								voxelY + dir[ 1 ],
+								voxelZ + dir[ 2 ] );
+							if ( ! neighbor ) {
+
+								// this voxel has no neighbor in this direction so we need a face.
+								const ndx = positions.length / 3;
+								for ( const { pos, uv } of corners ) {
+
+									positions.push( pos[ 0 ] + x, pos[ 1 ] + y, pos[ 2 ] + z );
+									normals.push( ...dir );
+									uvs.push(
+										( uvVoxel + uv[ 0 ] ) * tileSize / tileTextureWidth,
+										1 - ( uvRow + 1 - uv[ 1 ] ) * tileSize / tileTextureHeight );
+
+								}
+
+								indices.push(
+									ndx, ndx + 1, ndx + 2,
+									ndx + 2, ndx + 1, ndx + 3,
+								);
+
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
+		return {
+			positions,
+			normals,
+			uvs,
+			indices,
+		};
+
+	}
+
+	// from
+	// https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.42.3443&rep=rep1&type=pdf
+	intersectRay( start, end ) {
+
+		let dx = end.x - start.x;
+		let dy = end.y - start.y;
+		let dz = end.z - start.z;
+		const lenSq = dx * dx + dy * dy + dz * dz;
+		const len = Math.sqrt( lenSq );
+
+		dx /= len;
+		dy /= len;
+		dz /= len;
+
+		let t = 0.0;
+		let ix = Math.floor( start.x );
+		let iy = Math.floor( start.y );
+		let iz = Math.floor( start.z );
+
+		const stepX = ( dx > 0 ) ? 1 : - 1;
+		const stepY = ( dy > 0 ) ? 1 : - 1;
+		const stepZ = ( dz > 0 ) ? 1 : - 1;
+
+		const txDelta = Math.abs( 1 / dx );
+		const tyDelta = Math.abs( 1 / dy );
+		const tzDelta = Math.abs( 1 / dz );
+
+		const xDist = ( stepX > 0 ) ? ( ix + 1 - start.x ) : ( start.x - ix );
+		const yDist = ( stepY > 0 ) ? ( iy + 1 - start.y ) : ( start.y - iy );
+		const zDist = ( stepZ > 0 ) ? ( iz + 1 - start.z ) : ( start.z - iz );
+
+		// location of nearest voxel boundary, in units of t
+		let txMax = ( txDelta < Infinity ) ? txDelta * xDist : Infinity;
+		let tyMax = ( tyDelta < Infinity ) ? tyDelta * yDist : Infinity;
+		let tzMax = ( tzDelta < Infinity ) ? tzDelta * zDist : Infinity;
+
+		let steppedIndex = - 1;
+
+		// main loop along raycast vector
+		while ( t <= len ) {
+
+			const voxel = this.getVoxel( ix, iy, iz );
+			if ( voxel ) {
+
+				return {
+					position: [
+						start.x + t * dx,
+						start.y + t * dy,
+						start.z + t * dz,
+					],
+					normal: [
+						steppedIndex === 0 ? - stepX : 0,
+						steppedIndex === 1 ? - stepY : 0,
+						steppedIndex === 2 ? - stepZ : 0,
+					],
+					voxel,
+				};
+
+			}
+
+			// advance t to next nearest voxel boundary
+			if ( txMax < tyMax ) {
+
+				if ( txMax < tzMax ) {
+
+					ix += stepX;
+					t = txMax;
+					txMax += txDelta;
+					steppedIndex = 0;
+
+				} else {
+
+					iz += stepZ;
+					t = tzMax;
+					tzMax += tzDelta;
+					steppedIndex = 2;
+
+				}
+
+			} else {
+
+				if ( tyMax < tzMax ) {
+
+					iy += stepY;
+					t = tyMax;
+					tyMax += tyDelta;
+					steppedIndex = 1;
+
+				} else {
+
+					iz += stepZ;
+					t = tzMax;
+					tzMax += tzDelta;
+					steppedIndex = 2;
+
+				}
+
+			}
+
+		}
+
+		return null;
+
+	}
 
-      // advance t to next nearest voxel boundary
-      if (txMax < tyMax) {
-        if (txMax < tzMax) {
-          ix += stepX;
-          t = txMax;
-          txMax += txDelta;
-          steppedIndex = 0;
-        } else {
-          iz += stepZ;
-          t = tzMax;
-          tzMax += tzDelta;
-          steppedIndex = 2;
-        }
-      } else {
-        if (tyMax < tzMax) {
-          iy += stepY;
-          t = tyMax;
-          tyMax += tyDelta;
-          steppedIndex = 1;
-        } else {
-          iz += stepZ;
-          t = tzMax;
-          tzMax += tzDelta;
-          steppedIndex = 2;
-        }
-      }
-    }
-    return null;
-  }
 }
 
 VoxelWorld.faces = [
-  { // left
-    uvRow: 0,
-    dir: [ -1,  0,  0, ],
-    corners: [
-      { pos: [ 0, 1, 0 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 0, 0 ], },
-      { pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
-      { pos: [ 0, 0, 1 ], uv: [ 1, 0 ], },
-    ],
-  },
-  { // right
-    uvRow: 0,
-    dir: [  1,  0,  0, ],
-    corners: [
-      { pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 1, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 1, 1 ], },
-      { pos: [ 1, 0, 0 ], uv: [ 1, 0 ], },
-    ],
-  },
-  { // bottom
-    uvRow: 1,
-    dir: [  0, -1,  0, ],
-    corners: [
-      { pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
-      { pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 0, 0 ], uv: [ 1, 1 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 0, 1 ], },
-    ],
-  },
-  { // top
-    uvRow: 2,
-    dir: [  0,  1,  0, ],
-    corners: [
-      { pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
-      { pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 1, 0 ], uv: [ 1, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 0, 0 ], },
-    ],
-  },
-  { // back
-    uvRow: 0,
-    dir: [  0,  0, -1, ],
-    corners: [
-      { pos: [ 1, 0, 0 ], uv: [ 0, 0 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 1, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 1, 0 ], uv: [ 1, 1 ], },
-    ],
-  },
-  { // front
-    uvRow: 0,
-    dir: [  0,  0,  1, ],
-    corners: [
-      { pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
-      { pos: [ 0, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 1, 1, 1 ], uv: [ 1, 1 ], },
-    ],
-  },
+	{ // left
+		uvRow: 0,
+		dir: [ - 1, 0, 0, ],
+		corners: [
+			{ pos: [ 0, 1, 0 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 0, 0 ], },
+			{ pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
+			{ pos: [ 0, 0, 1 ], uv: [ 1, 0 ], },
+		],
+	},
+	{ // right
+		uvRow: 0,
+		dir: [ 1, 0, 0, ],
+		corners: [
+			{ pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 1, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 1, 1 ], },
+			{ pos: [ 1, 0, 0 ], uv: [ 1, 0 ], },
+		],
+	},
+	{ // bottom
+		uvRow: 1,
+		dir: [ 0, - 1, 0, ],
+		corners: [
+			{ pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
+			{ pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 0, 0 ], uv: [ 1, 1 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 0, 1 ], },
+		],
+	},
+	{ // top
+		uvRow: 2,
+		dir: [ 0, 1, 0, ],
+		corners: [
+			{ pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
+			{ pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 1, 0 ], uv: [ 1, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 0, 0 ], },
+		],
+	},
+	{ // back
+		uvRow: 0,
+		dir: [ 0, 0, - 1, ],
+		corners: [
+			{ pos: [ 1, 0, 0 ], uv: [ 0, 0 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 1, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 1, 0 ], uv: [ 1, 1 ], },
+		],
+	},
+	{ // front
+		uvRow: 0,
+		dir: [ 0, 0, 1, ],
+		corners: [
+			{ pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
+			{ pos: [ 0, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 1, 1, 1 ], uv: [ 1, 1 ], },
+		],
+	},
 ];
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const cellSize = 32;
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(-cellSize * .3, cellSize * .8, -cellSize * .3);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(cellSize / 2, cellSize / 3, cellSize / 2);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('lightblue');
-
-  const tileSize = 16;
-  const tileTextureWidth = 256;
-  const tileTextureHeight = 64;
-  const loader = new THREE.TextureLoader();
-  const texture = loader.load('resources/images/minecraft/flourish-cc-by-nc-sa.png', render);
-  texture.magFilter = THREE.NearestFilter;
-  texture.minFilter = THREE.NearestFilter;
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
-
-  const world = new VoxelWorld({
-    cellSize,
-    tileSize,
-    tileTextureWidth,
-    tileTextureHeight,
-  });
-
-  const material = new THREE.MeshLambertMaterial({
-    map: texture,
-    side: THREE.DoubleSide,
-    alphaTest: 0.1,
-    transparent: true,
-  });
-
-  const cellIdToMesh = {};
-  function updateCellGeometry(x, y, z) {
-    const cellX = Math.floor(x / cellSize);
-    const cellY = Math.floor(y / cellSize);
-    const cellZ = Math.floor(z / cellSize);
-    const cellId = world.computeCellId(x, y, z);
-    let mesh = cellIdToMesh[cellId];
-    const geometry = mesh ? mesh.geometry : new THREE.BufferGeometry();
-
-    const {positions, normals, uvs, indices} = world.generateGeometryDataForCell(cellX, cellY, cellZ);
-    const positionNumComponents = 3;
-    geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
-    const normalNumComponents = 3;
-    geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
-    const uvNumComponents = 2;
-    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
-    geometry.setIndex(indices);
-    geometry.computeBoundingSphere();
-
-    if (!mesh) {
-      mesh = new THREE.Mesh(geometry, material);
-      mesh.name = cellId;
-      cellIdToMesh[cellId] = mesh;
-      scene.add(mesh);
-      mesh.position.set(cellX * cellSize, cellY * cellSize, cellZ * cellSize);
-    }
-  }
 
-  const neighborOffsets = [
-    [ 0,  0,  0], // self
-    [-1,  0,  0], // left
-    [ 1,  0,  0], // right
-    [ 0, -1,  0], // down
-    [ 0,  1,  0], // up
-    [ 0,  0, -1], // back
-    [ 0,  0,  1], // front
-  ];
-  function updateVoxelGeometry(x, y, z) {
-    const updatedCellIds = {};
-    for (const offset of neighborOffsets) {
-      const ox = x + offset[0];
-      const oy = y + offset[1];
-      const oz = z + offset[2];
-      const cellId = world.computeCellId(ox, oy, oz);
-      if (!updatedCellIds[cellId]) {
-        updatedCellIds[cellId] = true;
-        updateCellGeometry(ox, oy, oz);
-      }
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+
+	const cellSize = 32;
+
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( - cellSize * .3, cellSize * .8, - cellSize * .3 );
+
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( cellSize / 2, cellSize / 3, cellSize / 2 );
+	controls.update();
+
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'lightblue' );
+
+	const tileSize = 16;
+	const tileTextureWidth = 256;
+	const tileTextureHeight = 64;
+	const loader = new THREE.TextureLoader();
+	const texture = loader.load( 'resources/images/minecraft/flourish-cc-by-nc-sa.png', render );
+	texture.magFilter = THREE.NearestFilter;
+	texture.minFilter = THREE.NearestFilter;
+	texture.colorSpace = THREE.SRGBColorSpace;
 
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const height = (Math.sin(x / cellSize * Math.PI * 2) + Math.sin(z / cellSize * Math.PI * 3)) * (cellSize / 6) + (cellSize / 2);
-        if (y < height) {
-          world.setVoxel(x, y, z, randInt(1, 17));
-        }
-      }
-    }
-  }
+	function addLight( x, y, z ) {
 
-  function randInt(min, max) {
-    return Math.floor(Math.random() * (max - min) + min);
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
 
-  updateVoxelGeometry(1, 1, 1);  // 0,0,0 will generate
+	}
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
 
-  let renderRequested = false;
+	const world = new VoxelWorld( {
+		cellSize,
+		tileSize,
+		tileTextureWidth,
+		tileTextureHeight,
+	} );
 
-  function render() {
-    renderRequested = undefined;
+	const material = new THREE.MeshLambertMaterial( {
+		map: texture,
+		side: THREE.DoubleSide,
+		alphaTest: 0.1,
+		transparent: true,
+	} );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const cellIdToMesh = {};
+	function updateCellGeometry( x, y, z ) {
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+		const cellX = Math.floor( x / cellSize );
+		const cellY = Math.floor( y / cellSize );
+		const cellZ = Math.floor( z / cellSize );
+		const cellId = world.computeCellId( x, y, z );
+		let mesh = cellIdToMesh[ cellId ];
+		const geometry = mesh ? mesh.geometry : new THREE.BufferGeometry();
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const { positions, normals, uvs, indices } = world.generateGeometryDataForCell( cellX, cellY, cellZ );
+		const positionNumComponents = 3;
+		geometry.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( positions ), positionNumComponents ) );
+		const normalNumComponents = 3;
+		geometry.setAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), normalNumComponents ) );
+		const uvNumComponents = 2;
+		geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( uvs ), uvNumComponents ) );
+		geometry.setIndex( indices );
+		geometry.computeBoundingSphere();
 
-  let currentVoxel = 0;
-  let currentId;
-
-  document.querySelectorAll('#ui .tiles input[type=radio][name=voxel]').forEach((elem) => {
-    elem.addEventListener('click', allowUncheck);
-  });
-
-  function allowUncheck() {
-    if (this.id === currentId) {
-      this.checked = false;
-      currentId = undefined;
-      currentVoxel = 0;
-    } else {
-      currentId = this.id;
-      currentVoxel = parseInt(this.value);
-    }
-  }
+		if ( ! mesh ) {
 
-  function getCanvasRelativePosition(event) {
-    const rect = canvas.getBoundingClientRect();
-    return {
-      x: (event.clientX - rect.left) * canvas.width  / rect.width,
-      y: (event.clientY - rect.top ) * canvas.height / rect.height,
-    };
-  }
+			mesh = new THREE.Mesh( geometry, material );
+			mesh.name = cellId;
+			cellIdToMesh[ cellId ] = mesh;
+			scene.add( mesh );
+			mesh.position.set( cellX * cellSize, cellY * cellSize, cellZ * cellSize );
 
-  function placeVoxel(event) {
-    const pos = getCanvasRelativePosition(event);
-    const x = (pos.x / canvas.width ) *  2 - 1;
-    const y = (pos.y / canvas.height) * -2 + 1;  // note we flip Y
-
-    const start = new THREE.Vector3();
-    const end = new THREE.Vector3();
-    start.setFromMatrixPosition(camera.matrixWorld);
-    end.set(x, y, 1).unproject(camera);
-
-    const intersection = world.intersectRay(start, end);
-    if (intersection) {
-      const voxelId = event.shiftKey ? 0 : currentVoxel;
-      // the intersection point is on the face. That means
-      // the math imprecision could put us on either side of the face.
-      // so go half a normal into the voxel if removing (currentVoxel = 0)
-      // our out of the voxel if adding (currentVoxel  > 0)
-      const pos = intersection.position.map((v, ndx) => {
-        return v + intersection.normal[ndx] * (voxelId > 0 ? 0.5 : -0.5);
-      });
-      world.setVoxel(...pos, voxelId);
-      updateVoxelGeometry(...pos);
-      requestRenderIfNotRequested();
-    }
-  }
+		}
 
-  const mouse = {
-    x: 0,
-    y: 0,
-  };
+	}
+
+	const neighborOffsets = [
+		[ 0, 0, 0 ], // self
+		[ - 1, 0, 0 ], // left
+		[ 1, 0, 0 ], // right
+		[ 0, - 1, 0 ], // down
+		[ 0, 1, 0 ], // up
+		[ 0, 0, - 1 ], // back
+		[ 0, 0, 1 ], // front
+	];
+	function updateVoxelGeometry( x, y, z ) {
+
+		const updatedCellIds = {};
+		for ( const offset of neighborOffsets ) {
+
+			const ox = x + offset[ 0 ];
+			const oy = y + offset[ 1 ];
+			const oz = z + offset[ 2 ];
+			const cellId = world.computeCellId( ox, oy, oz );
+			if ( ! updatedCellIds[ cellId ] ) {
+
+				updatedCellIds[ cellId ] = true;
+				updateCellGeometry( ox, oy, oz );
+
+			}
+
+		}
+
+	}
+
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const height = ( Math.sin( x / cellSize * Math.PI * 2 ) + Math.sin( z / cellSize * Math.PI * 3 ) ) * ( cellSize / 6 ) + ( cellSize / 2 );
+				if ( y < height ) {
+
+					world.setVoxel( x, y, z, randInt( 1, 17 ) );
+
+				}
+
+			}
+
+		}
+
+	}
+
+	function randInt( min, max ) {
+
+		return Math.floor( Math.random() * ( max - min ) + min );
+
+	}
+
+	updateVoxelGeometry( 1, 1, 1 ); // 0,0,0 will generate
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	let currentVoxel = 0;
+	let currentId;
+
+	document.querySelectorAll( '#ui .tiles input[type=radio][name=voxel]' ).forEach( ( elem ) => {
+
+		elem.addEventListener( 'click', allowUncheck );
+
+	} );
+
+	function allowUncheck() {
+
+		if ( this.id === currentId ) {
+
+			this.checked = false;
+			currentId = undefined;
+			currentVoxel = 0;
+
+		} else {
+
+			currentId = this.id;
+			currentVoxel = parseInt( this.value );
+
+		}
+
+	}
+
+	function getCanvasRelativePosition( event ) {
+
+		const rect = canvas.getBoundingClientRect();
+		return {
+			x: ( event.clientX - rect.left ) * canvas.width / rect.width,
+			y: ( event.clientY - rect.top ) * canvas.height / rect.height,
+		};
+
+	}
+
+	function placeVoxel( event ) {
+
+		const pos = getCanvasRelativePosition( event );
+		const x = ( pos.x / canvas.width ) * 2 - 1;
+		const y = ( pos.y / canvas.height ) * - 2 + 1; // note we flip Y
+
+		const start = new THREE.Vector3();
+		const end = new THREE.Vector3();
+		start.setFromMatrixPosition( camera.matrixWorld );
+		end.set( x, y, 1 ).unproject( camera );
+
+		const intersection = world.intersectRay( start, end );
+		if ( intersection ) {
+
+			const voxelId = event.shiftKey ? 0 : currentVoxel;
+			// the intersection point is on the face. That means
+			// the math imprecision could put us on either side of the face.
+			// so go half a normal into the voxel if removing (currentVoxel = 0)
+			// our out of the voxel if adding (currentVoxel  > 0)
+			const pos = intersection.position.map( ( v, ndx ) => {
+
+				return v + intersection.normal[ ndx ] * ( voxelId > 0 ? 0.5 : - 0.5 );
+
+			} );
+			world.setVoxel( ...pos, voxelId );
+			updateVoxelGeometry( ...pos );
+			requestRenderIfNotRequested();
+
+		}
+
+	}
+
+	const mouse = {
+		x: 0,
+		y: 0,
+	};
+
+	function recordStartPosition( event ) {
+
+		mouse.x = event.clientX;
+		mouse.y = event.clientY;
+		mouse.moveX = 0;
+		mouse.moveY = 0;
+
+	}
+
+	function recordMovement( event ) {
+
+		mouse.moveX += Math.abs( mouse.x - event.clientX );
+		mouse.moveY += Math.abs( mouse.y - event.clientY );
+
+	}
+
+	function placeVoxelIfNoMovement( event ) {
+
+		if ( mouse.moveX < 5 && mouse.moveY < 5 ) {
+
+			placeVoxel( event );
+
+		}
+
+		window.removeEventListener( 'pointermove', recordMovement );
+		window.removeEventListener( 'pointerup', placeVoxelIfNoMovement );
+
+	}
+
+	canvas.addEventListener( 'pointerdown', ( event ) => {
+
+		event.preventDefault();
+		recordStartPosition( event );
+		window.addEventListener( 'pointermove', recordMovement );
+		window.addEventListener( 'pointerup', placeVoxelIfNoMovement );
+
+	}, { passive: false } );
+	canvas.addEventListener( 'touchstart', ( event ) => {
+
+		// prevent scrolling
+		event.preventDefault();
+
+	}, { passive: false } );
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  function recordStartPosition(event) {
-    mouse.x = event.clientX;
-    mouse.y = event.clientY;
-    mouse.moveX = 0;
-    mouse.moveY = 0;
-  }
-  function recordMovement(event) {
-    mouse.moveX += Math.abs(mouse.x - event.clientX);
-    mouse.moveY += Math.abs(mouse.y - event.clientY);
-  }
-  function placeVoxelIfNoMovement(event) {
-    if (mouse.moveX < 5 && mouse.moveY < 5) {
-      placeVoxel(event);
-    }
-    window.removeEventListener('pointermove', recordMovement);
-    window.removeEventListener('pointerup', placeVoxelIfNoMovement);
-  }
-  canvas.addEventListener('pointerdown', (event) => {
-    event.preventDefault();
-    recordStartPosition(event);
-    window.addEventListener('pointermove', recordMovement);
-    window.addEventListener('pointerup', placeVoxelIfNoMovement);
-  }, {passive: false});
-  canvas.addEventListener('touchstart', (event) => {
-    // prevent scrolling
-    event.preventDefault();
-  }, {passive: false});
-
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 337 - 268
manual/examples/voxel-geometry-culled-faces-with-textures.html

@@ -35,293 +35,362 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 class VoxelWorld {
-  constructor(options) {
-    this.cellSize = options.cellSize;
-    this.tileSize = options.tileSize;
-    this.tileTextureWidth = options.tileTextureWidth;
-    this.tileTextureHeight = options.tileTextureHeight;
-    const {cellSize} = this;
-    this.cellSliceSize = cellSize * cellSize;
-    this.cell = new Uint8Array(cellSize * cellSize * cellSize);
-  }
-  computeVoxelOffset(x, y, z) {
-    const {cellSize, cellSliceSize} = this;
-    const voxelX = THREE.MathUtils.euclideanModulo(x, cellSize) | 0;
-    const voxelY = THREE.MathUtils.euclideanModulo(y, cellSize) | 0;
-    const voxelZ = THREE.MathUtils.euclideanModulo(z, cellSize) | 0;
-    return voxelY * cellSliceSize +
+
+	constructor( options ) {
+
+		this.cellSize = options.cellSize;
+		this.tileSize = options.tileSize;
+		this.tileTextureWidth = options.tileTextureWidth;
+		this.tileTextureHeight = options.tileTextureHeight;
+		const { cellSize } = this;
+		this.cellSliceSize = cellSize * cellSize;
+		this.cell = new Uint8Array( cellSize * cellSize * cellSize );
+
+	}
+	computeVoxelOffset( x, y, z ) {
+
+		const { cellSize, cellSliceSize } = this;
+		const voxelX = THREE.MathUtils.euclideanModulo( x, cellSize ) | 0;
+		const voxelY = THREE.MathUtils.euclideanModulo( y, cellSize ) | 0;
+		const voxelZ = THREE.MathUtils.euclideanModulo( z, cellSize ) | 0;
+		return voxelY * cellSliceSize +
            voxelZ * cellSize +
            voxelX;
-  }
-  getCellForVoxel(x, y, z) {
-    const {cellSize} = this;
-    const cellX = Math.floor(x / cellSize);
-    const cellY = Math.floor(y / cellSize);
-    const cellZ = Math.floor(z / cellSize);
-    if (cellX !== 0 || cellY !== 0 || cellZ !== 0) {
-      return null;
-    }
-    return this.cell;
-  }
-  setVoxel(x, y, z, v) {
-    const cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      return;  // TODO: add a new cell?
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    cell[voxelOffset] = v;
-  }
-  getVoxel(x, y, z) {
-    const cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      return 0;
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    return cell[voxelOffset];
-  }
-  generateGeometryDataForCell(cellX, cellY, cellZ) {
-    const {cellSize, tileSize, tileTextureWidth, tileTextureHeight} = this;
-    const positions = [];
-    const normals = [];
-    const uvs = [];
-    const indices = [];
-    const startX = cellX * cellSize;
-    const startY = cellY * cellSize;
-    const startZ = cellZ * cellSize;
-
-    for (let y = 0; y < cellSize; ++y) {
-      const voxelY = startY + y;
-      for (let z = 0; z < cellSize; ++z) {
-        const voxelZ = startZ + z;
-        for (let x = 0; x < cellSize; ++x) {
-          const voxelX = startX + x;
-          const voxel = this.getVoxel(voxelX, voxelY, voxelZ);
-          if (voxel) {
-            // voxel 0 is sky (empty) so for UVs we start at 0
-            const uvVoxel = voxel - 1;
-            // There is a voxel here but do we need faces for it?
-            for (const {dir, corners, uvRow} of VoxelWorld.faces) {
-              const neighbor = this.getVoxel(
-                  voxelX + dir[0],
-                  voxelY + dir[1],
-                  voxelZ + dir[2]);
-              if (!neighbor) {
-                // this voxel has no neighbor in this direction so we need a face.
-                const ndx = positions.length / 3;
-                for (const {pos, uv} of corners) {
-                  positions.push(pos[0] + x, pos[1] + y, pos[2] + z);
-                  normals.push(...dir);
-                  uvs.push(
-                        (uvVoxel +   uv[0]) * tileSize / tileTextureWidth,
-                    1 - (uvRow + 1 - uv[1]) * tileSize / tileTextureHeight);
-                }
-                indices.push(
-                  ndx, ndx + 1, ndx + 2,
-                  ndx + 2, ndx + 1, ndx + 3,
-                );
-              }
-            }
-          }
-        }
-      }
-    }
 
-    return {
-      positions,
-      normals,
-      uvs,
-      indices,
-    };
-  }
+	}
+	getCellForVoxel( x, y, z ) {
+
+		const { cellSize } = this;
+		const cellX = Math.floor( x / cellSize );
+		const cellY = Math.floor( y / cellSize );
+		const cellZ = Math.floor( z / cellSize );
+		if ( cellX !== 0 || cellY !== 0 || cellZ !== 0 ) {
+
+			return null;
+
+		}
+
+		return this.cell;
+
+	}
+	setVoxel( x, y, z, v ) {
+
+		const cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			return; // TODO: add a new cell?
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		cell[ voxelOffset ] = v;
+
+	}
+	getVoxel( x, y, z ) {
+
+		const cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			return 0;
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		return cell[ voxelOffset ];
+
+	}
+	generateGeometryDataForCell( cellX, cellY, cellZ ) {
+
+		const { cellSize, tileSize, tileTextureWidth, tileTextureHeight } = this;
+		const positions = [];
+		const normals = [];
+		const uvs = [];
+		const indices = [];
+		const startX = cellX * cellSize;
+		const startY = cellY * cellSize;
+		const startZ = cellZ * cellSize;
+
+		for ( let y = 0; y < cellSize; ++ y ) {
+
+			const voxelY = startY + y;
+			for ( let z = 0; z < cellSize; ++ z ) {
+
+				const voxelZ = startZ + z;
+				for ( let x = 0; x < cellSize; ++ x ) {
+
+					const voxelX = startX + x;
+					const voxel = this.getVoxel( voxelX, voxelY, voxelZ );
+					if ( voxel ) {
+
+						// voxel 0 is sky (empty) so for UVs we start at 0
+						const uvVoxel = voxel - 1;
+						// There is a voxel here but do we need faces for it?
+						for ( const { dir, corners, uvRow } of VoxelWorld.faces ) {
+
+							const neighbor = this.getVoxel(
+								voxelX + dir[ 0 ],
+								voxelY + dir[ 1 ],
+								voxelZ + dir[ 2 ] );
+							if ( ! neighbor ) {
+
+								// this voxel has no neighbor in this direction so we need a face.
+								const ndx = positions.length / 3;
+								for ( const { pos, uv } of corners ) {
+
+									positions.push( pos[ 0 ] + x, pos[ 1 ] + y, pos[ 2 ] + z );
+									normals.push( ...dir );
+									uvs.push(
+										( uvVoxel + uv[ 0 ] ) * tileSize / tileTextureWidth,
+										1 - ( uvRow + 1 - uv[ 1 ] ) * tileSize / tileTextureHeight );
+
+								}
+
+								indices.push(
+									ndx, ndx + 1, ndx + 2,
+									ndx + 2, ndx + 1, ndx + 3,
+								);
+
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
+		return {
+			positions,
+			normals,
+			uvs,
+			indices,
+		};
+
+	}
+
 }
 
 VoxelWorld.faces = [
-  { // left
-    uvRow: 0,
-    dir: [ -1,  0,  0, ],
-    corners: [
-      { pos: [ 0, 1, 0 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 0, 0 ], },
-      { pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
-      { pos: [ 0, 0, 1 ], uv: [ 1, 0 ], },
-    ],
-  },
-  { // right
-    uvRow: 0,
-    dir: [  1,  0,  0, ],
-    corners: [
-      { pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 1, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 1, 1 ], },
-      { pos: [ 1, 0, 0 ], uv: [ 1, 0 ], },
-    ],
-  },
-  { // bottom
-    uvRow: 1,
-    dir: [  0, -1,  0, ],
-    corners: [
-      { pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
-      { pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 0, 0 ], uv: [ 1, 1 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 0, 1 ], },
-    ],
-  },
-  { // top
-    uvRow: 2,
-    dir: [  0,  1,  0, ],
-    corners: [
-      { pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
-      { pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 1, 0 ], uv: [ 1, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 0, 0 ], },
-    ],
-  },
-  { // back
-    uvRow: 0,
-    dir: [  0,  0, -1, ],
-    corners: [
-      { pos: [ 1, 0, 0 ], uv: [ 0, 0 ], },
-      { pos: [ 0, 0, 0 ], uv: [ 1, 0 ], },
-      { pos: [ 1, 1, 0 ], uv: [ 0, 1 ], },
-      { pos: [ 0, 1, 0 ], uv: [ 1, 1 ], },
-    ],
-  },
-  { // front
-    uvRow: 0,
-    dir: [  0,  0,  1, ],
-    corners: [
-      { pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
-      { pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
-      { pos: [ 0, 1, 1 ], uv: [ 0, 1 ], },
-      { pos: [ 1, 1, 1 ], uv: [ 1, 1 ], },
-    ],
-  },
+	{ // left
+		uvRow: 0,
+		dir: [ - 1, 0, 0, ],
+		corners: [
+			{ pos: [ 0, 1, 0 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 0, 0 ], },
+			{ pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
+			{ pos: [ 0, 0, 1 ], uv: [ 1, 0 ], },
+		],
+	},
+	{ // right
+		uvRow: 0,
+		dir: [ 1, 0, 0, ],
+		corners: [
+			{ pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 1, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 1, 1 ], },
+			{ pos: [ 1, 0, 0 ], uv: [ 1, 0 ], },
+		],
+	},
+	{ // bottom
+		uvRow: 1,
+		dir: [ 0, - 1, 0, ],
+		corners: [
+			{ pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
+			{ pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 0, 0 ], uv: [ 1, 1 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 0, 1 ], },
+		],
+	},
+	{ // top
+		uvRow: 2,
+		dir: [ 0, 1, 0, ],
+		corners: [
+			{ pos: [ 0, 1, 1 ], uv: [ 1, 1 ], },
+			{ pos: [ 1, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 1, 0 ], uv: [ 1, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 0, 0 ], },
+		],
+	},
+	{ // back
+		uvRow: 0,
+		dir: [ 0, 0, - 1, ],
+		corners: [
+			{ pos: [ 1, 0, 0 ], uv: [ 0, 0 ], },
+			{ pos: [ 0, 0, 0 ], uv: [ 1, 0 ], },
+			{ pos: [ 1, 1, 0 ], uv: [ 0, 1 ], },
+			{ pos: [ 0, 1, 0 ], uv: [ 1, 1 ], },
+		],
+	},
+	{ // front
+		uvRow: 0,
+		dir: [ 0, 0, 1, ],
+		corners: [
+			{ pos: [ 0, 0, 1 ], uv: [ 0, 0 ], },
+			{ pos: [ 1, 0, 1 ], uv: [ 1, 0 ], },
+			{ pos: [ 0, 1, 1 ], uv: [ 0, 1 ], },
+			{ pos: [ 1, 1, 1 ], uv: [ 1, 1 ], },
+		],
+	},
 ];
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const cellSize = 32;
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(-cellSize * .3, cellSize * .8, -cellSize * .3);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(cellSize / 2, cellSize / 3, cellSize / 2);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('lightblue');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
-
-  const loader = new THREE.TextureLoader();
-  const texture = loader.load('resources/images/minecraft/flourish-cc-by-nc-sa.png', render);
-  texture.magFilter = THREE.NearestFilter;
-  texture.minFilter = THREE.NearestFilter;
-
-  const tileSize = 16;
-  const tileTextureWidth = 256;
-  const tileTextureHeight = 64;
-  const world = new VoxelWorld({
-    cellSize,
-    tileSize,
-    tileTextureWidth,
-    tileTextureHeight,
-  });
-
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const height = (Math.sin(x / cellSize * Math.PI * 2) + Math.sin(z / cellSize * Math.PI * 3)) * (cellSize / 6) + (cellSize / 2);
-        if (y < height) {
-          world.setVoxel(x, y, z, randInt(1, 17));
-        }
-      }
-    }
-  }
 
-  function randInt(min, max) {
-    return Math.floor(Math.random() * (max - min) + min);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  const {positions, normals, uvs, indices} = world.generateGeometryDataForCell(0, 0, 0);
-  const geometry = new THREE.BufferGeometry();
-  const material = new THREE.MeshLambertMaterial({
-    map: texture,
-    side: THREE.DoubleSide,
-    alphaTest: 0.1,
-    transparent: true,
-  });
-
-  const positionNumComponents = 3;
-  const normalNumComponents = 3;
-  const uvNumComponents = 2;
-  geometry.setAttribute(
-      'position',
-      new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
-  geometry.setAttribute(
-      'normal',
-      new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
-  geometry.setAttribute(
-      'uv',
-      new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
-  geometry.setIndex(indices);
-  const mesh = new THREE.Mesh(geometry, material);
-  scene.add(mesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const cellSize = 32;
 
-  let renderRequested = false;
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( - cellSize * .3, cellSize * .8, - cellSize * .3 );
 
-  function render() {
-    renderRequested = undefined;
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( cellSize / 2, cellSize / 3, cellSize / 2 );
+	controls.update();
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'lightblue' );
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+	function addLight( x, y, z ) {
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
+
+	}
+
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
+
+	const loader = new THREE.TextureLoader();
+	const texture = loader.load( 'resources/images/minecraft/flourish-cc-by-nc-sa.png', render );
+	texture.magFilter = THREE.NearestFilter;
+	texture.minFilter = THREE.NearestFilter;
+	texture.colorSpace = THREE.SRGBColorSpace;
+
+	const tileSize = 16;
+	const tileTextureWidth = 256;
+	const tileTextureHeight = 64;
+	const world = new VoxelWorld( {
+		cellSize,
+		tileSize,
+		tileTextureWidth,
+		tileTextureHeight,
+	} );
+
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const height = ( Math.sin( x / cellSize * Math.PI * 2 ) + Math.sin( z / cellSize * Math.PI * 3 ) ) * ( cellSize / 6 ) + ( cellSize / 2 );
+				if ( y < height ) {
+
+					world.setVoxel( x, y, z, randInt( 1, 17 ) );
+
+				}
+
+			}
+
+		}
+
+	}
+
+	function randInt( min, max ) {
+
+		return Math.floor( Math.random() * ( max - min ) + min );
+
+	}
+
+	const { positions, normals, uvs, indices } = world.generateGeometryDataForCell( 0, 0, 0 );
+	const geometry = new THREE.BufferGeometry();
+	const material = new THREE.MeshLambertMaterial( {
+		map: texture,
+		side: THREE.DoubleSide,
+		alphaTest: 0.1,
+		transparent: true,
+	} );
+
+	const positionNumComponents = 3;
+	const normalNumComponents = 3;
+	const uvNumComponents = 2;
+	geometry.setAttribute(
+		'position',
+		new THREE.BufferAttribute( new Float32Array( positions ), positionNumComponents ) );
+	geometry.setAttribute(
+		'normal',
+		new THREE.BufferAttribute( new Float32Array( normals ), normalNumComponents ) );
+	geometry.setAttribute(
+		'uv',
+		new THREE.BufferAttribute( new Float32Array( uvs ), uvNumComponents ) );
+	geometry.setIndex( indices );
+	const mesh = new THREE.Mesh( geometry, material );
+	scene.add( mesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 292 - 226
manual/examples/voxel-geometry-culled-faces.html

@@ -35,250 +35,316 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 class VoxelWorld {
-  constructor(cellSize) {
-    this.cellSize = cellSize;
-    this.cellSliceSize = cellSize * cellSize;
-    this.cell = new Uint8Array(cellSize * cellSize * cellSize);
-  }
-  computeVoxelOffset(x, y, z) {
-    const {cellSize, cellSliceSize} = this;
-    const voxelX = THREE.MathUtils.euclideanModulo(x, cellSize) | 0;
-    const voxelY = THREE.MathUtils.euclideanModulo(y, cellSize) | 0;
-    const voxelZ = THREE.MathUtils.euclideanModulo(z, cellSize) | 0;
-    return voxelY * cellSliceSize +
+
+	constructor( cellSize ) {
+
+		this.cellSize = cellSize;
+		this.cellSliceSize = cellSize * cellSize;
+		this.cell = new Uint8Array( cellSize * cellSize * cellSize );
+
+	}
+	computeVoxelOffset( x, y, z ) {
+
+		const { cellSize, cellSliceSize } = this;
+		const voxelX = THREE.MathUtils.euclideanModulo( x, cellSize ) | 0;
+		const voxelY = THREE.MathUtils.euclideanModulo( y, cellSize ) | 0;
+		const voxelZ = THREE.MathUtils.euclideanModulo( z, cellSize ) | 0;
+		return voxelY * cellSliceSize +
            voxelZ * cellSize +
            voxelX;
-  }
-  getCellForVoxel(x, y, z) {
-    const {cellSize} = this;
-    const cellX = Math.floor(x / cellSize);
-    const cellY = Math.floor(y / cellSize);
-    const cellZ = Math.floor(z / cellSize);
-    if (cellX !== 0 || cellY !== 0 || cellZ !== 0) {
-      return null;
-    }
-    return this.cell;
-  }
-  setVoxel(x, y, z, v) {
-    const cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      return;  // TODO: add a new cell?
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    cell[voxelOffset] = v;
-  }
-  getVoxel(x, y, z) {
-    const cell = this.getCellForVoxel(x, y, z);
-    if (!cell) {
-      return 0;
-    }
-    const voxelOffset = this.computeVoxelOffset(x, y, z);
-    return cell[voxelOffset];
-  }
-  generateGeometryDataForCell(cellX, cellY, cellZ) {
-    const {cellSize} = this;
-    const positions = [];
-    const normals = [];
-    const indices = [];
-    const startX = cellX * cellSize;
-    const startY = cellY * cellSize;
-    const startZ = cellZ * cellSize;
-
-    for (let y = 0; y < cellSize; ++y) {
-      const voxelY = startY + y;
-      for (let z = 0; z < cellSize; ++z) {
-        const voxelZ = startZ + z;
-        for (let x = 0; x < cellSize; ++x) {
-          const voxelX = startX + x;
-          const voxel = this.getVoxel(voxelX, voxelY, voxelZ);
-          if (voxel) {
-            // There is a voxel here but do we need faces for it?
-            for (const {dir, corners} of VoxelWorld.faces) {
-              const neighbor = this.getVoxel(
-                  voxelX + dir[0],
-                  voxelY + dir[1],
-                  voxelZ + dir[2]);
-              if (!neighbor) {
-                // this voxel has no neighbor in this direction so we need a face.
-                const ndx = positions.length / 3;
-                for (const pos of corners) {
-                  positions.push(pos[0] + x, pos[1] + y, pos[2] + z);
-                  normals.push(...dir);
-                }
-                indices.push(
-                  ndx, ndx + 1, ndx + 2,
-                  ndx + 2, ndx + 1, ndx + 3,
-                );
-              }
-            }
-          }
-        }
-      }
-    }
 
-    return {
-      positions,
-      normals,
-      indices,
-    };
-  }
+	}
+	getCellForVoxel( x, y, z ) {
+
+		const { cellSize } = this;
+		const cellX = Math.floor( x / cellSize );
+		const cellY = Math.floor( y / cellSize );
+		const cellZ = Math.floor( z / cellSize );
+		if ( cellX !== 0 || cellY !== 0 || cellZ !== 0 ) {
+
+			return null;
+
+		}
+
+		return this.cell;
+
+	}
+	setVoxel( x, y, z, v ) {
+
+		const cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			return; // TODO: add a new cell?
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		cell[ voxelOffset ] = v;
+
+	}
+	getVoxel( x, y, z ) {
+
+		const cell = this.getCellForVoxel( x, y, z );
+		if ( ! cell ) {
+
+			return 0;
+
+		}
+
+		const voxelOffset = this.computeVoxelOffset( x, y, z );
+		return cell[ voxelOffset ];
+
+	}
+	generateGeometryDataForCell( cellX, cellY, cellZ ) {
+
+		const { cellSize } = this;
+		const positions = [];
+		const normals = [];
+		const indices = [];
+		const startX = cellX * cellSize;
+		const startY = cellY * cellSize;
+		const startZ = cellZ * cellSize;
+
+		for ( let y = 0; y < cellSize; ++ y ) {
+
+			const voxelY = startY + y;
+			for ( let z = 0; z < cellSize; ++ z ) {
+
+				const voxelZ = startZ + z;
+				for ( let x = 0; x < cellSize; ++ x ) {
+
+					const voxelX = startX + x;
+					const voxel = this.getVoxel( voxelX, voxelY, voxelZ );
+					if ( voxel ) {
+
+						// There is a voxel here but do we need faces for it?
+						for ( const { dir, corners } of VoxelWorld.faces ) {
+
+							const neighbor = this.getVoxel(
+								voxelX + dir[ 0 ],
+								voxelY + dir[ 1 ],
+								voxelZ + dir[ 2 ] );
+							if ( ! neighbor ) {
+
+								// this voxel has no neighbor in this direction so we need a face.
+								const ndx = positions.length / 3;
+								for ( const pos of corners ) {
+
+									positions.push( pos[ 0 ] + x, pos[ 1 ] + y, pos[ 2 ] + z );
+									normals.push( ...dir );
+
+								}
+
+								indices.push(
+									ndx, ndx + 1, ndx + 2,
+									ndx + 2, ndx + 1, ndx + 3,
+								);
+
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
+		return {
+			positions,
+			normals,
+			indices,
+		};
+
+	}
+
 }
 
 VoxelWorld.faces = [
-  { // left
-    dir: [ -1,  0,  0, ],
-    corners: [
-      [ 0, 1, 0 ],
-      [ 0, 0, 0 ],
-      [ 0, 1, 1 ],
-      [ 0, 0, 1 ],
-    ],
-  },
-  { // right
-    dir: [  1,  0,  0, ],
-    corners: [
-      [ 1, 1, 1 ],
-      [ 1, 0, 1 ],
-      [ 1, 1, 0 ],
-      [ 1, 0, 0 ],
-    ],
-  },
-  { // bottom
-    dir: [  0, -1,  0, ],
-    corners: [
-      [ 1, 0, 1 ],
-      [ 0, 0, 1 ],
-      [ 1, 0, 0 ],
-      [ 0, 0, 0 ],
-    ],
-  },
-  { // top
-    dir: [  0,  1,  0, ],
-    corners: [
-      [ 0, 1, 1 ],
-      [ 1, 1, 1 ],
-      [ 0, 1, 0 ],
-      [ 1, 1, 0 ],
-    ],
-  },
-  { // back
-    dir: [  0,  0, -1, ],
-    corners: [
-      [ 1, 0, 0 ],
-      [ 0, 0, 0 ],
-      [ 1, 1, 0 ],
-      [ 0, 1, 0 ],
-    ],
-  },
-  { // front
-    dir: [  0,  0,  1, ],
-    corners: [
-      [ 0, 0, 1 ],
-      [ 1, 0, 1 ],
-      [ 0, 1, 1 ],
-      [ 1, 1, 1 ],
-    ],
-  },
+	{ // left
+		dir: [ - 1, 0, 0, ],
+		corners: [
+			[ 0, 1, 0 ],
+			[ 0, 0, 0 ],
+			[ 0, 1, 1 ],
+			[ 0, 0, 1 ],
+		],
+	},
+	{ // right
+		dir: [ 1, 0, 0, ],
+		corners: [
+			[ 1, 1, 1 ],
+			[ 1, 0, 1 ],
+			[ 1, 1, 0 ],
+			[ 1, 0, 0 ],
+		],
+	},
+	{ // bottom
+		dir: [ 0, - 1, 0, ],
+		corners: [
+			[ 1, 0, 1 ],
+			[ 0, 0, 1 ],
+			[ 1, 0, 0 ],
+			[ 0, 0, 0 ],
+		],
+	},
+	{ // top
+		dir: [ 0, 1, 0, ],
+		corners: [
+			[ 0, 1, 1 ],
+			[ 1, 1, 1 ],
+			[ 0, 1, 0 ],
+			[ 1, 1, 0 ],
+		],
+	},
+	{ // back
+		dir: [ 0, 0, - 1, ],
+		corners: [
+			[ 1, 0, 0 ],
+			[ 0, 0, 0 ],
+			[ 1, 1, 0 ],
+			[ 0, 1, 0 ],
+		],
+	},
+	{ // front
+		dir: [ 0, 0, 1, ],
+		corners: [
+			[ 0, 0, 1 ],
+			[ 1, 0, 1 ],
+			[ 0, 1, 1 ],
+			[ 1, 1, 1 ],
+		],
+	},
 ];
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const cellSize = 32;
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(-cellSize * .3, cellSize * .8, -cellSize * .3);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(cellSize / 2, cellSize / 3, cellSize / 2);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('lightblue');
-
-  function addLight(x, y, z) {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(x, y, z);
-    scene.add(light);
-  }
-  addLight(-1,  2,  4);
-  addLight( 1, -1, -2);
-
-  const world = new VoxelWorld(cellSize);
-
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const height = (Math.sin(x / cellSize * Math.PI * 2) + Math.sin(z / cellSize * Math.PI * 3)) * (cellSize / 6) + (cellSize / 2);
-        if (y < height) {
-          world.setVoxel(x, y, z, 1);
-        }
-      }
-    }
-  }
 
-  const {positions, normals, indices} = world.generateGeometryDataForCell(0, 0, 0);
-  const geometry = new THREE.BufferGeometry();
-  const material = new THREE.MeshLambertMaterial({color: 'green'});
-
-  const positionNumComponents = 3;
-  const normalNumComponents = 3;
-  geometry.setAttribute(
-      'position',
-      new THREE.BufferAttribute(new Float32Array(positions), positionNumComponents));
-  geometry.setAttribute(
-      'normal',
-      new THREE.BufferAttribute(new Float32Array(normals), normalNumComponents));
-  geometry.setIndex(indices);
-  const mesh = new THREE.Mesh(geometry, material);
-  scene.add(mesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  let renderRequested = false;
+	const cellSize = 32;
 
-  function render() {
-    renderRequested = undefined;
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( - cellSize * .3, cellSize * .8, - cellSize * .3 );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( cellSize / 2, cellSize / 3, cellSize / 2 );
+	controls.update();
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'lightblue' );
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+	function addLight( x, y, z ) {
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( x, y, z );
+		scene.add( light );
+
+	}
+
+	addLight( - 1, 2, 4 );
+	addLight( 1, - 1, - 2 );
+
+	const world = new VoxelWorld( cellSize );
+
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const height = ( Math.sin( x / cellSize * Math.PI * 2 ) + Math.sin( z / cellSize * Math.PI * 3 ) ) * ( cellSize / 6 ) + ( cellSize / 2 );
+				if ( y < height ) {
+
+					world.setVoxel( x, y, z, 1 );
+
+				}
+
+			}
+
+		}
+
+	}
+
+	const { positions, normals, indices } = world.generateGeometryDataForCell( 0, 0, 0 );
+	const geometry = new THREE.BufferGeometry();
+	const material = new THREE.MeshLambertMaterial( { color: 'green' } );
+
+	const positionNumComponents = 3;
+	const normalNumComponents = 3;
+	geometry.setAttribute(
+		'position',
+		new THREE.BufferAttribute( new Float32Array( positions ), positionNumComponents ) );
+	geometry.setAttribute(
+		'normal',
+		new THREE.BufferAttribute( new Float32Array( normals ), normalNumComponents ) );
+	geometry.setIndex( indices );
+	const mesh = new THREE.Mesh( geometry, material );
+	scene.add( mesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 104 - 77
manual/examples/voxel-geometry-merged.html

@@ -36,93 +36,120 @@
 <script type="module">
 import * as THREE from 'three';
 import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const cellSize = 256;
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(cellSize / 2, 60, cellSize);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(cellSize / 2, 60, cellSize / 2);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('lightblue');
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const geometries = [];
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const height = (Math.sin(x / cellSize * Math.PI * 4) + Math.sin(z / cellSize * Math.PI * 6)) * 20 + 60;
-        //if (y < height) {
-        if (height > y && height < y + 1) {
-          const geometry = new THREE.BoxGeometry(1, 1, 1);
-          geometry.applyMatrix4((new THREE.Matrix4()).makeTranslation(x, y, z));
-          geometries.push(geometry);
-        }
-      }
-    }
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  const mergedGeometry = BufferGeometryUtils.mergeGeometries(
-        geometries, false);
-  const material = new THREE.MeshPhongMaterial({color: 'green'});
-  const mesh = new THREE.Mesh(mergedGeometry, material);
-  scene.add(mesh);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const cellSize = 256;
 
-  let renderRequested = false;
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( cellSize / 2, 60, cellSize );
 
-  function render() {
-    renderRequested = undefined;
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( cellSize / 2, 60, cellSize / 2 );
+	controls.update();
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'lightblue' );
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+	{
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	const geometries = [];
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const height = ( Math.sin( x / cellSize * Math.PI * 4 ) + Math.sin( z / cellSize * Math.PI * 6 ) ) * 20 + 60;
+				//if (y < height) {
+				if ( height > y && height < y + 1 ) {
+
+					const geometry = new THREE.BoxGeometry( 1, 1, 1 );
+					geometry.applyMatrix4( ( new THREE.Matrix4() ).makeTranslation( x, y, z ) );
+					geometries.push( geometry );
+
+				}
+
+			}
+
+		}
+
+	}
+
+	const mergedGeometry = BufferGeometryUtils.mergeGeometries(
+		geometries, false );
+	const material = new THREE.MeshPhongMaterial( { color: 'green' } );
+	const mesh = new THREE.Mesh( mergedGeometry, material );
+	scene.add( mesh );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 119 - 84
manual/examples/voxel-geometry-separate-cubes.html

@@ -35,106 +35,141 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const cellSize = 256;
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 1000;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(-cellSize * .3, cellSize * .8, -cellSize * .3);
-
-  const controls = new OrbitControls(camera, canvas);
-  controls.target.set(cellSize / 2, cellSize / 3, cellSize / 2);
-  controls.update();
-
-  const scene = new THREE.Scene();
-  scene.background = new THREE.Color('lightblue');
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const cell = new Uint8Array(cellSize * cellSize * cellSize);
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const height = (Math.sin(x / cellSize * Math.PI * 4) + Math.sin(z / cellSize * Math.PI * 6)) * 20 + cellSize / 2;
-        if (height > y && height < y + 1) {
-          const offset = y * cellSize * cellSize +
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+
+	const cellSize = 256;
+
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 1000;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( - cellSize * .3, cellSize * .8, - cellSize * .3 );
+
+	const controls = new OrbitControls( camera, canvas );
+	controls.target.set( cellSize / 2, cellSize / 3, cellSize / 2 );
+	controls.update();
+
+	const scene = new THREE.Scene();
+	scene.background = new THREE.Color( 'lightblue' );
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	const cell = new Uint8Array( cellSize * cellSize * cellSize );
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const height = ( Math.sin( x / cellSize * Math.PI * 4 ) + Math.sin( z / cellSize * Math.PI * 6 ) ) * 20 + cellSize / 2;
+				if ( height > y && height < y + 1 ) {
+
+					const offset = y * cellSize * cellSize +
                        z * cellSize +
                        x;
-          cell[offset] = 1;
-        }
-      }
-    }
-  }
+					cell[ offset ] = 1;
+
+				}
+
+			}
+
+		}
+
+	}
 
-  const geometry = new THREE.BoxGeometry(1, 1, 1);
-  const material = new THREE.MeshPhongMaterial({color: 'green'});
+	const geometry = new THREE.BoxGeometry( 1, 1, 1 );
+	const material = new THREE.MeshPhongMaterial( { color: 'green' } );
 
-  for (let y = 0; y < cellSize; ++y) {
-    for (let z = 0; z < cellSize; ++z) {
-      for (let x = 0; x < cellSize; ++x) {
-        const offset = y * cellSize * cellSize +
+	for ( let y = 0; y < cellSize; ++ y ) {
+
+		for ( let z = 0; z < cellSize; ++ z ) {
+
+			for ( let x = 0; x < cellSize; ++ x ) {
+
+				const offset = y * cellSize * cellSize +
                        z * cellSize +
                        x;
-        const block = cell[offset];
-        if (block) {
-          const mesh = new THREE.Mesh(geometry, material);
-          mesh.position.set(x, y, z);
-          scene.add(mesh);
-        }
-      }
-    }
-  }
+				const block = cell[ offset ];
+				if ( block ) {
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+					const mesh = new THREE.Mesh( geometry, material );
+					mesh.position.set( x, y, z );
+					scene.add( mesh );
 
-  let renderRequested = false;
+				}
 
-  function render() {
-    renderRequested = undefined;
+			}
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		}
 
-    controls.update();
-    renderer.render(scene, camera);
-  }
-  render();
+	}
 
-  function requestRenderIfNotRequested() {
-    if (!renderRequested) {
-      renderRequested = true;
-      requestAnimationFrame(render);
-    }
-  }
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	let renderRequested = false;
+
+	function render() {
+
+		renderRequested = undefined;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		controls.update();
+		renderer.render( scene, camera );
+
+	}
+
+	render();
+
+	function requestRenderIfNotRequested() {
+
+		if ( ! renderRequested ) {
+
+			renderRequested = true;
+			requestAnimationFrame( render );
+
+		}
+
+	}
+
+	controls.addEventListener( 'change', requestRenderIfNotRequested );
+	window.addEventListener( 'resize', requestRenderIfNotRequested );
 
-  controls.addEventListener('change', requestRenderIfNotRequested);
-  window.addEventListener('resize', requestRenderIfNotRequested);
 }
 
 main();

+ 114 - 90
manual/examples/webxr-basic-vr-optional.html

@@ -44,111 +44,135 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
-import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 5;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const params = (new URL(document.location)).searchParams;
-  const allowvr = params.get('allowvr') === 'true';
-  if (allowvr) {
-    renderer.xr.enabled = true;
-    document.body.appendChild(VRButton.createButton(renderer));
-    document.querySelector('#vr').style.display = 'none';
-  } else {
-    // no VR, add some controls
-    const controls = new OrbitControls(camera, canvas);
-    controls.target.set(0, 1.6, -2);
-    controls.update();
-    document.querySelector('#nonvr').style.display = 'none';
-  }
 
-  const scene = new THREE.Scene();
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 5;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const params = ( new URL( document.location ) ).searchParams;
+	const allowvr = params.get( 'allowvr' ) === 'true';
+	if ( allowvr ) {
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+		renderer.xr.enabled = true;
+		document.body.appendChild( VRButton.createButton( renderer ) );
+		document.querySelector( '#vr' ).style.display = 'none';
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	} else {
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+		// no VR, add some controls
+		const controls = new OrbitControls( camera, canvas );
+		controls.target.set( 0, 1.6, - 2 );
+		controls.update();
+		document.querySelector( '#nonvr' ).style.display = 'none';
 
-    return cube;
-  }
+	}
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const scene = new THREE.Scene();
+	{
 
-  function render(time) {
-    time *= 0.001;
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	}
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	{
 
-    renderer.render(scene, camera);
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
+
+	function makeInstance( geometry, color, x ) {
+
+		const material = new THREE.MeshPhongMaterial( { color } );
+
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 98 - 78
manual/examples/webxr-basic-w-background.html

@@ -35,98 +35,118 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const scene = new THREE.Scene();
+	{
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	}
 
-    return cube;
-  }
+	{
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  function render(time) {
-    time *= 0.001;
+	}
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+	function makeInstance( geometry, color, x ) {
 
-    renderer.render(scene, camera);
-  }
+		const material = new THREE.MeshPhongMaterial( { color } );
+
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 85 - 67
manual/examples/webxr-basic.html

@@ -35,86 +35,104 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	const scene = new THREE.Scene();
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	{
 
-    return cube;
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	function makeInstance( geometry, color, x ) {
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
+
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 109 - 95
manual/examples/webxr-look-to-select-selector.html

@@ -36,104 +36,118 @@
 import * as THREE from 'three';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-
-  const left = -2;    // Use values for left
-  const right = 2;    // right, top and bottom
-  const top = 1;      // that match the default
-  const bottom = -1;  // canvas size.
-  const near = -1;
-  const far = 1;
-  const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
-
-  function makeDataTexture(data, width, height) {
-    const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
-    texture.minFilter = THREE.NearestFilter;
-    texture.magFilter = THREE.NearestFilter;
-    texture.needsUpdate = true;
-    return texture;
-  }
-
-  const backgroundColors = new Uint8Array([
-      0,   0,   0, 255,  // black
-     90,  38,  38, 255,  // dark red
-    100, 175, 103, 255,  // medium green
-    255, 239, 151, 255,  // light yellow
-  ]);
-  const backgroundTexture = makeDataTexture(backgroundColors, 2, 2);
-  backgroundTexture.wrapS = THREE.RepeatWrapping;
-  backgroundTexture.wrapT = THREE.RepeatWrapping;
-  backgroundTexture.repeat.set(4, 4);
-
-  const scene = new THREE.Scene();
-  scene.background = backgroundTexture;
-
-  //const innerRadius = 0.4;
-  //const outerRadius = 0.5;
-  //const segments = 64;
-  //const cursorGeometry = new THREE.RingGeometry(
-  //    innerRadius, outerRadius, segments);
-
-  const ringRadius = 0.4;
-  const tubeRadius = 0.1;
-  const tubeSegments = 4;
-  const ringSegments = 64;
-  const cursorGeometry = new THREE.TorusGeometry(
-      ringRadius, tubeRadius, tubeSegments, ringSegments);
-
-  const cursorColors = new Uint8Array([
-    64, 64, 64, 64,       // dark gray
-    255, 255, 255, 255,   // white
-  ]);
-  const cursorTexture = makeDataTexture(cursorColors, 2, 1);
-
-  const cursorMaterial = new THREE.MeshBasicMaterial({
-    color: 'white',
-    map: cursorTexture,
-    transparent: true,
-    blending: THREE.CustomBlending,
-    blendSrc: THREE.OneMinusDstColorFactor,
-    blendDst: THREE.OneMinusSrcColorFactor,
-  });
-  const cursor = new THREE.Mesh(cursorGeometry, cursorMaterial);
-  scene.add(cursor);
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
 
-  function render(time) {
-    time *= 0.001;
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+
+	const left = - 2; // Use values for left
+	const right = 2; // right, top and bottom
+	const top = 1; // that match the default
+	const bottom = - 1; // canvas size.
+	const near = - 1;
+	const far = 1;
+	const camera = new THREE.OrthographicCamera( left, right, top, bottom, near, far );
+
+	function makeDataTexture( data, width, height ) {
+
+		const texture = new THREE.DataTexture( data, width, height, THREE.RGBAFormat );
+		texture.minFilter = THREE.NearestFilter;
+		texture.magFilter = THREE.NearestFilter;
+		texture.needsUpdate = true;
+		return texture;
+
+	}
+
+	const backgroundColors = new Uint8Array( [
+		0, 0, 0, 255, // black
+		90, 38, 38, 255, // dark red
+		100, 175, 103, 255, // medium green
+		255, 239, 151, 255, // light yellow
+	] );
+	const backgroundTexture = makeDataTexture( backgroundColors, 2, 2 );
+	backgroundTexture.wrapS = THREE.RepeatWrapping;
+	backgroundTexture.wrapT = THREE.RepeatWrapping;
+	backgroundTexture.repeat.set( 4, 4 );
+
+	const scene = new THREE.Scene();
+	scene.background = backgroundTexture;
+
+	//const innerRadius = 0.4;
+	//const outerRadius = 0.5;
+	//const segments = 64;
+	//const cursorGeometry = new THREE.RingGeometry(
+	//    innerRadius, outerRadius, segments);
+
+	const ringRadius = 0.4;
+	const tubeRadius = 0.1;
+	const tubeSegments = 4;
+	const ringSegments = 64;
+	const cursorGeometry = new THREE.TorusGeometry(
+		ringRadius, tubeRadius, tubeSegments, ringSegments );
+
+	const cursorColors = new Uint8Array( [
+		64, 64, 64, 64, // dark gray
+		255, 255, 255, 255, // white
+	] );
+	const cursorTexture = makeDataTexture( cursorColors, 2, 1 );
+
+	const cursorMaterial = new THREE.MeshBasicMaterial( {
+		color: 'white',
+		map: cursorTexture,
+		transparent: true,
+		blending: THREE.CustomBlending,
+		blendSrc: THREE.OneMinusDstColorFactor,
+		blendDst: THREE.OneMinusSrcColorFactor,
+	} );
+	const cursor = new THREE.Mesh( cursorGeometry, cursorMaterial );
+	scene.add( cursor );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			const aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.left = - aspect;
+			camera.right = aspect;
+			camera.updateProjectionMatrix();
+
+		}
+
+		const fromStart = 0;
+		const fromEnd = 2;
+		const toStart = - 0.5;
+		const toEnd = 0.5;
+		cursorTexture.offset.x = THREE.MathUtils.mapLinear(
+			time % 2,
+			fromStart, fromEnd,
+			toStart, toEnd );
+
+		renderer.render( scene, camera );
+
+	}
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      const aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.left = -aspect;
-      camera.right = aspect;
-      camera.updateProjectionMatrix();
-    }
-
-    const fromStart = 0;
-    const fromEnd = 2;
-    const toStart = -0.5;
-    const toEnd = 0.5;
-    cursorTexture.offset.x = THREE.MathUtils.mapLinear(
-        time % 2,
-        fromStart, fromEnd,
-        toStart, toEnd);
-
-    renderer.render(scene, camera);
-  }
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 238 - 196
manual/examples/webxr-look-to-select-w-cursor.html

@@ -35,221 +35,263 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  function makeDataTexture(data, width, height) {
-    const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
-    texture.minFilter = THREE.NearestFilter;
-    texture.magFilter = THREE.NearestFilter;
-    texture.needsUpdate = true;
-    return texture;
-  }
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const boxGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const scene = new THREE.Scene();
+	{
+
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
+
+	}
+
+	{
+
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
+
+	}
+
+	function makeDataTexture( data, width, height ) {
+
+		const texture = new THREE.DataTexture( data, width, height, THREE.RGBAFormat );
+		texture.minFilter = THREE.NearestFilter;
+		texture.magFilter = THREE.NearestFilter;
+		texture.needsUpdate = true;
+		return texture;
+
+	}
+
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const boxGeometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
+
+	const sphereRadius = 0.5;
+	const sphereGeometry = new THREE.SphereGeometry( sphereRadius );
+
+	function makeInstance( geometry, color, x ) {
+
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-  const sphereRadius = 0.5;
-  const sphereGeometry = new THREE.SphereGeometry(sphereRadius);
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+		return cube;
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+	}
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	const meshToMeshMap = new Map();
+	[
+		{ x: 0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
+		{ x: 2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
+		{ x: - 2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
+	].forEach( ( info ) => {
 
-    return cube;
-  }
+		const { x, boxColor, sphereColor } = info;
+		const sphere = makeInstance( sphereGeometry, sphereColor, x );
+		const box = makeInstance( boxGeometry, boxColor, x );
+		// hide the sphere
+		sphere.visible = false;
+		// map the sphere to the box
+		meshToMeshMap.set( box, sphere );
+		// map the box to the sphere
+		meshToMeshMap.set( sphere, box );
 
-  const meshToMeshMap = new Map();
-  [
-    { x:  0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
-    { x:  2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
-    { x: -2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
-  ].forEach((info) => {
-    const {x, boxColor, sphereColor} = info;
-    const sphere = makeInstance(sphereGeometry, sphereColor, x);
-    const box = makeInstance(boxGeometry, boxColor, x);
-    // hide the sphere
-    sphere.visible = false;
-    // map the sphere to the box
-    meshToMeshMap.set(box, sphere);
-    // map the box to the sphere
-    meshToMeshMap.set(sphere, box);
-  });
-
-  class PickHelper {
-    constructor(camera) {
-      this.raycaster = new THREE.Raycaster();
-      this.pickedObject = null;
-      this.pickedObjectSavedColor = 0;
-
-      const cursorColors = new Uint8Array([
-        64, 64, 64, 64,       // dark gray
-        255, 255, 255, 255,   // white
-      ]);
-      this.cursorTexture = makeDataTexture(cursorColors, 2, 1);
-
-      const ringRadius = 0.4;
-      const tubeRadius = 0.1;
-      const tubeSegments = 4;
-      const ringSegments = 64;
-      const cursorGeometry = new THREE.TorusGeometry(
-          ringRadius, tubeRadius, tubeSegments, ringSegments);
-
-      const cursorMaterial = new THREE.MeshBasicMaterial({
-        color: 'white',
-        map: this.cursorTexture,
-        transparent: true,
-        blending: THREE.CustomBlending,
-        blendSrc: THREE.OneMinusDstColorFactor,
-        blendDst: THREE.OneMinusSrcColorFactor,
-      });
-      const cursor = new THREE.Mesh(cursorGeometry, cursorMaterial);
-      camera.add(cursor);
-      cursor.position.z = -1;
-      const scale = 0.05;
-      cursor.scale.set(scale, scale, scale);
-      this.cursor = cursor;
-
-      this.selectTimer = 0;
-      this.selectDuration = 2;
-      this.lastTime = 0;
-    }
-    pick(normalizedPosition, scene, camera, time) {
-      const elapsedTime = time - this.lastTime;
-      this.lastTime = time;
-
-      const lastPickedObject = this.pickedObject;
-      // restore the color if there is a picked object
-      if (this.pickedObject) {
-        this.pickedObject = undefined;
-      }
-
-      // cast a ray through the frustum
-      this.raycaster.setFromCamera(normalizedPosition, camera);
-      // get the list of objects the ray intersected
-      const intersectedObjects = this.raycaster.intersectObjects(scene.children);
-      if (intersectedObjects.length) {
-        // pick the first object. It's the closest one
-        this.pickedObject = intersectedObjects[0].object;
-      }
-
-      // show or hide cursor
-      this.cursor.visible = this.pickedObject ? true : false;
-
-      let selected = false;
-
-      // if we're looking at the same object as before
-      // increment time select timer
-      if (this.pickedObject && lastPickedObject === this.pickedObject) {
-        this.selectTimer += elapsedTime;
-        if (this.selectTimer >= this.selectDuration) {
-          this.selectTimer = 0;
-          selected = true;
-        }
-      } else {
-        this.selectTimer = 0;
-      }
-
-      // set cursor material to show the timer state
-      const fromStart = 0;
-      const fromEnd = this.selectDuration;
-      const toStart = -0.5;
-      const toEnd = 0.5;
-      this.cursorTexture.offset.x = THREE.MathUtils.mapLinear(
-          this.selectTimer,
-          fromStart, fromEnd,
-          toStart, toEnd);
-
-      return selected ? this.pickedObject : undefined;
-    }
-  }
+	} );
 
-  const pickHelper = new PickHelper(camera);
-  scene.add(camera);
+	class PickHelper {
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+		constructor( camera ) {
 
-  function render(time) {
-    time *= 0.001;
+			this.raycaster = new THREE.Raycaster();
+			this.pickedObject = null;
+			this.pickedObjectSavedColor = 0;
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+			const cursorColors = new Uint8Array( [
+				64, 64, 64, 64, // dark gray
+				255, 255, 255, 255, // white
+			] );
+			this.cursorTexture = makeDataTexture( cursorColors, 2, 1 );
 
-    let ndx = 0;
-    for (const mesh of meshToMeshMap.keys()) {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      mesh.rotation.x = rot;
-      mesh.rotation.y = rot;
-      ++ndx;
-    }
+			const ringRadius = 0.4;
+			const tubeRadius = 0.1;
+			const tubeSegments = 4;
+			const ringSegments = 64;
+			const cursorGeometry = new THREE.TorusGeometry(
+				ringRadius, tubeRadius, tubeSegments, ringSegments );
 
-    // 0, 0 is the center of the view in normalized coordinates.
-    const selectedObject = pickHelper.pick({x: 0, y: 0}, scene, camera, time);
-    if (selectedObject) {
-      selectedObject.visible = false;
-      const partnerObject = meshToMeshMap.get(selectedObject);
-      partnerObject.visible = true;
-    }
+			const cursorMaterial = new THREE.MeshBasicMaterial( {
+				color: 'white',
+				map: this.cursorTexture,
+				transparent: true,
+				blending: THREE.CustomBlending,
+				blendSrc: THREE.OneMinusDstColorFactor,
+				blendDst: THREE.OneMinusSrcColorFactor,
+			} );
+			const cursor = new THREE.Mesh( cursorGeometry, cursorMaterial );
+			camera.add( cursor );
+			cursor.position.z = - 1;
+			const scale = 0.05;
+			cursor.scale.set( scale, scale, scale );
+			this.cursor = cursor;
 
-    renderer.render(scene, camera);
-  }
+			this.selectTimer = 0;
+			this.selectDuration = 2;
+			this.lastTime = 0;
+
+		}
+		pick( normalizedPosition, scene, camera, time ) {
+
+			const elapsedTime = time - this.lastTime;
+			this.lastTime = time;
+
+			const lastPickedObject = this.pickedObject;
+			// restore the color if there is a picked object
+			if ( this.pickedObject ) {
+
+				this.pickedObject = undefined;
+
+			}
+
+			// cast a ray through the frustum
+			this.raycaster.setFromCamera( normalizedPosition, camera );
+			// get the list of objects the ray intersected
+			const intersectedObjects = this.raycaster.intersectObjects( scene.children );
+			if ( intersectedObjects.length ) {
+
+				// pick the first object. It's the closest one
+				this.pickedObject = intersectedObjects[ 0 ].object;
+
+			}
+
+			// show or hide cursor
+			this.cursor.visible = this.pickedObject ? true : false;
+
+			let selected = false;
+
+			// if we're looking at the same object as before
+			// increment time select timer
+			if ( this.pickedObject && lastPickedObject === this.pickedObject ) {
+
+				this.selectTimer += elapsedTime;
+				if ( this.selectTimer >= this.selectDuration ) {
+
+					this.selectTimer = 0;
+					selected = true;
+
+				}
+
+			} else {
+
+				this.selectTimer = 0;
+
+			}
+
+			// set cursor material to show the timer state
+			const fromStart = 0;
+			const fromEnd = this.selectDuration;
+			const toStart = - 0.5;
+			const toEnd = 0.5;
+			this.cursorTexture.offset.x = THREE.MathUtils.mapLinear(
+				this.selectTimer,
+				fromStart, fromEnd,
+				toStart, toEnd );
+
+			return selected ? this.pickedObject : undefined;
+
+		}
+
+	}
+
+	const pickHelper = new PickHelper( camera );
+	scene.add( camera );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		let ndx = 0;
+		for ( const mesh of meshToMeshMap.keys() ) {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			mesh.rotation.x = rot;
+			mesh.rotation.y = rot;
+			++ ndx;
+
+		}
+
+		// 0, 0 is the center of the view in normalized coordinates.
+		const selectedObject = pickHelper.pick( { x: 0, y: 0 }, scene, camera, time );
+		if ( selectedObject ) {
+
+			selectedObject.visible = false;
+			const partnerObject = meshToMeshMap.get( selectedObject );
+			partnerObject.visible = true;
+
+		}
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 138 - 108
manual/examples/webxr-look-to-select.html

@@ -35,131 +35,161 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	const scene = new THREE.Scene();
+	{
 
-    const cube = new THREE.Mesh(geometry, material);
-    scene.add(cube);
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	}
 
-    return cube;
-  }
+	{
 
-  const cubes = [
-    makeInstance(geometry, 0x44aa88,  0),
-    makeInstance(geometry, 0x8844aa, -2),
-    makeInstance(geometry, 0xaa8844,  2),
-  ];
-
-  class PickHelper {
-    constructor() {
-      this.raycaster = new THREE.Raycaster();
-      this.pickedObject = null;
-      this.pickedObjectSavedColor = 0;
-    }
-    pick(normalizedPosition, scene, camera, time) {
-      // restore the color if there is a picked object
-      if (this.pickedObject) {
-        this.pickedObject.material.emissive.setHex(this.pickedObjectSavedColor);
-        this.pickedObject = undefined;
-      }
-
-      // cast a ray through the frustum
-      this.raycaster.setFromCamera(normalizedPosition, camera);
-      // get the list of objects the ray intersected
-      const intersectedObjects = this.raycaster.intersectObjects(scene.children);
-      if (intersectedObjects.length) {
-        // pick the first object. It's the closest one
-        this.pickedObject = intersectedObjects[0].object;
-        // save its color
-        this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex();
-        // set its emissive color to flashing red/yellow
-        this.pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFFFF00 : 0xFF0000);
-      }
-    }
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const pickHelper = new PickHelper();
+	}
 
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-  function render(time) {
-    time *= 0.001;
+	function makeInstance( geometry, color, x ) {
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    cubes.forEach((cube, ndx) => {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      cube.rotation.x = rot;
-      cube.rotation.y = rot;
-    });
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
 
-    // 0, 0 is the center of the view in normalized coordinates.
-    pickHelper.pick({x: 0, y: 0}, scene, camera, time);
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
 
-    renderer.render(scene, camera);
-  }
+		return cube;
+
+	}
+
+	const cubes = [
+		makeInstance( geometry, 0x44aa88, 0 ),
+		makeInstance( geometry, 0x8844aa, - 2 ),
+		makeInstance( geometry, 0xaa8844, 2 ),
+	];
+
+	class PickHelper {
+
+		constructor() {
+
+			this.raycaster = new THREE.Raycaster();
+			this.pickedObject = null;
+			this.pickedObjectSavedColor = 0;
+
+		}
+		pick( normalizedPosition, scene, camera, time ) {
+
+			// restore the color if there is a picked object
+			if ( this.pickedObject ) {
+
+				this.pickedObject.material.emissive.setHex( this.pickedObjectSavedColor );
+				this.pickedObject = undefined;
+
+			}
+
+			// cast a ray through the frustum
+			this.raycaster.setFromCamera( normalizedPosition, camera );
+			// get the list of objects the ray intersected
+			const intersectedObjects = this.raycaster.intersectObjects( scene.children );
+			if ( intersectedObjects.length ) {
+
+				// pick the first object. It's the closest one
+				this.pickedObject = intersectedObjects[ 0 ].object;
+				// save its color
+				this.pickedObjectSavedColor = this.pickedObject.material.emissive.getHex();
+				// set its emissive color to flashing red/yellow
+				this.pickedObject.material.emissive.setHex( ( time * 8 ) % 2 > 1 ? 0xFFFF00 : 0xFF0000 );
+
+			}
+
+		}
+
+	}
+
+	const pickHelper = new PickHelper();
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		cubes.forEach( ( cube, ndx ) => {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			cube.rotation.x = rot;
+			cube.rotation.y = rot;
+
+		} );
+
+		// 0, 0 is the center of the view in normalized coordinates.
+		pickHelper.pick( { x: 0, y: 0 }, scene, camera, time );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 257 - 201
manual/examples/webxr-point-to-select-w-move.html

@@ -35,224 +35,280 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-  // object to put pickable objects on so we can easily
-  // separate them from non-pickable objects
-  const pickRoot = new THREE.Object3D();
-  scene.add(pickRoot);
-
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const boxGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  const sphereRadius = 0.5;
-  const sphereGeometry = new THREE.SphereGeometry(sphereRadius);
+	const scene = new THREE.Scene();
+	// object to put pickable objects on so we can easily
+	// separate them from non-pickable objects
+	const pickRoot = new THREE.Object3D();
+	scene.add( pickRoot );
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	{
 
-    const cube = new THREE.Mesh(geometry, material);
-    pickRoot.add(cube);
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	}
 
-    return cube;
-  }
+	{
 
-  const meshToMeshMap = new Map();
-  [
-    { x:  0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
-    { x:  2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
-    { x: -2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
-  ].forEach((info) => {
-    const {x, boxColor, sphereColor} = info;
-    const sphere = makeInstance(sphereGeometry, sphereColor, x);
-    const box = makeInstance(boxGeometry, boxColor, x);
-    // hide the sphere
-    sphere.visible = false;
-    // map the sphere to the box
-    meshToMeshMap.set(box, sphere);
-    // map the box to the sphere
-    meshToMeshMap.set(sphere, box);
-  });
-
-  class ControllerPickHelper extends THREE.EventDispatcher {
-    constructor(scene) {
-      super();
-      this.raycaster = new THREE.Raycaster();
-      this.objectToColorMap = new Map();
-      this.controllerToObjectMap = new Map();
-      this.tempMatrix = new THREE.Matrix4();
-
-      const pointerGeometry = new THREE.BufferGeometry().setFromPoints([
-        new THREE.Vector3(0, 0, 0),
-        new THREE.Vector3(0, 0, -1),
-      ]);
-
-      this.controllers = [];
-
-      const selectListener = (event) => {
-        const controller = event.target;
-        const selectedObject = this.controllerToObjectMap.get(event.target);
-        if (selectedObject) {
-          this.dispatchEvent({type: event.type, controller, selectedObject});
-        }
-      };
-
-      const endListener = (event) => {
-        const controller = event.target;
-        this.dispatchEvent({type: event.type, controller});
-      };
-
-      for (let i = 0; i < 2; ++i) {
-        const controller = renderer.xr.getController(i);
-        controller.addEventListener('select', selectListener);
-        controller.addEventListener('selectstart', selectListener);
-        controller.addEventListener('selectend', endListener);
-        scene.add(controller);
-
-        const line = new THREE.Line(pointerGeometry);
-        line.scale.z = 5;
-        controller.add(line);
-        this.controllers.push({controller, line});
-      }
-    }
-    reset() {
-      // restore the colors
-      this.objectToColorMap.forEach((color, object) => {
-        object.material.emissive.setHex(color);
-      });
-      this.objectToColorMap.clear();
-      this.controllerToObjectMap.clear();
-    }
-    update(pickablesParent, time) {
-      this.reset();
-      for (const {controller, line} of this.controllers) {
-        // cast a ray through the from the controller
-        this.tempMatrix.identity().extractRotation(controller.matrixWorld);
-        this.raycaster.ray.origin.setFromMatrixPosition(controller.matrixWorld);
-        this.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(this.tempMatrix);
-        // get the list of objects the ray intersected
-        const intersections = this.raycaster.intersectObjects(pickablesParent.children);
-        if (intersections.length) {
-          const intersection = intersections[0];
-          // make the line touch the object
-          line.scale.z = intersection.distance;
-          // pick the first object. It's the closest one
-          const pickedObject = intersection.object;
-          // save which object this controller picked
-          this.controllerToObjectMap.set(controller, pickedObject);
-          // highlight the object if we haven't already
-          if (this.objectToColorMap.get(pickedObject) === undefined) {
-            // save its color
-            this.objectToColorMap.set(pickedObject, pickedObject.material.emissive.getHex());
-            // set its emissive color to flashing red/yellow
-            pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFF2000 : 0xFF0000);
-          }
-        } else {
-          line.scale.z = 5;
-        }
-      }
-    }
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const controllerToSelection = new Map();
-  const pickHelper = new ControllerPickHelper(scene);
-  pickHelper.addEventListener('selectstart', (event) => {
-    const {controller, selectedObject} = event;
-    const existingSelection = controllerToSelection.get(controller);
-    if (!existingSelection) {
-      controllerToSelection.set(controller, {
-        object: selectedObject,
-        parent: selectedObject.parent,
-      });
-      controller.attach(selectedObject);
-    }
-  });
-
-  pickHelper.addEventListener('selectend', (event) => {
-    const {controller} = event;
-    const selection = controllerToSelection.get(controller);
-    if (selection) {
-      controllerToSelection.delete(controller);
-      selection.parent.attach(selection.object);
-    }
-  });
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const boxGeometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const sphereRadius = 0.5;
+	const sphereGeometry = new THREE.SphereGeometry( sphereRadius );
 
-    let ndx = 0;
-    for (const mesh of meshToMeshMap.keys()) {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      mesh.rotation.x = rot;
-      mesh.rotation.y = rot;
-      ++ndx;
-    }
+	function makeInstance( geometry, color, x ) {
 
-    pickHelper.update(pickRoot, time);
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		pickRoot.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
+
+		return cube;
+
+	}
+
+	const meshToMeshMap = new Map();
+	[
+		{ x: 0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
+		{ x: 2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
+		{ x: - 2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
+	].forEach( ( info ) => {
+
+		const { x, boxColor, sphereColor } = info;
+		const sphere = makeInstance( sphereGeometry, sphereColor, x );
+		const box = makeInstance( boxGeometry, boxColor, x );
+		// hide the sphere
+		sphere.visible = false;
+		// map the sphere to the box
+		meshToMeshMap.set( box, sphere );
+		// map the box to the sphere
+		meshToMeshMap.set( sphere, box );
+
+	} );
+
+	class ControllerPickHelper extends THREE.EventDispatcher {
+
+		constructor( scene ) {
+
+			super();
+			this.raycaster = new THREE.Raycaster();
+			this.objectToColorMap = new Map();
+			this.controllerToObjectMap = new Map();
+			this.tempMatrix = new THREE.Matrix4();
+
+			const pointerGeometry = new THREE.BufferGeometry().setFromPoints( [
+				new THREE.Vector3( 0, 0, 0 ),
+				new THREE.Vector3( 0, 0, - 1 ),
+			] );
+
+			this.controllers = [];
+
+			const selectListener = ( event ) => {
+
+				const controller = event.target;
+				const selectedObject = this.controllerToObjectMap.get( event.target );
+				if ( selectedObject ) {
+
+					this.dispatchEvent( { type: event.type, controller, selectedObject } );
+
+				}
+
+			};
+
+			const endListener = ( event ) => {
+
+				const controller = event.target;
+				this.dispatchEvent( { type: event.type, controller } );
+
+			};
+
+			for ( let i = 0; i < 2; ++ i ) {
+
+				const controller = renderer.xr.getController( i );
+				controller.addEventListener( 'select', selectListener );
+				controller.addEventListener( 'selectstart', selectListener );
+				controller.addEventListener( 'selectend', endListener );
+				scene.add( controller );
+
+				const line = new THREE.Line( pointerGeometry );
+				line.scale.z = 5;
+				controller.add( line );
+				this.controllers.push( { controller, line } );
+
+			}
+
+		}
+		reset() {
+
+			// restore the colors
+			this.objectToColorMap.forEach( ( color, object ) => {
+
+				object.material.emissive.setHex( color );
+
+			} );
+			this.objectToColorMap.clear();
+			this.controllerToObjectMap.clear();
+
+		}
+		update( pickablesParent, time ) {
+
+			this.reset();
+			for ( const { controller, line } of this.controllers ) {
+
+				// cast a ray through the from the controller
+				this.tempMatrix.identity().extractRotation( controller.matrixWorld );
+				this.raycaster.ray.origin.setFromMatrixPosition( controller.matrixWorld );
+				this.raycaster.ray.direction.set( 0, 0, - 1 ).applyMatrix4( this.tempMatrix );
+				// get the list of objects the ray intersected
+				const intersections = this.raycaster.intersectObjects( pickablesParent.children );
+				if ( intersections.length ) {
+
+					const intersection = intersections[ 0 ];
+					// make the line touch the object
+					line.scale.z = intersection.distance;
+					// pick the first object. It's the closest one
+					const pickedObject = intersection.object;
+					// save which object this controller picked
+					this.controllerToObjectMap.set( controller, pickedObject );
+					// highlight the object if we haven't already
+					if ( this.objectToColorMap.get( pickedObject ) === undefined ) {
+
+						// save its color
+						this.objectToColorMap.set( pickedObject, pickedObject.material.emissive.getHex() );
+						// set its emissive color to flashing red/yellow
+						pickedObject.material.emissive.setHex( ( time * 8 ) % 2 > 1 ? 0xFF2000 : 0xFF0000 );
+
+					}
+
+				} else {
+
+					line.scale.z = 5;
+
+				}
+
+			}
+
+		}
+
+	}
+
+	const controllerToSelection = new Map();
+	const pickHelper = new ControllerPickHelper( scene );
+	pickHelper.addEventListener( 'selectstart', ( event ) => {
+
+		const { controller, selectedObject } = event;
+		const existingSelection = controllerToSelection.get( controller );
+		if ( ! existingSelection ) {
+
+			controllerToSelection.set( controller, {
+				object: selectedObject,
+				parent: selectedObject.parent,
+			} );
+			controller.attach( selectedObject );
+
+		}
+
+	} );
+
+	pickHelper.addEventListener( 'selectend', ( event ) => {
+
+		const { controller } = event;
+		const selection = controllerToSelection.get( controller );
+		if ( selection ) {
+
+			controllerToSelection.delete( controller );
+			selection.parent.attach( selection.object );
+
+		}
+
+	} );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		let ndx = 0;
+		for ( const mesh of meshToMeshMap.keys() ) {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			mesh.rotation.x = rot;
+			mesh.rotation.y = rot;
+			++ ndx;
+
+		}
+
+		pickHelper.update( pickRoot, time );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 223 - 175
manual/examples/webxr-point-to-select.html

@@ -35,198 +35,246 @@
 
 <script type="module">
 import * as THREE from 'three';
-import {VRButton} from 'three/addons/webxr/VRButton.js';
+import { VRButton } from 'three/addons/webxr/VRButton.js';
 
 function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
-  renderer.xr.enabled = true;
-  document.body.appendChild(VRButton.createButton(renderer));
-
-  const fov = 75;
-  const aspect = 2;  // the canvas default
-  const near = 0.1;
-  const far = 50;
-  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
-  camera.position.set(0, 1.6, 0);
-
-  const scene = new THREE.Scene();
-  // object to put pickable objects on so we can easily
-  // separate them from non-pickable objects
-  const pickRoot = new THREE.Object3D();
-  scene.add(pickRoot);
-
-  {
-    const loader = new THREE.CubeTextureLoader();
-    const texture = loader.load([
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-      'resources/images/grid-1024.png',
-    ]);
-    scene.background = texture;
-  }
 
-  {
-    const color = 0xFFFFFF;
-    const intensity = 1;
-    const light = new THREE.DirectionalLight(color, intensity);
-    light.position.set(-1, 2, 4);
-    scene.add(light);
-  }
+	const canvas = document.querySelector( '#c' );
+	const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
+	renderer.useLegacyLights = false;
+	renderer.xr.enabled = true;
+	document.body.appendChild( VRButton.createButton( renderer ) );
 
-  const boxWidth = 1;
-  const boxHeight = 1;
-  const boxDepth = 1;
-  const boxGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+	const fov = 75;
+	const aspect = 2; // the canvas default
+	const near = 0.1;
+	const far = 50;
+	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
+	camera.position.set( 0, 1.6, 0 );
 
-  const sphereRadius = 0.5;
-  const sphereGeometry = new THREE.SphereGeometry(sphereRadius);
+	const scene = new THREE.Scene();
+	// object to put pickable objects on so we can easily
+	// separate them from non-pickable objects
+	const pickRoot = new THREE.Object3D();
+	scene.add( pickRoot );
 
-  function makeInstance(geometry, color, x) {
-    const material = new THREE.MeshPhongMaterial({color});
+	{
 
-    const cube = new THREE.Mesh(geometry, material);
-    pickRoot.add(cube);
+		const loader = new THREE.CubeTextureLoader();
+		const texture = loader.load( [
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+			'resources/images/grid-1024.png',
+		] );
+		scene.background = texture;
 
-    cube.position.x = x;
-    cube.position.y = 1.6;
-    cube.position.z = -2;
+	}
 
-    return cube;
-  }
+	{
 
-  const meshToMeshMap = new Map();
-  [
-    { x:  0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
-    { x:  2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
-    { x: -2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
-  ].forEach((info) => {
-    const {x, boxColor, sphereColor} = info;
-    const sphere = makeInstance(sphereGeometry, sphereColor, x);
-    const box = makeInstance(boxGeometry, boxColor, x);
-    // hide the sphere
-    sphere.visible = false;
-    // map the sphere to the box
-    meshToMeshMap.set(box, sphere);
-    // map the box to the sphere
-    meshToMeshMap.set(sphere, box);
-  });
-
-  class ControllerPickHelper extends THREE.EventDispatcher {
-    constructor(scene) {
-      super();
-      this.raycaster = new THREE.Raycaster();
-      this.objectToColorMap = new Map();
-      this.controllerToObjectMap = new Map();
-      this.tempMatrix = new THREE.Matrix4();
-
-      const pointerGeometry = new THREE.BufferGeometry().setFromPoints([
-        new THREE.Vector3(0, 0, 0),
-        new THREE.Vector3(0, 0, -1),
-      ]);
-
-      this.controllers = [];
-      for (let i = 0; i < 2; ++i) {
-        const controller = renderer.xr.getController(i);
-        controller.addEventListener('select', (event) => {
-          const controller = event.target;
-          const selectedObject = this.controllerToObjectMap.get(controller);
-          if (selectedObject) {
-            this.dispatchEvent({type: 'select', controller, selectedObject});
-          }
-        });
-        scene.add(controller);
-
-        const line = new THREE.Line(pointerGeometry);
-        line.scale.z = 5;
-        controller.add(line);
-        this.controllers.push({controller, line});
-      }
-    }
-    reset() {
-      // restore the colors
-      this.objectToColorMap.forEach((color, object) => {
-        object.material.emissive.setHex(color);
-      });
-      this.objectToColorMap.clear();
-      this.controllerToObjectMap.clear();
-    }
-    update(pickablesParent, time) {
-      this.reset();
-      for (const {controller, line} of this.controllers) {
-        // cast a ray through the from the controller
-        this.tempMatrix.identity().extractRotation(controller.matrixWorld);
-        this.raycaster.ray.origin.setFromMatrixPosition(controller.matrixWorld);
-        this.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(this.tempMatrix);
-        // get the list of objects the ray intersected
-        const intersections = this.raycaster.intersectObjects(pickablesParent.children);
-        if (intersections.length) {
-          const intersection = intersections[0];
-          // make the line touch the object
-          line.scale.z = intersection.distance;
-          // pick the first object. It's the closest one
-          const pickedObject = intersection.object;
-          // save which object this controller picked
-          this.controllerToObjectMap.set(controller, pickedObject);
-          // highlight the object if we haven't already
-          if (this.objectToColorMap.get(pickedObject) === undefined) {
-            // save its color
-            this.objectToColorMap.set(pickedObject, pickedObject.material.emissive.getHex());
-            // set its emissive color to flashing red/yellow
-            pickedObject.material.emissive.setHex((time * 8) % 2 > 1 ? 0xFF2000 : 0xFF0000);
-          }
-        } else {
-          line.scale.z = 5;
-        }
-      }
-    }
-  }
+		const color = 0xFFFFFF;
+		const intensity = 3;
+		const light = new THREE.DirectionalLight( color, intensity );
+		light.position.set( - 1, 2, 4 );
+		scene.add( light );
 
-  const pickHelper = new ControllerPickHelper(scene);
-  pickHelper.addEventListener('select', (event) => {
-    event.selectedObject.visible = false;
-    const partnerObject = meshToMeshMap.get(event.selectedObject);
-    partnerObject.visible = true;
-  });
-
-  function resizeRendererToDisplaySize(renderer) {
-    const canvas = renderer.domElement;
-    const width = canvas.clientWidth;
-    const height = canvas.clientHeight;
-    const needResize = canvas.width !== width || canvas.height !== height;
-    if (needResize) {
-      renderer.setSize(width, height, false);
-    }
-    return needResize;
-  }
+	}
 
-  function render(time) {
-    time *= 0.001;
+	const boxWidth = 1;
+	const boxHeight = 1;
+	const boxDepth = 1;
+	const boxGeometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
 
-    if (resizeRendererToDisplaySize(renderer)) {
-      const canvas = renderer.domElement;
-      camera.aspect = canvas.clientWidth / canvas.clientHeight;
-      camera.updateProjectionMatrix();
-    }
+	const sphereRadius = 0.5;
+	const sphereGeometry = new THREE.SphereGeometry( sphereRadius );
 
-    let ndx = 0;
-    for (const mesh of meshToMeshMap.keys()) {
-      const speed = 1 + ndx * .1;
-      const rot = time * speed;
-      mesh.rotation.x = rot;
-      mesh.rotation.y = rot;
-      ++ndx;
-    }
+	function makeInstance( geometry, color, x ) {
 
-    pickHelper.update(pickRoot, time);
+		const material = new THREE.MeshPhongMaterial( { color } );
 
-    renderer.render(scene, camera);
-  }
+		const cube = new THREE.Mesh( geometry, material );
+		pickRoot.add( cube );
+
+		cube.position.x = x;
+		cube.position.y = 1.6;
+		cube.position.z = - 2;
+
+		return cube;
+
+	}
+
+	const meshToMeshMap = new Map();
+	[
+		{ x: 0, boxColor: 0x44aa88, sphereColor: 0xFF4444, },
+		{ x: 2, boxColor: 0x8844aa, sphereColor: 0x44FF44, },
+		{ x: - 2, boxColor: 0xaa8844, sphereColor: 0x4444FF, },
+	].forEach( ( info ) => {
+
+		const { x, boxColor, sphereColor } = info;
+		const sphere = makeInstance( sphereGeometry, sphereColor, x );
+		const box = makeInstance( boxGeometry, boxColor, x );
+		// hide the sphere
+		sphere.visible = false;
+		// map the sphere to the box
+		meshToMeshMap.set( box, sphere );
+		// map the box to the sphere
+		meshToMeshMap.set( sphere, box );
+
+	} );
+
+	class ControllerPickHelper extends THREE.EventDispatcher {
+
+		constructor( scene ) {
+
+			super();
+			this.raycaster = new THREE.Raycaster();
+			this.objectToColorMap = new Map();
+			this.controllerToObjectMap = new Map();
+			this.tempMatrix = new THREE.Matrix4();
+
+			const pointerGeometry = new THREE.BufferGeometry().setFromPoints( [
+				new THREE.Vector3( 0, 0, 0 ),
+				new THREE.Vector3( 0, 0, - 1 ),
+			] );
+
+			this.controllers = [];
+			for ( let i = 0; i < 2; ++ i ) {
+
+				const controller = renderer.xr.getController( i );
+				controller.addEventListener( 'select', ( event ) => {
+
+					const controller = event.target;
+					const selectedObject = this.controllerToObjectMap.get( controller );
+					if ( selectedObject ) {
+
+						this.dispatchEvent( { type: 'select', controller, selectedObject } );
+
+					}
+
+				} );
+				scene.add( controller );
+
+				const line = new THREE.Line( pointerGeometry );
+				line.scale.z = 5;
+				controller.add( line );
+				this.controllers.push( { controller, line } );
+
+			}
+
+		}
+		reset() {
+
+			// restore the colors
+			this.objectToColorMap.forEach( ( color, object ) => {
+
+				object.material.emissive.setHex( color );
+
+			} );
+			this.objectToColorMap.clear();
+			this.controllerToObjectMap.clear();
+
+		}
+		update( pickablesParent, time ) {
+
+			this.reset();
+			for ( const { controller, line } of this.controllers ) {
+
+				// cast a ray through the from the controller
+				this.tempMatrix.identity().extractRotation( controller.matrixWorld );
+				this.raycaster.ray.origin.setFromMatrixPosition( controller.matrixWorld );
+				this.raycaster.ray.direction.set( 0, 0, - 1 ).applyMatrix4( this.tempMatrix );
+				// get the list of objects the ray intersected
+				const intersections = this.raycaster.intersectObjects( pickablesParent.children );
+				if ( intersections.length ) {
+
+					const intersection = intersections[ 0 ];
+					// make the line touch the object
+					line.scale.z = intersection.distance;
+					// pick the first object. It's the closest one
+					const pickedObject = intersection.object;
+					// save which object this controller picked
+					this.controllerToObjectMap.set( controller, pickedObject );
+					// highlight the object if we haven't already
+					if ( this.objectToColorMap.get( pickedObject ) === undefined ) {
+
+						// save its color
+						this.objectToColorMap.set( pickedObject, pickedObject.material.emissive.getHex() );
+						// set its emissive color to flashing red/yellow
+						pickedObject.material.emissive.setHex( ( time * 8 ) % 2 > 1 ? 0xFF2000 : 0xFF0000 );
+
+					}
+
+				} else {
+
+					line.scale.z = 5;
+
+				}
+
+			}
+
+		}
+
+	}
+
+	const pickHelper = new ControllerPickHelper( scene );
+	pickHelper.addEventListener( 'select', ( event ) => {
+
+		event.selectedObject.visible = false;
+		const partnerObject = meshToMeshMap.get( event.selectedObject );
+		partnerObject.visible = true;
+
+	} );
+
+	function resizeRendererToDisplaySize( renderer ) {
+
+		const canvas = renderer.domElement;
+		const width = canvas.clientWidth;
+		const height = canvas.clientHeight;
+		const needResize = canvas.width !== width || canvas.height !== height;
+		if ( needResize ) {
+
+			renderer.setSize( width, height, false );
+
+		}
+
+		return needResize;
+
+	}
+
+	function render( time ) {
+
+		time *= 0.001;
+
+		if ( resizeRendererToDisplaySize( renderer ) ) {
+
+			const canvas = renderer.domElement;
+			camera.aspect = canvas.clientWidth / canvas.clientHeight;
+			camera.updateProjectionMatrix();
+
+		}
+
+		let ndx = 0;
+		for ( const mesh of meshToMeshMap.keys() ) {
+
+			const speed = 1 + ndx * .1;
+			const rot = time * speed;
+			mesh.rotation.x = rot;
+			mesh.rotation.y = rot;
+			++ ndx;
+
+		}
+
+		pickHelper.update( pickRoot, time );
+
+		renderer.render( scene, camera );
+
+	}
+
+	renderer.setAnimationLoop( render );
 
-  renderer.setAnimationLoop(render);
 }
 
 main();

+ 1 - 0
manual/ko/voxel-geometry.html

@@ -644,6 +644,7 @@ scene.add(mesh);
 const texture = loader.load('resources/images/minecraft/flourish-cc-by-nc-sa.png', render);
 texture.magFilter = THREE.NearestFilter;
 texture.minFilter = THREE.NearestFilter;
+texture.colorSpace = THREE.SRGBColorSpace;
 </pre>
 <p>그리고 <code class="notranslate" translate="no">VoxelWorld</code>에 설정값을 넘겨줍니다.</p>
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const tileSize = 16;