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

Flun Draw

  1. const canvas = document.createElement('canvas')
  2. const c = canvas.getContext('2d')
  3.  
  4. canvas.width = innerWidth * 2
  5. canvas.height = innerHeight * 2
  6. document.body.append(canvas)
  7. canvas.style.width = innerWidth + 'px'
  8. canvas.style.height = innerHeight + 'px'
  9. c.fillStyle = 'white'
  10. c.fillRect(0, 0, canvas.width, canvas.height)
  11.  
  12. const flun = (
  13.   ax = innerWidth,
  14.   ay = innerHeight,
  15.   r = 0,
  16.   x = 0, y = 0,
  17.   t = 0,
  18.   dt = 0,
  19.   spin = 0,
  20.   spinc = .1,
  21.   rinc = 0,
  22.   col = 'black',
  23.   hist = []
  24. ) => {
  25.  
  26.   const init = () => {
  27.     dt = Math.random() * Math.PI * 2
  28.     r = 0
  29.     rinc = Math.random() * 1
  30.     spinc = Math.random() * .01 - .005
  31.     col = ['black', 'white', 'rgba(0, 0, 0, 0.2)']
  32.       [~~(Math.random() * 3)]
  33.   }
  34.   init()
  35.  
  36.   return () => {
  37.  
  38.     spin += spinc
  39.     if (Math.random() < .005) {
  40.       init()
  41.     } else {
  42.       r += rinc
  43.     }
  44.  
  45.     if (Math.random() < .01) {
  46.       ax = x
  47.       ay = y
  48.       const inside = ax > 0 &&
  49.         ax < canvas.width &&
  50.         ay > 0 &&
  51.         ay < canvas.height
  52.       if (!inside) {
  53.         const p = hist[~~(Math.random() * hist.length)]
  54.         ax = p[0]
  55.         ay = p[1]
  56.       }
  57.       init()
  58.     } 
  59.  
  60.     t += (dt - t) / 22
  61.  
  62.     x = ax + Math.cos(t + spin) * r
  63.     y = ay + Math.sin(t + spin) * r
  64.  
  65.     if (x > 0 && x < canvas.width &&
  66.       y > 0 && y < canvas.height) {
  67.       hist.push([x, y])
  68.     }
  69.  
  70.     c.fillStyle = col
  71.     c.fillRect(x, y, 4, 4)
  72.   }
  73. }
  74.  
  75. const f = flun()
  76.  
  77. setInterval(() => {
  78.   for (let i = 0; i < 20; i++) f()
  79. }, 16)

Just randomly coded this one morning for a short – simple – but never did this exact motion before. It looks surprisingly organic and occasionally draws things that look like faces and other objects

