diff --git a/src/index.html b/src/index.html
index d02e512a776d06df273422fceecb580868173185..b147d3469d021a7db33dbb16e03e74eca56c1bd1 100644
--- a/src/index.html
+++ b/src/index.html
@@ -5,6 +5,45 @@
 <link rel="stylesheet" href="lib/css/bootstrap.min.css">
 <link rel="stylesheet" href="index.css">
 <link rel="stylesheet" href="index-mobile.css">
+<script id="vertex-shader-shadow-map" type="x-shader/x-vertex">
+  precision mediump float;
+
+  uniform mat4 mProj;
+  uniform mat4 mView;
+  uniform mat4 mWorld;
+
+  attribute vec4 vPos;
+
+  varying vec3 fPos;
+
+  void main()
+  {
+    fPos = (mWorld * vPos).xyz;
+
+    gl_Position = mProj * mView * vec4(fPos, 1.0);
+  }
+</script>
+<script id="fragment-shader-shadow-map" type="x-shader/x-fragment">
+  precision mediump float;
+
+  uniform vec3 pointLightPosition;
+  uniform vec2 shadowClipNearFar;
+
+  varying vec3 fPos;
+
+  void main()
+  {
+    vec3 fromLightToFrag = (fPos - pointLightPosition);
+
+    float lightFragDist =
+      (length(fromLightToFrag) - shadowClipNearFar.x)
+      /
+      (shadowClipNearFar.y - shadowClipNearFar.x);
+
+    gl_FragColor = vec4(lightFragDist, lightFragDist, lightFragDist, 1.0);
+  }
+</script>
+
 <script id="vertex-shader" type="x-shader/x-vertex">
 attribute vec4 vPosition;
 attribute vec3 vNormal;
@@ -97,9 +136,6 @@ void main()
 }
 </script>
 
-
-
-
 <script  id="vertex-shader-3d" type="x-shader/x-vertex">
   attribute vec4 vPosition;
   attribute vec2 a_texcoord;
diff --git a/src/modules/brand-new-class.js b/src/modules/brand-new-class.js
index 705d2bbb71db49fcc76cdcba393c87a411e72efc..9f62f0121821e8368ae4607992f5925ee4719dc0 100644
--- a/src/modules/brand-new-class.js
+++ b/src/modules/brand-new-class.js
@@ -65,7 +65,6 @@ class Geometry {
       return
     }
 
-    console.log('update buffers')
 
     let gl = renderer.gl
     let attributes = renderer.attribs
