Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b6a651f
feat(sync-timelines): reconcile drifted timeline mirrors from draft_c…
renezander030 Jul 8, 2026
97f74c5
feat(lint): fix line-too-long + caption-gap-too-small; new unknown-ef…
renezander030 Jul 8, 2026
c1a1731
feat(export-srt): word-level caption export with karaoke SRT/VTT
renezander030 Jul 8, 2026
40dd0de
feat(keyframe): easing curves via CapCut FreeCurveInOut bezier handles
renezander030 Jul 8, 2026
368a819
feat(detect-scenes): deterministic ffmpeg scene-cut detection to seed…
renezander030 Jul 8, 2026
7b64894
feat(preset): make-preset extracts a reusable text-style preset; appl…
renezander030 Jul 8, 2026
9140380
merge: feat/sync-timelines
renezander030 Jul 8, 2026
0db66df
merge: feat/lint-fix-extend
renezander030 Jul 8, 2026
84c73f5
merge: feat/srt-word-level
renezander030 Jul 8, 2026
80aaa84
merge: feat/keyframe-easing
renezander030 Jul 8, 2026
aa07f37
merge: feat/scene-detect
renezander030 Jul 8, 2026
006e5b4
merge: feat/make-preset
renezander030 Jul 8, 2026
69848f6
fix(test): use escape sequences instead of raw control bytes in sync-…
renezander030 Jul 8, 2026
d26453c
chore: release v0.13.0
renezander030 Jul 8, 2026
f172399
fix(lint): honor render floor in gap repair, correct wrap break posit…
renezander030 Jul 8, 2026
d17439d
fix(sync-timelines): direction safety, exact write set, honest verdicts
renezander030 Jul 8, 2026
8f7874e
fix(srt): karaoke collapse per repetition, ms rollover carry, valid W…
renezander030 Jul 8, 2026
7ac470c
fix(keyframe): easing validation, stale bezier handles, and lone-keyf…
renezander030 Jul 8, 2026
4a54f8d
fix(scenes): video-stream duration, honest spawn errors, timecode carry
renezander030 Jul 8, 2026
ddbd02e
merge: fix/sync (review findings)
renezander030 Jul 8, 2026
e5f1418
merge: fix/lint (review findings)
renezander030 Jul 8, 2026
e24490b
merge: fix/srt (review findings)
renezander030 Jul 8, 2026
32f7a2b
merge: fix/keyframe (review findings)
renezander030 Jul 8, 2026
98d2220
merge: fix/scene (review findings)
renezander030 Jul 8, 2026
ea1bc0e
fix(preset): enforce flag precedence, validate schema, honor dry-run
renezander030 Jul 8, 2026
dd1b887
test(preset): cover flag precedence, schema validation, collapse, dry…
renezander030 Jul 8, 2026
a43aa70
fix(cli): scope new release flags to the commands that declare them
renezander030 Jul 8, 2026
6bf43fd
merge: fix/preset (review findings)
renezander030 Jul 8, 2026
1ecbad0
merge: fix/flags (review findings)
renezander030 Jul 8, 2026
36a47d7
docs(release): finalize v0.13.0 changelog and command reference
renezander030 Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,29 @@

All notable changes to capcut-cli are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [0.13.0] — 2026-07-08