Diagrams 2

  1. const canvas = document.createElement('canvas')
  2. canvas.width = 400
  3. canvas.height = 400
  4. document.body.append(canvas)
  5. document.body.style.background = 'black'
  6. Object.assign(document.body.style, {
  7.   position: 'absolute',
  8.   left: '50%', 
  9.   top: '50%',
  10.   transform: 'translate(-50%, -50%)'
  11. })
  12.  
  13. const ctx = canvas.getContext('2d')
  14. const width = canvas.width;
  15. const height = canvas.height;
  16.  
  17. // --- Global Variables ---
  18. const num = 4;
  19. const smp = new Array(num);
  20. let isMousePressed = false;
  21. let drag = false;
  22. let mouseX = 0;
  23. let mouseY = 0;
  24.  
  25. let theSize, t;
  26. let col = 0;
  27. const alpha = 255;
  28. let curveRes = 0.01;
  29.  
  30. let pan;
  31. const blank = new Int32Array(300 * 400);
  32.  
  33.  
  34. // ===================================================================
  35. //  CLASS AND FUNCTION DEFINITIONS
  36. //  All classes and functions are defined here, before they are called.
  37. // ===================================================================
  38.  
  39. // --- PModel Class (Shape logic) ---
  40. class PModel {
  41.   constructor(p_col) {
  42.     this.pNum = 9;
  43.     this.theColor = p_col;
  44.     this.pLocX = new Float32Array(this.pNum);
  45.     this.pLocY = new Float32Array(this.pNum);
  46.     this.bLocX = new Float32Array(this.pNum);
  47.     this.bLocY = new Float32Array(this.pNum);
  48.     this.bx = new Float32Array(this.pNum);
  49.     this.by = new Float32Array(this.pNum);
  50.     this.down = new Array(this.pNum).fill(false);
  51.     this.outlineColor = convertPColor(0xff0000);
  52.  
  53.     for (let i = 0; i < this.pNum; i++) {
  54.       this.pLocX[i] = this.bLocX[i] = this.bx[i] = Math.random() *
  55.       300; // Start in main area
  56.       this.pLocY[i] = this.bLocY[i] = this.by[i] = Math.random() * 400;
  57.     }
  58.   }
  59.  
  60.   action(pixels) {
  61.     this.outlineColor = this.theColor;
  62.     for (let i = 0; i < this.pNum; i++) {
  63.       if (Math.floor(Math.random() * 300) === 1) {
  64.         if (this.bLocX[i] < 250) {
  65.           drawText(`E-${Math.floor(Math.random() * 11100)}`, this.bLocX[
  66.             i], this.bLocY[i]);
  67.         }
  68.       }
  69.       if (dist(this.bLocX[i], this.bLocY[i], mouseX, mouseY) < 10 && !
  70.         drag) {
  71.         this.outlineColor = convertPColor(0xff0000);
  72.         if (isMousePressed) {
  73.           this.down[i] = true;
  74.           drag = true;
  75.         }
  76.       } else {
  77.         if (!drag) {
  78.           this.down[i] = false;
  79.         }
  80.       }
  81.  
  82.       if (this.down[i]) {
  83.         if (this.bLocX[i] < 250) {
  84.           drawText(`V-${Math.floor(Math.random() * 1100)}`, this.bLocX[i],
  85.             this.bLocY[i]);
  86.         }
  87.         this.outlineColor = convertPColor(0xff0000);
  88.         this.pLocX[i] = mouseX;
  89.         this.pLocY[i] = mouseY;
  90.       }
  91.  
  92.       this.bLocX[i] -= this.bx[i];
  93.       this.bx[i] = ((this.bLocX[i] - this.pLocX[i]) / 17 + this.bx[i]) /
  94.         1.5;
  95.       this.bLocY[i] -= this.by[i];
  96.       this.by[i] = ((this.bLocY[i] - this.pLocY[i]) / 17 + this.by[i]) /
  97.         1.5;
  98.     }
  99.  
  100.     this.ccc(0, 1, 40, 14);
  101.     this.ccc(0, 2, 40, 14);
  102.     this.ccc(0, 3, 40, 14);
  103.     this.ccc(0, 4, 40, 14);
  104.     this.ccc(0, 5, 40, 14);
  105.     this.ccc(0, 6, 40, 14);
  106.     this.ccc(0, 7, 40, 14);
  107.     this.ccc(0, 8, 40, 14);
  108.     this.ccc(1, 2, 40, 14);
  109.     this.ccc(2, 3, 40, 14);
  110.     this.ccc(3, 4, 40, 14);
  111.     this.ccc(4, 5, 40, 14);
  112.     this.ccc(5, 6, 40, 14);
  113.     this.ccc(6, 7, 40, 14);
  114.     this.ccc(8, 7, 40, 14);
  115.     this.ccc(8, 1, 40, 14);
  116.     this.ccc(1, 3, 80, 0);
  117.     this.ccc(3, 5, 80, 0);
  118.     this.ccc(5, 7, 80, 0);
  119.     this.ccc(7, 1, 80, 0);
  120.  
  121.     for (let i = 0; i < this.pNum; i++) {
  122.       if (this.pLocX[i] < 0) this.pLocX[i] += 5;
  123.       if (this.pLocX[i] > 300) this.pLocX[i] -= 5;
  124.       if (this.pLocY[i] < 0) this.pLocY[i] += 5;
  125.       if (this.pLocY[i] > 400) this.pLocY[i] -= 5;
  126.     }
  127.  
  128.     col = this.outlineColor;
  129.     apixel(pixels, this.bLocX[0], this.bLocY[0]);
  130.  
  131.     curveRes = 0.01;
  132.     curvePoint(pixels, this.bLocX[1], this.bLocY[1], this.bLocX[2], this
  133.       .bLocY[2], this.bLocX[3], this.bLocY[3], this.bLocX[2], this
  134.       .bLocY[2]);
  135.     curvePoint(pixels, this.bLocX[3], this.bLocY[3], this.bLocX[4], this
  136.       .bLocY[4], this.bLocX[5], this.bLocY[5], this.bLocX[4], this
  137.       .bLocY[4]);
  138.     curvePoint(pixels, this.bLocX[5], this.bLocY[5], this.bLocX[6], this
  139.       .bLocY[6], this.bLocX[7], this.bLocY[7], this.bLocX[6], this
  140.       .bLocY[6]);
  141.     curvePoint(pixels, this.bLocX[7], this.bLocY[7], this.bLocX[8], this
  142.       .bLocY[8], this.bLocX[1], this.bLocY[1], this.bLocX[8], this
  143.       .bLocY[8]);
  144.  
  145.     curveRes = 0.02;
  146.     col = this.theColor;
  147.     curvePoint(pixels, this.bLocX[1], this.bLocY[1], this.bLocX[0], this
  148.       .bLocY[0], this.bLocX[3], this.bLocY[3], this.bLocX[0], this
  149.       .bLocY[0]);
  150.     curvePoint(pixels, this.bLocX[3], this.bLocY[3], this.bLocX[0], this
  151.       .bLocY[0], this.bLocX[5], this.bLocY[5], this.bLocX[0], this
  152.       .bLocY[0]);
  153.     curvePoint(pixels, this.bLocX[5], this.bLocY[5], this.bLocX[0], this
  154.       .bLocY[0], this.bLocX[7], this.bLocY[7], this.bLocX[0], this
  155.       .bLocY[0]);
  156.     curvePoint(pixels, this.bLocX[7], this.bLocY[7], this.bLocX[0], this
  157.       .bLocY[0], this.bLocX[1], this.bLocY[1], this.bLocX[0], this
  158.       .bLocY[0]);
  159.   }
  160.  
  161.   ccc(indexA, indexB, clength, off) {
  162.     if (dist(this.pLocX[indexA], this.pLocY[indexA], this.pLocX[indexB],
  163.         this.pLocY[indexB]) > clength) {
  164.       this.pLocX[indexA] += (this.pLocX[indexB] - this.pLocX[indexA]) / 6;
  165.       this.pLocY[indexA] += (this.pLocY[indexB] - this.pLocY[indexA]) / 6;
  166.       this.pLocX[indexB] += (this.pLocX[indexA] - this.pLocX[indexB]) / 6;
  167.       this.pLocY[indexB] += (this.pLocY[indexA] - this.pLocY[indexB]) / 6;
  168.     }
  169.     for (let i = 0; i < this.pNum; i++) {
  170.       if (i !== indexA) {
  171.         if (dist(this.pLocX[indexA], this.pLocY[indexA], this.pLocX[i],
  172.             this.pLocY[i]) < clength - off) {
  173.           this.pLocX[indexA] -= (this.pLocX[i] - this.pLocX[indexA]) / 6;
  174.           this.pLocY[indexA] -= (this.pLocY[i] - this.pLocY[indexA]) / 6;
  175.         }
  176.       }
  177.     }
  178.   }
  179. }
  180.  
  181. // --- Panel Class (UI on the right) ---
  182. class Panel {
  183.   constructor() {
  184.     this.h1 = 80;
  185.     this.h2 = 80;
  186.     this.h3 = 80;
  187.     this.h4 = 80;
  188.     this.dh1 = 80;
  189.     this.dh2 = 80;
  190.     this.dh3 = 80;
  191.     this.dh4 = 80;
  192.     this.numsA = 0;
  193.   }
  194.  
  195.   // Static drawing for panel background (called once in setupPanel)
  196.   drawStatic() {
  197.     ctx.fillStyle = "rgb(115,115,115)";
  198.     ctx.fillRect(300, 0, 100, 400);
  199.     ctx.beginPath();
  200.     ctx.moveTo(300, 300);
  201.     ctx.lineTo(400, 400);
  202.     ctx.strokeStyle = "rgb(155,145,105)";
  203.     ctx.stroke();
  204.     /* ctx.strokeStyle = "red";
  205.       for (let i = 0; i < 40; i++) {
  206.           ctx.beginPath(); ctx.moveTo(101, i * 10); ctx.lineTo(400, 20 + i * 20); ctx.stroke();
  207.       }
  208.       ctx.stroke()*/
  209.  
  210.     ctx.strokeStyle = "white";
  211.     ctx.strokeStyle = "rgb(205,205,205)";
  212.     ctx.strokeRect(309.5, 11.5, 82, 111);
  213.     ctx.strokeRect(359.5, 130.5, 32, 21);
  214.     ctx.strokeRect(359.5, 160.5, 32, 21);
  215.     ctx.strokeRect(359.5, 190.5, 32, 21);
  216.   }
  217.  
  218.   action() {
  219.     ctx.strokeStyle = "rgb(135,125,85)";
  220.     ctx.fillStyle = "rgb(165,165,165)";
  221.     ctx.fillRect(310, 10, 80, 110);
  222.     ctx.beginPath();
  223.     ctx.moveTo(301.5, 0);
  224.     ctx.lineTo(301.5, 400);
  225.     ctx.stroke();
  226.  
  227.  
  228.     if (Math.floor(Math.random() * 60) === 1) this.dh1 = Math.random() *
  229.       75 + 5;
  230.     if (Math.floor(Math.random() * 60) === 1) this.dh2 = Math.random() *
  231.       75 + 5;
  232.     if (Math.floor(Math.random() * 60) === 1) this.dh3 = Math.random() *
  233.       75 + 5;
  234.     if (Math.floor(Math.random() * 60) === 1) this.dh4 = Math.random() *
  235.       75 + 5;
  236.  
  237.     this.h1 += (this.dh1 - this.h1) * 0.09;
  238.     this.h2 += (this.dh2 - this.h2) * 0.09;
  239.     this.h3 += (this.dh3 - this.h3) * 0.09;
  240.     this.h4 += (this.dh4 - this.h4) * 0.09;
  241.  
  242.  
  243.  
  244.     ctx.fillRect(310, 130, 10, this.h1);
  245.     ctx.fillRect(320, 130, 10, this.h2);
  246.     ctx.fillRect(330, 130, 10, this.h3);
  247.     ctx.fillRect(340, 130, 10, this.h4);
  248.  
  249.     ctx.fillRect(360, 130, 30, 20);
  250.     ctx.fillRect(360, 160, 30, 20);
  251.     ctx.fillRect(360, 190, 30, 20);
  252.  
  253.     ctx.strokeRect(310, 130, 10, this.h1);
  254.     ctx.fillRect(320, 130, 10, this.h2);
  255.     ctx.strokeRect(330, 130, 10, this.h3);
  256.     ctx.fillRect(340, 130, 10, this.h4);
  257.  
  258.     ctx.strokeRect(360, 130, 30, 20);
  259.     ctx.fillRect(360, 160, 30, 20);
  260.     ctx.fillRect(360, 190, 30, 20);
  261.  
  262.     if (Math.floor(Math.random() * 10) === 1) this.numsA = Math.floor(Math
  263.       .random() * 10000000);
  264.     drawText(`E-${this.numsA}`, 315, 116, "white");
  265.   }
  266. }
  267.  
  268. // --- Main Setup and Loop ---
  269. function setup() {
  270.   ctx.fillStyle = 'black';
  271.   ctx.fillRect(0, 0, width, height);
  272.   theSize = width * height;
  273.   t = 0;
  274.  
  275.   for (let i = 0; i < num; i++) {
  276.     if (i < num / 2) {
  277.       smp[i] = new PModel(convertPColor(0x330000));
  278.     } else {
  279.       smp[i] = new PModel(convertPColor(0xffffff));
  280.     }
  281.   }
  282.   setupPanel();
  283.   addEventListeners();
  284. }
  285.  
  286. function loop() {
  287.   const imageData = ctx.getImageData(0, 0, width, height);
  288.   const pixels = new Uint32Array(imageData.data.buffer);
  289.  
  290.   if (isMousePressed) {
  291.     for (let i = 0; i < 120000 - 300; i++) {
  292.       pixels[blank[i]] = blendC(pixels[blank[i]] << 8, ~pixels[blank[i +
  293.         300]], 40);
  294.     }
  295.   } else {
  296.     for (let i = 0; i < 120000 - 300; i++) {
  297.       pixels[blank[i]] = blendC(~pixels[blank[i]], pixels[blank[i + 300]] |
  298.         0x111111, 150);
  299.     }
  300.   }
  301.  
  302.   if (t < 12) {
  303.     if (t !== 11) {
  304.       for (let i = 400; i < theSize; i++) {
  305.         pixels[i] = blendC(~pixels[i] & 0xDDDDDD, pixels[i - 400], 20);
  306.       }
  307.     } else {
  308.       for (let i = 400; i < theSize; i++) {
  309.         pixels[i] = blendC(0x000000, pixels[i], 50);
  310.       }
  311.     }
  312.     for (let i = 0; i < 120000; i++) {
  313.       pixels[blank[i]] = 0xFFFFFFFF;
  314.     }
  315.   }
  316.   t++;
  317.  
  318.   for (let i = 0; i < num; i++) {
  319.     smp[i].action(pixels);
  320.   }
  321.  
  322.   for (let a = 0; a < num; a++) {
  323.     for (let b = 0; b < num; b++) {
  324.       if (a === b) continue;
  325.       repel(a, b, 0, 0, 120);
  326.       if (Math.floor(Math.random() * 400) === 1) {
  327.         col = convertPColor(0xFFFFFFFF);
  328.         drawLine(pixels, smp[a].bLocX[0], smp[a].bLocY[0], smp[b].bLocX[0],
  329.           smp[b].bLocY[0]);
  330.       }
  331.     }
  332.   }
  333.  
  334.   ctx.putImageData(imageData, 0, 0);
  335.   pan.action();
  336.   ctx.strokeStyle = "white";
  337.   ctx.strokeRect(0.5, 0.5, 399, 399);
  338.   ctx.fillStyle = 'rgba(110, 50, 0, 0.04)'
  339.   ctx.fillRect(300, 0, 100, 400);
  340.   requestAnimationFrame(loop);
  341. }
  342.  
  343.  
  344. // --- Utility & Drawing Functions ---
  345. function repel(ind, ind2, indexA, indexB, clength) {
  346.   if (dist(smp[ind].pLocX[indexA], smp[ind].pLocY[indexA], smp[ind2].pLocX[
  347.       indexB], smp[ind2].pLocY[indexB]) < clength) {
  348.     smp[ind].pLocX[indexA] -= (smp[ind2].pLocX[indexB] - smp[ind].pLocX[
  349.       indexA]) / 2;
  350.     smp[ind].pLocY[indexA] -= (smp[ind2].pLocY[indexB] - smp[ind].pLocY[
  351.       indexA]) / 2;
  352.   }
  353. }
  354.  
  355. function curvePoint(pixels, x1, y1, x2, y2, x3, y3, x4, y4) {
  356.   for (let a = 0; a < 1; a += curveRes) {
  357.     const b = 1 - a;
  358.     const pre1 = a * a * a;
  359.     const pre2 = 3 * (a * a) * b;
  360.     const pre3 = 3 * a * (b * b);
  361.     const pre4 = b * b * b;
  362.     const x = pre1 * x1 + pre2 * x2 + pre3 * x4 + pre4 * x3;
  363.     const y = pre1 * y1 + pre2 * y2 + pre3 * y4 + pre4 * y3;
  364.     apixel(pixels, x, y);
  365.   }
  366. }
  367.  
  368. function blendC(c1, c2, amount) {
  369.   const r1 = c1 & 0xff;
  370.   const g1 = (c1 >> 8) & 0xff;
  371.   const b1 = (c1 >> 16) & 0xff;
  372.   const r2 = c2 & 0xff;
  373.   const g2 = (c2 >> 8) & 0xff;
  374.   const b2 = (c2 >> 16) & 0xff;
  375.   const r = (((amount * (r1 - r2)) >> 8) + r2);
  376.   const g = (((amount * (g1 - g2)) >> 8) + g2);
  377.   const b = (((amount * (b1 - b2)) >> 8) + b2);
  378.   return (0xff000000 | (b << 16) | (g << 8) | r) >>> 0;
  379. }
  380.  
  381. function apixel(pixels, ax, ay) {
  382.   const x = Math.floor(ax);
  383.   const y = Math.floor(ay);
  384.   if (x <= 0 || x >= width - 2 || y <= 0 || y >= height - 2) return;
  385.   const fx = ax - x;
  386.   const fy = ay - y;
  387.   const nfx = 1 - fx;
  388.   const nfy = 1 - fy;
  389.   const loc = x + y * width;
  390.   const loc2 = loc + width;
  391.   const loc3 = loc + 1;
  392.   const loc4 = loc2 + 1;
  393.   pixels[loc] = blendC(col, pixels[loc], Math.floor(nfx * nfy * alpha));
  394.   pixels[loc3] = blendC(col, pixels[loc3], Math.floor(fx * nfy * alpha));
  395.   pixels[loc2] = blendC(col, pixels[loc2], Math.floor(nfx * fy * alpha));
  396.   pixels[loc4] = blendC(col, pixels[loc4], Math.floor(fx * fy * alpha));
  397. }
  398.  
  399. function drawLine(pixels, x1, y1, x2, y2) {
  400.   const dx = x2 - x1;
  401.   const dy = y2 - y1;
  402.   let n = Math.abs(dx) > Math.abs(dy) ? Math.abs(dx) : Math.abs(dy);
  403.   if (n === 0) return;
  404.   const dt = 1.0 / n;
  405.   const dxdt = dx * dt;
  406.   const dydt = dy * dt;
  407.   let x = x1;
  408.   let y = y1;
  409.   while (n-- >= 0) {
  410.     if (x > 1 && x < width - 1 && y > 1 && y < height - 1) {
  411.       apixel(pixels, x, y);
  412.     }
  413.     x += dxdt;
  414.     y += dydt;
  415.   }
  416. }
  417.  
  418. function setupPanel() {
  419.   pan = new Panel();
  420.   pan.drawStatic(); // Draw the static background of the panel once.
  421.   ctx.font = "12px sans-serif";
  422.   let index = 0;
  423.   for (let j = 0; j < 160000; j += 400) {
  424.     for (let i = 0; i < 300; i++) {
  425.       blank[index++] = i + j;
  426.     }
  427.   }
  428. }
  429.  
  430. function dist(x1, y1, x2, y2) {
  431.   const dx = x1 - x2;
  432.   const dy = y1 - y2;
  433.   return Math.sqrt(dx * dx + dy * dy);
  434. }
  435.  
  436. function convertPColor(pColor) {
  437.   const alpha = (pColor & 0xFF000000) >>> 0;
  438.   const red = (pColor & 0x00FF0000) >> 16;
  439.   const green = (pColor & 0x0000FF00);
  440.   const blue = (pColor & 0x000000FF) << 16;
  441.   return (alpha | blue | green | red) >>> 0;
  442. }
  443.  
  444. function drawText(txt, x, y, color = "white") {
  445.   ctx.fillStyle = color;
  446.   ctx.fillText(txt, x, y);
  447. }
  448.  
  449. function addEventListeners() {
  450.   canvas.addEventListener('mousedown', () => {
  451.     isMousePressed = true;
  452.   });
  453.   canvas.addEventListener('mouseup', () => {
  454.     isMousePressed = false;
  455.     drag = false;
  456.   });
  457.   canvas.addEventListener('mouseout', () => {
  458.     isMousePressed = false;
  459.     drag = false;
  460.   });
  461.   canvas.addEventListener('mousemove', (e) => {
  462.     const rect = canvas.getBoundingClientRect();
  463.     mouseX = e.clientX - rect.left;
  464.     mouseY = e.clientY - rect.top;
  465.   });
  466. }
  467.  
  468. // ===================================================================
  469. //  START THE SKETCH
  470. //  This is the final step, ensuring everything above is defined.
  471. // ===================================================================
  472. setup();
  473. requestAnimationFrame(loop);

