The 1280 720 Lesson: Why a Zip Isn't Shippable Until It Has a Cover"**
I had 39 finished products sitting in a folder and nothing to sell. Every zip was just files. No cover image, no thumbnail, no way to show anyone what was inside. I uploaded one to Gumroad as a bare zip and it looked exactly like what it was: a random archive nobody would trust with a dollar. The fix took one evening and one script. The lesson took longer: a zip isn’t shippable until it has a cover.
我曾有 39 个成品放在文件夹里,却什么也卖不出去。每个压缩包里都只是文件,没有封面图,没有缩略图,也没法向任何人展示里面的内容。我曾把一个裸压缩包上传到 Gumroad,它看起来就像它本身的样子:一个没人会愿意花一美元去信任的随机归档文件。解决这个问题只花了一个晚上和一个脚本,但领悟这个教训却用了更久:没有封面的压缩包是无法交付的。
Here is what I learned getting from 39 bare zips to 1,700 assets made, 58 live on Adobe Stock, and a first sale of $0.99. The cover is the product page. A 1280×720 cover and a 600×600 thumbnail are not decoration. They are the only thing a buyer sees before deciding whether to open their wallet. Marketplace thumbnails are small, and a zip file icon communicates nothing. When I added a rendered cover with the product title and subtitle baked in, the product started looking like something a person made on purpose.
以下是我从 39 个裸压缩包,到制作出 1,700 个资产、在 Adobe Stock 上线 58 个产品并获得 0.99 美元首单的过程中学到的经验。封面就是产品页面。1280×720 的封面和 600×600 的缩略图不是装饰品,它们是买家在决定是否掏钱之前唯一能看到的东西。市场缩略图很小,而压缩包图标传达不了任何信息。当我添加了带有产品标题和副标题的渲染封面后,产品看起来才像是有人刻意制作出来的。
The script that does this, pack_product.py, uses Pillow and nothing else. It takes a folder, a title, a subtitle, and a price, and writes three files: the zip, the cover, and the thumbnail. One command: python pack_product.py my-product “My Product” “A short subtitle” 9. It writes into a _system folder by default, configurable with —dir or the PACK_ROOT environment variable. No editing the script, no framework, no cloud account.
实现这一功能的脚本 pack_product.py 只使用了 Pillow 库。它接收一个文件夹、标题、副标题和价格,然后生成三个文件:压缩包、封面和缩略图。只需一条命令:python pack_product.py my-product "My Product" "A short subtitle" 9。它默认写入 _system 文件夹,也可以通过 --dir 或 PACK_ROOT 环境变量进行配置。无需修改脚本,无需框架,也无需云账户。
Packaging is where solo makers stall, not creation. Making the art is the fun part. The four things that actually stall people are metadata, double-posting, turning a doc into a product, and packaging. I hit all four. Metadata first. All three stock channels reject a wrong CSV header instantly. Adobe wants a 5-column header, Vecteezy wants 4 columns, Dreamstime wants 15. Guess one column and your whole batch bounces.
独立创作者卡壳的地方在于打包,而不是创作。制作艺术品是很有趣的部分。真正阻碍人们的四件事是:元数据、重复发布、将文档转化为产品以及打包。这四点我都遇到过。首先是元数据。所有三个素材库渠道都会立即拒绝错误的 CSV 表头。Adobe 需要 5 列的表头,Vecteezy 需要 4 列,Dreamstime 需要 15 列。只要猜错一列,你整批文件都会被退回。
My metadata script writes the exact header each platform demands and nothing else, built straight from a folder of files: python make_metadata.py ./my-assets —platform adobe —out metadata.csv —ext .jpg. Without a titles file it title-cases the filename as a placeholder. Fine for a first pass, but replace it before you submit. Reviewers notice lazy titles.
我的元数据脚本会直接根据文件文件夹生成各平台要求的精确表头,不多不少:python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg。如果没有标题文件,它会将文件名转换为标题格式作为占位符。初次尝试尚可,但在提交前务必替换掉,审核人员会注意到敷衍的标题。
Double-posting is the fastest way to get flagged. This one cost me real anxiety. Run your upload batch twice, because you lost track of what you already submitted, and you are posting duplicates. That is the kind of behavior that gets an account flagged. With 58 assets live on Adobe, I was not willing to risk that over bad bookkeeping. So the pipeline has a ledger. upload_tracker.py is a plain-text tracker that remembers what is done.
重复发布是账号被标记的最快途径。这曾让我非常焦虑。如果你因为忘记了已经提交的内容而运行了两次上传批次,就会发布重复内容。这种行为会导致账号被标记。在 Adobe 上有 58 个资产上线的情况下,我不想因为糟糕的记录管理而冒这个险。因此,流水线中加入了一个账本。upload_tracker.py 是一个纯文本追踪器,用于记录已完成的工作。
The whole thing runs on a 1-core, 2 GB box. I did not have a GPU farm. The pipeline ran on 1 vCPU and 2 GB RAM, no GPU, and it packaged 856 MB of output across those 39 products. It works because of habits, not hardware: One process at a time. Never fan out image jobs in parallel on a single core. Call gc.collect() after each asset to free memory between items. Measure peak RSS, not average, with resource.getrusage(RUSAGE_SELF).ru_maxrss. Average lies, the peak is your real ceiling.
整个系统运行在一台单核、2GB 内存的机器上。我没有 GPU 集群。流水线运行在 1 个 vCPU 和 2GB 内存上,没有 GPU,它处理了 39 个产品,输出了 856MB 的内容。它之所以能运行,靠的是习惯而非硬件:一次只运行一个进程。永远不要在单核上并行处理图像任务。在处理每个资产后调用 gc.collect() 以释放内存。使用 resource.getrusage(RUSAGE_SELF).ru_maxrss 测量峰值 RSS,而不是平均值。平均值会骗人,峰值才是你真正的上限。
One structural mistake I made exactly once: deleting my research folder to “clean up”. Scrape logs, notes, keyword lists. Those are the raw material for the next product. Now the layout is fixed and the research folder is permanent: project/ assets/ raw output output/ ready-to-submit files + metadata.csv packs/ finished zips + covers research/ notes and sources, never deleted scripts/ the tools. A catalogue without a fixed structure turns into a junk drawer.
我曾犯过一次结构性错误:为了“清理”而删除了研究文件夹。抓取日志、笔记、关键词列表,这些都是下一个产品的原材料。现在布局已经固定,研究文件夹被永久保留:project/ 下包含 assets/(原始输出)、output/(待提交文件 + metadata.csv)、packs/(成品压缩包 + 封面)、research/(笔记和来源,永不删除)以及 scripts/(工具)。没有固定结构的目录最终会变成杂物抽屉。
What it added up to: 1,700 assets made. 58 live on Adobe Stock. First sale: $0.99. That number is small and I am not going to pretend otherwise. But it is real money from a pipeline that runs on a server weaker than most laptops, and the bottleneck was never the art. It was packaging and metadata, the boring layer nobody writes tutorials about.
最终成果是:制作了 1,700 个资产,在 Adobe Stock 上线了 58 个。首单收入:0.99 美元。这个数字很小,我不会假装它很大。但这是通过一个性能比大多数笔记本电脑还弱的服务器运行的流水线赚到的真金白银,瓶颈从来不是艺术创作,而是打包和元数据——那些没人愿意写教程的枯燥环节。