Six features in one release — the top of the opportunity backlog, bundled. Two build on prior art from the [capcut-cli-david](https://github.com/Davidb-2107/capcut-cli-david) fork (thanks @Davidb-2107); see #36.

### Added

- `lint <project> --fix` — auto-repair mechanically-fixable draft defects (`cue-too-long`, `caption-overlap`). Trims over-long captions to the configured cap and shortens overlapping caption pairs so each ends where the next begins. Writes atomically with a `.bak` snapshot; combine with `--dry-run` to preview without touching the draft. Non-fixable issues (`missing-material`, `missing-file`, `line-too-long`, `caption-gap-too-small`) are still reported and continue to drive the exit code. Closes #40.
- `sync-timelines <project-dir> [--apply] [--force-write]` — reconcile a CapCut >= 8.7 draft whose `template-2.tmp` / `draft_info.json` timeline mirror has drifted from `draft_content.json`, so CLI edits are honored by the app instead of silently ignored. `draft_content.json` is always canonical and is treated read-only. Accepts only a project directory or its `draft_content.json` (any other filename exits 1). Plan-only by default: the per-target drift report includes each mirror's mtime plus `newer_mirrors` / `canonical_stale`, and warns when `draft_content.json` is older than a drifted mirror (you would overwrite newer edits). `--apply` refuses that direction unless you add `--force-write` (exit 1), then rewrites **only** the drifted mirrors — the canonical file is never re-sorted or backed up, and in-sync mirrors are left untouched; `reconciled` / `backups` list exactly the files written. No-ops with exit 0 when all targets already agree. An unreadable (binary/encrypted) mirror is reported unreconcilable (`ok:false`, `in_sync:false`, exit 2) and stays idempotent on re-run instead of pretending success. `--apply --dry-run` reports the plan only (`would_reconcile`, `reconciled: []`). `diagnose` now recommends the plan form (with a back-up caution) instead of deferring to issue #35. Closes #39.
- `lint <project> --fix` — auto-repair mechanically-fixable draft defects, now four codes: `cue-too-long` (trims over-long captions to the configured cap), `caption-overlap` (shortens overlapping pairs so each ends where the next begins), `line-too-long` (greedy word wrap that swaps spaces for newlines 1:1, keeping styled-range byte offsets valid; never splits words — instances the wrap cannot actually fix, i.e. space-less/CJK text and over-cap single words, are stamped `fixable:false`), and `caption-gap-too-small` (pulls the earlier caption's end back to restore the minimum gap; never moves starts, never creates a new overlap). The gap repair honors a hard floor — exported `MIN_CAPTION_DURATION_US = 100_000` (100ms) — so a shrink that would land a caption below the floor is skipped and stamped `fixable:false` for that instance instead of collapsing it. Writes atomically with a `.bak` snapshot; combine with `--dry-run` to preview. `missing-material` and `missing-file` stay report-only deliberately: the only mechanical repairs would delete user timeline content or act on host-dependent paths. Closes #40.
- `lint` — new report-only rule `unknown-effect-slug` (**info** severity, exit 0): flags effect/filter/animation resource ids in the draft that are not in the bundled enum table, surfacing them before CapCut silently drops them (the silent-failure mode reported across ecosystem tools, e.g. GuanYixuan/pyCapCut#12). Info rather than warning because store-downloaded effects on app-authored drafts are legitimate; only CLI-written stale slugs are at risk.
- `export-srt <project> [--granularity line|word] [--format srt|vtt]` — word-level caption export. Captions created by `caption --karaoke` carry real per-word timing and export it exactly; plain captions interpolate word timing proportionally by word length (stated in `--help`). SRT + word emits one cue per word; VTT + word emits one cue per phrase with inline `<hh:mm:ss.mmm>` karaoke timestamps for burn-in pipelines. Defaults (`line`, `srt`) reproduce the previous output byte-identically.
- `keyframe ... --easing <linear|ease-in|ease-out|ease-in-out>` — CapCut-native easing curves, also accepted per-line (`easing` key) in `keyframe --batch` JSONL and in the `compile` spec's keyframe op. The app does not store named curve types: the UI writes `FreeCurveInOut` bezier control handles on both keyframes of the eased segment, and the emitted encodings are locked against a UI-oracle capture (prior art: capcut-cli-david). The `ken-burns` skill default changed linear → ease-out to match what the CapCut UI itself produces.
- `detect-scenes <video> [--threshold <0..1>] [--min-gap <s>] [--limit <n>] [--json]` — deterministic ffmpeg scene-cut detection (no AI, zero new dependencies) to seed the long-form → shorts flow: prints detected cut points (seconds, `hh:mm:ss.mmm` timecode, scene score) plus a ready-to-use contiguous segment list in seconds and draft-native microseconds. Follows the `probe`/`render` external-binary pattern, including a clear actionable error when ffmpeg is missing.
- `make-preset <project> <text-segment-id> --out <preset.json>` — extract a hand-tuned text style (font, colors, style flags, alignment/transform, bubble, karaoke/multi-style ranges) from an existing draft into a versioned, portable preset file; apply it with the new `--preset <file>` flag on `add-text`, `text-style`, and `caption`. Addresses the recurring ecosystem ask for programmatic font/style reuse (GuanYixuan/pyJianYingDraft#192, Hommy-master/capcut-mate#57). Contract:
- **Explicit flags beat the preset — including its ranges.** `--color` / `--font-size` override every captured `text_ranges` block over the covered span, not just the base style, so a karaoke/highlight preset re-renders in the flag color/size; applying the same preset without those flags preserves the per-range styling.
- **Presets are schema-validated on load.** `transform` must be an object with finite numeric `x`/`y`, `bubble` must carry non-empty `effect_id`/`resource_id`, `text_ranges` must be an array of objects with integer `start`/`end` where `end > start` and correctly typed style fields. A malformed preset is rejected with a clear error and is never written into the draft.
- **Rangeless preset onto a multi-range segment collapses the ranges.** Applying a preset that carries no `text_ranges` onto a segment that still holds multiple range blocks (leftover karaoke/highlight) collapses them to the single uniform preset style spanning the whole text — consistent with the "applies the full preset" contract. A preset that itself carries ranges applies them unchanged. Documented in `--help`.
- **`make-preset --dry-run` writes nothing** — the `--out` file is neither created nor overwritten, and the JSON output reports `dryRun:true` with `written:false` (a normal run reports `written:true`).
- Parser: the value-consuming flags introduced in this release (`--threshold`, `--min-gap`, `--limit`, `--json`, `--granularity`, `--format`, `--easing`, `--preset`, `--apply`) are scoped to the commands that declare them instead of being consumed globally, so free-text positionals that contain a flag-like substring survive verbatim (e.g. `add-text ... New Year --limit 5 drinks` stores the literal text). Flags that earlier releases already parsed globally are unchanged.

### Documentation

- `docs/version-support.md` — the CapCut 8.7 row now names `sync-timelines` as the repair path for drifted mirrors.
- `docs/draft-schema/03-keyframes-and-animations.md` — documents the `FreeCurveInOut` bezier-handle easing encoding.

## [0.12.0] — 2026-06-27

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ JSON by default (pipe to `jq`); add `-H` for a human-readable table. Pass `--jia
| **Create** | `init` · `quickstart` · `compile` (build a draft from a JSON spec) |
| **Preview** | `render` (low-res ffmpeg proxy — not CapCut's final render) |
| **Add** | `add-video` · `add-audio` · `add-text` (Wikimedia URLs supported, license-checked) |
| **Edit / animate** | trim · speed · volume · transitions · masks · text/image animations |
| **Templates** | apply and extract reusable layouts |
| **Subtitles & i18n** | `caption` · `import-srt` · `translate` (multi-language draft clone) |
| **Edit / animate** | trim · speed · volume · transitions · masks · text/image animations · easing curves |
| **Templates** | apply and extract reusable layouts · `make-preset` (portable text-style presets) |
| **Subtitles & i18n** | `caption` · `import-srt` · `export-srt` (line/word SRT + VTT) · `translate` (multi-language draft clone) |
| **Effects** | `sfx` · `chroma` (chroma key) |
| **Long-form → short** | `cut` |
| **Automation** | `serve` (stateless JSONL runner) · `migrate` · `doctor` |
| **Long-form → short** | `cut` · `detect-scenes` (ffmpeg scene-cut detection) |
| **Automation** | `serve` (stateless JSONL runner) · `migrate` · `doctor` · `sync-timelines` (8.7 mirror repair) |

**Full reference** for every command, option, and exit code: **[docs/command-reference.md](./docs/command-reference.md)**.

Expand Down
10 changes: 5 additions & 5 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ capcut info ./my-first/ # 查看草稿(加 -H 显示
| **创建** | `init` · `quickstart` · `compile`(用 JSON spec 构建草稿)|
| **预览** | `render`(低清 ffmpeg 代理预览 —— 非 CapCut 最终渲染)|
| **添加** | `add-video` · `add-audio` · `add-text`(支持 Wikimedia URL,自动校验授权)|
| **编辑 / 动画** | 裁剪 · 变速 · 音量 · 转场 · 蒙版 · 文字/图片动画 |
| **模板** | 应用与提取可复用版式 |
| **字幕 / 多语言** | `caption` · `import-srt` · `translate`(多语言草稿克隆)|
| **编辑 / 动画** | 裁剪 · 变速 · 音量 · 转场 · 蒙版 · 文字/图片动画 · 缓动曲线 |
| **模板** | 应用与提取可复用版式 · `make-preset`(可移植文字样式预设)|
| **字幕 / 多语言** | `caption` · `import-srt` · `export-srt`(行级/逐词 SRT + VTT)· `translate`(多语言草稿克隆)|
| **特效** | `sfx` · `chroma`(绿幕抠像)|
| **长视频切短** | `cut` |
| **自动化** | `serve`(无状态 JSONL 执行器)· `migrate` · `doctor` |
| **长视频切短** | `cut` · `detect-scenes`(ffmpeg 场景切点检测)|
| **自动化** | `serve`(无状态 JSONL 执行器)· `migrate` · `doctor` · `sync-timelines`(8.7 时间线镜像修复)|

**完整命令参考**(每个命令、参数与退出码):**[docs/command-reference.md](./docs/command-reference.md)**。

Expand Down
Loading
Loading