This is a port of an old Processing experiment from the early 2000s that I ported to JS with Gemini 2.5 pro…

iwrjgnb

  1. const canvas = document.createElement('canvas')
  2. const c = canvas.getContext('2d')
  3.  
  4. canvas.width = innerWidth * 2
  5. canvas.height = innerHeight * 2
  6. canvas.style.scale = '.5 .5'
  7. canvas.style.transformOrigin = '0 0' 
  8.  
  9. c.fillStyle = 'rgba(255, 236, 168, 1)'
  10. c.fillRect(0, 0, canvas.width, canvas.height)
  11. document.body.append(canvas)
  12.  
  13. let width = 300
  14. let height = 300
  15.  
  16. function cell(ox = 0, oy = 0) {
  17.  
  18.   let ax = ox + width / 2
  19.   let ay = oy + height / 2
  20.   let x, y
  21.   let r = width * Math.random()
  22.   let rx = r
  23.   let ry = r
  24.   if (Math.random() < .5) rx *= Math.random()
  25.   if (Math.random() < .5) ry *= Math.random()
  26.   let t = Math.random() * 7
  27.  
  28.   let ti = Math.random() * .1 - .05
  29.   let te;
  30.   let dr = 0
  31.   if (ti > 0) {
  32.     te = t + Math.random() * 7
  33.     dr = 1
  34.   } else {
  35.     te = t - Math.random() * 7
  36.   }
  37.   let rm = 0
  38.   if (Math.random() < .5) rm = Math.random() * 3
  39.  
  40.   return () => {
  41.     x = ax + rx * Math.cos(t)
  42.     y = ay + ry * Math.sin(t)
  43.     if (rm !== 0) {
  44.       rx -= rm;
  45.       ry -= rm
  46.     }
  47.     t += ti
  48.     if ((t > te && dr === 1) || (t < te && dr === 0)) {
  49.       return
  50.     }
  51.     c.fillStyle = 'black'
  52.     c.fillRect(x, y, 2, 2)
  53.  
  54.     if (Math.random() < .5) {
  55.       cls.push(cl(x, y))
  56.     }
  57.   }
  58. }
  59.  
  60. function cl(x, y) {
  61.   let vy = .2 + Math.random() * 2 - 1
  62.   let col = 'rgba(0, 0, 0, 0.08)'
  63.   if (Math.random() < .1) col = 'rgba(0, 178, 227, .3)'
  64.   if (Math.random() < .01) col = 'rgba(255, 0, 0, .3)'
  65.   let vx = 0
  66.   if (Math.random() < .03) {
  67.     vx = 1
  68.     vy = 0;
  69.     col = 'rgba(255, 255, 255, .2)'
  70.   }
  71.   let dead = false;
  72.   return () => {
  73.     if (dead) return
  74.     y += vy
  75.     x += vx
  76.     if (Math.random() < .01) {
  77.       dead = true
  78.     }
  79.     c.fillStyle = col
  80.     c.fillRect(x, y, 2, 2)
  81.   }
  82. }
  83.  
  84. let NUM = 5
  85. let cs = []
  86. let cls = []
  87. for (let j = 0; j < NUM; j++) {
  88.   let yy = Math.random() * innerHeight
  89.   let xx = Math.random() * innerWidth
  90.   let num = 5 + ~~(Math.random() * Math.random() * 10)
  91.   if (Math.random() < .3) num = Math.random() * 50
  92.   for (let i = 0; i < NUM; i++) {
  93.     for (let k = 0; k < num; k++) {
  94.       cs.push(cell(xx, yy))
  95.     }
  96.   }
  97. }
  98.  
  99. function loop() {
  100.   cs.forEach(f => f())
  101.   cls.forEach(f => f())
  102.   requestAnimationFrame(loop)
  103. }
  104. loop()

