DEV Community

Dominic Myers
Dominic Myers

Posted on • Originally published at drmsite.blogspot.com on

2

Op Art with p5

My Dad and I both love Op art, and he recently forwarded an email from Tumblr with this link. It piqued my interest as I'm playing with p5 an awful lot at the minute in my spare time as you'll see from previous posts.

So I got to it but clocked that there might be an issue in terms of masking the squares which make up the image. A little judicious playing with Gimp meant that I knew the graphic would be made up of multiple squares. The squares either started with a black or yellow background and they changed after a delay. To get around the issue of masking, I opted to use createGraphics() and then embed that graphic in the main body of the image using the image() function. I ended up making a simple error though, but Stack Overflow came to my rescue, and I'm quite pleased with the result.

The code, which is also up on GitHub and as a single file on JSFiddle:


class Tile {
  constructor(p5, x, y, dimension, row, delay) {
    this.p5 = p5;
    this.x = x;
    this.y = y;
    this.dimension = dimension;
    this.delay = delay;
    this.onFirst = row % 2;
    this.on = p5.color(255, 184, 0);
    this.off = p5.color(26, 17, 16);
    this.diameter = Math.sqrt(Math.pow(dimension, 2) * 2)
    this.pg = p5.createGraphics(dimension, dimension)
    this.pg.noStroke();
  }
  update() {
    if (this.delay === 0) {
      if (this.diameter < 0) {
        this.diameter = Math.sqrt(Math.pow(this.dimension, 2) * 2);
        this.onFirst = !this.onFirst;
        this.delay = 120;
      } else {
        this.diameter -= 1;
      }
    } else {
      this.delay -= 1;
    }
    return this.draw();
  }
  draw() {
    this.pg.fill(this.onFirst ? this.off : this.on);
    this.pg.rect(0, 0, this.dimension, this.dimension);
    this.pg.fill(this.onFirst ? this.on : this.off);
    this.pg.circle(this.dimension / 2, this.dimension / 2, this.diameter);
    return this.pg;
  }
}

new p5(p5 => {
  const rows = 14;
  const columns = 14;
  const dimension = 40;
  const framerate = 20;
  const tiles = [];
  const delay = 30;
  p5.setup = () => {
    p5.createCanvas(columns * dimension, rows * dimension);
    for (let row = 0; row < rows; row++) {
      for (let column = 0; column < columns; column++) {
        tiles.push(new Tile(
          p5,
          column * dimension,
          row * dimension,
          dimension,
          row,
          column % 2 ? ((rows - row) * 5) + 80 : row * 5
        ));
      }
    }
  };
  p5.draw = () => {
    p5.background(200);
    tiles.forEach((tile) => {
      p5.image(tile.update(), tile.x, tile.y);
    });
  };
});
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay