Guides

Preparing a screenshot for upload

Accepted formats, the size cap, and the 2000 pixel long edge rule, checked in the code, plus the order of the checks and where your image lands.

Updated 27 August 2026

Three formats are accepted

PNG, JPEG, and WebP. The filter the file picker uses is those same three, and the upload validation lets through those same three. Checking the two against each other confirms that what you can pick in the dialog matches what actually passes. Screenshot uploads and background image uploads both use the same three.

A format outside the list, such as HEIC or SVG, is filtered out by the picker, and dragging one in is stopped by the check.

The size cap is 25MiB

The constant is 25 times 1024 times 1024, which is exactly 26,214,400 bytes. A file over that is turned back without any attempt to decode it.

Input constants
ItemValue
Accepted formatsPNG, JPEG, WebP
Size cap26,214,400 bytes (25MiB)
As written in the message26MB
Working bitmap long edge cap2000 pixels

The checks run in this order

The order has a reason. Looking at size first avoids bogging the tab down decoding a large file.

Upload validation order
OrderCheckIf it does not pass
1Is the file size at or under the capEnds with a size message
2Is the file type on the accepted listEnds with a format message
3Can the browser decode the imageEnds with a message to try another file
4Is the long edge at or under 2000 pixelsMoves on to the downscale step in the next section

Whichever step stops it, the screen shows a short message and the edit state is left as it was. Even on failure, any bitmap created along the way is closed to free the memory.

Work happens at a 2000 pixel long edge

A long edge over 2000 pixels is scaled down with the ratio preserved. The notable part is when the scaling happens. Rather than expanding the original into memory and shrinking it afterwards, the code calls decoding again and passes the target size along with it. That keeps the large intermediate bitmap out of memory, and the resize quality is set to high.

The arithmetic is plain. The ratio is 2000 divided by the long edge, width and height are each multiplied by that ratio and rounded, and neither side is allowed below 1 pixel.

(calculated) Result of the 2000 pixel long edge downscale
Uploaded sizeLong edgeWorking size
1920 × 108019201920 × 1080 (unchanged)
1170 × 25322532924 × 2000
1290 × 27962796923 × 2000
2048 × 153620482000 × 1500
3840 × 216038402000 × 1125

Once the downscale is done, the original bitmap is closed. That stops the reduced copy and the original sitting in memory together and doubling the cost.

2000 pixels is not the output resolution

This is where the common mix up happens. 2000 pixels is the cap on the working bitmap you hold while editing, not the size of the file you export. Output size is the canvas size of the format you picked multiplied by the export scale.

The two are related, though. However large the original was, the working bitmap has already been reduced to 2000 pixels, so raising the scale does not bring back detail that existed only in the original. How far raising the scale is worth it is covered separately in the article below.

Worth reading alongside

Which device does the image go into?

Drop it directly onto a particular device on the canvas and it goes into that device. Otherwise the target is picked in this order.

The order for picking the slot an image goes into
PriorityTarget
1The device under the drop point (when dropped directly on the canvas)
2The device that is selected
3A device that is still empty
4The first device

Because of that order, in a format holding several devices you can pick the spot you want first and the image lands there. When you drop directly on the canvas, that device becomes selected so you can see which one it went to.

Uploading again onto a device that already holds an image reuses the existing identifier rather than making a new one. The store closes and replaces the old bitmap when a new one arrives under the same identifier, so swapping images repeatedly does not pile up bitmaps nobody uses.

Uploading with no device on the canvas leaves nowhere to put the image, so you get a message to add a device first.

The background image follows the same rules

An image used as a background goes through the same validation and downscale. The format and size limits are the same, and so is the long edge cap. A background is enlarged to cover the canvas, using the larger of the width and height ratios, so a background smaller than the canvas gets blurry by however much it was stretched.

How to prepare

  • Pick PNG, JPEG, or WebP.
  • Keep the file within 26,214,400 bytes.
  • A long edge over 2000 pixels is allowed, but everything past it is dropped at the working stage.
  • Crop an image meant for a device screen to the screen ratio and no letterboxing appears.
  • When filling several devices, select the one you want first or drop directly onto it.

Every number on this page comes from this service's own implementation code. The evidence table at the bottom names the file and the constant behind each sentence.

What this article is based on

What this article is based on
StatementWhere it comes from
Accepted formats PNG, JPEG, and WebPeditorConstants.ACCEPTED_IMAGE_MIME, the accept attribute in panels/UploadPanel.tsx
The file picker filter and the validation list name the same three formats, confirmed by comparing the twoisAcceptedMime in engine/uploadImage.ts, which reads editorConstants.ACCEPTED_IMAGE_MIME, against the accept attribute in panels/UploadPanel.tsx and panels/BackgroundPanel.tsx. This is the result of comparing the two values, not a claim that one is derived from the other
Clipboard input skips the format check and goes on to decodingthe file instanceof File branch in engine/uploadImage.ts
The size cap of 26,214,400 byteseditorConstants.MAX_UPLOAD_BYTES (25 * 1024 * 1024)
Why the message reads 26MBMath.round(MAX_UPLOAD_BYTES / 1e6) in engine/uploadImage.ts
The order of the checks, size then format then decode then long edgethe order of the body of decodeAndDownscale in engine/uploadImage.ts
Intermediate bitmaps are cleaned up on failuredecoded.bitmap.close() in the catch branch of engine/ingestImage.ts
The 2000 pixel long edge capeditorConstants.WORK_MAX_EDGE
Downscaling by passing a target size at the decode step, with quality set to highcreateImageBitmap(probe, { resizeWidth, resizeHeight, resizeQuality: 'high' }) in engine/uploadImage.ts
The ratio formula and the 1 pixel floorratio and Math.max(1, Math.round(...)) in engine/uploadImage.ts
The original bitmap is closed after the downscaleprobe.close() in engine/uploadImage.ts
A browser that cannot take a target size keeps the originalthe resize failure catch branch in engine/uploadImage.ts
Output size is canvas size times scaleoutW and outH in panels/ExportPanel.tsx, toCanvas({ pixelRatio }) in engine/exportImage.ts
The slot order, drop point then selection then empty slot then first nodethe explicitValid branch and pickTargetId in engine/ingestImage.ts
A canvas drop switches the target device to selectedsetSelection([targetId]) in engine/ingestImage.ts
Re-uploading into an existing slot reuses the identifier and replaces the old bitmaptargetNode?.imageId ?? makeImageId() in engine/ingestImage.ts, add in state/imageRegistry.ts
A message to add a device when there is nonethe branch for a missing targetId in engine/ingestImage.ts
The background image uses the same validation and downscalethe decodeAndDownscale call in panels/BackgroundPanel.tsx
The background is enlarged to cover the canvasMath.max(width / bitmap.width, height / bitmap.height) in canvas/BackgroundLayer.tsx

Related guides