Just posting more code from recent shorts… more here

GLSL Sierpiński Glitch Texture #3

  1. const vert = `#version 300 es
  2. layout(location = 0) in vec3 position;
  3. out vec2 uv;
  4. void main(void) {
  5.   uv = position.xy * 0.5 + 0.5;
  6.   gl_Position = vec4(position, 1.0);
  7. }
  8. `;
  9.  
  10. const frag1 = `#version 300 es
  11. precision highp float;
  12. uniform float time;
  13. uniform float dx;
  14. uniform float dy;
  15.  
  16. float w2 = 1.0 / float(${innerWidth * 2});
  17. float w10 = 1.0 / (float(${innerWidth * 2}) * 100.); 
  18. float convert = 3.141592653589 / 180.;
  19.  
  20. float sn;
  21. float cs;
  22.  
  23. out vec4 fragColor;
  24.  
  25. void main(void) {
  26.   vec2 uv = gl_FragCoord.xy / vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
  27.  
  28.   float xp = uv.x * float(${innerWidth * 2});
  29.   float yp = (1. - uv.y) * float(${innerHeight * 2});
  30.   int x = 10 | 2;
  31.   int xp2 = int(xp) << 1; 
  32.   float t = mod(float(int(yp) | int(xp + yp * .1) ) * (xp + dx) * (w10), 6.283185307179586);
  33.  
  34.   if (t < 0.) {
  35.     sn = 1.27323954 * t + .405284735 * t * t; 
  36.   } else {
  37.     sn = 1.27323954 * t - 0.405284735 * t * t;
  38.   }
  39.  
  40.   t = mod(float( (xp2 | int(yp + xp * .1 + dy) )) * convert, 6.283185307179586);
  41.  
  42.   t += 1.57079632;
  43.   if (t > 3.14159265) {
  44.     t -= 6.28318531;
  45.   }
  46.   if (t < 0.) {
  47.     cs = 1.27323954 * t + 0.405284735 * t * t;
  48.   } else {
  49.     cs = 1.27323954 * t - 0.405284735 * t * t;
  50.   }
  51.  
  52.   float c1 = 30. * (sn - cs);
  53.  
  54.   if (c1 < 0.) c1 = 255. - c1;
  55.   c1 = float((int(c1) << 4 | int(c1)) & 255) / 255.;
  56.  
  57.   fragColor = vec4(c1, c1, c1, 1.0);
  58. } 
  59. `;
  60.  
  61. const frag2 = `#version 300 es
  62. precision highp float;
  63. in vec2 uv;
  64.  
  65.   // The max kernel size (impacts performance)
  66. #define maxKernel 1.0
  67.  
  68. // The max offset (doesn't impact performance)
  69. #define maxOffset 34.0
  70. uniform sampler2D uTexture; 
  71.  
  72.  
  73. // https://www.shadertoy.com/view/mdGcRh
  74. vec3 fastBlur(vec2 uv, vec2 texel, vec2 kd)
  75. {
  76. float r = kd.x * kd.y;
  77. float rr = 1.0/r;
  78. vec3 col = vec3(0.0);
  79. float a = 1.0;
  80.  
  81. for (float x = -r; x <= r; x += kd.y) {       
  82. for (float y = -r; y <= r; y += kd.y)  {
  83. a++;
  84. vec2 c = uv + vec2(x,y) * texel;
  85. col += texture(uTexture, c + fract(sin(dot(c, vec2(12.9898, 78.233))) * 43758.5453) * texel * kd.y * 2.0 - kd.yy * texel).rgb * (2.0 - distance(vec2(x,y) * rr, vec2(0.0))); 
  86. }
  87. }
  88.  
  89. return col / a;
  90. }
  91.  
  92.  
  93. out vec4 fragColor;
  94. void main(void) {
  95.   vec4 color = texture(uTexture, uv);
  96.   vec4 colorB = texture(uTexture, vec2(uv.x, 1. - uv.y));
  97.   vec3 result = (color.rgb - colorB.rgb) * 1.2;
  98.  
  99.     float amt = .4;
  100.     vec2 texel = vec2(1.0)/ vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
  101.  
  102.     vec2 kd = round(vec2(amt * maxKernel + 1.0, amt * maxOffset + 1.0));
  103.  
  104.     vec3 blur = fastBlur(uv, texel, kd);
  105.  
  106.   fragColor = vec4(result, color.a);
  107. }
  108. `;
  109.  
  110.   const frag3 = `#version 300 es
  111. precision highp float;
  112. in vec2 uv;
  113.  
  114.   // The max kernel size (impacts performance)
  115. #define maxKernel 4.0
  116.  
  117. // The max offset (doesn't impact performance)
  118. #define maxOffset 34.0
  119. uniform sampler2D uTexture; 
  120.  
  121.  
  122. // https://www.shadertoy.com/view/mdGcRh
  123. vec3 fastBlur(vec2 uv, vec2 texel, vec2 kd)
  124. {
  125. float r = kd.x * kd.y;
  126. float rr = 1.0/r;
  127. vec3 col = vec3(0.0);
  128. float a = 1.0;
  129.  
  130. for (float x = -r; x <= r; x += kd.y) {       
  131. for (float y = -r; y <= r; y += kd.y)  {
  132. a++;
  133.       vec2 c = uv + vec2(x,y) * texel;
  134.  
  135.       col += texture(
  136.  
  137.       uTexture, 
  138.  
  139.       c 
  140.       + fract(sin(dot(c, vec2(2.9898, 78.233))) * 13758.5453) * texel * kd.y * 2.4
  141.       - kd.yy * texel
  142.  
  143.       ).rgb * (2.0 - distance(vec2(x,y) * rr, vec2(0.0)));
  144. }
  145. }
  146.  
  147. return col / a;
  148. }
  149.  
  150.  
  151. out vec4 fragColor;
  152. void main(void) {
  153.   vec4 color = texture(uTexture, uv);
  154.  
  155.     float amt = .4;
  156.     vec2 texel = vec2(1.0)/ vec2(float(${innerWidth * 2}), float(${innerHeight * 2}));
  157.  
  158.     vec2 kd = round(vec2(amt * maxKernel + 1.0, amt * maxOffset + 1.0));
  159.  
  160.   vec4 blur = vec4(fastBlur(uv, texel, kd), 1.);
  161.     //1-(1-A)*(1-B)
  162.   vec3 f = 1. - (1. - color.rgb) * (1. - blur.rgb);  
  163.  
  164.  
  165.   fragColor = vec4(f.rgb, 1.);
  166. } 
  167. `;
  168.  
  169.  
  170.  
  171. document.body.style.background = '#000';
  172. const gl = document.body
  173.   .appendChild(document.createElement('canvas'))
  174.   .getContext('webgl2');
  175.  
  176. Object.assign(gl.canvas.style, {
  177.   position: 'absolute',
  178.   left: 0,
  179.   top: 0
  180. });
  181.  
  182. const s = 1;
  183. const verts = new Float32Array([
  184.   -s, -s, 0,
  185.   s, -s, 0,
  186.   -s, s, 0,
  187.   s, s, 0,
  188. ]);
  189.  
  190. const buffer = gl.createBuffer();
  191. gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  192. gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
  193.  
  194. function createShaderProgram(vertexSource, fragmentSource) {
  195.   const vs = gl.createShader(gl.VERTEX_SHADER);
  196.   gl.shaderSource(vs, vertexSource);
  197.   gl.compileShader(vs);
  198.  
  199.   const fs = gl.createShader(gl.FRAGMENT_SHADER);
  200.   gl.shaderSource(fs, fragmentSource);
  201.   gl.compileShader(fs);
  202.  
  203.   const program = gl.createProgram();
  204.   gl.attachShader(program, vs);
  205.   gl.attachShader(program, fs);
  206.   gl.linkProgram(program);
  207.  
  208.   if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  209.     console.error('Could not link program:', gl.getProgramInfoLog(program));
  210.   }
  211.  
  212.   return program;
  213. }
  214.  
  215. const program1 = createShaderProgram(vert, frag1);
  216. const program2 = createShaderProgram(vert, frag2);
  217. const program3 = createShaderProgram(vert, frag3);
  218.  
  219. const framebuffer1 = gl.createFramebuffer();
  220. const framebuffer2 = gl.createFramebuffer();
  221. const texture1 = gl.createTexture();
  222. const texture2 = gl.createTexture();
  223.  
  224. gl.bindTexture(gl.TEXTURE_2D, texture1);
  225. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth, innerHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  226. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  227. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  228. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  229.  
  230. gl.bindTexture(gl.TEXTURE_2D, texture2);
  231. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth, innerHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  232. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  233. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  234. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  235.  
  236. gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer1);
  237. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture1, 0);
  238.  
  239. gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer2);
  240. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture2, 0);
  241.  
  242. const onResize = () => {
  243.   gl.canvas.width = innerWidth * 2;
  244.   gl.canvas.height = innerHeight * 2;
  245.   gl.canvas.style.width = innerWidth + 'px'
  246.   gl.canvas.style.height = innerHeight + 'px'
  247.   gl.viewport(0, 0, innerWidth * 2, innerHeight * 2);
  248.   gl.bindTexture(gl.TEXTURE_2D, texture1);
  249.   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth * 2, innerHeight * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  250.   gl.bindTexture(gl.TEXTURE_2D, texture2);
  251.   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, innerWidth * 2, innerHeight * 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  252. };
  253.  
  254. window.onresize = onResize;
  255. onResize();
  256.  
  257. gl.disable(gl.DEPTH_TEST);
  258.  
  259. let mx = 0;
  260. let my = 0;
  261. let dx = 0;
  262. let dy = 0;
  263.  
  264. window.onpointermove = e => {
  265.   mx = e.clientX;
  266.   my = e.clientY;
  267. };
  268.  
  269. const loop = () => {
  270.  
  271.   dx += (mx * 2 - (innerWidth) - dx) / 8;
  272.   dy += (my * 2 - dy) / 8;
  273.  
  274.   // first pass
  275.   gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer1);
  276.   gl.useProgram(program1);
  277.  
  278.   const mxUniform = gl.getUniformLocation(program1, 'dx');
  279.   gl.uniform1f(mxUniform, dx);
  280.  
  281.   const myUniform = gl.getUniformLocation(program1, 'dy');
  282.   gl.uniform1f(myUniform, dy);
  283.  
  284.   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  285.   const pos1 = gl.getAttribLocation(program1, 'position');
  286.   gl.enableVertexAttribArray(pos1);
  287.   gl.vertexAttribPointer(pos1, 3, gl.FLOAT, false, 0, 0);
  288.   gl.clearColor(0, 0, 0, 1);
  289.   gl.clear(gl.COLOR_BUFFER_BIT);
  290.   gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  291.  
  292.   // second pass
  293.   gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer2);
  294.   gl.useProgram(program2);
  295.   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  296.   const pos2 = gl.getAttribLocation(program2, 'position');
  297.   gl.enableVertexAttribArray(pos2);
  298.   gl.vertexAttribPointer(pos2, 3, gl.FLOAT, false, 0, 0);
  299.   const uTexture = gl.getUniformLocation(program2, 'uTexture');
  300.   gl.uniform1i(uTexture, 0);
  301.   gl.activeTexture(gl.TEXTURE0);
  302.   gl.bindTexture(gl.TEXTURE_2D, texture1);
  303.   gl.clearColor(0, 0, 0, 1);
  304.   gl.clear(gl.COLOR_BUFFER_BIT);
  305.   gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  306.  
  307.   // third pass
  308.   gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  309.   gl.useProgram(program3);
  310.   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  311.   const pos3 = gl.getAttribLocation(program3, 'position');
  312.   gl.enableVertexAttribArray(pos3);
  313.   gl.vertexAttribPointer(pos3, 3, gl.FLOAT, false, 0, 0);
  314.   const u2Texture = gl.getUniformLocation(program3, 'uTexture');
  315.   gl.uniform1i(u2Texture, 0);
  316.   gl.activeTexture(gl.TEXTURE0);
  317.   gl.bindTexture(gl.TEXTURE_2D, texture2);
  318.   gl.clearColor(0, 0, 0, 1);
  319.   gl.clear(gl.COLOR_BUFFER_BIT);
  320.   gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 
  321.  
  322.   requestAnimationFrame(loop);
  323. };
  324. loop();

this old thing was tricky to port to glsl, canvas port was easy (codepen here) – used gpt a bit for glsl version… got it eventually: take a look

// binary // color // filters // glsl // graphics // hacks // hex // javascript // math // webgl

Collatz Conjecture

  1. collatz = n => 
  2.   n % 2 == 0 ? n / 2 : 3 * n + 1
  3.  
  4. iter = (v, i = 10, o = 0) => {
  5.   n = collatz(v)
  6.   console.log(n)
  7.   o < i && iter(n, i, ++o)
  8. } 
  9.  
  10. iter(111, 100)

334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2

snippet.zone /// {s/z}