What each platform does to a deck after upload, the pre-flight rules, and why export renders through headless Chromium rather than a canvas library.
| TikTok | |||
|---|---|---|---|
| Size | 1080×1350 | 1080×1350 | 1080×1920 |
| Output | Numbered images | Numbered images | |
| Format / quality | JPEG 0.92 | JPEG 0.90 | JPEG 0.90 |
| Byte band | 800KB–2MB | 200KB–1.5MB | 200KB–2MB |
| Max slides | 300 | 10 API / 20 app | 35 |
| Safe zone T/R/B/L | 80/40/80/40 | 135/0/135/0 | 100/180/480/40 |
| Min body / heading | 18 / 24pt | 18 / 24pt | 20 / 28pt |
LinkedIn rasterises every PDF to 1080px wide at JPEG ~80–85%, so "keep the text vector" is folk wisdom that does not survive the pipeline. What survives is designing at the exact size, in sRGB, with type big enough to read after a lossy pass.
Instagram crops every slide to the first slide’s ratio. Get slide 1 wrong and all ten are ruined. Its profile grid also shows a centred square, which is why the safe inset at 4:5 is 135px top and bottom — anything outside it is invisible to anyone browsing your profile.
API ceilings differ from app ceilings. A 20-slide Instagram deck can be posted by hand and by no scheduler that exists.
Blocking: too many slides, an empty deck, type below the platform floor, text that does not fit its box. Warnings: the app-vs-API slide gap, wrong artboard size, placeholder copy, hairline strokes, anything reaching into a safe zone, a weak hook on slide 1, and — after rendering — a file outside the byte band.
Blocks block; warnings do not. A tool that refuses to export because a stroke is 1px is a tool people route around. The overflow message names another slide as the remedy and names shrinking as the thing not to do, because shrink-to-fit is the complaint rather than the fix.
The client serialises the markup LayerView already produced — renderToStaticMarkup per visible layer — and POSTs it. The server renders it in a real headless Chromium at exact pixel size.
A canvas library was rejected because FlashCC leans on background-clip: text for gradient type and the FontFace API for uploads, and the html-to-canvas converters are unreliable on exactly those two.
One browser is kept warm across requests; launching Chromium is most of the time budget for a ten-slide deck. Uploaded faces travel with the markup as @font-face rules carrying their data URLs — they live in that browser’s localStorage and the server has never heard of them, so anything not sent is silently substituted with Arial.
LinkedIn PDFs are built from JPEG pages, not PNG: PNG pages have been observed converting into a PDF that renders blank, and the failure is silent until the post is live.
Filenames are zero-padded (01.jpg), because every upload dialog sorts by filename and a carousel out of order is worse than no carousel. The zip uses STORE — JPEG is already compressed, so deflating costs time and saves nothing.