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

ASCII Circles (Bresenham Fun)

  1. // some circles made of text
  2.  
  3. const cols = 50;
  4. const rows = 50;
  5. const sym = '.';
  6. const body = document.body;
  7.  
  8. Object.assign(body.style, {
  9.   userSelect: 'none',
  10.   fontFamily: 'Courier, monospace',
  11.   position: 'fixed', 
  12.   width: '100%',
  13.   height: '100%',
  14.   margin: 0
  15. });
  16.  
  17. const el = body.appendChild(
  18.   document.createElement('span')
  19. );
  20. el.innerHTML = sym;
  21.  
  22. Object.assign(el.style, {
  23.   position: 'absolute',
  24.   left: '50%',
  25.   top: '50%',
  26.   wordWrap: 'break-word',
  27.   cursor: 'pointer'
  28. });
  29.  
  30. const charSize = el.getBoundingClientRect().width;
  31. const elWidth = charSize * cols;
  32. el.style.display = 'block'
  33. el.style.width = `${elWidth}px`;
  34.  
  35. const info = body.appendChild(
  36.   document.createElement('div')
  37. );
  38.  
  39. Object.assign(info.style, {
  40.   background: '#fff',
  41.   padding: '4px',
  42.   position: 'absolute'
  43. })
  44. info.innerHTML = 'click/tap and hold for different fx';
  45.  
  46. function resize() {
  47.   const scl = Math.min(
  48.     1.23, 
  49.     Math.min(innerWidth, innerHeight) / elWidth * .93
  50.   );
  51.   el.style.transform = `translate(-50%, -50%) scale(${scl}, ${scl * .55})`
  52. }
  53. addEventListener('resize', resize);
  54. resize();
  55.  
  56. const size = cols * rows;
  57. const pix = sym.repeat(size);
  58. el.innerHTML = pix;
  59.  
  60. let cells = pix.split('')
  61. const blank = cells.concat();
  62.  
  63. function setSym(x, y, col) {
  64.   const idx = x + y * cols;
  65.   if (cells[idx] != null) {
  66.     cells[idx] = col;
  67.   }
  68.   return setSym
  69. }
  70.  
  71. const grad = '::;|0UU888NN';
  72. function circ(shooter) {
  73.   let x = Math.round(Math.random() * cols);
  74.   let y = Math.round(Math.random() * rows);
  75.   const rad = Math.round(
  76.     shooter ? Math.random() * 2 :
  77.       Math.random() * Math.random() * 13 + 1
  78.   );
  79.  
  80.   const sym = shooter ? '#' : grad.charAt(rad % grad.length);
  81.   let speed = rad / 10 + .1;
  82.   let dir = Math.random() * 2 - 1;
  83.   return () => {
  84.     drawCircle(x, y, rad, sym, shooter);
  85.     y += speed;
  86.     if (shooter) x += speed * 3 * dir;
  87.     if (y > rows + 10) y = -14;
  88.   }
  89. }
  90.  
  91. const circs = [];
  92. const NUM = 40;
  93. for (let i = 0; i < NUM; i++) {
  94.   circs.push(circ(Math.random() > 0.5))
  95. }
  96.  
  97. let down;
  98. document.addEventListener('mousedown', () => {
  99.   down = true;
  100. });
  101. document.addEventListener('mouseup', () => {
  102.   down = false;
  103. });
  104. document.addEventListener('touchstart', () => {
  105.   down = true;
  106. });
  107. document.addEventListener('touchend', () => {
  108.   down = false;
  109. });
  110.  
  111. let tweak;
  112. let tweakChoice;
  113. let tweakChance = 0.4;
  114. const clear = () => cells = blank.concat();
  115.  
  116. function draw() {
  117.   if (!down) {
  118.     tweak = false;
  119.     tweakChoice = Math.random();
  120.     clear();
  121.   } else {
  122.     if (tweakChoice < tweakChance) {
  123.       tweak = true;
  124.       clear();
  125.     }
  126.   }
  127.  
  128.   circs.forEach(circ => circ());
  129.   el.innerHTML = cells.join('');
  130. }
  131.  
  132. // 60fps is too fast, so use 30ms interval
  133. setInterval(draw, 30);
  134.  
  135. function hLine(xp, yp, w, col) {
  136.   for (let i = 0; i < w; i++) {
  137.     setSym(xp + i, yp, col);
  138.   }
  139.   return hLine;
  140. }
  141.  
  142. // bresenham circle
  143. function drawCircle(xp, yp, radius, sym = '@', isFilled) {
  144.   if (isFilled && tweak) sym = '';
  145.  
  146.   xp = parseInt(xp, 10);
  147.   yp = parseInt(yp, 10);
  148.   radius = parseInt(radius, 10);
  149.   let balance = -radius,
  150.     xoff = 0,
  151.     yoff = radius;
  152.  
  153.   while (xoff <= yoff) {
  154.     const p0 = xp - xoff;
  155.     const p1 = xp + xoff;
  156.  
  157.     const p2 = yp + yoff;
  158.     const p3 = yp - yoff;
  159.     const p4 = yp + xoff;
  160.     const p5 = xp + yoff;
  161.     const p6 = xp - yoff;
  162.     const p7 = yp - xoff;
  163.  
  164.     if (isFilled) {
  165.       const w0 = xoff + xoff;
  166.       const w1 = yoff + yoff;
  167.  
  168.       hLine
  169.         (p0, yp + yoff, w0, sym)
  170.         (p0, yp - yoff, w0, sym)
  171.         (p6, yp + xoff, w1, sym)
  172.         (p6, yp - xoff, w1, sym);
  173.  
  174.     } else {
  175.       setSym
  176.         (p1, p2, sym)
  177.         (p0, p2, sym)
  178.         (p0, p3, sym)
  179.         (p1, p3, sym)
  180.         (p5, p4, sym)
  181.         (p6, p4, sym)
  182.         (p6, p7, sym)
  183.         (p5, p7, sym);
  184.     }
  185.  
  186.     // never been able to find the original 
  187.     // source for the below condition 
  188.     // more info here: https://actionsnippet.com/?p=492
  189.     if ((balance += xoff++ + xoff) >= 0) {
  190.       balance -= --yoff + yoff;
  191.     }
  192.   }
  193. }

