function loopArray(array, callback) {
for (let i = array.length - 1; i >= 0; i -= 1) {
callback(array[i], i, array);
return this.array.length;
return this.array[index];
this.array.push(element);
loopArray(this.array, callback);
class SteppableArray extends ArrayWrapper {
static stepFunction(value) {
this.loop(SteppableArray.stepFunction);
class DrawableArray extends ArrayWrapper {
static drawFunction(value) {
this.loop(DrawableArray.drawFunction);
class SpriteArray extends ArrayWrapper {
this.draw = DrawableArray.prototype.draw;
this.step = SteppableArray.prototype.step;
this.centerPosition = createVector();
this.shapeSize = params.shapeSize;
this.noiseMagnitudeFactor = params.noiseMagnitudeFactor;
this.vertexCount = params.vertexCount || Math.floor(0.75 * params.shapeSize);
this.noiseDistanceScale = params.noiseDistanceScale || params.shapeSize / 320;
this.noiseTimeScale = params.noiseTimeScale || 0.005;
this.xNoiseParameterOffset
= createVector(Math.random(), Math.random(), Math.random()).mult(1024);
this.yNoiseParameterOffset
= createVector(Math.random(), Math.random(), Math.random()).mult(1024);
this.noiseTime += this.noiseTimeScale;
const baseDistance = 0.5 * this.shapeSize;
const noiseMagnitude = this.noiseMagnitudeFactor * baseDistance;
for (let i = 0; i < this.vertexCount; i += 1) {
const vertexAngle = (i / this.vertexCount) * TWO_PI;
const cosine = cos(vertexAngle);
const sine = sin(vertexAngle);
const baseX = baseDistance * cosine;
const baseY = baseDistance * sine;
const noiseX = (2 * noise(this.xNoiseParameterOffset.x + this.noiseDistanceScale * cosine, this.xNoiseParameterOffset.y + this.noiseDistanceScale * sine, this.xNoiseParameterOffset.z + this.noiseTime) - 1) * noiseMagnitude;
const noiseY = (2 * noise(this.yNoiseParameterOffset.x + this.noiseDistanceScale * cosine, this.yNoiseParameterOffset.y + this.noiseDistanceScale * sine, this.yNoiseParameterOffset.z + this.noiseTime) - 1) * noiseMagnitude;
vertex(this.centerPosition.x + baseX + noiseX, this.centerPosition.y + baseY + noiseY);
static initializeStatic(frameRate) {
this.frameRate = frameRate;
return this.count % divisor;
getCycleProgressRatio(frequency) {
return ((frequency * this.count) % FrameCounter.frameRate) / FrameCounter.frameRate;
return Math.sin(this.getCycleProgressRatio(frequency) * TWO_PI);
class TimedFrameCounter extends FrameCounter {
constructor(on, duration = 0, completeBehavior = () => { }) {
this.isCompleted = false;
this.completeBehavior = completeBehavior;
this.durationFrameCount = duration;
this.durationFrameCount = duration;
if (this.count > this.durationFrameCount) {
if (this.durationFrameCount)
return constrain(this.count / this.durationFrameCount, 0, 1);
class AbstractShapeColor {
static createAlphaColorArray(c) {
for (let alphaValue = 0; alphaValue <= 255; alphaValue += 1) {
array.push(color(red(c), green(c), blue(c), alpha(c) * alphaValue / 255));
class ShapeColor extends AbstractShapeColor {
constructor(strokeColor, fillColor) {
this.strokeColorArray = AbstractShapeColor.createAlphaColorArray(strokeColor);
this.fillColorArray = AbstractShapeColor.createAlphaColorArray(fillColor);
apply(alphaValue = 255) {
const index = Math.floor(constrain(alphaValue, 0, 255));
stroke(this.strokeColorArray[index]);
fill(this.fillColorArray[index]);
class NoStrokeShapeColor extends AbstractShapeColor {
this.fillColorArray = AbstractShapeColor.createAlphaColorArray(fillColor);
apply(alphaValue = 255) {
const index = Math.floor(constrain(alphaValue, 0, 255));
fill(this.fillColorArray[index]);
class NoFillShapeColor extends AbstractShapeColor {
constructor(strokeColor) {
this.strokeColorArray = AbstractShapeColor.createAlphaColorArray(strokeColor);
apply(alphaValue = 255) {
const index = Math.floor(constrain(alphaValue, 0, 255));
stroke(this.strokeColorArray[index]);
class NullShapeColor extends AbstractShapeColor {
function randomInt(maxInt) {
return Math.floor(Math.random() * maxInt);
p5.disableFriendlyErrors = true;
const IDEAL_FRAME_RATE = 60;
const fontPath = 'Bellefair-Regular.ttf';
function createSignFunction(xMargin, yMargin, textSize, textColor, textBackgroundColor) {
const textAreaWidth = xMargin;
const textAreaHeight = yMargin + textSize * 1.1;
const leftX = width - textAreaWidth;
const topY = height - textAreaHeight;
const baseLineY = height - yMargin;
textBackgroundColor.apply();
rect(leftX, topY, textAreaWidth, textAreaHeight);
const title = 'Generative Something ' + getCurrentISODate() + ' - FAL';
text(title, leftX, baseLineY);
function getCurrentISODate() {
const dateTime = new Date().toISOString();
return dateTime.substring(0, dateTime.indexOf('T'));
currentFont = loadFont(fontPath);
const canvasSideLength = Math.min(windowWidth, windowHeight);
createCanvas(canvasSideLength, canvasSideLength);
frameRate(IDEAL_FRAME_RATE);
unitLength = Math.min(width, height) / 640;
unitSpeed = unitLength / IDEAL_FRAME_RATE;
strokeWeight(Math.max(1, 1 * unitLength));
backgroundColor = color(252);
currentFontSize = 14 * unitLength;
textFont(currentFont, currentFontSize);
sign = createSignFunction(270 * unitLength, 20 * unitLength, currentFontSize, new NoStrokeShapeColor(color(0)), new NoStrokeShapeColor(backgroundColor));
frameCounter = new TimedFrameCounter(true, 13 * IDEAL_FRAME_RATE, () => { noLoop(); });
background(backgroundColor);
noiseShape = new NoiseShape({
shapeSize: 200 * unitLength,
vertexCount: Math.floor(320 * unitLength),
noiseDistanceScale: random(0.3, 1.5),
noiseMagnitudeFactor: 2.2,
noiseTimeScale: random(0.001, 0.005),
noiseShape.centerPosition.set(0.5 * width, 0.5 * height);
colorMode(HSB, 360, 100, 100, 100);
hsbColor = color(0, 100, 45, 7);
hsbColor = color(120, 100, 45, 6);
hsbColor = color(240, 100, 40, 6);
noiseShapeColor = new NoFillShapeColor(hsbColor);
frameCounter.resetCount();
function mousePressed() {