xxxxxxxxxx
173
// Submission for @Sableraph's Birb's Nest weekly challenge
// CAW CAW CAW HONK
// Discord: https://discord.com/invite/hzsn3UHxbw
// Theme: Blend
// palettes from: https://coolors.co/
const PALETTES = [
["ff6d00","ff7900","ff8500","ff9100","ff9e00","240046","3c096c","5a189a","7b2cbf","9d4edd"],
["ff6700","ebebeb","c0c0c0","3a6ea5","004e98","272635","141115","4c2b36"],
["fff275","ff8c42","ff3c38","a23e48","6c8ead"],
["540d6e","ee4266","ffd23f","3bceac","0ead69"],
["ffbc42","d81159","8f2d56","218380","73d2de"],
["#000000","#14213d","#fca311","#e5e5e5","#ffffff"],
["011627","fdfffc","2ec4b6","e71d36","ff9f1c"],
["ffbe0b","fb5607","ff006e","8338ec","3a86ff"],
["9b5de5","f15bb5","fee440","00bbf9","00f5d4"],
["#FF8800", "#00FF88", "#8800FF", "#0088FF"],
]
.map(p => p.map(c => c[0] !== "#" ? "#" + c : c))
// fix for coolors hexcodes not having a '#'
// PARAMETERS
const GRADIENT_COUNT = 50; // 100 is max (unless you change max_grad_count in shader.frag)
const WAVE_COUNT = 5;
const SPREAD_COLORS = true;
const APPEAR_ANIMATION = false;
const BLEND_PALETTES_ANIMATION = false;
const NOISE = 0.002;
// RENDER
const LOOP_LENGTH = 10000; // ms
// CONTROLS
const MOUSE_Y_PALETTES = false;
const MOUSE_X_TIME = false;
function mouseClicked() {
randomPalette();
}
// press 1 for 4k screenshot
function keyPressed() {
if (keyCode === 49) {
const size = 1024 * 4;
resizeCanvas(size, size, WEBGL);
scene(t);
save();
windowResized();
}
}
// SETUP
let theShader;
function preload(){
theShader = loadShader('shader.vert', 'shader.frag');
}
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
}
function windowResized(){
resizeCanvas(windowWidth, windowHeight);
}
// SKETCH
let palettesIndex=0;
function randomPalette() {
palettesIndex = floor(random() * PALETTES.length);
}
let t;
function draw() {
t = fract(millis() / LOOP_LENGTH); // t value loops between 0 - 1
if (MOUSE_X_TIME) {
let mX = (mouseX / width);
t = mX
}
if (MOUSE_Y_PALETTES) {
let mY = (mouseY / height);
palettesIndex = floor(mY * PALETTES.length);
}
scene(t);
}
function scene(t) {
const palettes = PALETTES.map(p => p.map(c => color(c)._array))
// convert to [r, g, b] array
const count = APPEAR_ANIMATION
? (GRADIENT_COUNT - 3) * invCosn(t) + 3
: GRADIENT_COUNT;
const len = floor(count);
const gradients = Array(len).fill().map((_,i) => {
const f = i / count;
const wave = invCosn(f * WAVE_COUNT + t * 2);
const r = wave * 0.25 + 0.125;
return {
x: 0.5 + cos(f * TWO_PI) * r,
y: 0.5 + sin(f * TWO_PI) * r,
angle: f,
range: invCosn(t * 2),
color: getColor(palettes, i, f),
}
});
const grads = gradients.map(
({x, y, angle, range}) => [x, y, angle, range]
).flat();
const clrs = gradients.map(
({color: [r,g,b] }) => [r, g, b]
).flat();
theShader.setUniform("grads", grads);
theShader.setUniform("colors", clrs);
theShader.setUniform("grad_count", count);
theShader.setUniform("noise", NOISE);
theShader.setUniform("t", t);
theShader.setUniform("resolution", [width, height]);
shader(theShader);
rect(0,0,width,height);
}
const getColor = (palettes, i, f) => {
const get = (colors) => colors[
SPREAD_COLORS
? i % colors.length
: floor(colors.length * f)
];
if (BLEND_PALETTES_ANIMATION) {
let bt = fract(millis() / LOOP_LENGTH / 5);
// seperate t value for palette blending
const bPalettesIndex = (palettesIndex + floor(bt * PALETTES.length)) % PALETTES.length;
const blend = fract(bt * PALETTES.length);
const color1 = get(palettes[bPalettesIndex]);
const color2 = get(palettes[(bPalettesIndex + 1) % PALETTES.length]);
return mix(color1, color2, blend);
}
return get(palettes[palettesIndex])
}
// inverted normalized cos function (normalized phase and amplitude between 0 - 1)
function invCosn(v) {
return 1 - (cos(v * TWO_PI) * 0.5 + 0.5);
}
// lerp values at same index of 2 arrays
function mix(arr1, arr2, f) {
let res = [];
for (var key in arr1) {
res[key] = lerp(arr1[key], arr2[key], f);
}
return res;
}