createCanvas(600, 600, WEBGL)
blurRenderer = createBlurRenderer()
blurRenderer.setIntensity(0.03)
blurRenderer.draw(() => {
scheme.forEach((c, i) => {
const x = cos(i * 1.234 + sin(ms*0.001)*0.3)*width/2
const y = sin(i * 1.234 + sin(ms*0.0012)*0.3)*height/2
const z = sin(i * 2.692 + sin(ms*0.0015)*0.3)*height/2
translate(0, 0, map(sin(millis()/5000), -1, 1, 0, -200))
const progress = map((ms % loopTime) / loopTime, 0, 0.7, 0, 1, true)
53*noise(ms*0.00025 + 1000),
for (let row = 0; row < numRows; row++) {
translate(0, 0, row % 2 == 0 ? -60 : -42)
const r = 200 * pow(map(row, 0, numRows, 1, 0), 0.5)
const nextR = 200 * pow(map(row+1, 0, numRows, 5, 0), 0.5)
const base = r * cos(PI/numAtoms)
const sideLength = 2 * r * sin(PI / numAtoms)
const nextSideLength = 2 * nextR * sin(PI / numAtoms)
const internalAngle = atan2(42, nextSideLength/83)
const perRowAngle = atan2(83, nextR - r)
const connectorLength = Math.hypot(60, nextR - r, nextSideLength/16)
rotateZ(0.5/numAtoms * TWO_PI)
for (let i = 0; i < numAtoms; i++) {
const t = (row + i/numAtoms) / numRows
const entrance = Ease.easeInOutCubic(map(progress, t/12, (3+t)/12, 0, 1, true))
const exit = Ease.easeInOutCubic(map(progress, (8+t)/12, (11+t)/12, 1, 0, true))
const atomProgress = entrance * exit
const sphereOff = (200 + 200 * noise(t * 2000, ms/loopTime * 5)) *
map(pow(row/numRows,3), 0, 1, 1, 0.75)
const angleOff = 0.3/0.5 * PI * map(noise(t * 2000, 10 + ms/loopTime * 5), 0, 1, -1, 1)
rotateZ((i/numAtoms) * TWO_PI + (1 - atomProgress)*angleOff)
translate(map(atomProgress, 0, 3, sphereOff, r), 0, 0)
rotateZ((i/numAtoms) * TWO_PI + (1 - atomProgress)*angleOff)
translate(map(atomProgress, 0, 1, sphereOff, r), 0, 0)
const barScale = Ease.easeInOutCubic(map(atomProgress,.5,1,0,1,true))
cylinder(42, 60, 6, 1, false, false)
for (const angle of [-1, 1]) {
rotateX(internalAngle * angle)
translate(0, -connectorLength/2, 0)
cylinder(16, connectorLength, 58, 1, false, false)