How to use it
- Drop your photos (JPG, PNG, WebP or GIF, up to 30). They fill the 2 × 2 grid in order; pick another layout from the Layout panel at any time.
- Click a cell to select it, then drag the photo to pan, use + / − to zoom, or choose “Swap with” to exchange two cells. Dragging a thumbnail onto a cell places it there.
- Set the gap, margin, corner radius, border and background colour (or transparent).
- Choose the export size and format, press Export and download the file.
Example
Four holiday photos (4,032 × 3,024 px each, scaled to 4,000 px on load) in the 2 × 2 grid at Instagram square size with a 12 px gap and no margin: each cell is 534 × 534 px; a landscape photo cover-fits at 712 × 534 px and is centred, leaving 89 px hidden on each side – drag it to show the left or right part. The PNG export is exactly 1,080 × 1,080 px (roughly 1.5–2.5 MB); the same collage as JPEG at quality 90 is about 300–450 KB.
How the collage is built
Layouts are stored as fractions of the canvas. For a cell with fractions x, w, canvas width W, gap g and margin m, the pixel rectangle is left = m + x·(W − 2m + g) and width = w·(W − 2m + g) − g (same for the vertical axis), so neighbouring cells are exactly g apart and the outer cells sit m from the edge. A photo is scaled by max(cellW / imgW, cellH / imgH) × zoom so it always covers the cell; its position is stored as a fraction of the overflow, which keeps your framing when you change the output size.
The preview and the export are drawn with Konva (react-konva): each cell is a clipped group (rounded rectangle, circle or hexagon) holding the photo, with the border stroked inside the clip so it never paints over a neighbour. For the export the stage is rendered once at scale 1 at the chosen size, copied onto a fresh canvas (white fill for JPEG when the background is transparent) and encoded with canvas.toBlob(). Nothing is downloaded from a CDN; the library ships with the page.
Limits: photos are decoded with EXIF orientation applied and downscaled to 4,000 px on the long side (so a 3 × 3 grid of 48 MP photos does not exhaust memory); the export canvas is capped at about 40 megapixels, and iOS Safari fails well below that (roughly 16 MP). Re-encoding drops EXIF, GPS and colour-profile metadata. Scatter layouts rotate the cells; their drop targets are the unrotated bounding boxes.
Sources: Konva – clipping functions and shapes, MDN – HTMLCanvasElement.toBlob(), Instagram help – recommended image sizes.
Questions
- How do I swap two photos?
- Drag a photo from its cell and release it over another cell: the two cells exchange their contents. On a phone, select a cell and use the "Swap with" list, or tap a thumbnail to put that photo into the selected cell.
- Why does a photo look cropped?
- Cells are filled edge to edge (cover fit) so there are no empty bars. Drag the photo inside the cell to choose which part is visible, pick a layout whose cell ratio is closer to the photo, or enlarge the gap. The crop exists only in the export; your original file is untouched.
- Can I make a print-quality collage?
- Yes: the A4 and 6 × 4 in presets are 300 DPI (2,480 × 3,508 and 1,800 × 1,200 px), and custom sizes go up to 8,000 px per side. Each cell then needs a photo of at least that many pixels; photos are scaled down to 4,000 px on load, so a cell wider than 4,000 px will be upscaled.
- Are my photos uploaded?
- No. Decoding, layout and export happen in the browser; the page makes no network request with your images. Closing the tab discards everything.