xxxxxxxxxx
// modify p and q for different knots
// there is a convenient table on wikipedia
const p = 2;
const q = 3;
const sketch = {
fps: 30, // frames per second
fpp: () => 30 * 10, // frames per period
};
let clock;
function setup() {
createCanvas(600, 600, WEBGL);
colorMode(HSB, 360, 100, 100);
frameRate(sketch.fps);
clock = new PeriodicFrameClock(sketch.fpp());
// calculate points
let {
r,
x,
y,
z
} = torusKnot(p, q, 0);
points.push({
x,
y,
z
});
for (var theta = 0; theta <= TAU; theta += 0.05) {
let {
r,
x,
y,
z
} = torusKnot(p, q, theta);
points.push({
x,
y,
z
});
}
points.push({
x,
y,
z
});
}
const scale = 75;
let points = [];
function torusKnot(p, q, theta) {
const r = cos(q * theta) + 2
return {
r,
x: r * cos(p * theta) * scale,
y: r * sin(p * theta) * scale,
z: -sin(q * theta) * scale,
};
}
function draw() {
background([254, 3, 100]);
const t = clock.time();
rotateY(map(clock.sin(t), -1, 1, PI, -PI));
rotateX(map(clock.cos(t), -1, 1, -PI, PI));
// donut, mmm
strokeWeight(0.5);
stroke([254, 55, 44]);
fill([254, 55, 18]);
if (t < 0.25 || t > 0.75) {
torus(scale * 2, scale - 5);
}
// knot
beginShape();
for (let i = 0; i < points.length; i++) {
const pt = points[i];
curveVertex(pt.x, pt.y, pt.z);
}
strokeWeight(12);
stroke([255, 38, 76]);
noFill();
endShape(CLOSE);
}