What does asset-size-matrix do?
One master, every slot, nothing important cut off, and a receipt for each file.
What this skill is
A launch rarely needs one image. It needs a link preview, a video thumbnail, a square post, a portrait post, a 3:4 cover, a vertical story, a profile banner, an app icon, a repo preview, maybe a vertical video. Each one has its own pixel size, its own file rules, and its own interface overlay: the like column on the right of a vertical feed, the duration badge in the corner of a thumbnail, the avatar sitting on top of a banner, the rounded mask on an icon.
People usually handle this by dragging a crop box around a dozen times. The results are familiar: a headline sliced in half on the 9:16 version, a logo hidden under the avatar, text that was readable on the 4K master and is three pixels tall in the feed, a thumbnail rejected for being 2.3 MB, a short that plays 8 dB quieter than everything around it.
This skill makes the job a table. Every destination becomes a slot card with numbers and a date. The master gets marked once: which boxes must survive. A small planner computes, for each slot, the widest crop that keeps those boxes inside the slot's safe area, and says plainly when no crop can work. Then every exported file is checked against its card.
The problem it solves
- Crops are decided by eye, one at a time, so they are inconsistent and nobody can say why a given crop was chosen.
- Safe areas are forgotten until the post is live and the call-to-action sits under a button.
- "Just crop it" is applied to slots where cropping cannot work (a wide layout squeezed into 9:16), so the result is either cut off or shrunk to illegibility.
- Text size is judged on the master, not at the size the slot is actually displayed.
- File rules (format, weight, codec, frame rate, loudness) are discovered by upload errors.
- Platform numbers are copied from old blog posts with no date and no source.
When to use
Use it when:
- one design must be delivered in several sizes or to several platforms;
- someone asks for a "launch kit", "social pack", "all the sizes", "banner set";
- a cover or thumbnail keeps getting cut off or blurry after upload;
- a short video must also exist as a vertical, square and wide version;
- you are about to export a batch and want proof every file meets its spec.
Do not use it to create the design from nothing (make the master first), to edit video content (cutting, captions, color), or to publish. It can tell you that a slot needs a new layout; the new layout is a design task.
What you need
- The master: ideally the editable source (Figma/PSD/HTML/SVG/project file) plus a flat export at the largest size available. Pixels alone are fine for crop-only slots.
- The list of destinations, or the goal ("launching on X, Instagram and our blog").
- For video slots: the video file, and
ffmpeg/ffprobeinstalled if you want automatic checks. - Python 3.8+ for the helper
scripts/matrix.py(standard library only).
Step by step
1. Take stock of the master
Record in master.json (see examples/master.json):
- pixel width and height, and whether it is a still or video;
- whether an editable source exists (this decides how expensive a REFLOW is);
- the largest version available. Never plan from a downsized copy someone pasted in chat.
If the master is smaller than the biggest slot, say so now; it will show up as UPSCALE later.
2. Write the slot list, with dates
Create slots.json (start from examples/slots.json). One card per slot:
| field | meaning |
|---|---|
id | file name stem of the export, e.g. video-thumb -> video-thumb.jpg |
w, h | delivered pixel size; exact: false means "at least this, same aspect" |
safe | top, right, bottom, left insets in slot pixels that the platform UI covers |
drop | named boxes that should not appear in this slot (e.g. headline on an icon) |
fit | wide (default, keep as much context as possible) or tight (fill the safe area) |
display_w | how wide the slot is really shown, in CSS px, e.g. a thumbnail in a grid |
min_text_px | smallest cap height that is still readable at display_w |
formats, max_kb | allowed file types and weight cap |
| video fields | video_codec, audio_codec, pix_fmt, fps range, min_s/max_s, sample_rate, lufs (+lufs_tol), true_peak_max |
source | where the numbers came from |
Rules for the list:
- Put
as_of(today's date) at the top. Sizes and overlays change; a card without a date is a rumor. - Check each card against the platform's own current help page or downloadable template.
If you cannot verify a number, keep it but write
"source": "unverified"and say so in the hand-off. - Ask about slots only when the destination is unclear. One bundled question beats five: "I'll make link card, thumbnail, square, 9:16 story and banner. Add or remove any?"
3. Mark the master
Still in master.json, list boxes as [x, y, w, h] in master pixels:
keep: what must be visible in every slot that does not drop it (product, face, key art);text: each text block with itscap_px(height of a capital letter on the master);logo: the mark;focus: a point to center on when nothing is marked.
Get boxes by measuring in the design tool, reading the layer bounds from the source file, or by opening the image and estimating carefully. Pad each box by a few percent; a box that hugs a face cuts the chin off in practice.
4. Plan every slot
python3 scripts/matrix.py plan --master master.json --slots slots.json
For each slot you get a verdict:
- CROP: a crop + scale keeps everything required inside the safe area. The row includes
the crop rectangle and a ready
ffmpegfilter (crop=w:h:x:y,scale=W:H). - UPSCALE: a crop works but enlarges the master. The row says what master size is needed. Ask for a bigger export or a vector logo instead of shipping a soft image.
- REFLOW: no crop can work, or text would be unreadable at display size. If the row
includes
art_only, the artwork still crops cleanly and only the listed text/logo needs to be re-set for this shape. Otherwise the composition itself has to change.
Show the user the table before exporting anything. It is the cheapest moment to change your mind.
5. Resolve each REFLOW
Pick the lightest fix that works, in this order:
- Re-set the type: crop the art with the
art_onlyrectangle, then place the headline and logo again inside the slot's safe area, at a size that passesmin_text_px. - Restack: wide layouts (text left, art right) become tall ones (art top, text below), from the editable source, keeping the same fonts, colors and spacing ratios.
- Extend the canvas: widen the background in the source file (or with a plain brand color) so the art fits the safe area, rather than shrinking the art.
- Shorten for small slots: icons and avatars carry only the mark; a 3:4 cover in a two-column grid may need a shorter headline. Never rewrite copy yourself; propose the shorter line and let the owner approve it.
Re-run plan after each change until every slot is CROP or a deliberate, explained exception.
6. Export
- Crop-only slots: apply the planned filter, for stills or video alike:
ffmpeg -i master.png -vf "crop=...,scale=..." link-card.png. - REFLOW slots: export from the editable source at the exact slot size.
- Name every file
<slot id>.<ext>in one folder, so the checker can find it. - Stills: sRGB, no transparency where the platform flattens it onto an unknown color,
quality lowered step by step only until
max_kbis met. - Video: even width and height,
yuv420p, the frame rate of the source unless the card says otherwise, loudness normalized to the card's target. For a size cap, compute the bitrate:python3 scripts/matrix.py budget --seconds 58 --max-mb 50. - More recipes in
references/export-recipes.md.
7. Check every file
python3 scripts/matrix.py check --slots slots.json --dir out/ --loudness
Each slot comes back PASS, FAIL, CHECK (something could not be measured) or MISSING. Fix mechanical failures freely (wrong size, format, weight, pixel format, sample rate). Failures that change content (shorter duration, a tighter crop, louder audio that lifts background noise) need the owner's choice: state the option and its cost.
8. Look at it, at real size
The checker cannot see. Build a contact sheet that shows every slot at its display_w, with
the safe area outlined, and open it:
python3 scripts/matrix.py sheet --slots slots.json --dir out/ # writes out/contact-sheet.html
Look for: text crossing the safe line, faces cut at the joints (chin, top of head, hands), the logo on a busy background, two slots that look like different brands.
9. Hand over
Deliver the folder plus a short manifest:
Kit: Tidepool launch, slots as_of 2026-10-24 (2 cards unverified: note-cover, article-cover)
link-card.png 1200x630 184 KB PASS crop
video-thumb.jpg 1280x720 402 KB PASS reflow: headline re-set at 96 px cap
story-vertical.png 1080x1920 1.1 MB PASS reflow: restacked, canvas extended
app-icon.png 1024x1024 61 KB PASS from vector logo (raster was 1.6x too small)
vertical-video.mp4 1080x1920 21 MB PASS -14.2 LUFS, -1.3 dBTP, 30 fps, 41.0 s
Look: contact-sheet.html (all slots at display size)
Examples
"Make this launch banner work everywhere."
Master 4000x2250, headline left, phone mock-up right. Plan: link card and repo preview CROP;
thumbnail REFLOW (headline only 13.5 px tall at grid size, needs 14); square, portrait and 3:4
REFLOW with an art_only crop (re-set headline under the phone); 9:16 REFLOW without art-only
(the mock-up is too wide for the safe column, so extend the canvas and restack); app icon
UPSCALE (use the vector logo). See examples/plan.output.md.
"YouTube keeps rejecting my thumbnail." One slot. The check shows 2.4 MB against a 2 MB cap and 1280x721. Re-export at 1280x720, JPEG quality lowered from 95 to 88: 1.3 MB, PASS.
"Same short for Reels, Shorts and a wide YouTube cut."
Three video slots. Vertical slots CROP from the 16:9 master only because the speaker is
centered; the wide cut is the master. The check finds 44.1 kHz audio (WARN) and -21.9 LUFS
(FAIL against -14); normalize, re-export, re-check. See examples/check.output.txt.
Tips
- Mark the master once and keep
master.jsonwith the design file; the next campaign reuses it. - When two platforms share a shape, still give them separate cards if their overlays differ.
- Prefer one conservative safe box for vertical video if one export must serve several feeds.
- A crop that passes the numbers but cuts through a person's joint still fails; trust the look step.
fit: tightis for marks and icons; everything else should keep context (wide).- Keep unverified numbers visible in the manifest instead of quietly trusting them.
- Re-check after every re-export, not just the file you changed: batch tools overwrite neighbors.