First question: where will it be posted? That sets the aspect, the length, the safe areas and the loudness, and it is cheapest to know before the first still is made: generated shots for several aspects are planned (action in the middle third, a native vertical redraw per shot), not cropped afterwards.
Routes
| Where | Aspect and size | Length | Loudness | Load |
|---|---|---|---|---|
| TikTok, Reels, Shorts | 9:16, 1080×1920 | Ad 20 s; explainer or news short 30–50 s (45 s is about 110 words) | −14 LUFS, −1.5 dBTP | Safe areas below; ffmpeg-normalize-loudness |
| A feed (a square post) | 1:1, 1080×1080 | As the 9:16 cut | −16 LUFS | The shifted crop below |
| A site, YouTube, a deck, an email | 16:9, 1920×1080 | Any | −16 LUFS | guide-prepare-renders-for-delivery |
| An app-store preview, a vertical ad placement | 9:16 | ~30–35 s | −16 LUFS unless the placement says otherwise | Safe areas below |
Several places at once is common (a 20 s ad in 16:9, 1:1 and 9:16). Each aspect is its
own cut from the same shot list (ffmpeg-cut-clips-to-a-voiceover, --clip-key) and
its own title spec (hn4a-compositor-brand-ad-titles places each piece per aspect).
Pacing
- The hook in the first 3 s: the conflict or the pain, the counter by second 6
(
llm-write-a-hook). A slow scene-setter over a 6 s tilt read as dead air. - Shots of 2.5–6 s, one per sentence; a long hook sentence pair splits into two shots; the last shot can hold about 10 s under an open question or an end card.
- Words: a creator read runs about 2.5 words a second, an ad about 2.7
(
guide-make-a-script-from-source, Length). - One idea a shot.
- A progress bar on a short people scroll past: 12 px across the top, revealed left to right over the whole short, so the viewer sees how long is left.
Safe areas on 9:16
On a 1080×1920 frame, what stayed clear of the platform's buttons and captions:
- Captions in a 960 × 230 box at x 60, y 1330, at most 4 words or 22 characters at about 68 px.
- A title bar across the top at y ≈ 150.
- Stickers and graphics in y 300–1100.
- Dark gradients behind the top 360 px and the bottom 740 px, so type reads over bright frames.
Check a still of every scene against them:
exec ffmpeg -v error -y -i stills/v_06.png -vf "drawbox=x=60:y=1330:w=960:h=230:color=red@0.9:t=6,drawbox=x=0:y=300:w=iw:h=800:color=cyan@0.6:t=6,drawbox=x=0:y=120:w=iw:h=90:color=yellow@0.8:t=6" stills/v_06_safe.png
Several aspects from generated shots
-
Keep the action in the middle third of every 16:9 still, so the 1:1 and the 9:16 keep it.
-
Redraw each shot as a native 9:16, never crop: a 9:16 crop of a 1080p frame is 608 px wide and soft full screen; a redraw (
nano-banana-restage-for-new-aspect, "as if the same camera had shot it in portrait") was about $0.07 a shot, then animated at 9:16 like the 16:9. For an edit that already exists, crop and restage only the shots that lose a beat (workflow-reframe-to-vertical,ffmpeg-crop-to-vertical). -
The 1:1 is a centre crop of the 16:9, shifted per shot where the subject sits off centre: shift = the subject's x − 960 on the 1920 frame, clamped to ±420 (here the subject sits at x 1140):
exec ffmpeg -v error -y -i video/shot03.mp4 -vf "crop=1080:1080:(iw-1080)/2+180:0" -c:v libx264 -crf 14 -pix_fmt yuv420p -c:a copy video/sq/shot03.mp4Check a frame per shot.
-
Titles and end cards per aspect, never cropped: an end card in the lower third of a 16:9 sits in the lower part of a 9:16 too, clear of the bottom buttons.
Avoid
- One master cropped to every aspect after the fact.
- Captions or stickers placed by eye on a 9:16 frame: check them against the boxes above.
- Normalizing a short to −16 LUFS: it plays quieter than the feed around it.
- A 15 s full-frame talking head before anything happens on screen.
Related
guide-add-titles-and-motion-graphics: the titles and captions themselves.guide-prepare-renders-for-delivery: resolution, copies and the vertical crop of an existing cut.


