DEV Community

Cover image for à 720 or 600à 600: What Each Size Does in pack_product.py and Why

à 720 or 600à 600: What Each Size Does in pack_product.py and Why

720 or 600×600: What Each Size Does in pack_product.py and Why

Last spring I shipped a product with a cover that looked fine on my laptop and terrible on Gumroad. The preview grid cropped it. The title sat half off the image. I re-uploaded it three times before I stopped and measured what the platform actually wanted. That was the day I split the cover into two files, and pack_product.py has rendered both ever since.

Here is what each size does and why they are not interchangeable.

The 1280×720 cover is the marketing image

The cover at 1280×720 is what a buyer sees first. Marketplaces and storefronts display product cards in wide ratios, and 16:9 fits almost everywhere without cropping. When I render a cover, I draw the title and subtitle onto a background image with Pillow, then resize the longest side to fit exactly 1280×720. No guessing, no manual cropping in an editor.

The reason it exists is simple: a bare zip file sells badly. When I packaged the first few products without covers, the difference in click-through was obvious enough that I never shipped a naked zip again. The cover is the product's face. It needs real estate for the title, so wide beats square.

The 600×600 thumbnail is the grid image

The 600×600 thumbnail is square because grids are square. Stock platforms, sticker sheets, and marketplace category pages show assets as tiles. A 16:9 image in a square tile either gets letterboxed or cropped, and both look sloppy. A true square fills the tile edge to edge.

600 pixels is enough to look sharp at tile size on any normal screen, and it keeps the file small. On my 1 vCPU, 2 GB RAM server, every kilobyte and every pixel matters. Rendering a 600×600 thumbnail costs a fraction of the memory and time of a full-resolution render, and since the thumbnail never gets enlarged, there is no reason to render it bigger.

Why two files instead of one

I tried using one image for both. The wide cover in a square slot lost about a third of its height to cropping, which cut off the subtitle. The square thumbnail stretched into a wide slot looked blurry at the edges. Two renders from the same source image solve it. pack_product.py opens the background once, draws the text once for the cover with the wide layout, then draws again for the square layout. Same product, two correct aspect ratios.

This matters on a small server. I render one file per subprocess so memory returns to the OS between jobs, and I call gc.collect() after each asset. Two renders at target resolution, 1280×720 and 600×600, fit comfortably in 2 GB. Rendering at 3000 pixels wide and downsizing would not.

The naming convention that keeps it organized

The script writes three files per product: my-product.zip, my-product-cover.jpg, and my-product-thumb.jpg. The suffixes matter. When you have 39 products, you stop remembering which file is which. The suffix tells you instantly. The zip goes to the buyer, the cover goes in the listing's main image slot, the thumbnail goes in any grid or category view.

Everything lands in a _system folder next to where you run the script, or wherever --dir or the PACK_ROOT environment variable points. I keep packs/ for finished zips and covers in my project layout, so nothing gets mixed with raw assets in assets/ or submission files in output/.

What the zip actually contains

The cover and thumbnail are only half of pack_product.py. The script also zips the product files themselves. You pass the folder, the title, the subtitle, and a count, like this:

python pack_product.py my-product "My Product" "A short subtitle" 9
Enter fullscreen mode Exit fullscreen mode

That 9 is the number of files in the pack. The script bundles them, renders both images, and you have a finished product in one command. On my server, a typical pack with nine assets plus both renders takes seconds. Across 39 products and 856 MB of output, the whole packaging step ran on hardware worth nothing on the used market.

The reason I insist on doing this in code instead of by hand is repeatability. By hand, product 1 gets a nice cover, product 12 gets a lazy one, product 30 gets forgotten. In code, every product gets the same treatment, the same sizes, the same layout. That consistency is what makes a catalogue look professional instead of like a junk drawer.

Where to point each file

Quick reference for where each render goes:

  • 1280×720 cover: the main product image on any storefront, wide preview slots, social media cards
  • 600×600 thumb: grid tiles, category pages, anywhere a square is expected
  • zip: the deliverable itself

If you only render one image, render the cover. But the thumbnail costs almost nothing to produce and saves you from the cropped-tile look that made me re-upload three times.

The tool behind this

Everything I described here is pack_product.py, one of four scripts in the ai sticker factory playbook. The playbook covers the full pipeline: metadata CSVs for Adobe, Vecteezy, and Dreamstime, an upload tracker so you never double-post, the Markdown to PDF converter, and this packaging script with both renders. It ran the whole thing on 1 vCPU and 2 GB RAM, no GPU, and it is the same setup I use today.

If you want the scripts plus the rules behind them, that is what the playbook is for.

Get ai sticker factory playbook


Building digital products? Free guides & kits for digital product sellers.

Top comments (0)