@@ -94,7 +93,7 @@ class Geometry {
     gl.vertexAttribPointer(attributes.vNormal, 4, gl.FLOAT, false, 0, 0)
     gl.enableVertexAttribArray(attributes.vNormal)
 
-    Geometry.bufferDataNeedsUpdate = false
+    Geometry.bufferDataNeedsUpdate = true
   }
 
   /**
@@ -950,12 +949,37 @@ class Light extends Object3D {
 }
 
 
+var Camera = function (position, lookAt, up) {
+	this.forward = vec3();
+	this.up = vec3();
+	this.right = vec3();
+
+	this.position = position;
+
+	this.forward = subtract(lookAt, this.position);
+	this.right = cross(this.forward, up);
+	this.up = cross(this.right, this.forward);
+
+	this.forward =  normalize(this.forward);
+	this.right =  normalize(this.right);
+	this.up =  normalize(this.up);
+};
+
+Camera.prototype.GetViewMatrix = function (out) {
+	var lookAtVec = vec3();
+	lookAtVec = add(this.position, this.forward);
+	out = lookAt(this.position, lookAtVec, this.up);
+	return out;
+};
+
+
 
 class Renderer {
 
 
-  constructor(canvas) {
+  constructor(canvas, textureSize = 128) {
     this.canvas = canvas
+    this.textureSize = textureSize
     this.gl = null
     this.program = null
     this.textureProgram = null
@@ -1009,8 +1033,10 @@ class Renderer {
 
     gl.enable(gl.DEPTH_TEST)
 
+    
     this.textureProgram = initShaders(gl, 'vertex-shader-3d', 'fragment-shader-3d')
     this.program = initShaders(gl, 'vertex-shader', 'fragment-shader')
+    this.shadowMapProgram = initShaders(gl, 'vertex-shader-shadow-map', 'fragment-shader-shadow-map')
     gl.useProgram(this.program)
   }
 
@@ -1021,6 +1047,37 @@ class Renderer {
     this.verticesBuffer = gl.createBuffer()
     this.normalsBuffer = gl.createBuffer()
     this.texcoordsBuffer = gl.createBuffer()
+
+
+    this.shadowMapCube = this.gl.createTexture();
+		this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.shadowMapCube);
+		this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
+		this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
+		this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, this.gl.MIRRORED_REPEAT);
+		this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, this.gl.MIRRORED_REPEAT);
+		for (var i = 0; i < 6; i++) {
+			this.gl.texImage2D(
+				this.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
+				0, this.gl.RGBA,
+				this.textureSize, this.textureSize,
+				0, this.gl.RGBA,
+				this.gl.UNSIGNED_BYTE, null
+			);
+		}
+
+		this.shadowMapFramebuffer = this.gl.createFramebuffer();
+		this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.shadowMapFramebuffer);
+
+		this.shadowMapRenderbuffer = this.gl.createRenderbuffer();
+		this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.shadowMapRenderbuffer);
+		this.gl.renderbufferStorage(
+			this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16,
+			this.textureSize, this.textureSize
+		);
+
+		this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, null);
+		this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);
+		this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
   }
 
 
@@ -1032,6 +1089,16 @@ class Renderer {
     this.uniformList.forEach(uniformName => {
       uniforms[uniformName] = gl.getUniformLocation(program, uniformName)
     })
+    this.gl.useProgram(this.shadowMapProgram);
+    this.shadowMapProgram.uniforms = {
+			mProj: this.gl.getUniformLocation(this.shadowMapProgram, 'mProj'),
+			mView: this.gl.getUniformLocation(this.shadowMapProgram, 'mView'),
+			mWorld: this.gl.getUniformLocation(this.shadowMapProgram, 'mWorld'),
+			pointLightPosition: this.gl.getUniformLocation(this.shadowMapProgram, 'pointLightPosition'),
+			shadowClipNearFar: this.gl.getUniformLocation(this.shadowMapProgram, 'shadowClipNearFar'),
+    };
+    console.log('pointLightPosition: ', this.gl.getUniformLocation(this.shadowMapProgram, 'pointLightPosition'));
+    this.gl.useProgram(this.program);
   }
 
 
@@ -1043,6 +1110,10 @@ class Renderer {
     this.attributeList.forEach(attribName => {
       attribs[attribName] = gl.getAttribLocation(program, attribName)
     })
+
+    this.shadowMapProgram.attribs = {
+			vPos: this.gl.getAttribLocation(this.shadowMapProgram, 'vPos'),
+		};
   }
 
 
@@ -1067,8 +1138,167 @@ class Renderer {
       self.renderObjectTree(object, camera, app)
     })
 
+    this.renderShadowMap(scene, camera, app);
+    this.gl.useProgram(this.program);
+  }
+
+  renderShadowMap(scene, camera, app) {
+    this.gl.useProgram(this.shadowMapProgram)
+
+
+    this.lightPosition = app.objects['cube-lighting'].position.property
+    this.shadowMapCameras = [
+			// Positive X
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(1, 0, 0)),
+				vec3(0, -1, 0)
+			),
+			// Negative X
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(-1, 0, 0)),
+				vec3(0, -1, 0)
+			),
+			// Positive Y
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(0, 1, 0)),
+				vec3(0, 0, 1)
+			),
+			// Negative Y
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(0, -1, 0)),
+				vec3(0, 0, -1)
+			),
+			// Positive Z
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(0, 0, 1)),
+				vec3(0, -1, 0)
+			),
+			// Negative Z
+			new Camera(
+				this.lightPosition,
+				add(this.lightPosition, vec3(0, 0, -1)),
+				vec3(0, -1, 0)
+			),
+		];
+		this.shadowMapViewMatrices = [
+			mat4(),
+			mat4(),
+			mat4(),
+			mat4(),
+			mat4(),
+			mat4()
+		];
+		this.shadowClipNearFar = vec2(0.05, 15.0);
+		this.shadowMapProj = perspective(
+      degToRad(90),
+			1.0,
+			this.shadowClipNearFar[0],
+			this.shadowClipNearFar[1]
+		);
+
+
+    var gl = this.gl;
+  
+    // Set GL state status
+    gl.useProgram(this.shadowMapProgram);
+    gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.shadowMapCube);
+    gl.bindFramebuffer(gl.FRAMEBUFFER, this.shadowMapFramebuffer);
+    gl.bindRenderbuffer(gl.RENDERBUFFER, this.shadowMapRenderbuffer);
+  
+    gl.enable(gl.DEPTH_TEST);
+    gl.enable(gl.CULL_FACE);
+  
+    // Set per-frame uniforms
+    gl.uniform2fv(
+      this.shadowMapProgram.uniforms.shadowClipNearFar,
+      flatten(this.shadowClipNearFar)
+    );
+    gl.uniform3fv(
+      this.shadowMapProgram.uniforms.pointLightPosition,
+      flatten(this.lightPosition)
+    );
+    gl.uniformMatrix4fv(
+      this.shadowMapProgram.uniforms.mProj,
+      gl.FALSE,
+      flatten(this.shadowMapProj)
+    );
+  
+    for (var i = 0; i < this.shadowMapCameras.length; i++) {
+      // Set per light uniforms
+      gl.useProgram(this.shadowMapProgram)
+
+      gl.uniformMatrix4fv(
+        this.shadowMapProgram.uniforms.mView,
+        gl.FALSE,
+        flatten(this.shadowMapCameras[i].GetViewMatrix(this.shadowMapViewMatrices[i]))
+      );
+  
+      // Set framebuffer destination
+      gl.framebufferTexture2D(
+        gl.FRAMEBUFFER,
+        gl.COLOR_ATTACHMENT0,
+        gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
+        this.shadowMapCube,
+        0
+      );
+      gl.framebufferRenderbuffer(
+        gl.FRAMEBUFFER,
+        gl.DEPTH_ATTACHMENT,
+        gl.RENDERBUFFER,
+        this.shadowMapRenderbuffer
+      );
+  
+      gl.clearColor(0, 0, 0, 1);
+      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+  
+      gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer)
+      gl.bufferData(gl.ARRAY_BUFFER, flatten(Geometry.verticesBufferData), gl.STATIC_DRAW)
+
+      gl.vertexAttribPointer(this.shadowMapProgram.attribs.vPos, 4, gl.FLOAT, false, 0, 0)
+      gl.enableVertexAttribArray(this.shadowMapProgram.attribs.vPos)
+
+      scene.children.forEach(object => {
+        this.renderShadowTree(object, camera, app)
+      })
+    }
+  
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+    gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
+  };
+
+  /**
+   * Render this object and all of its children recursively
+   * while performing operations.
+   * 
+   * @param {*} object 
+   * @param {*} camera 
+   * @param {*} app 
+   */
+
+  renderShadowTree(object, camera, app) {
+    let gl = this.gl
+    gl.useProgram(this.shadowMapProgram)
+    const self = this
+    self.renderShadow(object, camera, app)
+    object.children.forEach(child => {
+      self.renderShadowTree(child, camera, app)
+    })
   }
 
