IrishWristWatchScrable

This sketch displays the tongue-twister phrase 'I wish to wash my Irish wristwatch.' as scattered text across the canvas, with each character positioned randomly. When the window is resized, the characters jump to new random positions, creating a playful, chaotic visual effect.

๐ŸŽ“ Concepts You'll Learn

Text renderingString manipulationArraysVector positioningRandom number generationWindow resizingCanvas clearingResponsive design

๐Ÿ”„ Code Flow

Code flow showing setup, generatepositions, draw, windowresized

๐Ÿ’ก Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> canvas-creation[Canvas Setup] setup --> text-formatting[Text Formatting Configuration] setup --> phrase-split[Phrase Splitting] setup --> generatepositions[generatepositions] setup --> draw[draw loop] draw --> background-clear[Canvas Clearing] draw --> character-display-loop[Character Display Loop] character-display-loop --> text-render[Text Rendering] draw --> draw click setup href "#fn-setup" click generatepositions href "#fn-generatepositions" click draw href "#fn-draw" click canvas-creation href "#sub-canvas-creation" click text-formatting href "#sub-text-formatting" click phrase-split href "#sub-phrase-split" click background-clear href "#sub-background-clear" click character-display-loop href "#sub-character-display-loop" click text-render href "#sub-text-render" windowresized[windowresized] --> canvas-resize[Canvas Resizing] windowresized --> array-reset[Array Reset] windowresized --> position-regeneration[Position Regeneration] position-regeneration --> position-loop[Position Generation Loop] position-loop --> vector-creation[Random Vector Creation] click windowresized href "#fn-windowresized" click canvas-resize href "#sub-canvas-resize" click array-reset href "#sub-array-reset" click position-regeneration href "#sub-position-regeneration" click position-loop href "#sub-position-loop" click vector-creation href "#sub-vector-creation"

๐Ÿ“ Code Breakdown

setup()

setup() runs once when the sketch starts. It's the perfect place to initialize your canvas, set drawing styles, and prepare data structures. The split("") method is a JavaScript string function that breaks a string into individual characters - it's very useful for working with text character-by-character.

function setup() {
  createCanvas(windowWidth, windowHeight);
  textSize(32);
  textAlign(CENTER, CENTER);
  noStroke();
  fill(0);

  // Split phrase into individual characters (including spaces and punctuation)
  chars = phrase.split("");
  generatePositions();
}

๐Ÿ”ง Subcomponents:

calculation Canvas Setup createCanvas(windowWidth, windowHeight)

Creates a canvas that fills the entire browser window

calculation Text Formatting Configuration textSize(32); textAlign(CENTER, CENTER); noStroke(); fill(0);

Sets up how text will be displayed - size, alignment, and color

calculation Phrase Splitting chars = phrase.split("");

Breaks the phrase string into an array of individual characters

Line by Line:

createCanvas(windowWidth, windowHeight);
Creates a canvas that matches the full width and height of the browser window, making the sketch responsive
textSize(32);
Sets the font size to 32 pixels for all text that will be drawn
textAlign(CENTER, CENTER);
Centers text both horizontally and vertically around the coordinates you provide
noStroke();
Removes any outline or border from text (only the filled text will show)
fill(0);
Sets the text color to black (0 in grayscale means pure black)
chars = phrase.split("");
Converts the phrase string into an array where each element is a single character, including spaces and punctuation
generatePositions();
Calls the function that creates random positions for each character

generatePositions()

This helper function creates random positions for each character. createVector() creates a p5.Vector object which stores x and y coordinates together. random(width) generates a number between 0 and the canvas width, and random(height) does the same for height. By calling this function again in windowResized(), we can regenerate positions whenever the window changes size.

function generatePositions() {
  positions = [];
  for (let i = 0; i < chars.length; i++) {
    positions.push(createVector(random(width), random(height)));
  }
}

๐Ÿ”ง Subcomponents:

calculation Array Reset positions = [];

Clears the positions array to prepare for new random positions

for-loop Position Generation Loop for (let i = 0; i < chars.length; i++)

Loops through each character and creates a random position for it

calculation Random Vector Creation positions.push(createVector(random(width), random(height)));

Creates a vector with random x and y coordinates and adds it to the positions array

Line by Line:

positions = [];
Empties the positions array so we can fill it with fresh random positions
for (let i = 0; i < chars.length; i++) {
Loops from 0 to the number of characters in the phrase (36 characters including spaces and punctuation)
positions.push(createVector(random(width), random(height)));
Creates a new vector with a random x position (0 to canvas width) and random y position (0 to canvas height), then adds it to the positions array

draw()

draw() runs 60 times per second (by default) and is where all animation happens. Each frame, we clear the canvas with background() and then redraw all characters at their stored positions. The characters don't move because their positions never change - they only change when windowResized() is called.

function draw() {
  background(240);

  for (let i = 0; i < chars.length; i++) {
    // Spaces will just show as blanks, which is fine
    text(chars[i], positions[i].x, positions[i].y);
  }
}

๐Ÿ”ง Subcomponents:

calculation Canvas Clearing background(240);

Fills the entire canvas with light gray color, clearing previous frames

for-loop Character Display Loop for (let i = 0; i < chars.length; i++)

Loops through each character and draws it at its corresponding position

calculation Text Rendering text(chars[i], positions[i].x, positions[i].y);

Draws the character at the x and y coordinates from the positions array

Line by Line:

background(240);
Fills the canvas with light gray (240 on a 0-255 scale) to clear everything from the previous frame
for (let i = 0; i < chars.length; i++) {
Loops through each character in the chars array by index
text(chars[i], positions[i].x, positions[i].y);
Draws the character at index i using the x and y coordinates from the positions array at the same index

windowResized()

windowResized() is a special p5.js function that automatically gets called whenever the browser window is resized. Without this function, the canvas would stay the same size and not respond to window changes. By calling generatePositions() here, we ensure characters get new random positions that fit the new canvas size.

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  // Re-randomize positions when the window size changes
  generatePositions();
}

๐Ÿ”ง Subcomponents:

calculation Canvas Resizing resizeCanvas(windowWidth, windowHeight);

Adjusts the canvas size to match the new window dimensions

calculation Position Regeneration generatePositions();

Creates new random positions for all characters to fit the new canvas size

Line by Line:

resizeCanvas(windowWidth, windowHeight);
p5.js automatically detects when the window is resized and calls this function. This line resizes the canvas to match the new window dimensions
generatePositions();
Regenerates random positions for all characters so they're distributed across the new canvas size

๐Ÿ“ฆ Key Variables

phrase string

Stores the tongue-twister text that will be scattered across the screen

let phrase = "I wish to wash my Irish wristwatch.";
chars array

Stores individual characters from the phrase after splitting it. Each element is a single character including spaces and punctuation

let chars = ["I", " ", "w", "i", "s", "h", ...];
positions array

Stores p5.Vector objects containing x and y coordinates for each character. The index matches the chars array so chars[0] is drawn at positions[0]

let positions = [createVector(150, 200), createVector(300, 100), ...];

๐Ÿงช Try This!

Experiment with the code by making these changes:

  1. Change the phrase variable to a different sentence or tongue-twister and watch how the characters scatter differently based on the new length
  2. Modify textSize(32) to textSize(64) in setup() to make the characters much larger and see how they overlap
  3. Change fill(0) to fill(255, 0, 0) to make the text red instead of black
  4. Change background(240) to background(0) in draw() to create a dark background with white text (you'll also need to change fill(0) to fill(255))
  5. Add a random color for each character by replacing fill(0) with fill(random(255), random(255), random(255)) in setup() - but you'll need to move it inside the draw loop to work properly
  6. Modify generatePositions() to constrain positions to a smaller area using constrain(), like: createVector(constrain(random(width), 100, width-100), constrain(random(height), 100, height-100))
Open in Editor & Experiment โ†’

๐Ÿ”ง Potential Improvements

Here are some ways this code could be enhanced:

STYLE setup() function

Text styling commands are scattered without clear organization

๐Ÿ’ก Group all text styling commands together with a comment like '// Text styling' to make the code more readable

FEATURE draw() function

Characters are static and don't animate - they only change position when the window resizes

๐Ÿ’ก Add animation by modifying positions in draw() using sine/cosine waves or Perlin noise to make characters float smoothly: positions[i].x += sin(frameCount * 0.01 + i) * 2

FEATURE sketch overall

All characters are the same color and size, making the design monotonous

๐Ÿ’ก Add variety by assigning different colors, sizes, or opacities to characters based on their index: fill(random(255)); textSize(random(20, 50));

PERFORMANCE draw() function

The loop redraws all 36 characters every frame even though they never move

๐Ÿ’ก For better performance with static text, consider using createGraphics() to render text once to an off-screen buffer, then display that buffer instead of redrawing each frame

BUG generatePositions() function

Characters can be positioned at the very edge of the canvas, potentially getting cut off

๐Ÿ’ก Add padding to keep characters fully visible: createVector(random(textWidth(chars[i])/2, width - textWidth(chars[i])/2), random(20, height - 20))

Preview

IrishWristWatchScrable - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of IrishWristWatchScrable - Code flow showing setup, generatepositions, draw, windowresized
Code Flow Diagram