Generative Code Review: k.a9 by p1xelfool
This series explores the code that powers generative art in the metaverse. The goal is to break down different approaches to making art with code and understand how different artists are adding unique style to their work. While all pieces that are analyzed in this series have code that lives permanently in the blockchain, it is not meant to encourage the unauthorized use of copyrighted code in copyminted work. You should know that anyone caught stealing artwork is subject to litigation based upon the licenses attached to the artwork.

Artwork title: k.a9
Artist: p1xelfool
Link: https://feralfile.com/artworks/k-a9-khb?fromExhibition=p1x3l-n36
Inspecting the file
The mysteries of how p1xelfool’s unique style is achieved aren’t usually accessible when viewing his work on Hicetnunc because the NFTs are pre-rendered frames converted to a GIF. This offers some advantages to putting live code on chain, but it does not allow us to inspect the underlying code. Fortunately though, p1xelfool has released a project for Feral File’s P1×3L exhibit that runs in-browser. We can review this code to glean some insights in to this excellent work.
There are a couple of standout qualities to p1xelfool’s work that we can immediately detect.
- It is using 8-bit graphics, which is unusual and eye catching. The pixels are massively oversized and have a delightful analog feel to them. There’s a flicker to the way that they change color, and no smooth transition can be found in this work. Is p1xelfool constrained by a specific library or framework that has these limitations, or have they written their program to mimic 8-bit graphics?
- They also appear to be using 3D space. Particles seem to be randomly emitted and a camera is orbiting the scene.
The Source
First thing you see when viewing the source is this little easter egg. Nice touch!
<!--
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒
▒▒▒▒▒▒ ▒▒░ ▒▒ ▒▒▒ ▒▓ ▒▒ ▓▒▒▒▒▒▒ ▒▒▒ ▒▒▒▒ ▒▒▒ ▓▒▒▒▒▒▒▒▒
▒▒▒▒▒▓ ░▒▒ ▒ ▒▒▒ ▒ ▒░▓ ░▒▒▒▓ ▒▒▒▒▒▓ ▒▒▒▒▒▒ ▒▒▒ ▒▒ ▒▒▒ ▒▓ ▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▓ ▓▒▒ ░░░▒ ▒▒░▒ ▒▒▒▒ ░▒▒▒▒▒ ▒░▒▒ ▒▒▒ ▒▒ ░▒▒ ▒▒ ░▒▒▒▒▒▒▒▒
▒▒▒▒▒▒ ░▒▒▒▒▒▒ ▒▒░ ▒ ▒▒▒ ▒▒▒▒▒ ░▒▒▒▒░ ▒▒▒░▒▒ ▒▒▒ ░▒ ▒▒▒ ░▒ ░▒▒▒▒▒▒▒▒
▒▒▒▒▒▒ ▒▒▒▒▒▒▒ ░▒ ▒▒▒ ▒░ ▒░ ▒░ ░▒▒▒▒░▒ ▒░░▒ ▒░░ ▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
!-->
The structure of the assets are familiar. A sketch.js file contains the Javascript, which clues me in that this is a P5JS project. This also sparks many questions, I know that P5 is a very capable framework for everything from vector line-based plotter art to beautifully detailed graphics, but I’ve never seen it stripped down to running in 8-bit mode. I’ve even tried and failed to achieve this effect in the past by running multiple canvas elements and sampling pixels from one and rendered to the other, only to give up when the performance was very low.
Opening the file, I notice that the entire script is 199 lines of code. This is a very impressive achievement for such a complex system. Code doesn’t have to be concise or pretty for generative art, and no one normally notices such details because they have no effect on the quality of the art.
Sketch setup
let t = 0.0;
let pg;
let runners = null;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
pg = createGraphics(192, 108, WEBGL);
frameRate(24);
canvas.imageSmoothingEnabled = false;
this._renderer.getTexture(pg).setInterpolation(NEAREST, NEAREST);
pg.noSmooth();
pg.noFill();
pg.strokeWeight(1.01);
pg.pixelDensity(1);
runners = new ParticleSystem();
}
There’s are big revelations in these few lines of code that help explain the unique look of this artwork.
First of all, the canvas is set to WEBGL
. P5JS supports a few different rendering types, including P2D
(default), SVG
*, and WEBGL
.
*SVG rendering is achieved with the brilliant P5-SVG plugin.
Utilizing WEBGL
turns this sketch in to a 3D experience with a z dimension and camera controls. Now we have a bit of a better idea how the 3D spinning effect is created.
The next thing to note is some interesting and funky manipulation occurring to our canvas. For one, there are actually two canvases, one is called pg
and is instantiated via the createGraphics
method. Its size is much smaller than you would expect, only 192
x 108
. We can assume that this is a way to make big chunky pixels, by emulating old school screens that may have only had a low number of pixels (vs my macbook pro screen that is 3072
x 1920
).
Not to be missed, the frame rate is lowered from the default of 60
to be 24
via the frameRate()
method. This again allows for the classic computer graphics style to be emulated.
It’s at this point that I began to wonder whether these values were arbitrarily selected or based on some legacy machine. A quick Google reveals that the original Atari ran at 160
x192
, so not exactly our size, but close.
Aliasing
canvas.imageSmoothingEnabled = false;
this._renderer.getTexture(pg).setInterpolation(NEAREST, NEAREST);
pg.noSmooth();
By default, the browser will render with anti-aliasing turned on, which usually is desirable. In fact, most generative art in P5JS would not look very good without it. Jagged edges and artifacts would distract from the normally smooth output of the canvas, causing the casual viewer to recoil.
For fun I turned on the anti-aliasing to see what this project would look like, and it wasn’t pretty.
P1xelfool’s trick to turn off anti-aliasing is not documented anywhere that I’ve found, so I have an extra appreciation for the ingenuity.
Drawing the particles
Particle.prototype.display = function () {
this.c = map(this.vel.x, -0.2, 0, 0, 360);
this.ca = map(this.vel.x, -0.2, 0, 0, 230);
pg.stroke(240, 255, this.ca);
pg.point(this.loc.x, this.loc.y, this.loc.z);
let r = random(10);
if (r > 1) {
pg.stroke(240, 255, this.ca);
} else {
pg.stroke(this.c, 255, 255);
}
pg.point(this.loc.x, this.loc.y * -1, this.loc.z * -1);
pg.stroke(this.c, 255, 255);
}
A particle is a 3D point(..)
in P5JS. In this system, a particles velocity appears to effect its color, along with a random chance of them flickering.
The particle system
The particle system is comprised of two main parts. the movers, which are the leading large boxes, and the Particles, which are the trails. Particle instances use velocity vectors to determine their direction and speed. This video does a good job of explaining how to build systems with vectors.
Particle.prototype.run = function () {
let noiseDist = 0.02;
this.sx = noise(this.loc.y, this.loc.x, this.loc.z);
this.sx2 = map(this.sx, 0, 1, -noiseDist, noiseDist);
this.sy = noise(this.loc.x + 10, this.loc.y + 10, this.loc.z + 10);
this.sy2 = map(this.sy, 0, 1, -noiseDist, noiseDist);
this.sz = noise(this.loc.x + 100, this.loc.y + 100, this.loc.z + 100);
this.sz2 = map(this.sy, 0, 1, -noiseDist, noiseDist);
this.acc = createVector(this.sx2, this.sy2, this.sz2);
this.vel.add(this.acc);
this.loc.add(this.vel);
this.vel.limit(2);
this.acc.mult(0);
this.lifespan -= this.killingTime;
}
Particle
instances have noise()
continuously applied to their position, this makes them fan out over time. The also die ⚰️ after a set period of time.
let ParticleSystem = function () {
let move = 0.0;
this.particles = [];
this.loc = createVector();
this.vel = createVector();
this.acc = createVector();
};
ParticleSystem.prototype.add = function () {
this.vel.add(this.acc);
this.loc.add(this.vel);
this.vel.limit(10);
this.acc.mult(0);
this.dist = 75.0;
this.move = sin(radians(t)) * this.dist;
this.rad = 20.0;
this.y = sin(radians(t * 2)) * this.rad;
this.z = cos(radians(t * 2)) * this.rad;
for (let i = 0; i < 3; ++i) {
this.particles.push(
new Particle(this.move * (1 - i * 0.02),
this.y,
this.z));
}
}
The ParticleSystem
appears to track where the spawn point of new particles is, and it follows the eye-catching spiral pattern visible in the artwork. Therefore we can assume that the Particle
really just inherits the initial position from the ParticleSystem
and applies some noise to it to make it deviate over time.
Finally, let’s look at the blink on the mover
which is the large leading particle that swirls around.
ParticleSystem.prototype.movers = function () {
this.dist = 75.0;
this.move = sin(radians(t + 10)) * this.dist;
this.rad = 20.0;
this.y = sin(radians(t * 2 + 10)) * this.rad;
this.z = cos(radians(t * 2 + 10)) * this.rad;
if (frameCount % 2 == 0) {
pg.push();
pg.noFill();
pg.translate(this.move, this.y, this.z);
pg.box(2, 2, 2);
pg.pop();
pg.push();
pg.translate(this.move, this.y * -1, this.z * -1);
pg.box(2, 2, 2);
pg.pop();
} else {
}
}
(frameCount % 2 == 0) {...}
is interesting because it explains why the particles blink on and off like Christmas lights. The modulo makes them flicker, adding a nice analog effect.
In conclusion
There are more secrets within this code that I didn’t cover, including how the particle system makes its shape. However my goal was to get a better understanding of how p1xelfool accomplishes his unique style, and I was able to find some practical tricks that he has employed to make 8-bit style artwork on modern devices.
To see more artwork from p1xelfool, check out his Twitter, Website, or HEN.