Painting 2/16/2026

This sketch loads an external image file and displays it centered on the canvas, scaled proportionally to fit the window without distortion. The image is drawn once and animation stops, creating a static gallery-like viewer.

🧪 Try This!

Experiment with the code by making these changes:

  1. Change the background color — The black background becomes a different shade, framing the image
  2. Load a different image — The sketch displays a new image file from your project folder instead
  3. Make the image smaller — The image displays at half its calculated size, leaving more black border around it
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch demonstrates one of the most practical skills in p5.js: loading external images and displaying them elegantly. It takes a file called thumbnail.png and centers it on the canvas while scaling it proportionally to fit the window perfectly—no stretching, no letterboxing. The code uses loadImage() to fetch the file, calculates proportional scaling with the min() function, and positions the image mathematically at the center.

The sketch is organized into three key functions: preload() handles loading the image file before anything else starts, setup() prepares the canvas to match the window size, and draw() calculates the perfect scale and position, then draws the image once before stopping. By studying this code you will learn the pattern for working with external assets in p5.js and how to keep aspect ratios intact—a technique that applies to photos, artwork, and any rectangular content.

⚙️ How It Works

  1. When the sketch begins, preload() runs first and loads the image file thumbnail.png into the img variable, ensuring the image data is ready before setup() runs
  2. setup() creates a canvas that matches the current window width and height, so the display fills the entire browser window
  3. In draw(), the background is set to black, and then the code checks if the image loaded successfully using if (img)
  4. A scale factor is calculated using min() to find which dimension (width or height) is more restrictive—this prevents the image from being stretched or cropped
  5. The x and y coordinates are calculated to center the scaled image on the canvas by finding the leftover space and dividing it equally on both sides
  6. The image() function draws the scaled image at the calculated position, then noLoop() stops the draw function from repeating

🎓 Concepts You'll Learn

Image loadingProportional scalingAspect ratioCanvas centeringpreload() functionConditional rendering

📝 Code Breakdown

preload()

preload() is a special p5.js function that runs before setup(). Use it to load images, sounds, or data files so they are ready when your sketch needs them. Without preload(), images might not be loaded yet when draw() tries to display them.

function preload() {
  img = loadImage('thumbnail.png');
}
Line-by-line explanation (1 lines)
img = loadImage('thumbnail.png');
loadImage() fetches the image file from your project folder and stores it in the img variable. preload() ensures this completes before setup() runs, preventing 'undefined image' errors

setup()

setup() runs once when the sketch starts. Here we create a canvas sized to the window, which is why resizing the browser window after load won't change the display (the canvas was already sized once).

function setup() {
  createCanvas(windowWidth, windowHeight);
}
Line-by-line explanation (1 lines)
createCanvas(windowWidth, windowHeight);
Creates a canvas that matches the full width and height of the browser window, so the image viewer fills the entire screen

draw()

draw() runs on every frame, but noLoop() stops it after the first one. This sketch is 'static'—the image never changes. If you removed noLoop(), draw() would keep running uselessly, redrawing the same image 60 times per second with no visible difference.

🔬 These three lines handle all the math for centering and scaling. What happens if you change min() to max()? Predict: will the image get bigger or smaller, and will it fit entirely on screen?

    let scale = min(width / img.width, height / img.height);
    let x = (width - img.width * scale) / 2;
    let y = (height - img.height * scale) / 2;

🔬 The last two arguments control the displayed width and height. What if you multiply scale by 0.5 instead? How much smaller will the image appear?

    image(img, x, y, img.width * scale, img.height * scale);
function draw() {
  background(0);
  if (img) {
    let scale = min(width / img.width, height / img.height);
    let x = (width - img.width * scale) / 2;
    let y = (height - img.height * scale) / 2;
    image(img, x, y, img.width * scale, img.height * scale);
  }
  noLoop();
}
Line-by-line explanation (7 lines)

🔧 Subcomponents:

conditional Image Loaded Check if (img) {

Ensures the image was successfully loaded before attempting to draw it

calculation Proportional Scale Factor let scale = min(width / img.width, height / img.height);

Calculates the largest scale that keeps the image from exceeding canvas boundaries while preserving aspect ratio

calculation Horizontal Centering let x = (width - img.width * scale) / 2;

Computes leftover horizontal space and divides it in half to center the image horizontally

calculation Vertical Centering let y = (height - img.height * scale) / 2;

Computes leftover vertical space and divides it in half to center the image vertically

control Stop Animation noLoop();

Stops the draw function from repeating, making the display static after the first frame

background(0);
Fills the canvas with black color (0 in grayscale). This creates the dark background behind the centered image
if (img) {
Checks whether img exists and loaded successfully. Without this, the sketch could crash if the file is missing
let scale = min(width / img.width, height / img.height);
Calculates two ratios: how much space the canvas width offers (width / img.width) and how much the height offers (height / img.height). min() picks the smaller one so the image fits in both directions without cropping
let x = (width - img.width * scale) / 2;
Finds leftover horizontal space by subtracting the scaled image width from canvas width, then divides by 2 to position it centered horizontally
let y = (height - img.height * scale) / 2;
Finds leftover vertical space by subtracting the scaled image height from canvas height, then divides by 2 to position it centered vertically
image(img, x, y, img.width * scale, img.height * scale);
Draws the image at position (x, y) with width and height both multiplied by the scale factor, keeping the aspect ratio intact
noLoop();
Stops the draw loop immediately, so after this first frame, draw() no longer runs and the display becomes static

📦 Key Variables

img p5.Image

Stores the loaded image data from thumbnail.png so it can be drawn on the canvas

let img;

🔧 Potential Improvements (3)

Here are some ways this code could be enhanced:

FEATURE setup()

Canvas size is set once at startup and doesn't respond to window resizing

💡 Add windowResized() function to redraw the canvas and image when the browser window is resized: function windowResized() { resizeCanvas(windowWidth, windowHeight); redraw(); }

STYLE draw()

noLoop() is called inside draw(), which only executes once anyway—this is redundant

💡 Move noLoop() into setup() so the intent is clearer: it prevents animation from starting, rather than stopping it mid-function

BUG preload()

If thumbnail.png is missing or misspelled, img will be undefined and the sketch will fail silently

💡 Add error handling or a console log to confirm the image loaded: console.log('Image loaded:', img); or use a fallback color if img fails to load

🔄 Code Flow

Code flow showing preload, setup, draw

💡 Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> draw[draw loop] draw --> imagecheck[Image Loaded Check] imagecheck -->|Image Loaded| scalecalculation[Proportional Scale Factor] scalecalculation --> centerx[Horizontal Centering] centerx --> centery[Vertical Centering] centery --> stoploop[Stop Animation] stoploop -->|End of Draw| draw click setup href "#fn-setup" click draw href "#fn-draw" click imagecheck href "#sub-image-check" click scalecalculation href "#sub-scale-calculation" click centerx href "#sub-center-x" click centery href "#sub-center-y" click stoploop href "#sub-stop-loop"

Preview

Painting 2/16/2026 - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of Painting 2/16/2026 - Code flow showing preload, setup, draw
Code Flow Diagram