const TEXTS = ["AU", "TO", "NO", "MY"];
const SPACES = [0.3, 0.33, 0.36, 0.38];
const XS = [-20, -20, -30, -20];
var font, emitters, renderer;
var xScale, yScale, centerX, centerY;
OPC.slider('FONT_SIZE', 440, 300, 600, 1);
OPC.slider('FONT_RESOLUTION', 0.2, 0.1, 0.4, 0.01);
OPC.slider('PARTICLE_SIZE', 0.1, 0.1, 4, 0.1);
OPC.slider('VARIATION', 0, 0, 11, 1);
OPC.slider('SCALE', 5, 1, 20, 1);
OPC.slider('VELOCITY', 1, 0, 5, 0.1);
OPC.slider('LINE_HEIGHT', 0.8, 0.5, 1, 0.01);
var lastFontSize, lastFontResolution, lastLineHeight;
font = loadFont("ProcessingSansPro-Semibold.ttf");
renderer = createCanvas(2250/size, 3000/size);
if(lastFontSize != FONT_SIZE ||
lastFontResolution != FONT_RESOLUTION ||
lastLineHeight != LINE_HEIGHT){
lastFontSize = FONT_SIZE;
lastFontResolution = FONT_RESOLUTION;
lastLineHeight = LINE_HEIGHT;
yScale = height/SCALE*(width/height);
for(let i = 0; i < 20; i++){
let x = mouseX + random(-100, 100);
let y = mouseY + random(-100, 100);
var blob = getNewBlob(x, y);
emitters.forEach(emitter => {
var blob = getNewBlob(emitter.x, emitter.y);
rect(0, 0, width, height);
var stepsize = deltaTime * VELOCITY * 0.002;
for(var i = blobs.length-1; i >= 0; i--){
var x = getSlopeX(blob.x, blob.y);
var y = getSlopeY(blob.x, blob.y);
blob.x += blob.direction * x * stepsize;
blob.y += blob.direction * y * stepsize;
var size = lerp(blob.size, 0, (time-blob.time)/blob.life);
line(x, y, blob.lastX, blob.lastY);
if(x < -border || y < -border || x > width+border || y > height+border || time-blob.time > blob.life){
CanvasToTIFF.toObjectURL(renderer.canvas, function(url) {
window.location.href = url;
var isIE = typeof AudioContext === "undefined" && typeof webkitAudioContext === "undefined";
var a = btn = document.querySelector("a");
a.innerHTML = "Right-click this link to download";
var totalHeight = TEXTS.length * FONT_SIZE * LINE_HEIGHT;
TEXTS.forEach((msg, index) => {
var y = centerY + map(index, 0, TEXTS.length, -totalHeight / 2, totalHeight / 2) + FONT_SIZE * 0.75 - 10;
var space = SPACES[index];
for (var i = 0; i < msg.length; i++) {
var bounds = font.textBounds(msg.charAt(i), 0, 0, FONT_SIZE);
var x = centerX + XS[index] + map(i, 0, msg.length-1, -FONT_SIZE * space, FONT_SIZE * space) - bounds.w / 2;
var points = font.textToPoints(msg.charAt(i), x, y, FONT_SIZE, {sampleFactor: FONT_RESOLUTION});
emitters = emitters.concat(points);
function getNewBlob(x, y){
size : random(1, 10) * PARTICLE_SIZE,
direction : random(0.01, 0.5) * (random() > 0.5 ? 1 : -1),
function getSlopeY(x, y){
case 0:return Math.sin(x);
case 1:return Math.sin(x*5)*y*0.3;
case 2:return Math.cos(x*y);
case 3:return Math.sin(x)*Math.cos(y);
case 4:return Math.cos(x)*y*y;
case 5:return Math.log(Math.abs(x))*Math.log(Math.abs(y));
case 6:return Math.tan(x)*Math.cos(y);
case 7:return -Math.sin(x*0.1)*3;
case 8:return (x-x*x*x)*0.01;
case 9:return -Math.sin(x);
case 10:return -y-Math.sin(1.5*x) + 0.7;
case 11:return Math.sin(x)*Math.cos(y);
case 0:return Math.cos(y);
case 1:return Math.cos(y*5)*x*0.3;
case 7:return Math.sin(y*0.1)*3;
case 11:return Math.sin(y)*Math.cos(x);
return (x-centerX)/xScale;
return (y-centerY)/yScale;