Genuary 2023.12: Tessellation

Genuary!

Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.

Let’s do it!

12) Tessellation

Wikipedia: Tessellation (List)

This was not at all the direction I ended to go, but it got really interesting, so I decided to keep it.

What I remember doing years and years ago, I think roughly around the time of Windows 95 (I feel old) or perhaps even pre-Windows was using a tesselation program that would give you a basic shape and then allow you to pull the edges in a way it would propagate to automatically keep the tesselation valid. It was pretty awesome… but I have no idea what it was called any more.

It might have been Shodor on Tessellations.org, or perhaps TesselMania!. Been a while.

In any case, enjoy!


const SIZE = 40;

let gui;
let params = {
  scale: 1.0, scaleMin: 0.25, scaleMax: 3.0, scaleStep: 0.01,
  drawBorders: true,
  applyRotation: true,
  fastFlux: true,
  varyRotations: true,
}

let g;
let buffer;
let bufferMask;
let lastRedrawBuffer;

function setup() {
  createCanvas(400, 400);
  g = createGraphics(width, height);
  
  buffer = createGraphics(2 * SIZE, 2 * SIZE);
  for (let i = 0; i < 100; i++) {
    buffer.fill(
      255 * random(),
      255 * random(),
      255 * random(),
      255 * random()
    );
    buffer.rect(
      random(4 * SIZE) - 2 * SIZE,
      random(4 * SIZE) - 2 * SIZE, 
      random(2 * SIZE),
      random(2 * SIZE)
    )
  }
  redrawBuffer();
  
  bufferMask = createGraphics(2 * SIZE, 2 * SIZE);
  bufferMask.push();
  {
    bufferMask.translate(SIZE, SIZE);
    bufferMask.scale(params.scale);
    bufferMask.stroke("black");
    bufferMask.fill("black");
    ngon(bufferMask, 6, SIZE);
  }
  bufferMask.pop();
 
  gui = createGuiPanel('params');
  gui.addObject(params);
  gui.setPosition(420, 0);
}

function draw() {
  g.background(255);
  
  if (params.fastFlux) {
    drawOneToBuffer();
  } else {
    if (millis() - lastRedrawBuffer > 1000) {
      redrawBuffer();
    }
  }
  
  let masked = buffer.get();
  masked.mask(bufferMask);
  
  g.push(); 
  {
    g.stroke("black");
    g.fill("green");
  
    g.translate(200, 200);
    g.scale(params.scale);
    
    g.stroke("black");
    g.noFill();
    
    if (params.drawBorders) {
      g.stroke("black");
      g.strokeWeight(2);
      ngon(g, 6, SIZE);      
    }
    
    g.push();
    {
      g.translate(-SIZE, -SIZE);
      g.image(masked, 0, 0);
    }
    g.pop();
        
    for (let xd = -10; xd < 10; xd++) {
      for (let yd = -50; yd < 50; yd++) {
        if (xd == 0 && yd == 0) continue;
        
        g.push();
        {
          let rowOffset = abs(yd) % 2 == 1 ? 1.5 * SIZE : 0;
          
          // Major thanks to:
          // https://www.redblobgames.com/grids/hexagons/
          g.translate(
            rowOffset + 3.0 * xd * SIZE, 
            sqrt(3) / 2 * yd * SIZE
          );
          
          if (params.applyRotation) {
            let n = noise(
                xd,
                yd,
                params.varyRotations ? frameCount / 500.0 : 0
            );
            g.rotate(TWO_PI / 6.0 * parseInt(n * 6));
          }
          
          g.push();
          {
            g.translate(-SIZE, -SIZE);
            g.image(masked, 0, 0);
          }
          g.pop();
          
          if (params.drawBorders) {
            g.stroke("black");
            g.strokeWeight(2);
            ngon(g, 6, SIZE);            
          }
        }
        g.pop();
      }
    }
  }
  g.pop();
  
  image(g, 0, 0);
}

function ngon(g, n, size) {
  g.beginShape();
  for (let i = 0; i < n; i++) {
    let x = size * cos(TWO_PI * i / n);
    let y = size * sin(TWO_PI * i / n);
    g.vertex(x, y);
  }
  g.endShape(CLOSE);
}

function redrawBuffer() {
  buffer.background(255);
  for (let i = 0; i < 100; i++) {
    drawOneToBuffer();
  }
  lastRedrawBuffer = millis();
}

function drawOneToBuffer() {
  buffer.fill(
    255 * random(),
    255 * random(),
    255 * random(),
    255 * random()
  );
  buffer.rect(
    random(4 * SIZE) - 2 * SIZE,
    random(4 * SIZE) - 2 * SIZE, 
    random(2 * SIZE),
    random(2 * SIZE)
  );
}

read more...


Genuary 2023.10: Generative Music

Genuary!

Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.

Let’s do it!

10) Generative music

Wikipedia: Generative music

NOTE: Because of limitations in JavaScript autoplaying sound, you must click to start.

NOTE: This currently doesn’t work in Safari. Something funny with the p5.sound addon. I’m working on it.

read more...


Genuary 2023.09: Plants

Genuary!

Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'.

Let’s do it!

9) Plants

read more...


Genuary 2023.05: Debug view

Genuary! Spend a month making one beautiful thing per day, given a bunch of prompts. A month late, but as they say, ’the second best time is now'. Let’s do it! 5) Debug view I like Boids. Here are some Boids with debug vectors drawn showing the three forces acting on them (red to stay away from one another, green to move in the same direction as their friends, blue to move towards the center of their friends).

read more...