xxxxxxxxxx
169
const FRAMES = 500;
const QUALITY = 0.25;
const BALL_COUNT = 2;
const LINE_WIDTH = 20;
const OUTLINE_WIDTH = 7;
let SIZE;
let SCALE;
let bg, ball_clr;
function setup() {
colorMode(RGB, 1);
SIZE = min(windowWidth, windowHeight);
// SIZE = 1080;
SCALE = SIZE / 1080;
createCanvas(SIZE, SIZE);
bg = color(1/3, 0, 1);
ball_clr = color(1, 0.5, 0);
}
function generate_shapes() {
let shapes = [];
const count = 5;
for (let i=0; i<count; i++) {
const f = i / count;
shapes = [
shapes,
generate_shape(
f + t,
color(1, 1, 1),
6,
)
];
}
return shapes;
}
function generate_shape(t, clr, wave_count) {
const shape = [];
const count = 700 * QUALITY;
for (let i=0; i<count; i++) {
const f = i / count;
const f_n = (i + 1) / count;
const s = {
kind: "line",
p1: generate_point(f, t, wave_count),
p2: generate_point(f_n, t, wave_count),
lineWidth: LINE_WIDTH * SCALE,
clr,
}
const z = get_z(s);
const shade = lerpColor(bg, ball_clr, ballWave(f, 4));
s.clr = lerpColor(clr, shade, -z * 7.5);
shape.push(s);
}
const outlineback = 0.05;
return [shape, shape.map(line => {
line = structuredClone(line);
line.p1.z -= outlineback;
line.p2.z -= outlineback;
line.clr = bg;
line.lineWidth += OUTLINE_WIDTH * SCALE;
return line;
})];
}
function ballWave(f, p) {
let vals = [];
for (let i=0; i<BALL_COUNT; i++) {
let i_f = i / BALL_COUNT;
const lf = sin((i_f - t) * TAU) / BALL_COUNT * 1/3;
vals.push(pow(sinn(f - t + lf + i_f + 0.25), p * BALL_COUNT * BALL_COUNT))
}
return Math.max(vals)
// return pow(sinn(f * BALL_COUNT + lf + 0.25), p) * 1
}
function generate_point(f, lt, wave_count) {
const ball_wave = ballWave(f, 5);
const wave = sin((f * wave_count + lt) * TAU) * (1/2 + ball_wave) / 8
const r = 0.5
return {
x: cos(f * TAU) * (0.5 + wave) * r,
y: sin(f * TAU) * (0.5 + wave) * r,
z: cos((f * wave_count + lt) * TAU) / 8
};
}
function generate_balls() {
let shapes = [];
const count = BALL_COUNT;
for (let i=0; i<count; i++) {
const f = i / count;
let r = 1/4
const lf = t + f + sin((f + t) * TAU) / BALL_COUNT * 1/3;
shapes.push({
kind: "circle",
p: {
x: cos(lf * TAU) * r,
y: sin(lf * TAU) * r,
z: 0
},
r: 1/10,
clr: color("white"),
})
}
const outlineback = 0.05;
return [shapes, shapes.map(circle => {
circle = structuredClone(circle);
circle.p.z -= outlineback;
circle.clr = ball_clr;
circle.r += OUTLINE_WIDTH / SIZE;
return circle;
})];
}
function get_z(shape) {
const { kind } = shape;
switch(kind) {
case "line": return (shape.p1.z + shape.p2.z) / 2;
case "circle": return shape.p.z;
}
}
let t;
let mx;
let my;
let capture;
function draw() {
t = frameCount / FRAMES;
mx = mouseX / width;
my = mouseY / height;
translate(width / 2, height / 2);
background(bg);
stroke("white");
let shapes = [
generate_shapes(),
generate_balls(),
];
shapes.sort((s1, s2) => get_z(s1) - get_z(s2));
shapes.forEach(l => {
const {kind} = l;
switch(kind) {
case "line": {
let {p1, p2, clr, lineWidth} = l;
strokeWeight(lineWidth);
stroke(clr)
line(p1.x * SIZE, p1.y * SIZE, p2.x * SIZE, p2.y * SIZE);
} break;
case "circle": {
const {p, r, clr} = l;
noStroke();
fill(clr);
circle(p.x * SIZE, p.y * SIZE, r * SIZE);
} break
}
});
}
const sinn = (v) => sin(v * TAU) * 0.5 + 0.5
const cosn = (v) => cos(v * TAU) * 0.5 + 0.5