<script src="https://threejs.org/build/three.js"></script>

<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

<div id="container">
  <!-- This div will hold our scene-->
</div>

body {
  background-color: #000;
  margin: 0px;
  overflow: hidden;
  color: white;
  text-align: center;
}

a {
  color: white;
}
a:hover{
  color: red;
}

#container {
  position: absolute;
  top: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}
// these need to be accessed inside more than one function so we'll declare them first
let container;
let camera;
let renderer;
let scene;
let silhouette;
let clippingPlane;
const planePosition = new THREE.Vector3( 0, 0, 1 );

function init() {

  container = document.querySelector( '#container' );

  initScene();
  initCamera();
  initControls();
  initLights();
  initSilhouettes();
  initRenderer();

  start();

}

function initScene() {

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

}

function initCamera() {

  camera = new THREE.PerspectiveCamera(
    35,
    container.clientWidth / container.clientHeight, 
    0.1, 
    100, 
  );

  camera.position.set( -5, 5, 10 );
  camera.lookAt( new THREE.Vector3() );
  
  new THREE.OrbitControls( camera, container )

}

function initControls() {

  // controls = new THREE.OrbitControls( camera, container );

}

function initLights() {

  const ambientLight = new THREE.AmbientLight( 0xffffff, 1.0 );
  scene.add( ambientLight );

  const mainLight = new THREE.DirectionalLight( 0xffffff, 0.75 );

  camera.add( mainLight );
  scene.add( camera );
}


function initSilhouettes() {
  
  clippingPlane = new THREE.Plane( new THREE.Vector3( 0, 0, 1 ), 0 );
  
  const helper = new THREE.PlaneHelper( clippingPlane, 10, 0x0000ff );
  scene.add( helper );

  const boxgeo = new THREE.BoxBufferGeometry( 2, 2, 2 );
  const mainMaterial = new THREE.MeshStandardMaterial( { 
    color: "silver", 
    clippingPlanes: [ clippingPlane ],
    onBeforeCompile: shader => {
      console.log(shader.fragmentShader);
      shader.fragmentShader = shader.fragmentShader
        .replace(`#include <clipping_planes_fragment>`,``)
        .replace(
        `#include <color_fragment>`,
        `#include <color_fragment>
          float fe = fwidth(length(vClipPosition)) * 0.5;
          vec4 plane = clippingPlanes[ 0 ];
          float pDot = dot( vClipPosition, plane.xyz );
          diffuseColor.rgb = mix(diffuseColor.rgb, vec3(0, 0.25, 1), smoothstep(pDot + fe, pDot - fe, plane.w));
        `
      );
    }
  } );
  mainMaterial.extensions = {derivatives: true}

  const mainMesh = new THREE.Mesh( boxgeo, mainMaterial );
  
  silhouette = new THREE.Group();
  silhouette.add( mainMesh );
  scene.add( silhouette );

}

function initRenderer() {

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setSize( container.clientWidth, container.clientHeight );
  
  renderer.setPixelRatio( window.devicePixelRatio );

  container.appendChild( renderer.domElement );
  
  renderer.localClippingEnabled = true;

}

function start() {

  renderer.setAnimationLoop( () => {

    update();
    render();

  } );

}

function stop() {

  renderer.setAnimationLoop( null );

}


function update() {
  
  silhouette.rotation.x += 0.005;
  silhouette.rotation.y += 0.005;
  silhouette.rotation.z += 0.005;
  
}

function render() {

  renderer.render( scene, camera );

}

function onWindowResize() {

  camera.aspect = container.clientWidth / container.clientHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( container.clientWidth, container.clientHeight );

}

window.addEventListener( 'resize', onWindowResize );

init();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.