Get In Touch
[email protected]

Creative Code

Where art and code meet.

In the future, I’d like to incorporate creative code into client work to solve specific problems, preferrably mixed with live exhibits or events. Combine this with my game design abilities and I could help create really awe-inspiring experiences!

Projects on page: Sea of Shapes, Palette Generator, Shader Sampler, Sol Lewitt, Architecture, Organic Rectangles, Color Stumbler, Negative Space, Concentric Blitzkrieg, Color Matcher, No Computer, and Chromatic Abberation.

Sea of Shapes
Sea of Shapes

Observing individual variations in a symphony of shapes.

[code language=”javascript”]

//This work is licensed under a Creative Commons Non-Commercial 4.0 International License
var colors = [];
var waves = [];
var wavesNum = 20;
var rOff = 0;
var xSpacing, ySpacing;
var maxSize = 30;
var fps = 60;

var testColor;

function setup() {
createCanvas(800, 800);

frameRate(fps);
colors = [
color(“#002535”),
color(“#003851”),
color(“#f57e7e”),
color(“#bfd2d9”),
color(“#3b89ac”),
];
shuffle(colors, true);

var longestSide = false;
xSpacing = round(width / wavesNum);
ySpacing = round(height / wavesNum);
waves = make2DArray(xSpacing, ySpacing);

for (i = 0; i < wavesNum; i++) { for (j = 0; j < wavesNum; j++) { randomColorNumber = round(random(1, colors.length - 1)); waves[i][j] = new Wave(colors[randomColorNumber]); } } noStroke(); } function draw() { background(colors[0]); for (i = 2; i < wavesNum - 1; i++) { for (j = 2; j < wavesNum; j++) { waves[i][j].display(xSpacing * i, ySpacing * j, PI, 0); } } } class Wave { constructor(color) { this.color = color; } display(xPos, yPos, start, stop) { rOff = sin(frameCount * 0.00003); var radius = sin((xPos + yPos) * rOff); radius *= radius; radius *= maxSize*1.15; fill(this.color); arc(xPos, yPos, radius * 2, radius * 2, start, stop); } } function make2DArray(cols, rows) { let arr = new Array(cols); for (let i = 0; i < arr.length; i++) { arr[i] = new Array(rows); } return arr; } } function getColor(aColor) { r = aColor._array[0]; g = aColor._array[1]; b = aColor._array[2]; a = aColor._array[3]; newColor = color(r, g, b, a); return newColor; } function subStep(gradient, steps) { return floor(gradient * steps) / steps; } [/code] [/ohio_text][vc_empty_space height="1vh" el_class="vc_hidden-xs vc_hidden-sm"][ohio_text text_typo="null"]

View Live Code in a new tab

Palette Generator
Palette Generator

Pseudo-random number generator turned color palette generator.

[code language=”javascript”]

//This work is licensed under a Creative Commons Non-Commercial 4.0 International License
let img = [];
var imgNumber = 0;

let pixelArray = [];
var fps = 60;
var dimensions = 800;
var t = 0;

var rando = 0;
var dark = false;

var imageIndex = 0;

function getImageFromASite() {
// var rand = round(random(0, 3));
// console.log(rand);
imageIndex = (imageIndex + 1) % 4;
if (imageIndex == 0) {
return loadImage(“https://picsum.photos/” + dimensions);
} else if (imageIndex == 1) {
return loadImage(
“https://source.unsplash.com/random/” +
dimensions +
“x” +
dimensions +
“sig=${Math.random()/?flower”
);
} else if (imageIndex == 2) {
return loadImage(
“https://source.unsplash.com/random/” +
dimensions +
“x” +
dimensions +
“sig=${Math.random()/?illustration”
);
} else {
return loadImage(
“https://source.unsplash.com/random/” +
dimensions +
“x” +
dimensions +
“sig=${Math.random()/?fruit”
);
}
}

function preload() {
//If two images are loaded here, they will be the same
img.push(getImageFromASite());
}

function setup() {
pixelDensity(1);
createCanvas(dimensions, dimensions);
frameRate(fps);
noStroke();
refresh();
}

function getNextImageNumber() {
imgNumber = (imgNumber + 1) % 2;
console.log(“Img number is now: ” + imgNumber);
return imgNumber;
}

function refresh() {
//If another image has been loaded, get the next one
if (img.length > 1) imgNumber = getNextImageNumber();

console.log(“Loading image: ” + imgNumber);
image(img[imgNumber], 0, 0, dimensions, dimensions);

loadPixels();
fill(pixels[0], pixels[1], pixels[2], 255 / 2);
pixelArray = pixels;
updatePixels();
//todo:: Check if the average value is dark or light and swap dark and light mode accordingly
// if (round(random(0, 1)) == 1) dark = true;
// console.log(“dark is: ” + dark);
rando = round(random(0, 3));

if (img.length == 1) {
img.push(getImageFromASite());
console.log(
“Added another image to img array. length is now: ” + img.length
);
} else {
imgNumber = getNextImageNumber();
console.log(“Splicing next image into: ” + imgNumber);
img.splice(imgNumber, 1, getImageFromASite());

//Flip back to the previously loaded image for draw()
imgNumber = getNextImageNumber();
}
t = 0;
console.log(“Ready to DRAW”);
console.log(“Pixels in Array: ” + pixelArray.length / 4);
console.log(“pixels in canvas: ” + dimensions * dimensions);
}

var lineWidth = 2;

function draw() {
image(img[imgNumber], 0, 0, dimensions, dimensions);

for (row = 0; row < dimensions; row++) { var widthIndex; if (t > (pixelArray.length / 4) * 0.5) {
// When you effectively hit the max
widthIndex = (pixelArray.length / 4 – t) * 8;
//console.log(widthIndex);
} else {
widthIndex = ((t * 2) % pixelArray.length) * 4;
}
var value =
(pixels[widthIndex + 0] +
pixels[widthIndex + 1] +
pixels[widthIndex + 2]) /
3;
var colorIndex = ((t * 2) % pixelArray.length) * 2;
lineColor = color(
pixelArray[colorIndex + 0],
pixelArray[colorIndex + 1],
pixelArray[colorIndex + 2],
255 * 0.95
);
fill(lineColor);
var mappedWidth;
if (!dark) mappedWidth = map(value, 0, 255, 0, width);
else mappedWidth = map(value, 0, 255, width, 0);

if (rando == 0) {
ellipse(0, row, mappedWidth * 3, lineWidth);
} else if (rando == 1) {
ellipse(height, row, mappedWidth * 3, lineWidth);
} else if (rando == 2) {
ellipse(row, 0, lineWidth, mappedWidth * 3);
} else {
ellipse(row, height, lineWidth, mappedWidth * 3);
}
// strokeWeight(2);
// stroke(lineColor);
// line(0, row, mappedWidth, row);
t++;
if (t > pixelArray.length / 4) {
console.log(“t: ” + t);
t = 0;
refresh();
console.log(“REFRESH!”);
}
}
}

function keyReleased() {
if (key == “s” || key == “S”) saveCanvas(gd.timestamp(), “png”);
}

[/code]

Shader Sampler
Shader Sampler

Unity Shaders Sampler

Sol Lewitt
Sol Lewitt

My take on Sol Lewitt's evenly spaced points.

Architecture
Architecture

Capturing the feeling of architectural photography in motion.

[code language=”javascript”]

//This work is licensed under a Creative Commons Non-Commercial 4.0 International License
let colors;

var structureCount = 100;
var minDepth = 10;
var structures = [];

var fps = 60;
var xOff = 0;

function setup() {

createCanvas(windowHeight, windowHeight, WEBGL);

structureCount = random(20, 60);

colors = [
color("#060606"),
color("#1B9AAA"),
color("#DDDBCB "),
color("#F5F1E3 "),
color("#FFFFFF"),
];
shuffle(colors, true);
frameRate(fps);

background(colors[0]);
for (j = 0; j < structureCount; j++) {
randomColorNumber = round(random(1, colors.length - 1));
newColor = color(colors[randomColorNumber]);
newStrokeColor = color(colors[(randomColorNumber + 1) % colors.length]);
randomHeight = (height * 1.2) / structureCount;
randomWidth = noise(xOff) + j * 10;
randomDepth = minDepth;
structures[j] = new Structure(
randomWidth,
randomHeight,
randomDepth,
newColor,
newStrokeColor
);
xOff += 0.1;
}}

function draw() {
background(colors[0]);
translate(0, -height * 0.6, 0);

ambientLight(255);
directionalLight(255, 0, 0, 100, 20, 0);
for (var i = 0; i < structureCount; i++) {
translate(0, randomHeight, 0);
structures[i].display((frameCount * 0.01) % fps, i);
}}

class Structure {
constructor(w, h, d, color, strokeColor) {
this.w = w;
this.h = h;
this.d = d;

this.color = color;
this.strokeColor = strokeColor;
}

display(yRotation, index) {
push();
fill(this.color);
stroke(colors[0]);
strokeWeight(0.8);

var rOff = cos(frameCount * 0.004);
var rotation = (sin(index * rOff * 0.2))*1.3;
rotation *= rotation;
rotateY(rotation + index*2);
box(this.w, this.h, rotation*400 + minDepth*index);
pop();
}
}
[/code]

Organic Rectangles
Organic Rectangles

The synchronized swimming of rectangles.

[code language="javascript"]

//This work is licensed under a Creative Commons Non-Commercial 4.0 International License

var fps = 60;

var pieCount;
var xCount, yCount;
var rhombtangles = [];
var radius = 25;
var spacingBetweenShapes;
var widthCropping, heightCropping;

let colors = [];

var asdf;

var tlOff = 0;
var trOff = 0;
var brOff = 0;
var blOff = 0;
var heightFactor = 1.614;

let timer = 5000;
let nextChange = timer; //syncs the timer and change rate

function setup() {
rectMode(RADIUS);
createCanvas(windowWidth, windowHeight);
colors = [
color("#ECAAA7"),
color("#F17273"),
color("#D85265"),
color("#B9203F"),
color("#F6F5F5"),
color("#1E3A58"),
color("#1C3147"),
];

pixelDensity(1);
frameRate(fps);
noStroke();

restart();
}

function restart() {
shuffle(colors, true);

widthCropping = width * 0.2;
heightCropping = height * 0.1;
spacingBetweenShapes = radius / 2;
spacingBetweenShapes = 4;

radius = random(4, 100);
spacingBetweenShapes = random(2, radius*0.5);
heightFactor = random(0.4, 1.614*2);
console.log("radius:" + radius);
console.log("spacing:" + spacingBetweenShapes);
console.log("Height Diff: " + heightFactor);

xCount = round(
(width - widthCropping * 2 - radius) / (radius * 2 + spacingBetweenShapes)
);
yCount = round(
(height - heightCropping * 2 - radius * heightFactor) /
(radius * heightFactor * 2 + spacingBetweenShapes)
);

if(yCount <= 0 || xCount <= 0)
{
console.log("========x or yCount was 0, trying again========");
restart();
return;
}

console.log("xCount: " + xCount);
console.log("yCount: " + yCount);

rhombtangles = make2DArray(xCount, yCount);

for (i = 0; i < xCount; i++) {
for (j = 0; j < yCount; j++) {
randomColorNumber = round(random(1, colors.length - 1));
rhombtangles[i][j] = new rhombtangle(radius, colors[randomColorNumber]);
}
}
}

function draw() {
background(20);

background(colors[0]);
fill(colors[1]);

// tlOff += 0.01;
trOff = 0.01;
brOff += 0.02;
blOff += 0.03;

for (i = 0; i < xCount; i++) {
for (j = 0; j < yCount; j++) {
rhombtangles[i][j].display(
i * (radius * 2 + spacingBetweenShapes) +
widthCropping +
radius +
spacingBetweenShapes,
j * (radius * heightFactor * 2 + spacingBetweenShapes) +
heightCropping +
radius * heightFactor +
spacingBetweenShapes,
i,
j
);
}
}

if (millis() > nextChange) {
nextChange = millis() + timer;
restart();
//console.log(`time elapsed: ${round(millis() / 1000)}`);
}

class rhombtangle {
constructor(radius, color) {
this.radius = radius;
this.color = color;
}

display(x, y, i, j) {
//tlOff = sin(frameCount * 0.00003);
tlOff = sin(frameCount * 0.03 + x + y);
//tlOff = sin((x + y) * tlOff);
tlOff *= tlOff;
tlOff *= this.radius;

// trOff = cos(frameCount * 0.0003);
// trOff = sin((x + y) * trOff);
trOff = cos(frameCount * 0.03 + x + y);
trOff *= trOff;
trOff *= this.radius;

// brOff = sin(frameCount * 0.00003);
// brOff = sin((x + y) * brOff);
brOff = cos(frameCount * 0.03 + x + y);
brOff *= brOff;
brOff *= this.radius;

// blOff = sin(frameCount * 0.00003);
// blOff = cos((x + y) * blOff);
blOff = cos(frameCount * 0.03 + x + y);
blOff *= blOff;
blOff *= this.radius;

//fill(this.color);
rect(
x,
y,
this.radius + 1,
this.radius * heightFactor + 1,
tlOff,
trOff,
brOff,
blOff
//noise(blOff) * this.radius * 2
);
}
}

function make2DArray(cols, rows) {
let arr = new Array(cols);
for (let i = 0; i < arr.length; i++) {
arr[i] = new Array(rows);
}
return arr;
}

function keyReleased() {
if (key == "s" || key == "S") saveCanvas(gd.timestamp(), "png");
}
[/code]

Color Stumbler
Color Stumbler

Stumble into a 3 color palette.

[code language="javascript"]

var mouseMoveChange = true;
var $saturation = 1;
var $sat1 = 100;
var $sat2 = 100;
var $sat3 = 100;
var $lightness = 100;
var $lightnessOffset = 50;

var $backgroundColor;
var $textColor;
var $thirdColor;
var $pageX = 0;
var $pageY = 0;
var $color1 = 0;
var $color2 = 120;
var $color3 = 240;
var $colorDist1 = 0;
var $colorDist2 = 120;
var $colorDist3 = 240;

//Spacebar Lock colors
$(window).keypress(function (e) {
if (e.key === ' ' || e.key === 'Spacebar') {
// ' ' is standard, 'Spacebar' was used by IE9 and Firefox < 37
e.preventDefault()
mouseMoveChange = !mouseMoveChange;

var onOff;
if (mouseMoveChange) {
onOff = "Off";
} else {
onOff = "On";
}
document.querySelector('.colorLock').innerHTML = onOff;
}
})

$(window).keypress(function (e) {
if (e.key === 'r') {
randomizeDistances();
}
})

$(window).keypress(function (e) {
if (e.key === 's') {
randomizeSaturation();
}
})

$(window).keypress(function (e) {
if (e.key === 'c') {
var copyText = document.querySelector('.color1').innerHTML + 
document.querySelector('.color2').innerHTML + 
document.querySelector('.color3').innerHTML;
copyToClipboard(copyText);
/* Alert the copied text */
alert("Copied:" + copyText);
}
})

$(window).keypress(function (e) {
if (e.key === 'h') {
$("div.hud").toggleClass("d-none");
}
})

//Mousewheel Saturation - Firefox
$(window).bind('DOMMouseScroll', function (e) {
if (e.originalEvent.detail < 0 && $lightnessOffset > 0) {
$lightnessOffset -= 2;
} else if (e.originalEvent.detail > 0 && $lightnessOffset < 100) {
$lightnessOffset += 2;
}

document.querySelector('.brightness').innerHTML = Math.round(100 - $lightnessOffset);
updateColors();

//prevent page fom scrolling
return false;
});

//Mousewheel Saturation - Chromebone
window.addEventListener('mousewheel', function (e) {

if (e.wheelDelta > 0 && $lightnessOffset > 0) {
$lightnessOffset -= 2;
} else if (e.wheelDelta < 0 && $lightnessOffset < 100) {
$lightnessOffset += 2;
}

document.querySelector('.brightness').innerHTML = Math.round(100 - $lightnessOffset);
updateColors();
});

var $maxLightness = 100;

function copyHex() {

}

//Get colors based on mouse position
$(document).mousemove(function (e) {
var $width;
var $height;
if (mouseMoveChange) {
$width = ($(document).width()) / 360;
$height = ($(document).height()) / $maxLightness;
$pageX = parseInt(e.pageX / $width, 10);
$pageY = parseInt(e.pageY / $height, 10);
}

updateColors();
});

function copyToClipboard(text) {
var dummy = document.createElement("textarea");
// to avoid breaking orgain page when copying more words
// cant copy when adding below this code
// dummy.style.display = 'none'
document.body.appendChild(dummy);
//Be careful if you use texarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard
dummy.value = text;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}

function hslToHex(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
const toHex = x => {
const hex = Math.round(x * 255).toString(16);
return hex.length === 1 ? '0' + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}

function updateColors() {
$color1 = ($pageX + $colorDist1) % 360;
$color2 = ($pageX + $colorDist2) % 360;
$color3 = ($pageX + $colorDist3) % 360;
$lightness = $pageY + $lightnessOffset;

$backgroundColor = "hsl(" + ($color1) + "," + ($sat1 * $saturation) + "%," + ($pageY) +
"%)";
$textColor = "hsl(" + ($color2) + "," + ($sat2 * $saturation) + "%," + (100 - $lightnessOffset) + "%)";
$thirdColor = "hsl(" + ($color3) + "," + ($sat3 * $saturation) + "%," + (100 - $lightnessOffset) + "%)";
$("body").css("background-color", $backgroundColor);
$("body").css("color", $textColor);
$("h1").css("color", $textColor);
$(".accentBar").css("background-color", $thirdColor);
$(".ui-state-default").css("color", $textColor);
$(".ui-state-default").css("background", $backgroundColor);
$(".ui-state-default").css("border-color", $thirdColor);
$(".ui-widget-header").css("background", $backgroundColor);
$(".ui-widget-content").css("background", $textColor);
$(".ui-widget-content").css("border-color", $thirdColor);
$("svg").css("fill", $textColor);
document.querySelector('.color1').innerHTML = "'" + hslToHex($color1, $sat1 * $saturation, $pageY) + "',";
document.querySelector('.color2').innerHTML = "'" + hslToHex($color2, $sat2 * $saturation, 100 - $lightnessOffset) + "',";
document.querySelector('.color3').innerHTML = "'" + hslToHex($color3, $sat3 * $saturation, 100 - $lightnessOffset) + "'";
}

function randomizeDistances() {
$maxRange = 360;
$colorDist1 = (Math.floor(Math.random() * ($maxRange + 1)));
$colorDist2 = (Math.floor(Math.random() * ($maxRange + 1)));
$colorDist3 = (Math.floor(Math.random() * ($maxRange + 1)));
$("#slider1").slider('value', $colorDist1);
document.querySelector('#custom-handle1').innerHTML = $colorDist1;
$("#slider2").slider('value', $colorDist2);
document.querySelector('#custom-handle2').innerHTML = $colorDist2;
$("#slider3").slider('value', $colorDist3);
document.querySelector('#custom-handle3').innerHTML = $colorDist3;
updateColors();
}

function randomizeSaturation() {
$maxRange = 100;
$sat1 = (Math.floor(Math.random() * ($maxRange + 1)));
$sat2 = (Math.floor(Math.random() * ($maxRange + 1)));
$sat3 = (Math.floor(Math.random() * ($maxRange + 1)));
$("#slider4").slider('value', $sat1);
document.querySelector('#custom-handle4').innerHTML = $sat1;
$("#slider5").slider('value', $sat2);
document.querySelector('#custom-handle5').innerHTML = $sat2;
$("#slider6").slider('value', $sat3);
document.querySelector('#custom-handle6').innerHTML = $sat3;
updateColors();
}

$(function () {
var handle = $("#custom-handle1");
$("#slider1").slider({
range: "max",
min: 0,
max: 360,
value: 0,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$colorDist1 = ui.value;
handle.text(ui.value);
$("#custom-handle1.ui-state-default").css("color", $backgroundColor);
$("#custom-handle1.ui-state-active").css("background", $textColor);
$("#custom-handle1.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(function () {
var handle = $("#custom-handle2");
$("#slider2").slider({
range: "max",
min: 0,
max: 360,
value: 120,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$colorDist2 = ui.value;
handle.text(ui.value);
$("#custom-handle2.ui-state-default").css("color", $backgroundColor);
$("#custom-handle2.ui-state-active").css("background", $textColor);
$("#custom-handle2.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(function () {
var handle = $("#custom-handle3");
$("#slider3").slider({
range: "max",
min: 0,
max: 360,
value: 240,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$colorDist3 = ui.value;
handle.text(ui.value);
$("#custom-handle3.ui-state-default").css("color", $backgroundColor);
$("#custom-handle3.ui-state-active").css("background", $textColor);
$("#custom-handle3.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(function () {
var handle = $("#custom-handle4");
$("#slider4").slider({
range: "max",
min: 0,
max: 100,
value: 100,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$sat1 = ui.value;
handle.text(ui.value);
$("#custom-handle1.ui-state-default").css("color", $backgroundColor);
$("#custom-handle1.ui-state-active").css("background", $textColor);
$("#custom-handle1.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(function () {
var handle = $("#custom-handle5");
$("#slider5").slider({
range: "max",
min: 0,
max: 100,
value: 100,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$sat2 = ui.value;
handle.text(ui.value);
$("#custom-handle1.ui-state-default").css("color", $backgroundColor);
$("#custom-handle1.ui-state-active").css("background", $textColor);
$("#custom-handle1.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(function () {
var handle = $("#custom-handle6");
$("#slider6").slider({
range: "max",
min: 0,
max: 100,
value: 100,
create: function () {
handle.text($(this).slider("value"));
},
slide: function (event, ui) {
$sat3 = ui.value;
handle.text(ui.value);
$("#custom-handle1.ui-state-default").css("color", $backgroundColor);
$("#custom-handle1.ui-state-active").css("background", $textColor);
$("#custom-handle1.ui-state-active").css("border-color", $backgroundColor);
updateColors();
}
});
});

$(window).on('load', function () {
document.querySelector('.brightness').innerHTML = Math.round($lightnessOffset);
randomizeDistances();
randomizeSaturation();
updateColors();
});
[/code]

https://caseyweeks.com/palpal/ (only works on desktop)    

Negative Space
Negative Space

An exploration of the shapes between shapes.

[code language="javascript"]

//This work is licensed under a Creative Commons Non-Commercial 4.0 International License

var fps = 60;

var rhombtangles = [];
var radius = 25;

let colors = [];

var tlOff = 0;
var trOff = 0;
var brOff = 0;
var blOff = 0;
var heightFactor = 1.614;

let timer = 3000;
let nextChange = timer; //syncs the timer and change rate

function setup() {
rectMode(RADIUS);
createCanvas(windowHeight, windowHeight);
colors = [
color("#B9203F"),
color("#F6F5F5"),
color("#1C3147"),
];

pixelDensity(1);
frameRate(fps);
noStroke();

restart();
}

function restart() {
shuffle(colors, true);

radius = width * 0.71;
for (var i = 0; i < 4; i++) {
randomColorNumber = round(random(1, colors.length - 1));
rhombtangles[i] = new rhombtangle(radius, colors[randomColorNumber]);
}
}

function draw() {
background(20);

background(colors[0]);
fill(colors[1]);

tlOff += 0.03;
trOff += 0.01;
brOff += 0.02;
asdfOff += 0.01;
blOff += 0.015;

var thingy = 1;

for (i = 0; i < 4; i++) {
if (i == 0) {
thingy = sin(frameCount*0.001);
rhombtangles[i].display(0, 0, i,thingy);
}

if (i == 1) {
thingy = cos(frameCount*0.002);
rhombtangles[i].display(width, 0, i,thingy);
}

if (i == 2) {
thingy = cos(frameCount*0.003);
rhombtangles[i].display(0, height, i,thingy);
}

if (i == 3) {
thingy = sin(frameCount*0.004);
rhombtangles[i].display(width, height, i,thingy);
}
}

if (millis() > nextChange) {
nextChange = millis() + timer;
restart();
}}

var asdfOff = 0;

class rhombtangle {
constructor(radius, color) {
this.radius = radius;
this.color = color;
}

display(x, y, i, thingy) {
tlOff = blOff = sin(frameCount * 0.008);
tlOff *= tlOff;
tlOff *= this.radius;

trOff = abs(cos(frameCount * 0.02));
trOff *= radius;
var asdf = width * 0.5;

brOff = sin(frameCount * 0.03);
brOff = sin(brOff);
brOff *= brOff;
brOff *= this.radius;

blOff = sin(frameCount * 0.01);
blOff *= blOff;
blOff *= this.radius;rect(x, y, radius*thingy, radius*thingy, tlOff, trOff, brOff, blOff);
}
}
[/code]

Concentric Blitzkrieg
Concentric Blitzkrieg

Circles and Bursts in Canvas Sketch.

[code language="javascript"]

const canvasSketch = require('canvas-sketch');
const random = require('canvas-sketch-util/random');
const math = require('canvas-sketch-util/math');
const colorUtils = require('canvas-sketch-util/color');

let colors = ["#99B898", "#FECEAB", "#FF847C", "#E84A5F", "#2A363B"];
let currentColors = [];
let backgroundNumber;
let lineNumber;

const setupColors = () => {
    backgroundNumber = Math.floor(random.range(0, colors.length));
    for (let i = 0; i < colors.length; i++) {
        if (i == backgroundNumber) continue;
        currentColors.push(colors[i]);
    }
}
const randCol = () => {
    let rand = Math.floor(random.range(0, currentColors.length));
    return currentColors[rand];
}

const settings = {
    dimensions: [1080, 1080],
    animate: true
};

const averagePointSize = 30;
const sketch = ({context, width, height}) => {
    setupColors();
    lineNumber = Math.floor(random.range(0, currentColors.length));
    const agents = [];
    const iterations = 60;
    let maxLineWidth = averagePointSize * 0.4;

    for (let i = 0; i < iterations; i++) {
        const x = random.range(0, width);
        const y = random.range(0, height);

        agents.push(new Agent(x, y, random.range(averagePointSize / 1.618, averagePointSize * 2)));
    }

    return ({context, width, height}) => {
        context.fillStyle = colors[backgroundNumber];
        context.fillRect(0, 0, width, height);

        for (let i = 0; i < agents.length; i++) {
            const agent = agents[i];
            for (let j = i + 1; j < agents.length; j++) {
                const other = agents[j];

                const dist = agent.pos.getDistance(other.pos);

                const maxDistance = 200;
                if (dist > maxDistance) continue;

                //context.lineWidth = 20;
                let distancePercent = math.mapRange(dist, 0, maxDistance, 0, 1);
                context.save();
                context.lineWidth = math.mapRange(dist, 0, maxDistance, maxLineWidth, 0);
                context.beginPath();
                context.moveTo(agent.pos.x, agent.pos.y);
                context.lineTo(other.pos.x, other.pos.y);
                context.strokeStyle = currentColors[lineNumber];
                context.stroke();
                context.restore();
            }
        }

        agents.forEach(agent => {
            agent.update();
            agent.draw(context);
            agent.wrap(width, height);
        });
    };
};

canvasSketch(sketch, settings);

class Vector {
    constructor(x, y, radius) {
        this.x = x;
        this.y = y;
    }

    getDistance(v) {
        const dx = this.x - v.x;
        const dy = this.y - v.y;
        return Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
    }
}

const speed = 1;

class Agent {
    constructor(x, y, radius) {
        this.pos = new Vector(x, y);
        this.vel = new Vector(random.range(-1, 1), random.range(-1, 1));
        this.radius = radius;

        this.color = randCol();
        this.strokeColor = randCol();
        this.strokeWeight = random.range(0, averagePointSize);
    }

    bounce(width, height) {
        if (this.pos.x <= 0 || this.pos.x >= width) this.vel.x *= -1;
        if (this.pos.y <= 0 || this.pos.y >= height) this.vel.y *= -1;
    }

    wrap(width, height) {
        if (this.pos.x < 0) this.pos.x = width;
        if (this.pos.x > width) this.pos.x = 0;
        if (this.pos.y < 0) this.pos.y = height;
        if (this.pos.y > height) this.pos.y = 0;
    }

    update() {
        this.pos.x += this.vel.x * speed * 2;
        this.pos.y += this.vel.y * speed;
    }

    draw(context) {

        context.save();

        context.fillStyle = this.color;
        context.fillStyle = "rgba(255, 255, 255, 0)";
        context.strokeStyle = this.strokeColor;
        context.translate(this.pos.x, this.pos.y);
        context.beginPath();
        context.arc(0, 0, this.radius, 0, Math.PI * 2);
        context.fill();

        context.restore();
    }

}

[/code]

Color Game
Color Game

Live coding a playdough-controlled game.

At Dreamhack, I made a playdough color-matching game using MaKey-MaKey to promote game development at the Society of Play booth. The game required players to match the playdough colors to the colors on the screen, and convention-goers could compete for fastest color-toucher.

No Computer
No Computer

Controlling each pixel of a font.

[code language="javascript"]

// This is a modification of: 
// http://www.generative-gestaltung.de/2/sketches/?01_P/P_3_2_5_01
//
// Generative Gestaltung – Creative Coding im Web
// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018
// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni
// with contributions by Joey Lee and Niels Poldervaart
// Copyright 2018
//
// http://www.generative-gestaltung.de
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* Animated type using loadPixels() method to get font area
*
* MOUSE
* position x/y : affect randomness
*
* KEYS
* A-Z : type letters
* Arrow up/down : increase/decrease point density
* CONTROL : save png
*
* CONTRIBUTED BY
* [Joey Lee](http://jk-lee.com)
*/
//'use strict';

var font;

var textTyped = 'NO';
var drawMode = 2;
var fontSize = 500;
var padding = 10;
var nOff = 0;
var pointDensity = 5;

var colors;

var paths;
var textImg;

var pixelImage;

var newColorsTimer = 2000;
var t = 0;

function preload() 
{
font = loadFont('Kelson Sans Bold.otf');
brown = loadImage('brownHeart.png');
tan = loadImage('tanHeart.png');
orange = loadImage('orangeHeart.png');
}

function setup() {
pixelDensity(1);
createCanvas(500, 500);
frameRate(25);
rectMode(CENTER);
frameRate(10);
//075352
//colors = [color("#106968"), color("#1e847f"), color("#ecc19c"), color("#075352")];
colors = [color("#E9E5C8"), color("#5D233C"), color("#E99D47"), color("#72C8BB")];
pixelDensity(1);

shuffle(colors, true);
t = newColorsTimer;
setupText();
}

function setupText() {
shuffle(colors, true);
// create an offscreen graphics object to draw the text into
fontSize = round(height*0.65);
textImg = createGraphics(round(fontSize*2.5), round(fontSize*2));
textImg.pixelDensity(1);
textImg.background(255);
textImg.textFont(font);
textImg.textSize(fontSize);
textImg.text(textTyped, round(width*0.5-fontSize*0.63), round(height*0.5+fontSize*0.35));
textImg.loadPixels();
noStroke();
}

function draw() {
background(colors[3]);

nOff++;

for (var y = textImg.height; y > 0; y -= pointDensity) {
for (var x = textImg.width; x > 0; x -= pointDensity) {
//for (var x = 0; x < textImg.width; x += pointDensity) {

// Calculate the index for the pixels array from x and y
var index = (x + y * textImg.width) * 4;
//console.log(index);
// Get the red value from image
var r = textImg.pixels[index];

if (r < 128) 
{
if (drawMode == 2)
{
push();
translate(x, y);

var w = noise((x - nOff) / 10, (y + nOff * 0.1) / 10) * 20;
var h = noise((x - nOff) / 10, (y + nOff * 0.1) / 10) * 10;

var num = noise(x / 10, (y + nOff) / 10);

if (num < 0.6) 
{
fill(colors[0]);
//image(tan, 0, 0, w, w);
} 
else if (num < 0.7) 
{
fill(colors[1]);
//image(brown, 0, 0, w, w);
} 
else 
{
fill(colors[2]);
//image(orange, 0, 0, w, w);
}

//ellipse(0, 0, w, w); // rect() is cool too
//triangle(0,0, 0+w, 0+w, 0+h, 0-h);
arc(0, 0, w, w, PI, TWO_PI);
pop();
}
}
}
}
//noLoop();

//t+= millis();
if(millis() > t)
{
setupText();
t = millis() + newColorsTimer;
}
//console.log(t);

}

function keyPressed() {
if (keyCode === CONTROL) saveCanvas(gd.timestamp(), 'png');

if (keyCode === DELETE || keyCode === BACKSPACE) {
textTyped = textTyped.substring(0,max(0,textTyped.length - 1));
setupText();
}
if (keyCode === ENTER || keyCode === RETURN) {
textTyped += '\n';
setupText();
}
if (keyCode === DOWN_ARROW) {
pointDensity--;
if (pointDensity < 4) pointDensity = 4;
}
if (keyCode === UP_ARROW) {
pointDensity++;
}

}

function keyTyped() {
if (keyCode >= 32){
textTyped += key;
setupText();
}
}

[/code]

Chromatic Abberation
Chromatic Abberation

Circles riding a sinewave.

[code language="javascript"]

var spacing = 50;
var size = 30;
var xOff = 0;

var fps = 60;
function setup() {
createCanvas(500, 500);
frameRate(fps);

blendMode(ADD); // Additive blend mode

pg = createGraphics(500, 500);
pixelAmount = width;
pg.noStroke();
pg.fill(255);

noiseRange = 10; // How far move each channel (how much to scale the noise)
noiseTime = 0; // Continuously increasing time value for noise calculations
noiseSpeed = 0.01; // `noiseTime` addend for each frame

// Noise offsets per axis per channel
noiseOffsetRX = random(100);
noiseOffsetRY = random(100);
noiseOffsetGX = random(100);
noiseOffsetGY = random(100);
noiseOffsetBX = random(100);
noiseOffsetBY = random(100);

function draw() {
xOff += 0.1;
// Normal drawing operations here, all prefixed with `pg.`
pg.clear(); // Using `clear` instead of `background`
clear();
background(0);
//pg.circle(width / 2, height / 2, 300); // Arbitrary drawing op

var cols = round(width / spacing);
var rows = round(height / spacing);

var stuff = false;
for (var col = 1; col < cols; col++) {
for (var row = 1; row < rows; row++) {
var asdf = sin(row + xOff) * size + size;
if (row % 2 == 1 && col % 2 == 1) {
if (stuff) {
//pg.circle(col * spacing, row * spacing, asdf);
pg.arc(
col * spacing,
row * spacing,
asdf * 0.5,
asdf * 0.5,
HALF_PI + sin(xOff),
PI + HALF_PI - cos(xOff)
);
} else {
pg.arc(
col * spacing,
row * spacing,
asdf * 0.5,
asdf * 0.5,
TWO_PI + sin(xOff),
PI - cos(xOff)
);
}
} else {
if (stuff) {
//pg.circle(col * spacing, row * spacing, asdf);
pg.arc(
col * spacing,
row * spacing,
asdf * 0.5,
asdf * 0.5,
PI + HALF_PI + sin(xOff),
TWO_PI + HALF_PI - cos(xOff)
);
} else {
pg.arc(
col * spacing,
row * spacing,
asdf * 0.5,
asdf * 0.5,
PI + sin(xOff),
TWO_PI - cos(xOff)
);
}
}
stuff = !stuff;
}
}

//pg.rect(width / 2, height / 2, size, size);

// Make it spaz out on mouseDown
// if (mouseIsPressed) {
// noiseTime += noiseSpeed * 100;
// } else {
// noiseTime += noiseSpeed;
// }

// Post-processing with rendered image
// Note that this is the actual point of this example
// All the "noise" business is just to have the channels moving, for effect
// The XY values of each `image` can just as easily be set manually

tint(255, 0, 0); // Tint red
image(pg, noiseFor(noiseOffsetRX), noiseFor(noiseOffsetRY)); // Render image to screen
tint(0, 255, 0); // Tint green
image(pg, noiseFor(noiseOffsetGX), noiseFor(noiseOffsetGY)); // Render image to screen
tint(0, 0, 255); // Tint blue
image(pg, noiseFor(noiseOffsetBX), noiseFor(noiseOffsetBY)); // Render image to screen

// Get the perlin noise for the current `noiseTime` plus the given `offset`.
// Result is mapped to the `noiseRange`.
function noiseFor(offset) {
return map(noise(noiseTime + offset), 0, 1, -noiseRange, noiseRange);
}

[/code]