---
created: 2025-09-01T19:52:00
updated: 2026-07-04T19:48
title: kaitwillows - cyberlucifolium
tags:
- backported
- releases
permalink: cyberlucifolium
---

cyberlucifolium
music/artwork by kaitwillows
september 1st, 2025
© 2025 selfsynthesized
***
> this is the first song of this little "challenge" i'm doing for myself, where i make and release one song per month for 12 months.
>
> i might be cheating a little bit with this first song, as i made it probably over a year ago, and it just lived as an .mp3 on my old phone for a while. every other song will be made as this year goes by.
>
> on the song itself, i don't have a lot to say. it has no lyrics, but as i was making it i thought of the title "cyberlucifolium breathing" as some sort of vague idea of a living plant powered by yellow gloey circuitry.
>
> as i was thinking about a cover art / visualizer, i thought about recreating porter robinson's squiggly style as a 3d rendering engine from scratch (as i'm thinking about it, the idea was verbatim just the start of the [dullscythe](https://youtu.be/oKMNj8v2gKE?si=IhjUMvbT2vGcGaFt) video). except, i kinda wanted it to seem like the lines were "drawn" in real time by a little moving pixel. i got really lazy though and it doesn't really match what was in my head but eh whatever.
>
> also idk the colour scheme with the beige and grey (although it's not super obvious its grey) is kinda nice idk i like it yuh
>
> ALSO lmao sorry i will admit it's probably not produced/mixed/mastered well at all. i think i made it in like, a couple hours, definitely didn't mix it or anything, and it's the first song i ever "mastered" (which was just making sure it was loud enough)
kaitlyn from the future would like to acknowledge that i very much never followed through with the 12 month thing. i have since found out i have executive function issues.
***
# files
## master mixes
final lossy mp3 320kbps:
![[cyberlucifolium.mp3]]
final lossless flac:
![[cyberlucifolium.flac]]
## covers
3000x3000 cover:
![[media/2025-09-01_cyberlucifolium/extra covers/3000x3000.png]]
1920x1080 widescreen cover:
![[media/2025-09-01_cyberlucifolium/extra covers/1920x1080.png]]
## videos
visualizer:
![[media/2025-09-01_cyberlucifolium/visualizer/visuializer.mov]]
vertical trailer:
![[media/2025-09-01_cyberlucifolium/visualizer/trailer.mp4]]
## additional files
### demos
> i released this song i think over a year after i made the song, so all i had was the final mix in mp3 form, so these are just different versions of the master pretty much
cyberlucifolium_breathing (unmastered).mp3:
![[cyberlucifolium_breathing (unmastered).mp3]]
cyberlucifolium (master1) (EVIL version).mp3:
![[cyberlucifolium (master1) (EVIL version).mp3]]
trailers.mp3:
![[media/2025-09-01_cyberlucifolium/demos/trailers.mp3]]
trailer2 is that gonna be better.wav:
![[media/2025-09-01_cyberlucifolium/demos/trailer2 is that gonna be better.wav]]
### visualizer source code
index.html:
![[media/2025-09-01_cyberlucifolium/visualizer/source code/index.html]]
```html
cyberlucifolium
```
pixltrace.js:
![[media/2025-09-01_cyberlucifolium/visualizer/source code/pixltrace.js]]
```js
//
// hiiii welcome to my shit code :p
// it's kinda shit, but feel free to use it for whatever you want,
// for your own projects and whatnot, so long as it's not for hate
//
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
canvasSize = 512;
const drawScale = 3; // so a 128 canvas, projected to 512 (i think idk)
let time = 0;
let depthScale = .01;
let boxScale = 30;
let lineSpeed = 4
const drawLines = true;
const rotateSpeed = 0.02;
initialRotation = 3;
let simplePoints = [
// i found these points by trial and error, a much better way might be to make cubes in blender then copy over their coordinates to here
// or make some way to interactively move each point in the web browser. i'm too lazy to do that though :(
[ 0, 0, -2.5 ],
[ 0, 0.2, -.5],
[ 0, 0.1, 0 ],
[ 0, 0.5, 0.1 ],
[ 0, 0.1, 0 ],
[ -0.08, 0.1, 0.8 ],
[ .5, 0.4, 1.2 ],
[ 0.5, 0, 1.3 ],
[ -0.08, 0.1, 0.8 ],
[ 0.35, -0.15, 1.3 ],
[ 0.20, -0.46, 1.28 ],
[ -0.08, 0.1, 0.8 ],
];
let points = []
function populatePoints(simplePoints) {
thisCounter = 0 // i swear i'll do better
for (let point of simplePoints) {
newPoint = {
x: point[0] * boxScale,
y: point[1] * boxScale,
z: (-point[2] * boxScale) + 30,
links: [thisCounter+1, thisCounter-1]}
if (newPoint.links[0] >= simplePoints.length) {
newPoint.links.splice(0, 1);
}
if (newPoint.links[1] < 0) {
newPoint.links.splice(1, 1);
}
// account for out of bounds shit
points.push(newPoint);
thisCounter ++;
};
};
populatePoints(simplePoints);
// pixl is the little thing that draws the line, you can kinda see
// how at the start of the video (or when you refresh) it's just a
// little line, then speeds up. it worked better in my head. also
// it's named after those little things in super paper mario :3
let pixl = {x: 0, y: 0, z: 0}
let pixlTargetNumber = 1
function rotatePoint(point, degrees) {
x =
point.x * Math.cos(degrees) +
point.y * -Math.sin(degrees) +
0;
y =
point.x * Math.sin(degrees) +
point.y * Math.cos(degrees) +
0;
z =
0 +
0 +
point.z * 1;
point.x = x
point.y = y
point.z = z
return {x: x, y: y, z: z}
}
function projectPoint(point3d) {
let point2d = { // placeholders
x: 0,
y: 0
}
point2d.x = (canvasSize/2) + Math.round(((point3d.y + (point3d.y * point3d.x * depthScale)))) * drawScale;
point2d.y = (canvasSize/2) + Math.round(((point3d.z + (point3d.z * point3d.x * depthScale)))) * drawScale;
return point2d;
}
function movePixl() {
minimumDistance = 2;
speed = 1;
newPoint = find3dSum(
pixl,
find3dScalar(
find3dDelta(points[pixlTargetNumber], pixl),
speed * (1/find3dDistance(pixl, points[pixlTargetNumber]))
)
);
if (find3dDistance(pixl, points[pixlTargetNumber]) < minimumDistance) {
pixlTargetNumber++;
console.log(pixlTargetNumber)
if (pixlTargetNumber >= points.length) {
newPoint = {x: 0*boxScale, y: 0*boxScale, z: 2.5*boxScale}
pixlTargetNumber = 1;
}
}
pixl.x = newPoint.x;
pixl.y = newPoint.y;
pixl.z = newPoint.z;
}
let lastTime = 0;
const fps = 10;
const interval = 1000/fps;
for (let point of points) {
point2d = projectPoint(point);
ctx.fillRect(
point2d.x,
point2d.y,
drawScale,
drawScale
);
rotatePoint(point, initialRotation);
}
function draw(timestamp) {
if (lineSpeed < 300) {
lineSpeed += 0.30;
}
if (timestamp - lastTime >= interval) {
lastTime = timestamp;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgba(63, 63, 63, 1)';
if (drawLines) {
for (let i = 0; i < lineSpeed; i++) {
point2d = projectPoint(pixl);
ctx.fillRect(
point2d.x,
point2d.y,
drawScale,
drawScale
);
movePixl(pixl)
}
}
for (let point of points) {
rotatePoint(point, rotateSpeed);
}
}
requestAnimationFrame(draw);
}
draw()
function find3dDelta (point1, point2) {
return {
x: point1.x - point2.x,
y: point1.y - point2.y,
z: point1.z - point2.z
}
}
function find3dDistance (point1, point2) {
delta = find3dDelta(point1, point2)
return Math.sqrt((delta.x ** 2) + (delta.y ** 2) + (delta.z ** 2))
}
function find3dSum(point1, point2) {
return {
x: point1.x + point2.x,
y: point1.y + point2.y,
z: point1.z + point2.z
};
}
function find3dScalar(point1, scalar) {
return {
x: scalar * point1.x,
y: scalar * point1.y,
z: scalar * point1.z,
};
}
```