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!
23) Moiré
Wikipedia: Moiré
Looks like I accidentally made Moiré patterns with my rays yesterday… so let’s take that and tweak it a bit to remove the shadows and add more colors!
Check out the different blend modes. Difference (default) and screen are my favorites.
let gui;
let params = {
gravity: 0.1, gravityMin: 0, gravityMax: 2.0, gravityStep: 0.01,
sepForce: 1.0, sepForceMin: 0, sepForceMax: 2.0, sepForceStep: 0.01,
friction: 0, frictionMin: 0, frictionMax: 1.0, frictionStep: 0.01,
ballCount: 2, ballCountMin: 1, ballCountMax: 10,
ballSize: 10,
blendMode: [
'difference',
'blend',
'add',
'lightest',
'screen',
'hard_light',
],
rays: 400, raysMin: 0, raysMax: 1000, raysStep: 1,
}
let state;
function setup() {
createCanvas(400, 400);
colorMode(HSL);
state = {
light: {p: createVector(200, 20)},
balls: [],
}
gui = createGuiPanel('params');
gui.addObject(params);
gui.setPosition(420, 0);
}
function draw() {
// Update
while (state.balls.length < params.ballCount) {
state.balls.push({
id: crypto.randomUUID(),
p: createVector(random(400), 20),
v: createVector(random() - 0.5, random() - 0.5),
c: random(255),
});
}
while (state.balls.length > params.ballCount) {
state.balls.shift();
}
for (let ball of state.balls) {
// Gravity
let forces = createVector(0, 0);
forces.y += params.gravity;
// Ball/ball collisions
for (let other of state.balls) {
if (ball.id == other.id) continue;
let offset = p5.Vector.sub(other.p, ball.p);
if (offset.mag() < 1.1 * params.ballSize) {
let force = p5.Vector.normalize(offset);
force.mult(-params.sepForce);
forces.add(force);
}
}
// Walls
if (ball.p.x < params.ballSize || ball.p.x > width - params.ballSize) {
ball.v.x *= -(1 - params.friction);
ball.p.x = max(params.ballSize, min(ball.p.x, width - params.ballSize));
}
if (ball.p.y < params.ballSize || ball.p.y > height - params.ballSize) {
ball.v.y *= -(1 - params.friction);
ball.p.y = max(params.ballSize, min(ball.p.y, height - params.ballSize));
}
// Kinematics
forces.mult(1.0 - params.friction);
ball.v.add(forces);
ball.p.add(ball.v);
}
// Draw
blendMode(DARKEST);
background(0);
blendMode({
blend: BLEND,
add: ADD,
darkest: DARKEST,
lightest: LIGHTEST,
difference: DIFFERENCE,
screen: SCREEN,
overlay: OVERLAY,
hard_light: HARD_LIGHT,
soft_light: SOFT_LIGHT,
dodge: DODGE,
burn: BURN,
}[params.blendMode]);
noFill();
for (let ball of state.balls) {
stroke([ball.c, 100, 50]);
for (let ray = 0; ray < params.rays; ray++) {
let a = TWO_PI * ray / params.rays;
let v = createVector(cos(a), sin(a));
line(
ball.p.x,
ball.p.y,
ball.p.x + 1000 * v.x,
ball.p.y + 1000 * v.y,
);
}
}
blendMode(BLEND);
stroke("black");
for (let ball of state.balls) {
fill([ball.c, 100, 50]);
circle(ball.p.x, ball.p.y, params.ballSize);
}
}
Posts in Genuary 2023:
- Genuary 2023.01: Perfect loop
- Genuary 2023.02: Made in 10 minutes
- Genuary 2023.03: Glitch art
- Genuary 2023.04: Intersections
- Genuary 2023.05: Debug view
- Genuary 2023.06: Steal like an artist
- Genuary 2023.07: Sample a color palette
- Genuary 2023.08: Signed Distance Functions
- Genuary 2023.09: Plants
- Genuary 2023.10: Generative Music
- Genuary 2023.11: Suprematism
- Genuary 2023.12: Tessellation
- Genuary 2023.13: Something you've always wanted to learn
- Genuary 2023.14: Asemic Writing
- Genuary 2023.15: Sine Waves
- Genuary 2023.16: Reflections of a Reflection
- Genuary 2023.17: A grid inside a grid inside a grid
- Genuary 2023.18: Definitely not a grid
- Genuary 2023.19: Black and white
- Genuary 2023.20: Art Deco
- Genuary 2023.21: Persian Carpet
- Genuary 2023.22: Shadows
- Genuary 2023.23: Moiré
- Genuary 2023.24: Textile
- Genuary 2023.25: Yayoi Kusama
- Genuary 2023.26: My kid could have made that
- Genuary 2023.27: In the style of Hilma Af Klint
- Genuary 2023.28: Generative poetry
- Genuary 2023.29: Maximalism
- Genuary 2023.30: Minimalism
- Genuary 2023.31: Break a previous image