xxxxxxxxxx
240
const FRAMES = 1000;
const QUALITY = 1;
const BALL_COUNT = 3;
const LINE_WIDTH = 30;
const OUTLINE_WIDTH = 7;
const THREAD_COUNT = 2;
const WAVE_COUNT = 4;
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 = THREAD_COUNT;
for (let i=0; i<count; i++) {
const f = i / count;
shapes = [
shapes,
generate_shape(
f + t,
color(1, 1, 1),
)
];
}
return shapes;
}
function generate_shape(t, clr) {
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),
p2: generate_point(f_n, t),
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 = 0; //sin((i_f - t) * TAU) / BALL_COUNT * 1/3;
vals.push(pow(sinn(f - t / 3 + lf + i_f + 0.25), p * 5))
}
return Math.max(vals)
// return pow(sinn(f * BALL_COUNT + lf + 0.25), p) * 1
}
function generate_point(f, lt) {
const ball_wave = ballWave(f, 5);
const wave = sin((f * WAVE_COUNT + lt) * TAU) * (0.5 + 1 * 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 / 3 + f;
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.00001;
return [shapes, shapes.map(circle => {
circle = structuredClone(circle);
circle.p.z -= outlineback;
circle.clr = ball_clr;
circle.r += OUTLINE_WIDTH / SIZE;
return circle;
})];
}
const EPS = 0.0001
function generate_darivative(f, lt) {
const p1 = generate_point(f - EPS, lt);
const p2 = generate_point(f + EPS, lt);
const v = createVector(p2.x - p1.x, p2.y - p1.y)
v.normalize();
return {x: v.x, y: v.y };
}
function generate_balls2() {
let shapes = [];
const count = 200;
for (let t_i=0; t_i<THREAD_COUNT; t_i++) {
const tf = t_i / THREAD_COUNT;
for (let i=0; i<count; i++) {
const f = i / count;
let r = 1/4
const lf = f;
const p = generate_point(lf, t + tf);
const deriv = generate_darivative(lf, t + tf);
const norm = {x: deriv.y, y: -deriv.x };
// const angle = atan2(norm.x, norm.y);
const dist = sin((t * 3 + f * 3) * TAU) * 0.025;
const z_offset = cos((t * 3 + f * 3) * TAU) * 0.025 * 3;
const s = {
kind: "circle",
p: {
x: p.x + norm.x * dist,
y: p.y + norm.y * dist,
z: p.z + z_offset,
},
r: 1/150,
norm,
f,
clr: color("white"),
}
shapes.push(s);
}
}
const outlineback = 0.00001;
return [shapes, shapes.map(circle => {
circle = structuredClone(circle);
circle.p.z -= outlineback;
circle.clr = bg; //color(1, 0, 0.5);
circle.r += 0.5 * OUTLINE_WIDTH / SIZE;
const z = get_z(circle);
circle.clr = lerpColor(bg, ball_clr, ballWave(circle.f, 8));
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() {
if (frameCount === 1) {
const capture = P5Capture.getInstance();
capture.start({
format: "webm",
duration: FRAMES,
quality: 1,
framerate: 60,
});
}
t = frameCount / FRAMES;
mx = mouseX / width;
my = mouseY / height;
translate(width / 2, height / 2);
background(bg);
stroke("white");
let shapes = [
generate_shapes(),
generate_balls(),
generate_balls2(),
];
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, norm } = l;
noStroke();
fill(clr);
circle(p.x * SIZE, p.y * SIZE, r * SIZE);
strokeWeight(1)
stroke("black");
// if (norm)
// line(p.x * SIZE, p.y * SIZE, (p.x + norm.x * 0.1) * SIZE, (p.y + norm.y* 0.1) * SIZE)
} break
}
});
}
const sinn = (v) => sin(v * TAU) * 0.5 + 0.5
const cosn = (v) => cos(v * TAU) * 0.5 + 0.5