art
generative
fxhash
Crazy Letter

Crazy Letter

written by reyrove

06 Oct 2024100 EDITIONS
1 TEZ

Setting the Basics

const ratio = 1 / 1;
const prefix = 'Crazy letter';

Here, we define the ratio for the canvas as 1/1, ensuring it is a perfect square. The prefix is set as 'Crazy letter', and it will be used for naming any files when the artwork is downloaded.

Defining Global Variables

const features = {};
let resizeTmr = null;
let thumbnailTaken = false;

const urlSearchParams = new URLSearchParams(window.location.search);
const urlParams = Object.fromEntries(urlSearchParams.entries());
let forceDownloaded = false;

const animated = false;
let nextFrame = null;
  • features : This object stores the various properties for the artwork, like background color and line color.
  • resizeTmr : A timer to handle canvas resizing events.
  • thumbnailTaken : A flag to make sure the thumbnail preview is only taken once.
  • urlSearchParams & urlParams : These extract any URL parameters, which might include instructions like forcing the download of the artwork.
  • forceDownloaded : A flag to prevent multiple downloads.
  • animated: Set to false because this artwork is static.
  • nextFrame : Stores the ID of the next frame in case of animations.

setup Function: Picking Random Colors

const setup = () => {
  const backgroundColours = ['#FFC0CB', '#FFA07A', '#FFFFE0', '#E6E6FA', '#ADFF2F', '#66CDAA', '#E0FFFF', '#FFE4C4', '#F5F5DC', '#DCDCDC', '#FFF0F5', '#FFF8DC'];
  const backgroundNames = ['Pink', 'LightSalmon', 'LightYellow', 'Lavender', 'GreenYellow', 'MediumAquamarine', 'LightCyan', 'Bisque', 'Beige', 'Gainsboro', 'LavenderBlush', 'Cornsilk'];

  const backgroundIndex = Math.floor($fx.rand() * backgroundColours.length);

  const foregroundColours = ['#f5a04e', '#931a1e', '#fad2db', '#f2e73d', '#14b9dc', '#d65a9c', '#f2f8ef', '#395370'];
  const foregroundIndex = Math.floor($fx.rand() * foregroundColours.length);

  features.backgroundColour = backgroundColours[backgroundIndex];
  features.lineColours = foregroundColours[foregroundIndex];

  const readableFeaturesObj = {};
  readableFeaturesObj['Background Color'] = backgroundNames[backgroundIndex];
  readableFeaturesObj['Lines Color'] = foregroundColours[foregroundIndex];

  $fx.features(readableFeaturesObj);
  console.table(readableFeaturesObj);
};

This function sets up the random selection of colors for the background and lines. The background colors are stored in the backgroundColours array, and the line colors in foregroundColours. We randomly pick a color using $fx.rand() and store the choices in the features object.

The selected colors and their names are printed to the console for easy reference.

Drawing the Line Pattern

The function drawLine generates a quirky line pattern across the canvas. Each line is drawn at a randomized Y-axis position, with varying colors and shadows.

function drawLine(ctx, lineY, margin) {
  const canvas = document.getElementById('target');
  const w = canvas.width;
  const range = map(lineY, margin * 2, w - margin * 2, 0, w / ($fx.rand() * 20 + 30));
  let prevX = margin * ($fx.rand() * 10 + 2);
  let prevY = lineY;
  const lineSpacing = w / ($fx.rand() * 100 + 20);

  for (let x = prevX + lineSpacing * $fx.rand() * 10; x <= w - margin * $fx.rand() * 10; x += lineSpacing) {
    const y = lineY + $fx.rand() * 2 * range - range;
    ctx.beginPath();
    ctx.moveTo(prevX, prevY);
    ctx.lineTo(x, y);
    ctx.stroke();

    prevX = x;
    prevY = y;
  }
}
  • drawLine(ctx, lineY, margin) : This function draws a zigzagging line across the canvas using random values for the line’s Y-axis position and spacing between points.
  • map(value, start1, stop1, start2, stop2) : Maps a value from one range to another (for example, mapping the Y-coordinate from the canvas width to a smaller range).
  • random(min, max) : Generates a random number between the given min and max values.

