)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Perlin Noise on JavaScript Canvas

  1. // IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN.
  2. const p = [];
  3. const permutation = [151,160,137,91,90,15,
  4. 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
  5. 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
  6. 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
  7. 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
  8. 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
  9. 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
  10. 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
  11. 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
  12. 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
  13. 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
  14. 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
  15. 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
  16.  
  17. for (let i = 0; i < 256 ; i++) 
  18.   p[256+i] = p[i] = permutation[i]; 
  19.  
  20. function noise(x, y, z) {
  21.   const X = Math.floor(x) & 255,                  
  22.         Y = Math.floor(y) & 255,                  
  23.         Z = Math.floor(z) & 255;
  24.   x -= Math.floor(x);                                
  25.   y -= Math.floor(y);                               
  26.   z -= Math.floor(z);
  27.  
  28.   const u = fade(x),                               
  29.         v = fade(y),                                
  30.         w = fade(z);
  31.   const A = p[X  ]+Y, AA = p[A]+Z, AB = p[A+1]+Z,      
  32.       B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z;      
  33.  
  34.   return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ),  
  35.                                   grad(p[BA  ], x-1, y  , z   )), 
  36.                           lerp(u, grad(p[AB  ], x  , y-1, z   ),   
  37.                                   grad(p[BB  ], x-1, y-1, z   ))), 
  38.                   lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ),   
  39.                                   grad(p[BA+1], x-1, y  , z-1 )),  
  40.                           lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
  41.                                   grad(p[BB+1], x-1, y-1, z-1 ))));
  42. }
  43. function fade(t) { 
  44.   return t * t * t * (t * (t * 6 - 15) + 10); 
  45. }
  46. function lerp(t, a, b) { 
  47.   return a + t * (b - a); 
  48. }
  49. function grad(hash, x, y, z) {
  50.   const h = hash & 15;                      
  51.   const u = h<8 ? x : y,                 
  52.         v = h<4 ? y : h==12||h==14 ? x : z;
  53.   return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
  54. }
  55.  
  56. const canvas = document.body.appendChild(document.createElement('canvas'));
  57. const c = canvas.getContext('2d');
  58. canvas.width = canvas.height = 200;
  59.  
  60. c.fillStyle = 'black';
  61. c.fillRect(0, 0, canvas.width, canvas.height);
  62.  
  63. const pix = c.createImageData(canvas.width, canvas.height);
  64.  
  65. const freq = 1 / 20;
  66. let inc = 0;
  67. let z = 0;
  68.  
  69. function loop() {
  70.   z += 0.02;
  71.   inc = 0;
  72.   for (var y = 0; y < canvas.height; y++) {
  73.     for (var x = 0; x < canvas.width; x++) {
  74.       var col = parseInt(Math.abs(noise(x * freq, y * freq, z)) * 500);
  75.       pix.data[inc++] = col;
  76.       pix.data[inc++] = col;
  77.       pix.data[inc++] = col;
  78.       pix.data[inc++] = 255;
  79.     }
  80.   }
  81.  
  82.   c.putImageData(pix, 0, 0);
  83.   window.requestAnimationFrame(loop);
  84. }
  85. loop();

Perlin noise (created by Ken Perlin).

Years ago I grabbed the noise function from here I think….

This shows how to do perlin noise on an html5 canvas. If you need a more performant one for animation and/or larger images – a glsl shader is the way to go.

Oscillating Canvas Wave

  1. const c = document.body
  2.   .appendChild(document.createElement('canvas'))
  3.   .getContext('2d');
  4.  
  5. Object.assign(document.body.style, {
  6.   margin: 0,
  7.   height: '100%'
  8. });
  9.  
  10. Object.assign(c.canvas.style, {
  11.   position: 'absolute',
  12.   left: 0,
  13.   top: 0,
  14.   width: '100%',
  15.   height: '100%'
  16. });
  17.  
  18. let t = 0;
  19.  
  20. function resize() {
  21.   c.canvas.width = innerWidth * 2;
  22.   c.canvas.height = innerHeight * 2;
  23.   draw();
  24. }
  25. window.addEventListener('resize', resize);
  26. resize();
  27.  
  28. function draw() {
  29.   const {
  30.     canvas: { width, height }
  31.   } = c;
  32.  
  33.   c.fillStyle = 'rgba(155, 155, 155, .4)';
  34.   c.fillRect(0, 0, width, height);
  35.   c.fillStyle = '#000';
  36.  
  37.   let x = innerWidth;
  38.   let y = 0;
  39.  
  40.   t += 0.05;
  41.   for (let i = 0; i < innerHeight; i++) {
  42.     x += 2 * Math.cos(t + i * 0.1 * Math.cos(i / 200));
  43.     y += 2;
  44.     c.fillRect(x, y, 100, 1);
  45.   }
  46. }
  47.  
  48. function loop() {
  49.   draw();
  50.   window.requestAnimationFrame(loop);
  51. }
  52. loop();

Speed coded oscillating wave on canvas… Looks better in fullscreen.