+  renderShadow(object) {
+    let gl = this.gl
+    gl.uniformMatrix4fv(this.shadowMapProgram.uniforms.mWorld, gl.FALSE, flatten(object.worldMatrix))
+    let geometry = object.geometry
+    let start = geometry.bufferStartIndex
+    let count = geometry.triangleVerticesCount
+    gl.drawArrays(gl.TRIANGLES, start, count)
+  }
 
   /**
    * Render this object and all of its children recursively
@@ -1079,9 +1309,9 @@ class Renderer {
    * @param {*} app 
    */
 
-  renderObjectTree(object, camera, app) {
+  renderObjectTree(object, camera, app, program) {
     let gl = this.gl
-
+    gl.useProgram(this.program)
     const self = this
     self.renderObject(object, camera, app)
     object.children.forEach(child => {
diff --git a/src/resources/objects/custom-objects.js b/src/resources/objects/custom-objects.js
index 408a133d85a0eefd702f12014b97aa023c9f7f19..ebcf63654be99d2459ed0bf0a672a1ed712fb593 100644
--- a/src/resources/objects/custom-objects.js
+++ b/src/resources/objects/custom-objects.js
@@ -7,66 +7,11 @@ var [LENGTH, WIDTH, HEIGHT] = [10.0, 10.0, 10.0];
 
 objects_info = {
     ...objects_info,
-    "Cube": {
-        "position": [
-            0.0,
-            0.0,
-            0.0
-        ],
-        "material_name": "cubes",
-        "rotation": [
-            0.0,
-            0.0,
-            0.0
-        ],
-        "scale": [
-            1.0,
-            1.0,
-            1.0
-        ]
-    },
-    "Cube.001": {
-        "position": [
-            2.525,
-            -1.463,
-            -0.45
-        ],
-        "material_name": "cubes",
-        "parent": "Cube",
-        "rotation": [
-            0.0,
-            0.0,
-            0.0
-        ],
-        "scale": [
-            0.5456840991973877,
-            0.5456840991973877,
-            0.5456840991973877
-        ]
-    },
-    "Suzanne": {
-        "position": [
-            0.886,
-            -2.385,
-            1.582
-        ],
-        "material_name": "monkey",
-        "rotation": [
-            0.0,
-            0.0,
-            0.0
-        ],
-        "scale": [
-            0.8567630648612976,
-            0.8567630648612976,
-            0.8567630648612976
-        ]
-    },
     "floor": {
         "position": [
             0.0,
             -3.0,
-            -1.0
+            -10.0
         ],
         "material_name": "floor",
         "rotation": [
@@ -102,7 +47,7 @@ objects_info = {
 
 objects_info.floor = {
   ...objects_info.floor,
-  position: [0.0, 0.0, -1.0],
+  position: [0.0, 0.0, -5.0],
   scale: [LENGTH, WIDTH, 1],
 };