timecode
Skill1 starsChanged 3 months agoMITView on GitHub
SMPTE timecode arithmetic with drop-frame and non-drop-frame support — convert between timecode and seconds, add/subtract offsets, retime between frame rates, convert DF↔NDF, and infer format from strings or ffprobe/MediaInfo metadata. Use when edit decisions are expressed as HH:MM:SS:FF or HH:MM:SS;FF or when aligning clips at NTSC rates.
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- site/AGENTS.mdAGENTS.md
- site/CLAUDE.mdCLAUDE.md
- audioSkill
- captions-complianceSkill
- downloadSkill
- forced-narrative-exactSkill
- imageSkill
- inspectSkill
- install-media-toolsSkill
- program-masterSkill
- shotsSkill
- speech-captionsSkill
- subtitlesSkill
- video-transformationSkill
- vision-analysisSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 53
If your tools showed a filesystem path when loading this SKILL.md, strip SKILL.md and use that folder.
- Very specific: line 54
If you already ran another mediaskills script (for example .../audio/scripts/extract.py), this skill is a sibling of that folder: same …
- Very specific: line 77
Prefer absolute paths for --input / --output when cwd is uncertain.
- Distinctive: line 82
Before running any script, treat these two failures differently:
- Very specific: line 85
Only escalate sandbox permissions if the error is explicitly a permission denial (e.g.
- Very specific: line 139
After extract.py reports e.g.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Timecode
Frame-accurate SMPTE timecode math using the eoyilmaz/timecode library. Supports drop-frame (DF) and non-drop-frame (NDF) counting, DF↔NDF conversion, cross-fps retiming, and format detection from delimiters and metadata.
When to use
- This skill — timecode ↔ seconds, offsets, fps conversion, DF/NDF conversion, format detection, read file timecode tags.
video-transformation— once you have seconds-based trim points from timecode math.inspect— container duration and stream frame rates before assuming fps.
Drop-frame vs non-drop-frame
| Signal | Meaning |
HH:MM:SS;FF (semicolon) | Drop-frame display — standard for 29.97 / 59.94 NTSC |
HH:MM:SS:FF (colon) | Non-drop-frame display |
NTSC nominal rate (29.97, 59.94, 30000/1001) | Library defaults to drop-frame unless --non-drop-frame |
MediaInfo Time code settings | Drop frame or Non drop frame |
Drop-frame timecode skips frame numbers 00 and 01 at the start of each minute except every tenth minute, so the counter stays aligned with wall-clock time at 29.97 fps. At 01:00:00;00 DF, the NDF equivalent at the same wall-clock is roughly 00:59:56;12 when preserving frame index — use convert_df.py with --preserve realtime to match wall-clock instead.
Gotchas
- Semicolon matters — do not normalize
;to:before parsing; it changes DF vs NDF meaning. - Two “seconds” values — scripts return
seconds(linear from frame index),seconds_system(video system grid), andseconds_realtime(wall clock). For ffmpeg-sson NTSC DF material, preferseconds_realtime. - 29.97 is not 30 — use
29.97or30000/1001, not rounded30, when DF is intended. When mapping file seconds → embedded TC, multiply by the exact rational fps from ffprobe (30000/1001), not the library's integer_int_framerate(30). - Embedded start TC — masters often start at embedded timecodes e.g.
00:58:40;00with episode at01:00:00;00. Runextract.pyto read the tmcd start; usecalculate.pyorprogram-masterto offset segment boundaries. - Missing file timecode — many MP4/H.264 files have no timecode tag;
extract.pyreturnstimecode: null— derive from fps + duration instead. - Cross-fps retiming — default
convert.pypreserves wall-clock duration (--preserve realtime). Use--preserve framesonly when you need the same frame index at a new rate.
Running scripts
This skill's scripts live in scripts/ alongside this file. Before running any script, resolve its absolute path from this skill's own directory — do not assume the shell cwd is the skill folder, the repo root, or the workspace. Stay in the workspace (so media paths resolve) and pass the absolute script path to uv run:
uv run <skill_directory>/scripts/to_seconds.py --timecode 00:01:30;15 --fps 29.97<skill_directory> is a placeholder. Never pass those angle brackets to the shell — the command will fail. Replace it with a real absolute directory before invoking uv run.
How to get that directory (do this yourself; do not ask the user first; do not skip the skill):
- If your tools showed a filesystem path when loading this
SKILL.md, stripSKILL.mdand use that folder. - If you already ran another mediaskills script (for example
.../audio/scripts/extract.py), this skill is a sibling of that folder: same parent, directory nametimecode. - Otherwise search standard install locations and confirm the script exists:
NAME=timecode
for d in \
"$HOME/.agents/skills/$NAME" \
"$HOME/.cursor/skills/$NAME" \
"$HOME/.codex/skills/$NAME" \
"$HOME/.claude/skills/$NAME" \
"$PWD/.agents/skills/$NAME" \
"$PWD/.cursor/skills/$NAME" \
"$PWD/skills/$NAME"
do
if [ -f "$d/SKILL.md" ] && [ -e "$d/scripts/to_seconds.py" ]; then
SKILL_DIR=$(cd "$d" && pwd)
break
fi
done
[ -n "$SKILL_DIR" ] || { echo "mediaskills: $NAME not found" >&2; exit 1; }
uv run "$SKILL_DIR/scripts/to_seconds.py" --timecode 00:01:30;15 --fps 29.97Prefer absolute paths for --input / --output when cwd is uncertain.
Missing binaries vs permissions
Before running any script, treat these two failures differently:
- If a required binary (
uv,ffprobe) reportsNo such file or directoryorcommand not found: this is a missing or unreachable binary, not a permissions issue. Escalating sandbox permissions will not fix it. Runcommand -v uvandcommand -v ffprobeto see whether they resolve at all. If not, install or re-link them (install-media-toolsdoctor/install) rather than retrying with wider permissions.ffprobeis required forextract.py; other scripts only needuv. - Only escalate sandbox permissions if the error is explicitly a permission denial (e.g.
Operation not permitted,Permission denied).
Recipes
Timecode to seconds (29.97 drop-frame)
uv run <skill_directory>/scripts/to_seconds.py --timecode 00:01:30;15 --fps 29.97Seconds to drop-frame timecode
uv run <skill_directory>/scripts/from_seconds.py --seconds 90.5 --fps 29.97Add a 5-second slate (wall-clock)
uv run <skill_directory>/scripts/calculate.py --timecode 01:00:00;00 --op add --offset-seconds 5 --fps 29.97Convert 24fps edit point to 29.97 DF sequence
uv run <skill_directory>/scripts/convert.py --timecode 00:10:00:00 --from-fps 24 --to-fps 29.97Convert drop-frame to non-drop-frame (same wall-clock)
uv run <skill_directory>/scripts/convert_df.py --timecode 01:00:00;00 --fps 29.97 --to non-drop-frameDetect format from a timecode string
uv run <skill_directory>/scripts/detect_format.py --timecode 01:00:00;00 --fps 29.97Analyze ffprobe or MediaInfo JSON
uv run <skill_directory>/scripts/analyze_metadata.py --input /path/to/ffprobe.jsonRead embedded timecode from a file
uv run <skill_directory>/scripts/extract.py --input /path/to/clip.movMap file seconds to embedded SMPTE (broadcast master)
After extract.py reports e.g. start 00:58:40;00 at 30000/1001:
uv run <skill_directory>/scripts/calculate.py --timecode 00:58:40;00 --op add --offset-seconds 80.013 --fps 30000/1001For full segment manifests with labels, prefer program-master label_segments.py (auto-detects tmcd).
Troubleshooting
| Symptom | Cause | Action |
| Off by ~3.6s per hour | DF treated as NDF (or vice versa) | Check delimiter; run detect_format.py |
| Frame count off by 1–2 | 0-based vs 1-based frames | Use frames (0-based) from script output |
Invalid timecode | Wrong field count | Use four fields HH:MM:SS:FF or HH:MM:SS;FF |
timecode null in extract | No tag in file | Use from_seconds with known fps |
| 24→29.97 mismatch | Used frame index instead of wall-clock | convert.py defaults to --preserve realtime |
Available scripts
| Script | Purpose |
scripts/info.py | Supported fps, formats, library reference |
scripts/to_seconds.py | Timecode → seconds + frames |
scripts/from_seconds.py | Seconds → timecode |
scripts/calculate.py | Add/subtract offset (wall-clock) |
scripts/convert.py | Retime timecode between fps values |
scripts/convert_df.py | Convert DF ↔ NDF |
scripts/detect_format.py | Infer DF/NDF from string + fps |
scripts/analyze_metadata.py | Infer format from ffprobe/MediaInfo JSON |
scripts/extract.py | Read timecode tags via ffprobe |
See references/DF_NDF.md for drop-frame background.
Acceptance checks (agent must pass before delivery)
- Contract: exit 0,
ok: true, anddata.seconds_realtime/ timecode fields present when converting for edits. - Spot-check: DF vs NDF matches source (semicolon vs colon); seconds feed into trim and output duration ≈ (end − start).
- On failure: recalculate; do not trim on guessed seconds.
Do not use for
- Actual video trimming (convert to seconds, then use
video-transformation) - Legal frame-rate standards beyond SMPTE timecode display math
Related skills
video-transformation— apply trim points in secondsinspect— probe frame rates and duration
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

