* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
display: grid;
place-items: center;
}
svg {
width: 75vmin;
height: 75vmin;
overflow: visible;
}
import { SVG } from "https://cdn.skypack.dev/@svgdotjs/svg.js";
import { spline } from "https://cdn.skypack.dev/@georgedoescode/generative-utils";
import gsap from "https://cdn.skypack.dev/gsap@3.7.0";
gsap.registerPlugin(DrawSVGPlugin);
const width = 200;
const height = 200;
const svg = SVG().viewbox(0, 0, width, height).addTo("body");
function mulberry32(a) {
return function () {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
var t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function lerp(position, target, amt) {
return {
x: (position.x += (target.x - position.x) * amt),
y: (position.y += (target.y - position.y) * amt)
};
}
function animate() {
let seed = Math.random() * 1000;
svg.clear();
const random = mulberry32(seed);
const radius = width / 2;
const numPoints = 8;
const basePoints = [];
const lerpPoints = [];
const pointElements = [];
const center = {
x: width / 2,
y: height / 2
};
const angleStep = (Math.PI * 2) / numPoints;
for (let i = 1; i <= numPoints; i++) {
const angle = i * angleStep;
const point = {
x: center.x + Math.cos(angle) * radius,
y: center.y + Math.sin(angle) * radius
};
basePoints.push(point);
lerpPoints.push(lerp({ ...point }, center, 0.375 * random()));
}
basePoints.forEach((p) => {
pointElements.push(
svg
.circle(8)
.cx(p.x)
.cy(p.y)
.fill("#1D1934")
.attr("class", "base-point")
.scale(0).node
);
});
lerpPoints.forEach((p) => {
svg
.circle(8)
.cx(p.x)
.cy(p.y)
.fill("#1D1934")
.attr("class", "lerp-point")
.opacity(0);
});
const path = spline(lerpPoints, 1, true);
svg
.path(path)
.fill("none")
.stroke({
width: 2,
color: "#1D1934"
})
.fill("none");
gsap.to(".base-point", {
scale: 1,
stagger: 0.075,
transformOrigin: "center"
});
for (let i = 0; i < pointElements.length; i++) {
gsap.to(pointElements[i], {
attr: {
cx: lerpPoints[i].x,
cy: lerpPoints[i].y
},
delay: 2
});
}
gsap.set("path", {
drawSVG: 0
});
gsap.to("path", {
duration: 1,
drawSVG: "100%",
delay: 3
});
gsap.to("path", {
stroke: "none",
fill: "#1D1934",
delay: 4
});
gsap.to(".base-point", {
scale: 0,
delay: 4
});
gsap.to("path", {
opacity: 0,
delay: 6
});
setTimeout(() => {
animate();
}, 7000);
}
animate();
This Pen doesn't use any external CSS resources.