<body style="
    margin-left: 0px;
    margin-top: 0px;
    margin-right: 0px;
    margin-bottom: 0px;
">
$white: #FFFFFF
$black: #000000

body 
  color: $black:
  margin: 0
  text-align: center
  background-color: black

canvas 
  display: block
  width: 100%
  height: 100%

p 
  color: rgba(255,255,255, 0.5)

.header 
  top: 50%
  transform: translatey(-50%)

a, a:hover, a:visited 
  color: $white
  text-decoration: none

h1 
  &:after 
    content: ' ThreeJS'
    font-size: 0.6rem
    position: relative
    top: -1rem
// Three JS
window.addEventListener('load', init, false);
function init() {
  createWorld();
  createLights();
  //createGrid();
  createPrimitive();
  createSky();
  //---
  animation();
}

var Theme = {
  primary: 0x000000,
  secundary: 0x00FF00,
  danger: 0x00FF00,
  darker: 0x00FF00
};

//--------------------------------------------------------------------
var scene, camera, renderer, container;
var _width, _height;
var controls, sky;
var _group = new THREE.Group();

function createWorld() {
  _width = window.innerWidth;
  _height= window.innerHeight;
  //---
  scene = new THREE.Scene();
  scene.fog = new THREE.Fog(Theme.primary, 9, 13);
  scene.background = new THREE.Color(Theme.primary);
  //---
  camera = new THREE.PerspectiveCamera(35, _width/_height, 1, 1000);
  camera.position.set(0,0,10);
  //---
  renderer = new THREE.WebGLRenderer({antialias:true, alpha:false});
  renderer.setSize(_width, _height);
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFShadowMap;
  //---
  controls = new THREE.OrbitControls( camera, renderer.domElement );
  controls.enableZoom = false;
  controls.update();
  //---
  //document.body.appendChild( WEBVR.createButton( renderer ) );
  document.body.appendChild(renderer.domElement);
  //---
  window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
  _width = window.innerWidth;
  _height = window.innerHeight;
  renderer.setSize(_width, _height);
  camera.aspect = _width / _height;
  camera.updateProjectionMatrix();
  console.log('- resize -');
}
//--------------------------------------------------------------------
var _ambientLights, _lights;
function createLights() {
  //_ambientLights = new THREE.AmbientLight(0xFFFFFF, 1);
  _ambientLights = new THREE.HemisphereLight(Theme.primary, Theme.darker, 1);
  _lights = new THREE.SpotLight(Theme.danger, 1, 200);
  _lights.castShadow = true;
  _lights.shadow.mapSize.width = 5000;
  _lights.shadow.mapSize.height = _lights.shadow.mapSize.width;
  _lights.penumbra = 0.8;
  _lights.position.set(10,20,20);
  scene.add(_lights);
  scene.add(_ambientLights);
}
//--------------------------------------------------------------------

function createSky() {
  //sky = new THREE.Sky();
  /*sky.scale.setScalar( 450000 );
  sky.material.uniforms.turbidity.value = 20;
  sky.material.uniforms.rayleigh.value = 0;
  sky.material.uniforms.luminance.value = 1;
  sky.material.uniforms.mieCoefficient.value = 0.01;
  sky.material.uniforms.mieDirectionalG.value = 0.8;

  scene.add( sky );

  sunSphere = new THREE.Mesh(
    new THREE.SphereBufferGeometry( 20000, 16, 8 ),
    new THREE.MeshBasicMaterial( { color: 0xffffff } )
  );
  sunSphere.visible = false;
  scene.add( sunSphere );

  var theta = Math.PI * ( -0.02 );
  var phi = 2 * Math.PI * ( -.25 );

  sunSphere.position.x = 400000 * Math.cos( phi );
  sunSphere.position.y = 400000 * Math.sin( phi ) * Math.sin( theta );
  sunSphere.position.z = 400000 * Math.sin( phi ) * Math.cos( theta );

  sky.material.uniforms.sunPosition.value.copy( sunSphere.position );*/
}

