Inspired again by @sorceror, I present Soap Bubbles aka Fizzy Lifting
v0.5 - static bubbles
// SoapBubbles v0.5 by Scruffynerf
var canvasHue = array(pixelCount)
var canvasSat = array(pixelCount)
var canvasVal = array(pixelCount)
var canvasAge = array(pixelCount)
var canvasType = array(pixelCount)
var height = sqrt(pixelCount) // y axis
var width = sqrt(pixelCount) // x axis
function DrawPixel(x, y, hue, sat, val, special) {
if (x < 0 || x > width-1 || y < 0 || y > height-1) { return }
index = x + y*height
canvasHue[index] = hue
canvasSat[index] = sat
canvasVal[index] = val
canvasAge[index] = 99
canvasType[index] = special
}
function DrawCircle(x0, y0, radius, fill, hue, sat, val, hue2, sat2, val2) {
var x = round(radius);
line = x
originalx = x
originalsat = sat
special = floor(random(3))
if (fill == 1 || fill == 3) {line = 0}
if (fill == 2) {
DrawCircle(x0, y0,radius,1,hue2,sat2,val2)
DrawCircle(x0, y0,radius,0,hue, sat, val)
}
for (xi = line; xi <=originalx; xi++){
if (fill == 3) {
sat = lerp(0,originalsat*.99,(xi)/(originalx))
}
x = xi
var y = 0;
var radiusError = 1 - x;
x0 = round(x0)
y0 = round(y0)
while (x >= y) {
x1 = round(x)
y1 = round(y)
DrawPixel(x1 + x0, y1 + y0,hue, sat, val, special);
DrawPixel(y1 + x0, x1 + y0,hue, sat, val, special);
DrawPixel(-x1 + x0, y1 + y0,hue, sat, val, special);
DrawPixel(-y1 + x0, x1 + y0,hue, sat, val, special);
DrawPixel(-x1 + x0, -y1 + y0,hue, sat, val, special);
DrawPixel(-y1 + x0, -x1 + y0,hue, sat, val, special);
DrawPixel(x1 + x0, -y1 + y0,hue, sat, val, special);
DrawPixel(y1 + x0, -x1 + y0,hue, sat, val, special);
y += .25;
if (radiusError < 0) {
radiusError += 2 * y + 1;
}
else {
x -= .25;
radiusError+= 2 * (y - x + 1);
}
}
}
}
export function beforeRender(delta) {
resetTransform()
scale(width,height)
if (random(1) > .99) {
radius = random(height/4)+2
fill = 3
DrawCircle(random(height-radius*1.5)+radius*.75,random(width-radius*1.5)+radius*.75,radius,fill,random(1),1,1)
}
canvasfade()
}
function canvasfade() {
canvasVal.mutate(fade)
}
/*
function canvasclear() {
canvasHue.mutate(wipe)
canvasSat.mutate(wipe)
canvasVal.mutate(wipe)
}
function wipe(){
return 0
}
*/
function fade(value, index, array){
canvasAge[index] -= random(1)
if (canvasType[index] == 0){
pop = canvasSat[index]
} else if (canvasType[index] == 1) {
pop = 1-canvasSat[index]
} else {
pop = canvasVal[index]
}
if (canvasAge[index] < 30*(pop) ){
canvasSat[index] = canvasSat[index] * .95
return value*canvasSat[index]
} else {
return value
}
}
function lerp(a, b, t) {
return a * (1-t) + b * t
}
export function render2D(index,x,y) {
x = floor(x)
y = floor(y)
pixel = x+y*height
hsv(canvasHue[pixel],canvasSat[pixel],canvasVal[pixel])
}
They have some depth, thanks to the sat changes, and they pop in 3 ways, either inside to out, outside to in, or just fizzle. This version doesn’t have any sliders (yet), nor does it have them rising into view, then popping. (I’ve figured out how I think I can do that, using additional height in the canvas, so we draw ‘offscreen’, then either copy the array up a row, or perhaps use translate to move the viewing window down (which would look like the bubbles were rising) [ way cleaner/faster, but have to handle how to smoothly move back up, or maybe I shift-copy the array only then when I hit bottom, then move back to zero?]
So I just did a straight copy (mutate the various arrays upwards by one row), no translation. I still like the idea, but this works, so… I’m definitely going to use this technique again… ideas come to mind, like the classic ‘road race’…
v0.7 of Soap Bubbles - now more of a Fizzy Lifting pattern
// v0.7 of Soap Bubbles - now more of a Fizzy Lifting pattern - by Scruffynerf
var canvasHue = array(pixelCount*2)
var canvasSat = array(pixelCount*2)
var canvasVal = array(pixelCount*2)
var canvasAge = array(pixelCount*2)
var canvasType = array(pixelCount*2)
var height = sqrt(pixelCount) // y axis
var width = sqrt(pixelCount) // x axis
function DrawPixel(x, y, hue, sat, val, special) {
if (x < 0 || x > width-1 || y < 0 || y > (2*height)-1) { return }
cindex = x + y*height
canvasHue[cindex] = hue
canvasSat[cindex] = sat
canvasVal[cindex] = val
canvasAge[cindex] = 60 + ((2*height)-y)*6
canvasType[cindex] = special
}
function DrawCircle(x0, y0, radius, fill, hue, sat, val, hue2, sat2, val2) {
var x = round(radius);
line = x
originalx = x
originalsat = sat
special = floor(random(3))
if (fill == 1 || fill == 3) {line = 0}
if (fill == 2) {
DrawCircle(x0, y0,radius,1,hue2,sat2,val2)
DrawCircle(x0, y0,radius,0,hue, sat, val)
}
for (xi = line; xi <=originalx; xi++){
if (fill == 3) {
sat = lerp(0,originalsat*.99,(xi)/(originalx))
}
x = xi
var y = 0;
var radiusError = 1 - x;
x0 = round(x0)
y0 = round(y0)
while (x >= y) {
x1 = round(x)
y1 = round(y)
DrawPixel(x1 + x0, y1 + y0,hue, sat, val, special);
DrawPixel(y1 + x0, x1 + y0,hue, sat, val, special);
DrawPixel(-x1 + x0, y1 + y0,hue, sat, val, special);
DrawPixel(-y1 + x0, x1 + y0,hue, sat, val, special);
DrawPixel(-x1 + x0, -y1 + y0,hue, sat, val, special);
DrawPixel(-y1 + x0, -x1 + y0,hue, sat, val, special);
DrawPixel(x1 + x0, -y1 + y0,hue, sat, val, special);
DrawPixel(y1 + x0, -x1 + y0,hue, sat, val, special);
y += .25;
if (radiusError < 0) {
radiusError += 2 * y + 1;
}
else {
x -= .25;
radiusError+= 2 * (y - x + 1);
}
}
}
}
var timer
export var speed
export function sliderSpeed(v){
speed = 400 * v
}
export function beforeRender(delta) {
timer = timer + delta
resetTransform()
scale(width,height)
if (random(1) > .98) {
radius = random(height/4)+2
fill = 3
DrawCircle(random(width-radius*1.5)+radius*.75,random(height)-radius-1+height,radius,fill,random(1),1,1)
}
canvasfade()
if (timer > speed){
timer = timer - speed
canvasscrollup()
}
}
function canvasfade() {
canvasVal.mutate(fade)
}
function canvasscrollup(){
canvasHue.mutate(scrollup)
canvasSat.mutate(scrollup)
canvasVal.mutate(scrollup)
canvasAge.mutate(scrollup)
canvasType.mutate(scrollup)
}
function scrollup(value, index, array){
if (index < (pixelCount*2)-height){
return array[index+height]
}
}
function fade(value, index, array){
if (index < pixelCount){
canvasAge[index] -= random(10 * (100/speed) * ((pixelCount-index)/pixelCount) )
if (canvasType[index] == 0){
pop = canvasSat[index]
} else if (canvasType[index] == 1) {
pop = 1-canvasSat[index]
} else {
pop = canvasVal[index]
}
if (canvasAge[index] < 90*(pop) ){
canvasSat[index] = canvasSat[index] * .95
return value*canvasSat[index]
} else {
return value
}
}
return value
}
function lerp(a, b, t) {
return a * (1-t) + b * t
}
export function render2D(index,x,y) {
x = floor(x)
y = floor(y)
pixel = x+y*(height)
if (pixel >=0 && pixel < pixelCount) {
hsv(canvasHue[pixel],canvasSat[pixel],canvasVal[pixel])
}
}
Absolutely needs more tweaking, and fine tuning, but not bad for a Saturday morning’s LED creation