diff --git a/src/parallax-css-testpage/particles.js b/src/parallax-css-testpage/particles.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9db1870a7bba9b80fda53483daa20d453ffe6ad
--- /dev/null
+++ b/src/parallax-css-testpage/particles.js
@@ -0,0 +1,213 @@
+/*
+ *  Particle.js
+ */
+
+
+//
+//  Config
+//
+
+
+const Fps = 16
+
+
+//
+//  Helper
+//
+
+
+// Variables needed for fps calculation.
+const FpsInterval = 1000 / Fps
+let   Then = Date.now() // Argh.. Global, mutable, variable..!
+
+function randomValue(min, max) {
+    return (Math.random() * (+max - +min) + +min)
+}
+
+
+
+//
+//  Data
+//
+
+
+
+function Point2D(x, y) {
+    return { x, y }
+}
+
+function MinMax(min, max) {
+    return { min, max }
+}
+
+function MaxValue(value, max) {
+    return { value, max }
+}
+
+function RandomPoint2D(minMaxX, minMaxY) {
+    const x = randomValue(minMaxX.min, minMaxX.max)
+    const y = randomValue(minMaxY.min, minMaxY.max)
+    return Point2D(x, y)
+}
+
+function Particle({ position, direction, size, color }) {
+    return { position, direction, size, color }
+}
+
+
+
+//
+//  Transformations | Actions
+//
+
+
+
+function Update(canvas, particle) {
+    // Animate the movement of the particle
+    //
+    const isRightEdge =
+        (particle.position.x + particle.size.value >= canvas.width)
+    const isLeftEdge   = (particle.position.x <= 0)
+    const isBottomEdge =
+        (particle.position.y + particle.size.value >= canvas.height)
+    const isTopEdge    = (particle.position.y <= 0)
+
+    const updateDirection =
+        Object.assign({}, particle, {
+            direction:
+                Point2D(
+                    (isRightEdge || isLeftEdge)
+                        ? particle.direction.x * -1
+                        : particle.direction.x,
+                    (isTopEdge || isBottomEdge)
+                        ? particle.direction.y * -1
+                        : particle.direction.y
+                )
+        })
+    const updatePosition =
+        Object.assign({}, updateDirection, {
+            position:
+                Point2D(
+                    updateDirection.position.x + updateDirection.direction.x,
+                    updateDirection.position.y + updateDirection.direction.y,
+                )
+        })
+
+    // Animate the pulse effect of the particle
+    //
+    const isMaxSize = updatePosition.size.value >= updatePosition.size.bound.max
+    const isMinSize = updatePosition.size.value <= updatePosition.size.bound.min
+    const updateSizeStep =
+        Object.assign({}, updatePosition, {
+            size: Object.assign({}, updatePosition.size, {
+                direction:
+                    (isMaxSize || isMinSize)
+                      ? updatePosition.size.direction * -1
+                      : updatePosition.size.direction
+            })
+        })
+    const updateSize =
+        Object.assign({}, updateSizeStep, {
+            size: Object.assign({}, updateSizeStep.size, {
+                value:
+                    // Todo: Animate puls effect with the help of Math.sin()
+                    updateSizeStep.size.value + updateSizeStep.size.step * updateSizeStep.size.direction,
+            })
+        })
+
+    const updatedParticle = Particle(updateSize)
+    return updatedParticle
+}
+
+function Clear(ctx) {
+    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
+}
+
+function Render(ctx, particles) {
+    particles.forEach(
+        function (particle) {
+            if (particle.size.value > 0) {
+                const offset = (particle.size.value*0.5)
+                ctx.fillStyle = particle.color
+                ctx.fillRect(
+                    particle.position.x - offset,
+                    particle.position.y - offset,
+                    particle.size.value,
+                    particle.size.value
+                )
+            }
+        }
+    )
+}
+
+function Animate(ctx, particles) {
+    // Update particle positions and register for the next 
+    // frame to render. 
+    requestAnimationFrame(() => {
+        const updatedParticles = 
+            particles.map(function (p) {
+                return Update(ctx.canvas, p)
+            })
+        Animate(ctx, updatedParticles)
+    }) 
+
+
+    // Render particles to canvas
+    const now = Date.now()
+    const elapsed = now - Then
+    if (elapsed > FpsInterval) {
+        Then = now - (elapsed % FpsInterval)
+        Clear(ctx)
+        Render(ctx, particles)  
+    }
+}
+
+ 
+
+//
+//  Api
+//
+
+
+
+function Particles({ canvasId, amount, color, size, lifespan }) {
+    // Init the canvas for rendering.
+    const canvas = document.getElementById(canvasId)
+    const ctx = canvas.getContext('2d')
+    ctx.canvas.width = window.innerWidth
+    ctx.canvas.height = window.innerHeight
+
+    // Generate random particles
+    const particles =
+        Array.from(
+            { length: amount },
+            () => Particle({
+                position:
+                    RandomPoint2D(
+                        MinMax(0, (ctx.canvas.width  - (size*2))),
+                        MinMax(0, (ctx.canvas.height - (size*2)))
+                    ),
+                direction:
+                    RandomPoint2D(
+                        MinMax(-0.2, 0.2),
+                        MinMax(-0.2, 0.2)
+                    ),
+                size: {
+                    value: randomValue(-size, size),
+                    bound: MinMax(-size, size),
+                    step: size / ((lifespan) / Fps),
+                    direction:
+                        (randomValue(0, 100) < 50)
+                            ? -1
+                            : +1
+                },
+                color
+            })
+        )
+     
+    Then = Date.now()
+    Animate(ctx, particles)
+}
+
+
+
diff --git a/src/parallax-css-testpage/template.css b/src/parallax-css-testpage/template.css
index b7f4e359591e3ea07a764819eea016e0d4cb905e..58ec1a4b2086e0db3dbdae3ee4f676163c6e3b50 100644
--- a/src/parallax-css-testpage/template.css
+++ b/src/parallax-css-testpage/template.css
@@ -59,8 +59,6 @@ div {
  *  Elements
  */
 
-
-
 .vignette {
     background-image: url("03_Vignette/RC3_vignette.png");
 }
@@ -92,13 +90,16 @@ div {
     opacity: 0.5;
 }
 
+.particles {
+    /* background-color: transparent; */
+}
+
 
 
 /*
  *  Parallax layer
  */
 
-
 .z-0 {
     transform: translateZ(0.5px) scale(-1.5);
 }
diff --git a/src/parallax-css-testpage/template.html b/src/parallax-css-testpage/template.html
index 7127045b19fd037516415729f699599063931235..c0a11ab14a9b02d5d67231a5850487e7be4c18b9 100644
--- a/src/parallax-css-testpage/template.html
+++ b/src/parallax-css-testpage/template.html
@@ -9,6 +9,7 @@
     <!-- <link rel="stylesheet" href="parallax.css"> -->
     <link rel="stylesheet" href="template.css">
     <!-- <script src="/rellax.min.js"></script> -->
+    <script src="particles.js"></script>
 </head>
 
 <body>
@@ -25,6 +26,7 @@
         <div class="static full-bg bg-image"></div>
         <div class="static full-bg vcr-overlay"></div>
         <div class="static full-bg grid"></div>
+        <canvas id="particles" class="static full-bg particles"></canvas>
         <div class="static full-bg vignette"></div>
     </div>
 
@@ -33,8 +35,8 @@
 
             <!-- <div class="parallax bg-image"></div> -->
             <div class="layer z-1 scroll-bg gradient"></div>
-            <div class="layer z-0 scroll-bg fg-pixels"></div>
-            <div class="layer z-6 scroll-bg bg-pixels"></div>
+            <!-- <div class="layer z-0 scroll-bg fg-pixels"></div> -->
+            <!-- <div class="layer z-6 scroll-bg bg-pixels"></div> -->
 
             <div id="content" class="content">
                 <h1>This is a Parallax Scroll Example</h1>
@@ -79,8 +81,16 @@
     </div>
 
 
-
-
+    <script>
+        var bgParticles = {
+            canvasId: 'particles',
+            amount: 75,
+            color: 'white',
+            size: 7,
+            lifespan: 4000 // in milliseconds
+        }
+        Particles(bgParticles)
+    </script>
 
 </body>