//--------------------------------------------------------------------
var _lomosize = 0.3;
var CreateBook = function() {
  this.mesh = new THREE.Object3D();
  var geo_cover = new THREE.CubeGeometry(2.4,3,0.05);
  var lmo_cover = new THREE.CubeGeometry(0.05,3,0.59);
  var ppr_cover = new THREE.CubeGeometry(2.3,2.8,2 / 4);
  var ppr_label = new THREE.CubeGeometry(0.05,0.6,0.6);
  var cr1_metal = new THREE.CubeGeometry(0.8,0.1,0.1);
  var cr2_metal = new THREE.CubeGeometry(0.1,1.2,0.1);
  //---
  var mat = new THREE.MeshPhongMaterial({color:Theme.darker});
  var mat_paper = new THREE.MeshPhongMaterial({color:Theme.primary});
  var mat_label = new THREE.MeshPhongMaterial({color:Theme.primary});
  
  var _cover1 = new THREE.Mesh(geo_cover, mat);
  var _cover2 = new THREE.Mesh(geo_cover, mat);
  var _lomo = new THREE.Mesh(lmo_cover, mat);
  var _paper = new THREE.Mesh(ppr_cover, mat_paper);
  var _label = new THREE.Mesh(ppr_label, mat_label);
  var _cross1 = new THREE.Mesh(cr1_metal, mat_label);
  var _cross2 = new THREE.Mesh(cr2_metal, mat_label);
  
  _cover1.castShadow = true;
  _cover2.castShadow = true;
  _lomo.castShadow = true;
  _paper.castShadow = true;
  _label.castShadow = true;
  _cross1.castShadow = true;
  _cross2.castShadow = true;
  
  _cover1.receiveShadow = true;
  _cover2.receiveShadow = true;
  _lomo.receiveShadow = true;
  _paper.receiveShadow = true;
  _label.receiveShadow = true;
  _cross1.receiveShadow = true;
  _cross2.receiveShadow = true;
  //---
  _cover1.position.z = _lomosize;
  _cover2.position.z = -_lomosize;
  _cross1.position.z = -_lomosize;
  _cross1.position.y = _lomosize;
  _cross2.position.z = -_lomosize;
  _lomo.position.x = 2.4 / 2;
  _label.position.x = 2.4 / 1.95;
  _label.position.y = -1;
  //---
  this.mesh.add(_cover1);
  this.mesh.add(_cover2);
  this.mesh.add(_lomo);
  this.mesh.add(_paper);
  this.mesh.add(_label);
  //this.mesh.add(_cross1);
 // this.mesh.add(_cross2);
  //---
}

function createPrimitive() {
  var a = 3;
  for (var i = 0; i<20; i++) {
    var _object = new CreateBook();
    
    var s = 0.1 + Math.random() * 0.5;
    _object.mesh.scale.set(s,s,s);
    
    _object.mesh.position.x = -Math.random() * a + Math.random() * a;
    _object.mesh.position.y = -Math.random() * a + Math.random() * a;
    _object.mesh.position.z = -Math.random() * a + Math.random() * a;
    
    _object.mesh.rotation.x = Math.random() * 360 * Math.PI / 180;
    _object.mesh.rotation.y = Math.random() * 360 * Math.PI / 180;
    _object.mesh.rotation.z = Math.random() * 360 * Math.PI / 180;
    
    TweenMax.to(_object.mesh.rotation, 3, {x:(Math.random()*180) * Math.PI / 180, y:(Math.random()*180) * Math.PI / 180, z:(Math.random()*180) * Math.PI / 180, yoyo:true, repeat:-1, ease:Circ.easeInOut, delay: 0.05 * i});
    
    _group.add(_object.mesh);
  }
  
  scene.add(_group);
}

function createGrid() {
  var gridHelper = new THREE.GridHelper(20, 20);
  gridHelper.position.y = -1;
  scene.add(gridHelper);
}
//--------------------------------------------------------------------
function animation() {
  _group.rotation.x -= 0.003;
  _group.rotation.y -= 0.003;
  _group.rotation.z -= 0.003;
  //---
  controls.update();
  requestAnimationFrame(animation);
  //renderer.render( scene, camera );
  renderer.render(scene, camera);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js
  3. https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js
  4. //cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js
  5. https://unpkg.com/three@0.84.0/examples/js/controls/OrbitControls.js
  6. https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js