QUICKUPSCALE

PRACTICAL GUIDE

Sprite sheet tools and workflows

Split a sprite sheet into individual PNG frames

Start here

Open the sprite sheet splitter, choose the original 64×32 sheet and enter 16×16 cells with zero margins and gaps. Check the eight-frame plan, then select Split into PNG frames. Download individual PNGs or the ZIP with its manifest.

Expected result:

Eight 16×16 PNGs in row-major order, with source-sheet crop coordinates and source-global frame IDs. Recorded browser exports match independently computed crops of the browser-decoded sheet.

What you need

Extract the original CC 0 project below and use assets/plain-sheet.png. The pack also contains a margin/gap variant, original reference frames, a geometry sidecar and a dependency-free Node 24 runner.

Choose a static PNG up to 10 MiB. The tool exports at most 32 selected cells per run and also checks full-source geometry and a conservative memory budget. It does not detect a grid or read irregular packed-atlas JSON.

Original four-column two-row sheet containing numbered cells zero through seven

Tested with: Chrome 154 on macOS: actual Next 16.3.8 split exports; separate bounded Cloudflare split/build replay. Node 24.22.0 reference runner and independent Pillow 12.3.0 checks.

1. Declare complete cells before splitting

Upload plain-sheet.png. Set Cell width and Cell height to 16, all four outer margins to 0, and both gaps to 0. The plan should show eight frames, four columns and two rows: first crop (0,0,16,16), last crop (48,16,16,16).

Coordinates start at the top left. Half-open rectangle (48,16,16,16) includes x 48–63 and y 16–31; its right/bottom boundary is (64,32). The next cell's first pixel is not part of that crop.

2. Export and retain the source frame IDs

Select Split into PNG frames. Results provide one link per PNG, Download ZIP and Download manifest. The ZIP contains the same PNG bytes and manifest.json. Keep that manifest with the frames.

The actual filenames run from plain-sheet-frame-000000.png through plain-sheet-frame-000007.png. The manifest's sourceIndex is 0 because all cells come from one image; sourceFrameIndex identifies the original cell.

For a subset, enable Limit frame range (zero-based, inclusive) and enter 2 through 5. Four PNGs retain source frame IDs 2,3,4,5. The first result has output frameIndex:0 and sourceFrameIndex:2; local output order does not rename the original sheet coordinates.

3. Enter all four margins and both gaps for the variant

Choose assets/margin-sheet.png, the same eight cells in a 79×42 image. Use 16×16 cells; left 2, top 3, right 4, bottom 5; horizontal gap 3 and vertical gap 2. The first crop is (2,3,16,16), and the last is (59,21,16,16). Disable the range to export all eight, or keep 2–5 for the measured four-frame case.

x = 2 + column × (16 + 3)
y = 3 + row × (16 + 2)
width  = 2 + 4×16 + 3×3 + 4 = 79
height = 3 + 2×16 + 1×2 + 5 = 42
Original eight cells with asymmetric outer margins and separate horizontal and vertical gaps
Original input PNG, not a tool screenshot. Margins and gaps are excluded from frame content.

4. Inspect the actual crops and manifest

Actual browser-exported first sixteen-by-sixteen frame from the original plain sheet
Actual 16×16 PNG download, enlarged for display. All eight exported cells were independently compared, including middle frames.

Inspect the recorded actual split manifest. Match each crop with its source frame ID. Rebuilding these decoded cells recovers the declared cell content; the margin variant does not export its outside margins or gaps.

To reproduce the separate file-level reference checks, run these commands inside the extracted sprite-grid folder. Its nine Node cases include the corrected CLI/import guards; they do not replay the browser UI.

node --test fixture.test.mjs
node generate.mjs
node generate.mjs --check

5. Reject incomplete grids and read failures

partial-sheet.png is 65×32. With 16×16 cells and zero margins/gaps, its extra right-hand column is incomplete and the tool rejects it. A confirmed right margin of 1 would describe a different valid declaration; the image alone does not establish that intent.

Reject negative gaps, blank/noninteger values and reversed/out-of-bounds ranges. A grid larger than 32 cells requires an explicit range of at most 32. Animated PNGs and corrupt files are rejected. A small range still requires decoding and reserving the full parent image. A failure or cancellation produces no partial export; fix the declaration and start a fresh run.

6. Compare decoded pixels at the codec boundary

The originals include alpha 0,1,85 and 128 probes, including invisible [100,150,200,0]. Pure cropping and the generated reference PNGs retain those file-level RGBA values. Browser decoding/encoding can normalize invisible RGB and round partial-alpha colors.

In the measured plain-sheet case, browser readback differed from the original in 72 channel bytes across the sheet; every exported crop matched that readback exactly. This establishes the recorded decoded-pixel result, not universal hidden-RGB, color-profile or metadata preservation. Keep your original PNG.

Sources and next steps