← The library

Infinite canvas

An endless wall of images, to drag

Members only

What's included

A masonry wall of images you drag with the mouse, a finger or the keyboard, repeating endlessly in both directions. In two files: a stylesheet and a script. No dependencies, no build step, no external requests — you copy them into a project and it works.

Your images stay in the HTML, in plain sight. The component reads them, makes a tile out of them and repeats it; it doesn't replace them. It's that same list screen readers read, once only, while the visual repetition is marked decorative. A CMS that changes the images has nothing to call: the wall rebuilds itself.

The Images / Videos pill ships with it, and can be used separately. They're native radio buttons: the group, the arrow keys, the value submitted with the form all come from the browser, not from the script.

Features

  • Endless in both directions — the tile repeats by modulo, so the number of elements in the page depends on the size of the window, never on the distance travelled. You can drag for an hour without adding a thing.
  • A single write per frame — the thumbnails are placed once and for all; on every animation frame, the component writes exactly one transform, however many photos are on screen.
  • Throw and inertia — the wall can be thrown and glides to a stop, with adjustable friction. A slow drift can keep it moving on its own at rest.
  • Four gestures — the wheel, the two-finger trackpad that pans diagonally, dragging with mouse or finger, and the keyboard: arrow keys to move, Shift to go faster, Home to recentre. Whatever you lay on top keeps its own clicks, and data-ic-wheel="off" gives the wheel back to the page when the wall is only one section among others.
  • Works without JavaScript — the wall goes back to being a scrolling column grid, at the same column width, the same gutter and the same radius.
  • One variable for the scale — every measurement derives from the text size: column, gutter, radii and pill all follow together.
  • Two ways of filling — balanced columns, whose seam is pixel-exact, or greedy masonry, which reproduces the reference position for position.

Dropping it into a page

Two files to load, then your images:

<link rel="stylesheet" href="infinite-canvas.css">
<script src="infinite-canvas.js" defer></script>
<div class="infinite-canvas" data-infinite-canvas>
  <div class="infinite-canvas__source">
    <img class="infinite-canvas__img" src="1.webp" width="600" height="600" alt="…">
    <img class="infinite-canvas__img" src="2.webp" width="735" height="413" alt="…">
    <img class="infinite-canvas__img" src="3.webp" width="600" height="800" alt="…">
  </div>
</div>

That's it: the data-infinite-canvas attribute is enough, the component installs itself when the page loads — and on walls a framework inserts later too. Give it a height in CSS, it assumes none.

The width et height attributes aren't decorative: they give each image's aspect ratio to the layout without waiting for it to decode. Without them, the wall waits for the load and then rebuilds.

What you should know

  • Don't change the text size inside it. The measurements are in em, and an em resolves on the element using it, not on the one declaring it. Set --ic-font-size on the block and everything follows; put a font-size on a child and everything shifts.
  • The frame clips, it doesn't scroll. Once the script is in place, the wall switches to overflow: clip and not hidden: a hidden box can still be scrolled by script, and the browser scrolls it itself to reveal whatever has just taken focus — which would shift the wall with nothing to put it back.
  • No inline styles, no inline scripts. The component honours the site's strict security policy, and never uses innerHTML: a caption coming out of a database can't inject a tag.
  • The design comes from elsewhere. The proportions follow those of a commercial Framer component, measured on the published page: a 300 px column, an 8 px gutter, five image formats, and a pill of 202 by 50. The code itself is original — nothing was taken from its implementation, and the demo images are ours.

Take it, open it, break it.

This component is free. The full library — the templates and the other components — comes with the subscription, alongside the course.

Immediate access · No commitment · Cancel in one click