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

Fake RNG

  1. let anchors
  2. let idx
  3. let leng = 10
  4. let size = 200
  5. let px = 0
  6. let py = 0
  7.  
  8. function seed() {
  9.   idx = 0
  10.   anchors = (Date.now() + '').split``
  11.     .reverse()
  12.     .map(v => parseFloat(v) / 10)
  13.     .splice(0, leng)
  14. }
  15.  
  16. let last = 0
  17. let zoom = 1
  18. function rand() {
  19.   if (idx > size * size) seed()
  20.  
  21.   px += zoom
  22.   py += ~~(px / size)
  23.  
  24.   if (px >= size) px = 0
  25.   if (py >= size) py = 0
  26.  
  27.   const point = {
  28.     x: anchors[idx % leng],
  29.     y: anchors[(idx + 1) % leng]
  30.   }
  31.   idx++
  32.  
  33.   let dists = []
  34.   for (let i = 0; i < anchors.length; i += 2) {
  35.     let dx = px - anchors[i] * size
  36.     let dy = py - anchors[i + 1] * size
  37.     dists.push(Math.sqrt(dx * dx + dy * dy))
  38.   }
  39.   dists.sort()
  40.   last += (dists[0] / size - last) / 4
  41.   return last
  42. }
  43.  
  44. seed()
  45.  
  46. let d = document
  47. let b = d.body
  48. with (b.appendChild(
  49.   Object.assign(d.createElement`canvas`, { width: 400, height: 400 })
  50. ).getContext`2d`) {
  51.   fillStyle = 'black'
  52.   fillRect(0, 0, 400, 400)
  53.  
  54.   for (let i = 0; i < 200; i++) {
  55.     for (let j = 0; j < 200; j++) {
  56.       const c = rand() * 255
  57.       fillStyle = `rgb(${c}, ${c}, ${c})`
  58.       fillRect(j * 2, i * 2, 1, 2)
  59.     }
  60.   }
  61. }

Another one for genuary “Create your own pseudo-random number generator and visually check the results.”

Speed Coded Cosine Dither

  1. d = document
  2. b = d.body
  3. wh = 300
  4. hs = wh / 2
  5. S = 1.5
  6. with(
  7.   b.appendChild(Object.assign(
  8.     d.createElement`canvas`, {
  9.       width: wh, height: wh
  10.     })).getContext`2d`) {
  11.  
  12.   canvas.style.transformOrigin = '0 0'
  13.   canvas.style.transform = `scale(${S})`
  14.   canvas.style.imageRendering = 'pixelated'
  15.  
  16.   fillStyle = 'gray'
  17.  
  18.   fillRect(0, 0, wh, wh)
  19.   shadowBlur = 80
  20.   shadowColor = 'black';
  21.   shadowOffsetY = 20
  22.   for (let i = 0; i < 70; i++) {
  23.     save()
  24.     translate(hs, hs)
  25.     rotate(i / 33)
  26.     scale(1 - i / 100, 1)
  27.     translate(-hs, -hs)
  28.     fillStyle = `hsl(${i << 2}, 50%, 50%)`
  29.     beginPath()
  30.     arc(hs, hs, hs * .8, 0, 7)
  31.     fill()
  32.     restore()
  33.     shadowColor = 'transparent'
  34.     shadowBlur = 0
  35.   }
  36.  
  37.   C = Object.assign(d.createElement`canvas`, {
  38.     width: wh, height: wh
  39.   }).getContext('2d')
  40.   C.drawImage(canvas, 0, 0);
  41.  
  42.   im = getImageData(0, 0, wh, wh);
  43.  
  44.   p = im.data
  45.   size = wh * wh * 4
  46.  
  47.   modd = Math.random() * 5550
  48.   for (let i = 0; i < size; i += 4) {
  49.     if (Math.random() < 0.0001) modd = Math.random() * 5550
  50.     M = Math.cos(i % modd) * 255
  51.     p[i] = M < p[i] ? 255 : 0;
  52.     p[i + 1] = M < p[i + 1] ? 255 : 0;
  53.     p[i + 2] = M < p[i + 2] ? 255 : 0;
  54.   }
  55.  
  56.   putImageData(im, 0, 0);
  57.   globalCompositeOperation = 'hard-light'
  58.   drawImage(C.canvas, 0, 0);
  59. }

Some speed-coded canvas stuff with a dither inspired by #genuary2022

valueOf for Shorter Function Calls

  1. r={valueOf:_=>Math.random()}
  2. console.log(+r)
  3. console.log(+r)
  4. console.log(+r)

Use valueOf to shorten function calls. I learned this trick over at stackexchange codegolf here from user cyoce.