This is a bit of a longer snippet that uses the Bresenham circle drawing algorithm to draw some circles with text. I recommend looking at it with the fullscreen button.

I like to do this:

  1. hLine
  2.   (p0, yp + yoff, w0, sym)
  3.   (p0, yp - yoff, w0, sym)
  4.   (p6, yp + xoff, w1, sym)
  5.   (p6, yp - xoff, w1, sym);

Make a function return itself, so that if you need to call it many times without having to repeat the function name. Because this isn’t a common style it is generally frowned upon, I’m always tempted to use it at work for some reason… maybe next April fools.

toString Hack Obfuscated

  1. x=''+self 
  2. j=''
  3. 'd1d7a1712345691a7512d427b1da7d9ab7519a4b721a961721d694'
  4. .split``
  5. .map(_=>j+=`x[0x${_}]+`)
  6. console.log(eval(j+'""'))

Yesterday’s snippet saying something else…

It’s simpler than it looks:

  1. x=''+self 
  2. // becomes "[object Window]"
  3.  
  4. j='' 
  5. // initialize `j` which will be javascript to pass to `eval`
  6.  
  7. 'd1d7a17123456...' 
  8. // this is a list of index values to 
  9. // look up in `x` in hexidecimal so that each 
  10. // index is a single character
  11.  
  12. .split``
  13. // split the index values into an array `[0xe, 0x2 ...`
  14.  
  15. .map(_=>j+=`x[0x${_}]+`)
  16. // map over the index values and write a string like
  17. // this `x[0xe]+x[0x2]+...` into `j`
  18.  
  19. console.log(eval(j+'""'))
  20. // evaluate `j` with an empty string at the end
  21. // `x[0xe]+x[0x2]+""` and log it out