Gravity Dots 2

  1. d = document
  2. b = d.body
  3. b.style.margin = 0
  4. b.style.background = 'black'
  5. r = (v = 1) => Math.random() * v
  6.  
  7. with(
  8.   b.appendChild(
  9.     d.createElement`canvas`
  10.   ).getContext`2d`) {
  11.  
  12.   onresize = () => {
  13.     canvas.width = innerWidth
  14.     canvas.height = innerHeight
  15.   }
  16.   onresize()
  17.  
  18.   fillStyle = 'red'
  19.  
  20.   dot = (
  21.     x = r(innerWidth),
  22.     y = 0,
  23.     mass = 20, sr = r(2) + 2, 
  24.     R = sr,
  25.     dx, dy,
  26.     col = '#005eb0',
  27.     dist, vx = .2, vy = 0) => { 
  28.  
  29.     return () => { 
  30.       fillStyle = col
  31.       R = sr
  32.       if (r() < .001) {
  33.         vx = r() * 4 - 2
  34.         R = sr * 2
  35.         fillStyle = 'red'
  36.         col = `hsl(${r(360)}deg, 50%, 50%)`
  37.       }
  38.  
  39.       dx = innerWidth / 2 - x
  40.       dy = innerHeight / 2 - y
  41.       dist = Math.sqrt(dx * dx + dy * dy)
  42.       dist *= dist
  43.       vx += dx / dist * mass
  44.       vy += dy / dist * mass
  45.  
  46.       x += vx
  47.       y += vy
  48.  
  49.       beginPath()
  50.       arc(x, y, R, 0, 6.29)
  51.       fill()
  52.     }
  53.   }
  54.  
  55.   const dots = []
  56.   for (let i = 0; i < 100; i++) dots.push(dot())
  57.   loop = () => {
  58.     fillStyle = 'rgba(0, 0, 0, 0.05)'
  59.     fillRect(0, 0, canvas.width, canvas.height)
  60.     dots.map(d => d())
  61.   }
  62.   setInterval(loop, 16)
  63. }

A variation on this recent post.

Gravity Dots

  1. d = document
  2. b = d.body
  3. b.style.margin = 0
  4. b.style.background = 'black'
  5. r = (v = 1) => Math.random() * v
  6.  
  7. with(
  8.   b.appendChild(
  9.     d.createElement`canvas`
  10.   ).getContext`2d`) {
  11.  
  12.   onresize = () => {
  13.     canvas.width = innerWidth
  14.     canvas.height = innerHeight
  15.   }
  16.   onresize()
  17.  
  18.   fillStyle = 'red'
  19.  
  20.   dot = (
  21.     x = r(innerWidth),
  22.     y = r(innerHeight),
  23.     mass = 10, sr = r(8) + 4, 
  24.     R = sr,
  25.     dx, dy,
  26.     dist, vx = .2, vy = 0) => { 
  27.  
  28.     return () => { 
  29.       fillStyle = '#005eb0'
  30.       R = sr
  31.       if (r() < .005) {
  32.         vx = r() * 4 - 2
  33.         R = sr * 2
  34.         fillStyle = 'white'
  35.       }
  36.  
  37.       dx = innerWidth / 2 - x
  38.       dy = innerHeight / 2 - y
  39.       dist = Math.sqrt(dx * dx + dy * dy)
  40.       dist *= dist
  41.       vx += dx / dist * mass
  42.       vy += dy / dist * mass
  43.  
  44.       x += vx
  45.       y += vy
  46.  
  47.       beginPath()
  48.       arc(x, y, R, 0, 6.29)
  49.       fill()
  50.     }
  51.   }
  52.  
  53.   const dots = []
  54.   for (let i = 0; i < 10; i++) dots.push(dot())
  55.   loop = () => {
  56.     fillStyle = 'rgba(0, 0, 0, 0.2)'
  57.     fillRect(0, 0, canvas.width, canvas.height)
  58.     dots.map(d => d())
  59.   }
  60.   setInterval(loop, 16)
  61. }

Some speed coded dots that gravitate to the center of the screen and occasionally change direction.

Fermat’s Spiral Tweak/Fork

  1. document.body.style.margin = 0;
  2. const canvas = document.body.appendChild(document.createElement('canvas'));
  3. const c = canvas.getContext('2d');
  4.  
  5. function resize() {
  6.   canvas.width = window.innerWidth;
  7.   canvas.height = window.innerHeight;
  8.   draw();
  9. }
  10.  
  11. setInterval(draw, 16);
  12.  
  13. let t = 0;
  14. function draw() {
  15.   c.fillStyle = 'rgba(155, 155, 155, .9)';
  16.   c.fillRect(0, 0, canvas.width, canvas.height);
  17.   c.fillStyle = 'rgba(0, 0, 0, 0.5)';
  18.  
  19.   const iter = 500;
  20.   const halfWidth = window.innerWidth / 2;
  21.   const halfHeight = window.innerHeight / 2;
  22.   let rad = 0,
  23.     scale = 20 * Math.min(window.innerWidth, window.innerHeight) * 0.006,
  24.     theta = 0,
  25.     x,
  26.     y;
  27.  
  28.   c.save();
  29.   c.translate(halfWidth, halfHeight);
  30.  
  31.   for (let i = 0; i < iter; i++) {
  32.     rad = 3 * Math.sin(Math.sqrt(theta)) * scale;
  33.     x = rad * Math.cos(theta);
  34.     y = rad * Math.sin(theta * 0.99);
  35.     c.fillRect(x, y, 2, 2);
  36.     c.fillRect(-x, -y, 4, 4);
  37.     theta += 0.05 + t * 0.001;
  38.   }
  39.   c.restore();
  40.   t += 0.1;
  41. }
  42.  
  43. resize();
  44. window.addEventListener('resize', resize);
snippet.zone /// {s/z}