TypeScript

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>

CSS

html, body {
  margin: 0;
  overflow: hidden;
  width: 100%;
  height: 100%;
  position: relative;
}
.canvasWebGL {
  position: absolute;
  top: 0%;
  width: 100%;
  height: 100%;
}
.canvas2D {
  position: absolute;
  top: 50%;
  width: 100%;
  height: 100%;
}

JavaScript

var camera, scene, renderer, vp, stats, sphere, normalsMat;

// WebGL boilerplate
function init() {
	// WebGL Renderer
	vp = new THREE.Vector2(window.innerWidth, window.innerHeight);
	renderer = new THREE.WebGLRenderer({antialias: true});
	renderer.setSize(vp.x, vp.y);
	renderer.domElement.classList.add("canvasWebGL");

	// scene
	scene = new THREE.Scene();
	scene.background = new THREE.Color(0xe1e1e1);

	// camera
	camera = new THREE.PerspectiveCamera(30, vp.x / vp.y, 0.05, 150);
  camera.position.z = 10;
  
  // stats
  stats = new Stats();
	
  // Normals material
  normalsMat = new THREE.MeshNormalMaterial();
  
  // Modify color so only Z-normal is visible    
  normalsMat.onBeforeCompile = function( shader ) {
    var newFrag = shader.fragmentShader.replace(
        'gl_FragColor = vec4( packNormalToRGB( normal ), opacity );', // Replace this line...
        'gl_FragColor = vec4(0.0, 0.0, normal.z, opacity );'          // ... with this line
        //'gl_FragColor = vec4(normal.x, 0.0, 0.0, opacity );'          // ... or this one for X-value
    );
    
    shader.fragmentShader = newFrag;
  }
  
	// sphere
	sphere = new THREE.Mesh(
		new THREE.SphereBufferGeometry( 1, 64, 64 ),
		normalsMat
	);
	scene.add(sphere);
  
  const helper = new THREE.AxesHelper(3);
  sphere.add(helper)
  
  // append all to DOM
	document.body.appendChild(renderer.domElement);
  document.body.appendChild(stats.domElement);
  
  window.addEventListener("resize", () => {
  	vp.set(window.innerWidth, window.innerHeight);
    renderer.setSize(vp.x, vp.y);
    camera.aspect = vp.x / vp.y;
    camera.updateProjectionMatrix();
  });
}

function animate(s) {
	sphere.position.set(
  	Math.cos(s / 2000) * 2,
  	Math.sin(s / 1000) * 2.5,
    0
  );
  
  // Render scene to canvas
  renderer.render(scene, camera);
  stats.update();
	requestAnimationFrame(animate);
}

init();
animate(0);