shorts-kit
v0.1.0
Published
Zero-dependency utilities for vertical video: SRT caption generation, WCAG contrast grading for thumbnails, and safe-zone margins for YouTube Shorts, TikTok and Reels.
Maintainers
Readme
shorts-kit
Zero-dependency utilities for vertical video. Three things that keep getting rewritten badly: turning a transcript into an SRT file, checking whether thumbnail text is actually readable, and knowing which part of a 1080×1920 frame the platform UI covers.
No dependencies, ESM + CJS, typed, works in Node and the browser.
npm install shorts-kitCaptions
Transcript in, SRT out. Timings are estimated from a words-per-minute rate, not derived from audio — enough to lay captions out and hand the file to an editor that snaps them to the waveform, not a substitute for forced alignment.
import { generateSrt, getSrtStats } from "shorts-kit";
const srt = generateSrt("the quick brown fox jumps", {
wordsPerCaption: 3, // default 6; drop to 4 for fast narration
maxLineLength: 32, // default 42; use 32 for vertical video
wordsPerMinute: 150, // default 150
});
// 1
// 00:00:00,000 --> 00:00:01,200
// the quick brown
//
// 2
// 00:00:01,200 --> 00:00:02,000
// fox jumps
getSrtStats(srt); // { count: 2, avgChars: 12, durationSeconds: 2 }Also exported: formatTimecode, parseTimecode, wrapLine.
Contrast
WCAG 2.1 contrast maths, pointed at thumbnail legibility. The WCAG thresholds were written for body text, not a headline viewed at postage-stamp size in a feed — but anything failing AA at normal size will be unreadable on a phone.
import { gradeContrast, HIGH_CONTRAST_PAIRS } from "shorts-kit";
gradeContrast("#ffffff", "#0a1628");
// { ratio: 18.13, grade: "excellent", wcagAA: true, wcagAAA: true }
gradeContrast("#bbbbbb", "#ffffff");
// { ratio: 1.92, grade: "fail", wcagAA: false, wcagAAA: false }
HIGH_CONTRAST_PAIRS; // 5 combinations that survive being shrunk to feed sizeGrades are excellent (≥7), good (≥4.5), borderline (≥3), fail. Accepts
3- or 6-digit hex and throws on anything that isn't a colour. Also exported:
contrastRatio, relativeLuminance, isValidHex, normaliseHex.
Safe zones
Where YouTube Shorts, TikTok and Instagram Reels draw their own interface over your frame.
import { getSafeArea, isInsideSafeZone, getCaptionBand, coverRect } from "shorts-kit";
getSafeArea("shorts"); // { x: 60, y: 180, width: 880, height: 1360 }
getSafeArea("all"); // worst case across all three platforms
isInsideSafeZone({ x: 60, y: 1720, width: 960, height: 120 }, "shorts");
// false — that's under the title and subscribe button
getCaptionBand("all"); // the middle third, where captions belong
coverRect(1920, 1080); // source rect for a centred 9:16 cropThese margins are conservative community-measured values, not published constants. No platform documents an organic safe zone, and the overlay moves with caption length, device size and whether the video is an ad. Treat them as a floor and check against a real handset before committing a layout.
| Platform | Top | Bottom | Left | Right | Safe area | |---|---|---|---|---|---| | YouTube Shorts | 180 | 380 | 60 | 140 | 880 × 1360 | | TikTok | 130 | 480 | 60 | 140 | 880 × 1310 | | Instagram Reels | 180 | 420 | 60 | 160 | 860 × 1320 | | All three | 180 | 480 | 60 | 160 | 860 × 1260 |
The biggest difference is at the bottom: TikTok's caption block eats noticeably more vertical space than Shorts, so a title that clears the Shorts UI can still land under TikTok's caption.
Hosted versions
These run as free browser tools, no install:
- Caption formatter — paste a transcript, download the
.srt - Thumbnail contrast checker — pick two colours, get the ratio
- Shorts safe zone checker — drop in a frame, download a 1080×1920 overlay template
Extracted from the tooling behind Leaxor.
Licence
MIT