`

toString hack

  1. x=self+''
  2. console.log(
  3.   x[8],x[9],x[6],' ',
  4.   x[3],x[1],x[2],' ',
  5.   x[10],x[4],x[8],' ',
  6.   x[5],x[1],x[11]
  7. )

Hit the “Try it out” and open the console….

Obfuscated Canvas Commands

  1. const oCan = (
  2.   d = document,
  3.   b = d.body,
  4.   canvas = b.appendChild(document.createElement('canvas')),
  5.   c = canvas.getContext('2d'),
  6.   props = [],
  7.   o = {},
  8.   docs = {},
  9.   cmds = [],
  10.   L,
  11.   k,
  12.   du,
  13.   j,
  14.   draw,
  15.   id
  16. ) => {
  17.   ;(onresize = () => {
  18.     canvas.width = innerWidth
  19.     canvas.height = innerHeight
  20.     if (draw) {
  21.       clearTimeout(id)
  22.       id = setTimeout(() => cmds.forEach(v => draw(v)), 500)
  23.     }
  24.   })()
  25.  
  26.   Object.assign(b.style, { margin: 0, height: '100%' })
  27.  
  28.   // longer way: console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(c)));
  29.   for (let i in c) props.push(i)
  30.  
  31.   // make alphabetical since object keys have
  32.   // no order
  33.   props.sort().map(i => {
  34.     L = i.match(/[A-Z]/)
  35.     k = i[0]
  36.     if (L) k += L[0]
  37.     du = 0
  38.     if (o[k]) {
  39.       j = 0
  40.       while (o[k]) k += i[++j]
  41.     }
  42.  
  43.     o[k] =
  44.       (typeof c[i])[0] == 'f'
  45.         ? (...args) => c[i].apply(c, args)
  46.         : v => (c[i] = v)
  47.     docs[i] = k
  48.   })
  49.  
  50.   console.log('docs:', JSON.stringify(docs, null, 2))
  51.  
  52.   return (draw = (s, cmd, currFn, args = [], part, fn, num) => {
  53.     cmd = s.split(/\s+/)
  54.     cmds.push(s)
  55.     c.save()
  56.     for (let i = 0; i < cmd.length; i++) {
  57.       part = cmd[i]
  58.       fn = o[part]
  59.       if (fn && currFn != fn) {
  60.         currFn && currFn.apply(c, args)
  61.         currFn = fn
  62.         args = []
  63.       } else {
  64.         num = parseFloat(part)
  65.         args.push(!isNaN(num) ? num : part)
  66.       }
  67.     }
  68.     currFn && currFn.apply(c, args)
  69.     c.restore()
  70.   })
  71. }
  72.  
  73. const c = oCan()
  74. // `font` & text not suppoted
  75. // make str a function so resize works?
  76. c(`
  77.   fS #ccc
  78.   fR 0 0 400 ${innerHeight}
  79.   fS blue
  80.   fR 40 0 20 20
  81.   gCl difference
  82.   ro .25
  83.   fR 50 0 30 30
  84.   gCl source-over
  85.   fS rgba(200,100,9)
  86.   fR 100 100 40 40
  87.   `)

I’ve had this idea for a long time, never bothered doing it until now. I wrote it in a semi-golfed style for no reason… Anyway, this lets you write canvas code in a strange obfuscated syntax that looks like this:

  1. c(`
  2.   fS #ccc
  3.   fR 0 0 400 ${innerHeight}
  4.   fS blue
  5.   fR 40 0 20 20
  6.   gCl difference
  7.   ro .25
  8.   fR 50 0 30 30
  9.   gCl source-over
  10.   fS rgba(200,100,9)
  11.   fR 100 100 40 40
  12.   `)

This snippet logs out some JSON that shows all the method aliases for the canvas context.

Nonsense Logs

  1. const SPEED = 700;
  2.  
  3. const addKeys = obj => {
  4.   obj.keys = Object.keys(obj)
  5.   return obj
  6. }
  7.  
  8. const wordParts = {
  9.   start: addKeys({
  10.     z: .3,
  11.     zim: .1,
  12.     zz: .1,
  13.     zzz: .1,
  14.     ziz: .05,
  15.     zoo: .1,
  16.     koe: .05,
  17.     kob: .05,
  18.     'cow cow': .1,
  19.     'how ': .02,
  20.     sl: .1,
  21.     ko: .05
  22.   }),
  23.  
  24.   mid: addKeys({
  25.     i: .1,
  26.     oo: .1,
  27.     a: .1,
  28.     e: .3,
  29.     oe: .1,
  30.     ebobe: .1,
  31.     y: .1
  32.   }),
  33.  
  34.   end: addKeys({
  35.     z: .3,
  36.     n: .1,
  37.     t: .05,
  38.     rat: .1,
  39.     '!': .05,
  40.     '?': .05,
  41.     '': .1
  42.   })
  43. };
  44.  
  45. const wordPart = (
  46.     type,
  47.     dupeOdds = .1,
  48.     dupeMax = 8,
  49.     capOdds = .05
  50.   ) => {
  51.  
  52.   let result = '';
  53.   const part = wordParts[type];
  54.   while (result === '') {
  55.     const choice = part.keys[
  56.       Math.floor(Math.random() * part.keys.length)
  57.     ];
  58.     if (Math.random() < part[choice]) {
  59.       result = choice;
  60.       if (Math.random() < dupeOdds) {
  61.         const dupes = Math.round(
  62.           Math.random() * Math.random() * dupeMax
  63.         );
  64.         result = result.repeat(dupes);
  65.       }
  66.     }
  67.   }
  68.   wordPart.accum += result;
  69.  
  70.   if (Math.random() < capOdds) {
  71.     wordPart.accum = wordPart.accum.toUpperCase()
  72.   }
  73.   return wordPart;
  74. }
  75. wordPart.accum  = '';
  76.  
  77. const word = () =>
  78.   wordPart('start')('mid')('end').accum + ' '
  79.  
  80. document.body.style.fontSize="2em";
  81. setInterval(() => {
  82.   document.body.innerHTML += word();
  83.   wordPart.accum = ''
  84. }, SPEED);

Sometimes to entertain myself I will write nonsense style print/log statements. Things like console.log('cowcow'). This snippet generates a variety of these kinds of phrases.

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