Actio 8 - Código de la portada

Portada realizada por código Javascript y la librería opentype

//declaramos un espacio de trabajo
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Cargamos el archivo de fuente
const fontUrl = 'fonts/ancizar_sans-black_italic-webfont.ttf'; //const wordsToRender = ['Actio', 'actio', 'ACTIO', 'Actio', 'actio', '4CT10', 'Act1o', 'acti0', 'ACTIO', 'Actio', 'actIo', 'ACTIO', 'Actio', 'aCtio', 'ACT_O','Actio', 'actio', 'ACTIO', '_ctio', 'actio', '4CT10', 'Act1o', 'acti0', 'ACtIO', 'Actio', 'actIo', 'ACTIO', 'Acti0', 'acTio', 'ACT_O']; // Array of words to render
// Declaramos ejes de anclaje de nodos
const snapX = 0 //Math.random();
const snapY = 0 //Math.random();
// Declaramos ejes de anclaje
const wordNumber = 16;
// Declaramos la fuerza de anclaje de nodos
//const snapStrength = 100; // Strength of snapping
// Declaramos la palabra base
const baseWord = 'Actio!8 ACTIO!8';
function generateVariations(word) {
  // Creamos un array de variaciones posibles
  const variations = [];  
  for (let i = 0; i < word.length; i++) {    
    const char = word[i];    
    // Cambiamos de mayúsculas y minúsculas    
    const upperCase = char.toUpperCase();    
    const lowerCase = char.toLowerCase();    
    // Declaramos los posibles caracteres a cambiar    
    const replacedChars = ['a', 'C', 'T', 'I', 'O', '4', '1', '0', '_', '*'];
    // Creamos un ciclo de variaciones
    for (const replacedChar of replacedChars) {      
    if (replacedChar !== char.toUpperCase() && replacedChar !== char.toLowerCase()) {        
    const variation = word.slice(0, i) + replacedChar + word.slice(i + 1);        
    variations.push(variation);      
    }    
    }    
    // Incluimos mayúsculas    
    const upperVariation = word.slice(0, i) + upperCase + word.slice(i + 1);    
    variations.push(upperVariation);    
    // Incluimos minúsculas    
    const lowerVariation = word.slice(0, i) + lowerCase + word.slice(i + 1);    
    variations.push(lowerVariation);  
    }  
    return variations;
    }
const variationsOfActio = generateVariations(baseWord);
// Copiamos el array
let wordsToFill = variationsOfActio.slice();
// Declaramos el número de repeticiones
const repetitions = 4;
for (let i = 0; i < repetitions - 1; i++) {
  // Concatenamos las variaciones multiples veces
  wordsToFill = wordsToFill.concat(variationsOfActio);
  }
  // Preparamos el archivo de fuente para las deformaciones
opentype.load(fontUrl, function (err, font) {  
  if (err) {    
    console.error('Font could not be loaded:', err);  
    } else {    
      let frame = 0;
      // Declaramos el número de fotogramas    
      const maxFrame = 300;    
      function animate() {
        // Hacemos que las variaciones se animen al vincular las deformaciones al conteo de fotogramas       //let snapStrength = Math.random(100);//Math.sin((frame / maxFrame) * Math.PI); // Example change in snapStrength over frames      
    let snapDistance = frame/12 //Math.sin((frame / maxFrame) * Math.PI); // Example change in snapStrength over frames
    // Renderizamos el texto con las variaciones      
    renderText(snapDistance);      
    frame++;    
    if (frame <= maxFrame) {        
    requestAnimationFrame(animate);      
    }              
    }
    // Organiamos el array of variaciones
    const wordsToRender = wordsToFill;
    // Organizamos por columnas
    const columnXPositions = [20, 280, 540, 790, 1050, 1310, 1570, 1840];
    // repetimos por filas
    const columnYStart = 20; //    
    function renderText(snapDistance) {
      // Tamaño de fuente
    const fontSize = 35;
    // Opciones adicionales
    const options = {};      
    ctx.clearRect(0, 0, canvas.width, canvas.height);      
    for (let i = 0; i < wordsToRender.length; i++) {        
    const columnIndex = i % columnXPositions.length;        
    const xPos = columnXPositions[columnIndex];        
    const yPos = columnYStart + Math.floor(i / columnXPositions.length) * 30;        
    const snapPath = font.getPath(wordsToRender[i], xPos, yPos, fontSize, options);
    // Aplicamos la distorsion a los nodos
    doSnap(snapPath, snapDistance);        
    snapPath.draw(ctx);        
    font.drawPoints(wordsToRender[i], xPos, yPos, fontSize);      
    }     }    
    function snap(v, distance, strength) {      
    return (v * (1.0 - strength)) + (strength * Math.round(v / distance) * distance);    
      }    
    function doSnap(path, snapDistance) {      
    var i;      
    var strength = Math.random(100);      
    //console.log(strength);    
    for (i = 0; i < path.commands.length; i++) {        
    var cmd = path.commands[i];        
    if (cmd.type !== 'Z') {        
    cmd.x = snap(cmd.x + snapX, snapDistance, strength) - snapX;        
    cmd.y = snap(cmd.y + snapY, snapDistance, strength) - snapY;        
    }        
    if (cmd.type === 'Q' || cmd.type === 'C') {          
    cmd.x1 = snap(cmd.x1 + snapX, snapDistance, strength) - snapX;          
    cmd.y1 = snap(cmd.y1 + snapY, snapDistance, strength) - snapY;      
    }      
    if (cmd.type === 'C') {          
    cmd.x2 = snap(cmd.x2 + snapX, snapDistance, strength) - snapX;          
    cmd.y2 = snap(cmd.y2 + snapY, snapDistance, strength) - snapY;      
    }      
    }    
      }
      // iniciamos la animación
    animate();  
    }
  });