script.
	window.canvasOptions = {
		autoClear: true,
		autoCompensate: false,
		autoPushPop: true,
		canvas: true,
		centered: true,
		width: null,
		height: null
	};
View Compiled
let keys = 'qwertyuiop,asdfghjkl,zxcvbnm';
let chars = [];
let prev;

function setup() {
	let now = performance.now();
	let isPreview = isPreviewEmbed();
	let rowOffsetsX = [ 0, 0.3, 0.8 ];
	keys = keys.split(',').map((row, rowIndex) => {
			return row.split('').map((n, i) => {
				let rowOffsetX = rowOffsetsX[rowIndex];
				let x = rowOffsetX + i + 0.5;
				let y = rowIndex + 0.5;
				let pos = createVector(x, y);
				let dist = ease.cubic.in(pos.dist(createVector()) / (SQRT2 * 8), 0, 1, 1);
				let c = {
						char: n.toUpperCase(),
						key: n,
						keyPressed: false,
						keyReleased: -Infinity,
						pos,
						oPos: pos.copy(),
						dist
					};
				if(isPreview) {
					setTimeout(() => c.keyReleased = performance.now(), dist * 500 + 50 + now);
					setTimeout(() => c.keyReleased = performance.now(), dist * 500 + 300 + now);
				}
				chars.push(c);
				return c;
			});
		});
	window.addEventListener('keydown', e => {
		let char = chars.find(n => n.key === e.key.toLowerCase());
		if(char) {
			char.keyPressed = true;
		}
	});
	window.addEventListener('keyup', e => {
		let char = chars.find(n => n.key === e.key.toLowerCase());
		if(char) {
			char.keyPressed = false;
			char.keyReleased = e.timeStamp;
		}
	});
}

function draw(e) {
	let maxRowLength = keys[0].length;
	let size = width / maxRowLength * 0.8;
	let size_half = size * 0.5;
	translate(
		// keys.reduce((p, n) => p.length > n.length ? p : n).length * 50 * -0.5,
		maxRowLength * -size_half,
		keys.length * -size_half
	);
	
	textAlign('center');
	textBaseline('middle');
	
	keys.forEach((row, rowIndex) => {
		row.forEach((c, i) => {
			let { char, keyPressed, keyReleased, pos: v } = c;
			let pos = v.copy().mult(size);
			globalAlpha(1);
			let timeDiff = ease.cubic.in(1 - constrain(keyPressed ? 0 : (e - keyReleased) * 0.001, 0, 1), 0, 1, 1);
			fillStyle(rgb(lerpRGB(0, 127, 255, 255, 255, 255, timeDiff)));
			let scl = timeDiff + 1;
			font(`800 ${scl * size_half}px sans-serif`);
			fillText(char, pos.x, pos.y);
			globalAlpha(timeDiff * 0.15 + 0.05);
			beginPath();
			let s = size * scl * 0.75;
			rect(pos.x - s * 0.5, pos.y - s * 0.5, s, s, s * 0.1);
			fill();
			if(scl > 1.01) {
				c.scl = true;
				let c_ = random(chars.filter(n => n.scl));
				if(c_) {
					v.lerp(c_.pos, 0.01);
				}
			}
			else {
				c.scl = false;
				v.lerp(c.oPos, 0.004);
			}
		});
	});
}
View Compiled
Run Pen

External CSS

  1. https://codepen.io/Alca/pen/XeZBab.scss

External JavaScript

  1. https://codepen.io/Alca/pen/XeZBab.js