Letter Particles With Keyboard

  1. const Key = {
  2.   LEFT: 37,
  3.   UP: 38,
  4.   RIGHT: 39,
  5.   DOWN: 40,
  6.   disabled: false
  7. };
  8.  
  9. const keyDown = {};
  10.  
  11. function setupKeys() {
  12.   const alph = 'abcdefghijklmnopqrstuvwxyz'.split('');
  13.   const keys = {};
  14.   const aKey = 65;
  15.   alph.forEach((letter, i) => {
  16.     const idx = aKey + i;
  17.     keyDown[idx] = false;
  18.     Key[letter.toUpperCase()] = idx;
  19.   });
  20.  
  21.   keyDown.allLetters = () => {
  22.     const lettersDown = alph.filter(
  23.       letter => keyDown[Key[letter.toUpperCase()]]
  24.     );
  25.     return lettersDown;
  26.   };
  27.  
  28.   document.addEventListener('keydown', e => {
  29.     e.preventDefault();
  30.     if (!Key.disabled) {
  31.       keyDown[e.which] = true;
  32.     }
  33.   });
  34.  
  35.   document.addEventListener('keyup', e => {
  36.     e.preventDefault();
  37.     keyDown[e.which] = false;
  38.   });
  39. }
  40.  
  41. setupKeys();
  42.  
  43. // later:
  44.  
  45. const dots = {};
  46. let id = 0;
  47. function dot(letter = '') {
  48.   const el = document.createElement('div');
  49.   el.innerHTML = letter;
  50.   const size = 20;
  51.   const scale = 1 + Math.random() * 2;
  52.   const vel = (2 - scale / 2) / 4;
  53.   let x = innerWidth / 2 - size;
  54.   let y = innerHeight / 2 - size;
  55.   let vx = Math.random() * 6 - 3;
  56.   let vy = Math.random() * 6 - 3;
  57.   let life = 0;
  58.   let maxLife = Math.floor(50 + Math.random() * 30);
  59.   Object.assign(el.style, {
  60.     position: 'absolute',
  61.     left: 0,
  62.     top: 0,
  63.     transform: `translate3d(${x}px, ${y}px)`,
  64.     borderRadius: '500px',
  65.     background: 'red',
  66.     width: `${size}px`,
  67.     fontFamily: 'sans-serif',
  68.     textAlign: 'center',
  69.     color: 'white'
  70.   });
  71.  
  72.   id++;
  73.  
  74.   let props = {
  75.     el,
  76.     id,
  77.     right() {
  78.       vx += vel;
  79.     },
  80.     left() {
  81.       vx -= vel;
  82.     },
  83.     down() {
  84.       vy += vel;
  85.     },
  86.     up() {
  87.       vy -= vel;
  88.     },
  89.     run() {
  90.       life++;
  91.       if (life === maxLife) {
  92.         document.body.removeChild(dots[props.id].el);
  93.         delete dots[props.id];
  94.       }
  95.       x += vx;
  96.       y += vy;
  97.       vx *= 0.999;
  98.       vy *= 0.999;
  99.       el.style.transform = `translate(${x}px, ${y}px) scale(${scale}) `;
  100.     }
  101.   };
  102.   dots[id] = props;
  103.   document.body.appendChild(el);
  104. }
  105.  
  106. function loop() {
  107.   keyDown.allLetters().forEach(letter => {
  108.     dot(letter);
  109.   });
  110.  
  111.   for (let i in dots) {
  112.     dots[i].run();
  113.   }
  114.  
  115.   if (keyDown[Key.LEFT]) {
  116.     for (let i in dots) {
  117.       dots[i].left();
  118.     }
  119.   }
  120.  
  121.   if (keyDown[Key.DOWN]) {
  122.     for (let i in dots) {
  123.       dots[i].down();
  124.     }
  125.   }
  126.  
  127.   if (keyDown[Key.RIGHT]) {
  128.     for (let i in dots) {
  129.       dots[i].right();
  130.     }
  131.   }
  132.  
  133.   if (keyDown[Key.UP]) {
  134.     for (let i in dots) {
  135.       dots[i].up();
  136.     }
  137.   }
  138.  
  139.   requestAnimationFrame(loop);
  140. }
  141. loop();
  142.  
  143. const info = document.createElement('div')
  144. info.innerHTML = 'click here, then type letters and use arrow keys'
  145. document.body.appendChild(info)

A demo showing how to use the keyboard snippet from yesterday. Also added a function to obtain an array of all currently pressed letter keys

// animation // javascript // keys // math // random // tricks // ui

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.

snippet.zone ~ 2021-24 /// {s/z}