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

External CSS

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

External JavaScript

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