diff --git a/index.html b/index.html
index f41143f7a5195add4f3449a5135c9e4cbf78e524..dad2cc89e4ef02fe19c6ac5c59ee59861a12a063 100644
--- a/index.html
+++ b/index.html
@@ -29,7 +29,36 @@
         }
     </script>
 
-     <script id="advectShader" type="x-shader/x-fragment">
+     <script id="diffuseShader" type="x-shader/x-fragment">
+        precision mediump float;
+
+        uniform sampler2D u_material;
+
+        uniform vec2 u_textureSize;
+
+        uniform float u_alpha;
+        uniform float u_reciprocalBeta;
+
+        void main() {
+
+            vec2 fragCoord = gl_FragCoord.xy;
+
+            vec2 currentState = texture2D(u_material, fragCoord/u_textureSize).xy;
+
+            //implicitly solve diffusion via jacobi iteration
+
+            vec2 n = texture2D(u_material, (fragCoord+vec2(0.0, 1.0))/u_textureSize).xy;
+            vec2 s = texture2D(u_material, (fragCoord+vec2(0.0, -1.0))/u_textureSize).xy;
+            vec2 e = texture2D(u_material, (fragCoord+vec2(1.0, 0.0))/u_textureSize).xy;
+            vec2 w = texture2D(u_material, (fragCoord+vec2(-1.0, 0.0))/u_textureSize).xy;
+
+            vec2 nextState = (n + s + e + w + u_alpha * currentState) * u_reciprocalBeta;
+
+            gl_FragColor = vec4(nextState, 0, 0);
+        }
+    </script>
+
+    <script id="advectShader" type="x-shader/x-fragment">
         precision mediump float;
 
         uniform sampler2D u_velocity;
diff --git a/main.js b/main.js
index 4e24ca7e5aa0ff7a9657913019c7416607ee2dd0..64768ac74522ad938cac24f56fe73f34cec8f889 100755
--- a/main.js
+++ b/main.js
@@ -9,6 +9,10 @@ var mouseEnable = false;
 
 var paused = false;//while window is resizing
 
+var dt = 1;
+var dx = 1;
+var nu = 1;//viscosity
+
 var GPU;
 
 window.onload = initGL;
@@ -39,10 +43,17 @@ function initGL() {
     // setup a GLSL programs
     GPU.createProgram("advect", "2d-vertex-shader", "advectShader");
     GPU.setUniformForProgram("advect" ,"u_textureSize", [width, height], "2f");
-    GPU.setUniformForProgram("advect", "u_dt", 1.0, "1f");
+    GPU.setUniformForProgram("advect", "u_dt", dt, "1f");
     GPU.setUniformForProgram("advect", "u_velocity", 0, "1i");
     GPU.setUniformForProgram("advect", "u_material", 1, "1i");
 
+    GPU.createProgram("diffuse", "2d-vertex-shader", "diffuseShader");
+    GPU.setUniformForProgram("diffuse" ,"u_textureSize", [width, height], "2f");
+    var alpha = dx*dx/(nu*dt);
+    GPU.setUniformForProgram("diffuse", "u_alpha", alpha, "1f");
+    GPU.setUniformForProgram("diffuse", "u_reciprocalBeta", 1/(4+alpha), "1f");
+    GPU.setUniformForProgram("diffuse", "u_material", 0, "1i");
+
     GPU.createProgram("render", "2d-vertex-shader", "2d-render-shader");
     GPU.setUniformForProgram("render" ,"u_textureSize", [width, height], "2f");
     GPU.setUniformForProgram("render", "u_material", 0, "1i");
@@ -70,12 +81,18 @@ function render(){
         // p = computePressure(u);
         // u = subtractPressureGradient(u, p);
 
-        GPU.step("advect", ["velocity", "velocity"], "advectedVelocity");//advect velocity
-        GPU.swapTextures("velocity", "advectedVelocity");
+        GPU.step("advect", ["velocity", "velocity"], "nextVelocity");//advect velocity
+        GPU.swapTextures("velocity", "nextVelocity");
+        for (var i=0;i<10;i++){
+            GPU.step("diffuse", ["velocity"], "nextVelocity");//diffuse velocity
+            GPU.step("diffuse", ["nextVelocity"], "velocity");//diffuse velocity
+        }
+        
 
-        GPU.step("advect", ["velocity", "material"], "advectedMaterial");
-        GPU.step("render", ["advectedMaterial"]);
-        GPU.swapTextures("advectedMaterial", "material");
+        // GPU.step("diffuse", ["material"], "nextMaterial");
+        GPU.step("advect", ["velocity", "material"], "nextMaterial");
+        GPU.step("render", ["nextMaterial"]);
+        GPU.swapTextures("nextMaterial", "material");
 
     } else resetWindow();
 
@@ -110,8 +127,8 @@ function resetWindow(){
         }
     }
     GPU.initTextureFromData("velocity", width, height, "FLOAT", velocity, true);
-    GPU.initTextureFromData("advectedVelocity", width, height, "FLOAT", new Float32Array(width*height*4), true);
-    GPU.initFrameBufferForTexture("advectedVelocity");
+    GPU.initTextureFromData("nextVelocity", width, height, "FLOAT", new Float32Array(width*height*4), true);
+    GPU.initFrameBufferForTexture("nextVelocity");
     var material = new Float32Array(width*height*4);
     for (var i=0;i<height;i++){
         for (var j=0;j<width;j++){
@@ -121,8 +138,8 @@ function resetWindow(){
     }
     GPU.initTextureFromData("material", width, height, "FLOAT", material, true);
     GPU.initFrameBufferForTexture("material");
-    GPU.initTextureFromData("advectedMaterial", width, height, "FLOAT", new Float32Array(width*height*4), true);
-    GPU.initFrameBufferForTexture("advectedMaterial");
+    GPU.initTextureFromData("nextMaterial", width, height, "FLOAT", new Float32Array(width*height*4), true);
+    GPU.initFrameBufferForTexture("nextMaterial");
 
     paused = false;
 }