Drawing the Entire Canvas

Next, we draw the entire canvas by invoking the drawCanvas function, which first fills the background and then applies the line pattern.

const drawCanvas = async () => {
  window.cancelAnimationFrame(nextFrame);
  const canvas = document.getElementById('target');
  const ctx = canvas.getContext('2d');
  const w = canvas.width;
  const h = canvas.height;

  const margin = w / ($fx.rand() * 20 + 50);
  ctx.fillStyle = features.backgroundColour;
  ctx.fillRect(0, 0, w, h);
  ctx.strokeStyle = features.lineColours;
  ctx.lineWidth = w / ($fx.rand() * 300 + 200);
  ctx.shadowColor = features.lineColours;
  ctx.shadowBlur = w / ($fx.rand() * 300 + 200);

  ctx.beginPath();
  ctx.rect(margin, margin, w - margin * 2, h - margin * 2);
  ctx.stroke();

  for (let y = margin * 2; y < h - margin * 2; y += w / ($fx.rand() * 50 + 50)) {
    drawLine(ctx, y, margin);
  }

  if (!thumbnailTaken) {
    $fx.preview();
    thumbnailTaken = true;
  }

  if ('forceDownload' in urlParams && forceDownloaded === false) {
    forceDownloaded = true;
    await autoDownloadCanvas();
    window.parent.postMessage('forceDownloaded', '*');
  }

  if (animated) {
    nextFrame = window.requestAnimationFrame(drawCanvas);
  }
};
  • Filling the Background : The canvas is filled with the background color selected earlier.
  • Stroke Properties : We set the stroke color and line width for the drawn lines. Shadows are added for a cool 3D effect.
  • Drawing the Frame : A rectangle is drawn inside the canvas to create a margin.
  • Drawing Lines : Lines are drawn across the canvas using the drawLine function in a loop, creating the artistic effect.

Handling Resizing and Canvas Layout

const layoutCanvas = async (windowObj = window, urlParamsObj = urlParams) => {
  windowObj.cancelAnimationFrame(nextFrame);

  const { innerWidth: wWidth, innerHeight: wHeight, devicePixelRatio = 1 } = windowObj;
  let dpr = devicePixelRatio;
  let cWidth = wWidth;
  let cHeight = cWidth / ratio;

  if (cHeight > wHeight) {
    cHeight = wHeight;
    cWidth = wHeight * ratio;
  }

  const canvases = document.getElementsByTagName('canvas');
  Array.from(canvases).forEach(canvas => canvas.remove());

  let targetHeight = cHeight;
  let targetWidth = targetHeight * ratio;

  if ('forceWidth' in urlParams) {
    targetWidth = parseInt(urlParams.forceWidth);
    targetHeight = Math.floor(targetWidth / ratio);
    dpr = 1;
  }

  targetWidth *= dpr;
  targetHeight *= dpr;

  const canvas = document.createElement('canvas');
  canvas.id = 'target';
  canvas.width = targetWidth;
  canvas.height = targetHeight;
  document.body.appendChild(canvas);

  canvas.style.position = 'absolute';
  canvas.style.width = `${cWidth}px`;
  canvas.style.height = `${cHeight}px`;
  canvas.style.left = `${(wWidth - cWidth) / 2}px`;
  canvas.style.top = `${(wHeight - cHeight) / 2}px`;

  drawCanvas();
};

This function ensures that the canvas adjusts its size responsively. It calculates the optimal size for the canvas based on the window size while maintaining the square aspect ratio.

Initiating the Canvas Drawing

document.addEventListener('DOMContentLoaded', init);

The init function is called once the page is fully loaded. It sets up event listeners for resizing the window and pressing keys (like 's' for saving the canvas).

To view the full code and customize it, click here to start your journey with the "Crazy Letter" canvas art.

Crafted with sparkle, style, and passion by Frostbond Coders 💖✨

feedback

stay ahead with our newsletter

receive news on exclusive drops, releases, product updates, and more

    Crazy Letter — fxhash