Skills
Skill 74 of 200
Check SRT or WebVTT captions and subtitles against published standards (Netflix English, BBC subtitle guidelines, DCMP Captioning Key) for reading speed, line length, line count…
4 minutes · 844 words · 6 sections
Install
npx skills add github/awesome-copilot --skill caption-qanpx skills add github/awesome-copilot/plugin marketplace add github/awesome-copilotThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Captions fail delivery and accessibility review on numbers: characters a second, characters a line, time on screen and the gap between captions. Each standard publishes its own limits, and they differ, so “are these captions OK?” has no answer until you know where they are going. This skill picks the right set of limits, measures every cue the same way the published limits are written, and fixes failures without cutting the speaker’s words.
.srt or .vtt file and asks whether it is ready to ship, or why a platform rejected it.If the user names no target, use Netflix English (adult) and say that you did.
| Standard | Reading speed | Line length | Lines | Time on screen | Gap between captions |
|---|---|---|---|---|---|
| Netflix English, adult | 20 characters a second | 42 characters | 2 | 5/6 s to 7 s | At least 2 frames; close gaps under 0.5 s to 2 frames |
| Netflix English, children’s | 17 characters a second | 42 characters | 2 | 5/6 s to 7 s | Same as adult |
| BBC subtitle guidelines | 160-180 words a minute; aim for about 0.3 s a word | 37 characters (broadcast); online, 68% of the width of a 16:9 frame | 2 | - | If you leave a gap, at least 1 s, preferably 1.5 s |
| DCMP Captioning Key (US educational media) | 130 / 140 / 160 words a minute for lower / middle / upper level | - | 2 (preferred) | 40 frames (1 s 10 frames) to 6 s | - |
Sources: Netflix English (USA) Timed Text Style Guide (opens in a new tab), Netflix subtitle timing guidelines (opens in a new tab), BBC subtitle guidelines (opens in a new tab), DCMP Captioning Key: text (opens in a new tab) and presentation rate (opens in a new tab). The BBC’s per-word time and minimum gap are guidance, so report them as suggestions, not failures.
<i>, <b>, {\an8}) or the cue number.00:00:01,000 (SRT) and 00:00:01.000 or 01.000 (WebVTT). Skip WebVTT NOTE, STYLE and REGION blocks, and treat cue settings after the timestamps (align:start) as part of the timing line.When the user wants a repeatable check (a folder of files, or CI), write this script, or adapt it to the chosen standard. It applies the Netflix adult limits from the table, prints each failing caption and exits with 1 when any caption fails, so it can gate a build. It needs only Python 3.
import re
import sys
# Netflix English, adult programs. Change these for another standard.
LIMITS = {"cps": 20, "cpl": 42, "lines": 2, "min_s": 5 / 6, "max_s": 7, "gap_frames": 2}
FPS = 24
T = r"(?:(\d+):)?(\d{1,2}):(\d{1,2})[,.](\d{1,3})"
TIMING = re.compile(T + r"\s*-->\s*" + T)
TAGS = re.compile(r"<[^>]+>|\{\\[^}]*\}")
def seconds(h, m, s, ms):
return int(h or 0) * 3600 + int(m) * 60 + int(s) + int((ms + "00")[:3]) / 1000
def read_cues(path):
text = open(path, encoding="utf-8-sig").read().replace("\r\n", "\n")
for block in re.split(r"\n[ \t]*\n", text):
lines = block.strip().split("\n")
for i, line in enumerate(lines[:3]):
m = TIMING.search(line)
if m:
body = [TAGS.sub("", t).rstrip() for t in lines[i + 1:]]
g = m.groups()
yield seconds(*g[:4]), seconds(*g[4:]), [t for t in body if t.strip()]
break
def check(path, lim=LIMITS, fps=FPS):
cues, failed = list(read_cues(path)), 0
for n, (start, end, text) in enumerate(cues, 1):
dur, chars, issues = end - start, sum(len(t) for t in text), []
if dur > 0 and chars / dur > lim["cps"]:
issues.append(f"{chars / dur:.1f} characters a second")
issues += [f"line {j} is {len(t)} characters"
for j, t in enumerate(text, 1) if len(t) > lim["cpl"]]
if len(text) > lim["lines"]:
issues.append(f"{len(text)} lines")
if dur < lim["min_s"] or dur > lim["max_s"]:
issues.append(f"on screen {dur:.2f} s")
if n < len(cues):
gap = cues[n][0] - end
if gap < 0:
issues.append(f"overlaps the next caption by {-gap:.2f} s")
elif gap * fps < lim["gap_frames"] - 0.01:
issues.append(f"gap of {gap * fps:.0f} frames at {fps} fps")
if issues:
failed += 1
print(f"{path} #{n} {start:.3f} -> {end:.3f}: " + "; ".join(issues))
print(f"{path}: {len(cues) - failed} of {len(cues)} captions pass")
return failed == 0
if __name__ == "__main__":
results = [check(p) for p in sys.argv[1:]]
sys.exit(0 if results and all(results) else 1)Run it as python3 check_captions.py captions/*.srt. For another standard, change LIMITS, and add a words-a-minute check (words divided by duration, times 60) for the BBC and DCMP. The script doesn’t check the advice-level rules (chaining short gaps, the BBC’s per-word time); report those separately.
In GitHub Actions:
- run: python3 check_captions.py captions/*.srtffmpeg -i subs.ass subs.srt, which keeps the timing and wraps the text in font tags that the character count ignores.Check SRT or WebVTT captions and subtitles against published standards (Netflix English, BBC subtitle guidelines, DCMP Captioning Key) for reading speed, line length, line count, time on screen, gaps and overlaps, then fix failures by retiming before rewording. Use when asked to QA, lint or validate captions, check whether subtitles read too fast, prepare captions for Netflix, broadcast or educational delivery, or add a caption check to CI.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
skills/caption-qa/SKILL.mdmain, last pushed 6 November 2026.SKILL.md, not by matching a directory convention. 2 distinct layouts observed: .github/skills/*/SKILL.md, skills/*/SKILL.md.h1 and no skipped levels:.github/plugin/marketplace.json by GitHub, declaring 207 plugins. It is read for editorial metadata only — never as the skill index, which is always the repository tree./github/awesome-copilot.md, and each skill at its own .md URL.