@gitruck/cli 1.3.6 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/AGENT.md +23 -0
  2. package/CHANGELOG.md +32 -0
  3. package/README.en.md +1 -0
  4. package/README.md +1 -0
  5. package/assets/composite-kit/kit.css +2 -2
  6. package/assets/composite-kit/kit.js +2 -0
  7. package/assets/composite-kit/stage.html +14 -2
  8. package/assets/readme/wordmark.svg +6 -6
  9. package/contracts/README.md +16 -16
  10. package/contracts/gsap-emit-v1.md +163 -163
  11. package/contracts/handoff-contracts.json +10 -10
  12. package/dist/index.js +352 -313
  13. package/docs/development.en.md +47 -47
  14. package/docs/development.md +47 -47
  15. package/docs/reference.en.md +71 -13
  16. package/docs/reference.md +74 -15
  17. package/package.json +2 -2
  18. package/skills/gtrk-ai-drama/SKILL.md +10 -10
  19. package/skills/gtrk-ai-drama/references/sparse-key-scenes.md +38 -38
  20. package/skills/gtrk-ai-drama/scripts/validate-storyboard.mjs +119 -119
  21. package/skills/gtrk-composite/SKILL.md +28 -5
  22. package/skills/gtrk-cover/SKILL.md +3 -3
  23. package/skills/gtrk-cover/references/layout-recipes.md +337 -337
  24. package/skills/gtrk-cover/references/prompt-templates.md +119 -119
  25. package/skills/gtrk-food-recap/SKILL.md +2 -2
  26. package/skills/gtrk-live-slicing/SKILL.md +10 -4
  27. package/skills/gtrk-long2short/SKILL.md +3 -0
  28. package/skills/gtrk-matrix/SKILL.md +5 -0
  29. package/skills/gtrk-mg/SKILL.md +398 -391
  30. package/skills/gtrk-music-visualizer/SKILL.md +3 -3
  31. package/skills/gtrk-narration/SKILL.md +6 -2
  32. package/skills/gtrk-ref-reading/SKILL.md +145 -0
  33. package/skills/gtrk-ref-reading/references/close-reading-checklist.md +47 -0
  34. package/skills/gtrk-ref-reading/references/landing-templates.md +95 -0
  35. package/skills/gtrk-splitter/SKILL.md +298 -298
  36. package/skills/gtrk-splitter/references/example-visual-split.json +645 -645
  37. package/skills/gtrk-splitter/references/example-visual-split.md +439 -439
  38. package/skills/gtrk-splitter/references/field-schema.md +171 -171
  39. package/skills/gtrk-style-maker/SKILL.md +7 -0
  40. package/skills/gtrk-style-maker/references/ammo.md +16 -16
  41. package/skills/gtrk-style-maker/references/contracts-ref.md +9 -9
  42. package/skills/gtrk-style-maker/references/seeds/README.md +4 -4
  43. package/skills/gtrk-style-maker/references/seeds/seed-ecom-home-goods.md +37 -37
  44. package/skills/gtrk-style-maker/references/seeds/seed-psych-humanities.md +35 -35
  45. package/skills/gtrk-talking-head/SKILL.md +11 -9
  46. package/skills/gtrk-tools/SKILL.md +1 -1
  47. package/skills/gtrk-transcript/SKILL.md +4 -4
  48. package/skills/gtrk-transcript/agents/openai.yaml +4 -4
  49. package/skills/gtrk-travel-recap/SKILL.md +8 -0
  50. package/skills/gtrk-vlog-docu/SKILL.md +8 -0
  51. package/skills/gtrk-voiceover/SKILL.md +7 -2
@@ -1,47 +1,47 @@
1
- # Development and contributions
2
-
3
- [Back to README](../README.en.md) · [Command reference](reference.en.md) · [简体中文](development.md)
4
-
5
- ## Local development
6
-
7
- The CLI runtime requires Node.js ≥ 20.6. Source development and builds use Bun.
8
-
9
- ```bash
10
- git clone https://github.com/Gitruck/cli.git
11
- cd cli
12
- bun install
13
- bun run src/index.ts --help
14
- npm run typecheck
15
- bun run build
16
- ```
17
-
18
- The public repository supports reading, developing and building the CLI. `test/` and `openspec/` are private submodules requiring maintainer access. Public contributors do not need a recursive clone; authorized maintainers run the complete test suite.
19
-
20
- ## Repository layout
21
-
22
- ```text
23
- src/index.ts Command entry point
24
- src/commands/ CLI commands
25
- src/lib/ Cloud calls, media processing, project assembly and rendering
26
- skills/ Bundled Agent Skills
27
- contracts/ Open project and motion graphics contracts
28
- docs/ Workflow, configuration, command and development references
29
- assets/ README artwork
30
- AGENT.md Portable agent playbook
31
- ```
32
-
33
- Add commands through registration functions in `src/commands/` and wire them into `src/index.ts`. Toolbox additions should reuse existing descriptors and runners where applicable. `src/commands/skills.ts` owns the bundled Skill list; see the [reference](reference.en.md) for details.
34
-
35
- ## Documentation and checks
36
-
37
- - README presents the product and onboarding. Maintain parameters, configuration and full explanations in `docs/reference.md` / `docs/reference.en.md`.
38
- - Update both READMEs and corresponding bilingual documents together. Preserve command names, flags, fields and artifact filenames; keep example commands identical.
39
- - Use publicly accessible images or files in `assets/`. Keep examples traceable and large videos out of the npm package.
40
- - Maintainers run `npm test`, which builds and uses Node's test runner. Do not substitute `bun test`. Documentation-only changes should at least run the relevant guards and check links and rendering.
41
- - Check `npm pack --dry-run` when moving bundled documentation so it remains in the package.
42
-
43
- ## Contributing
44
-
45
- Use [Issues](https://github.com/Gitruck/cli/issues) to describe problems, use cases or behavior you would like improved. Explain changes and validation in your PR. Do not include API keys, personal configuration, media paths, generated outputs or private submodule contents.
46
-
47
- See [contracts](../contracts/README.md) for interfaces and [AGENT.md](../AGENT.md) for agent usage.
1
+ # Development and contributions
2
+
3
+ [Back to README](../README.en.md) · [Command reference](reference.en.md) · [简体中文](development.md)
4
+
5
+ ## Local development
6
+
7
+ The CLI runtime requires Node.js ≥ 20.6. Source development and builds use Bun.
8
+
9
+ ```bash
10
+ git clone https://github.com/Gitruck/cli.git
11
+ cd cli
12
+ bun install
13
+ bun run src/index.ts --help
14
+ npm run typecheck
15
+ bun run build
16
+ ```
17
+
18
+ The public repository supports reading, developing and building the CLI. `test/` and `openspec/` are private submodules requiring maintainer access. Public contributors do not need a recursive clone; authorized maintainers run the complete test suite.
19
+
20
+ ## Repository layout
21
+
22
+ ```text
23
+ src/index.ts Command entry point
24
+ src/commands/ CLI commands
25
+ src/lib/ Cloud calls, media processing, project assembly and rendering
26
+ skills/ Bundled Agent Skills
27
+ contracts/ Open project and motion graphics contracts
28
+ docs/ Workflow, configuration, command and development references
29
+ assets/ README artwork
30
+ AGENT.md Portable agent playbook
31
+ ```
32
+
33
+ Add commands through registration functions in `src/commands/` and wire them into `src/index.ts`. Toolbox additions should reuse existing descriptors and runners where applicable. `src/commands/skills.ts` owns the bundled Skill list; see the [reference](reference.en.md) for details.
34
+
35
+ ## Documentation and checks
36
+
37
+ - README presents the product and onboarding. Maintain parameters, configuration and full explanations in `docs/reference.md` / `docs/reference.en.md`.
38
+ - Update both READMEs and corresponding bilingual documents together. Preserve command names, flags, fields and artifact filenames; keep example commands identical.
39
+ - Use publicly accessible images or files in `assets/`. Keep examples traceable and large videos out of the npm package.
40
+ - Maintainers run `npm test`, which builds and uses Node's test runner. Do not substitute `bun test`. Documentation-only changes should at least run the relevant guards and check links and rendering.
41
+ - Check `npm pack --dry-run` when moving bundled documentation so it remains in the package.
42
+
43
+ ## Contributing
44
+
45
+ Use [Issues](https://github.com/Gitruck/cli/issues) to describe problems, use cases or behavior you would like improved. Explain changes and validation in your PR. Do not include API keys, personal configuration, media paths, generated outputs or private submodule contents.
46
+
47
+ See [contracts](../contracts/README.md) for interfaces and [AGENT.md](../AGENT.md) for agent usage.
@@ -1,47 +1,47 @@
1
- # 开发与贡献
2
-
3
- [返回首页](../README.md) · [命令参考](reference.md) · [English](development.en.md)
4
-
5
- ## 本地开发
6
-
7
- CLI 运行时需要 Node.js ≥ 20.6;源码开发与构建使用 Bun。
8
-
9
- ```bash
10
- git clone https://github.com/Gitruck/cli.git
11
- cd cli
12
- bun install
13
- bun run src/index.ts --help
14
- npm run typecheck
15
- bun run build
16
- ```
17
-
18
- 公共仓库可用于阅读、开发和构建 CLI。`test/` 与 `openspec/` 是需要维护者权限的私有子模块,公开贡献者无需递归拉取它们;完整测试由有权限的维护者运行。
19
-
20
- ## 项目结构
21
-
22
- ```text
23
- src/index.ts 命令入口
24
- src/commands/ CLI 命令
25
- src/lib/ 云端调用、素材处理、工程装配与渲染
26
- skills/ 随包 Agent Skills
27
- contracts/ 工程与动态图等开放契约
28
- docs/ 工作流、配置、命令和开发参考
29
- assets/ README 配图
30
- AGENT.md 可移植 Agent 操作手册
31
- ```
32
-
33
- 新增命令在 `src/commands/` 中提供注册函数,并在 `src/index.ts` 接入;工具族优先复用已有描述器与执行器。随包 Skills 的权威清单在 `src/commands/skills.ts`,详细名单见[参考文档](reference.md)。
34
-
35
- ## 文档与校验
36
-
37
- - README 负责产品展示和上手;参数、配置与完整操作解释维护在 `docs/reference.md` / `docs/reference.en.md`。
38
- - 两份 README 和对应双语文档同步更新。命令名、参数、字段与产物文件名保持原样;示例命令保持一致。
39
- - 配图使用公开可访问资源,或放入 `assets/`;案例保持可追溯,不将大视频打包进 npm。
40
- - 维护者运行 `npm test`(构建后通过 Node 测试),不要用 `bun test` 代替。纯文档变更至少运行相关文档守卫、检查链接和展示效果。
41
- - 修改公开随包文档时,检查 `npm pack --dry-run` 的文件清单,避免移动后漏包。
42
-
43
- ## 提交贡献
44
-
45
- 通过 [Issues](https://github.com/Gitruck/cli/issues)描述问题、使用场景或希望改进的行为。提交 PR 时说明变更与验证方式。不要提交 API Key、个人配置、素材路径、生成产物或私有子模块的内容。
46
-
47
- 接口约定见 [contracts](../contracts/README.md),Agent 使用方式见 [AGENT.md](../AGENT.md)。
1
+ # 开发与贡献
2
+
3
+ [返回首页](../README.md) · [命令参考](reference.md) · [English](development.en.md)
4
+
5
+ ## 本地开发
6
+
7
+ CLI 运行时需要 Node.js ≥ 20.6;源码开发与构建使用 Bun。
8
+
9
+ ```bash
10
+ git clone https://github.com/Gitruck/cli.git
11
+ cd cli
12
+ bun install
13
+ bun run src/index.ts --help
14
+ npm run typecheck
15
+ bun run build
16
+ ```
17
+
18
+ 公共仓库可用于阅读、开发和构建 CLI。`test/` 与 `openspec/` 是需要维护者权限的私有子模块,公开贡献者无需递归拉取它们;完整测试由有权限的维护者运行。
19
+
20
+ ## 项目结构
21
+
22
+ ```text
23
+ src/index.ts 命令入口
24
+ src/commands/ CLI 命令
25
+ src/lib/ 云端调用、素材处理、工程装配与渲染
26
+ skills/ 随包 Agent Skills
27
+ contracts/ 工程与动态图等开放契约
28
+ docs/ 工作流、配置、命令和开发参考
29
+ assets/ README 配图
30
+ AGENT.md 可移植 Agent 操作手册
31
+ ```
32
+
33
+ 新增命令在 `src/commands/` 中提供注册函数,并在 `src/index.ts` 接入;工具族优先复用已有描述器与执行器。随包 Skills 的权威清单在 `src/commands/skills.ts`,详细名单见[参考文档](reference.md)。
34
+
35
+ ## 文档与校验
36
+
37
+ - README 负责产品展示和上手;参数、配置与完整操作解释维护在 `docs/reference.md` / `docs/reference.en.md`。
38
+ - 两份 README 和对应双语文档同步更新。命令名、参数、字段与产物文件名保持原样;示例命令保持一致。
39
+ - 配图使用公开可访问资源,或放入 `assets/`;案例保持可追溯,不将大视频打包进 npm。
40
+ - 维护者运行 `npm test`(构建后通过 Node 测试),不要用 `bun test` 代替。纯文档变更至少运行相关文档守卫、检查链接和展示效果。
41
+ - 修改公开随包文档时,检查 `npm pack --dry-run` 的文件清单,避免移动后漏包。
42
+
43
+ ## 提交贡献
44
+
45
+ 通过 [Issues](https://github.com/Gitruck/cli/issues)描述问题、使用场景或希望改进的行为。提交 PR 时说明变更与验证方式。不要提交 API Key、个人配置、素材路径、生成产物或私有子模块的内容。
46
+
47
+ 接口约定见 [contracts](../contracts/README.md),Agent 使用方式见 [AGENT.md](../AGENT.md)。
@@ -15,7 +15,7 @@ Once installed, a single sentence in any agent invokes a gtrk skill:
15
15
  | ![Calling gtrk from an agent, example 1](../assets/agent-example-1.png) | ![Calling gtrk from an agent, example 2](../assets/agent-example-2.png) |
16
16
  | ![Calling gtrk from an agent, example 3](../assets/agent-example-3.png) | ![Calling gtrk from an agent, example 4](../assets/agent-example-4.png) |
17
17
 
18
- `gtrk install` installs the 19 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-composite`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`·`gtrk-narration`·`gtrk-voiceover`·`gtrk-food-recap`·`gtrk-vlog-docu`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
18
+ `gtrk install` installs the 20 bundled CLI skills (`gtrk-oralcut`·`gtrk-long2short`·`gtrk-splitter`·`gtrk-matrix`·`gtrk-mg`·`gtrk-composite`·`gtrk-ai-drama`·`gtrk-style-maker`·`gtrk-transcript`·`gtrk-tools`·`gtrk-music-visualizer`·`gtrk-cover`·`gtrk-travel-recap`·`gtrk-live-slicing`·`gtrk-talking-head`·`gtrk-narration`·`gtrk-voiceover`·`gtrk-food-recap`·`gtrk-vlog-docu`·`gtrk-ref-reading`) into the agents detected on this machine. The mechanism matches lark-cli: gtrk hands its local skill sources to the generic `skills` CLI, which owns agent detection, directory mapping and update rules; gtrk no longer hardcodes per-vendor paths.
19
19
 
20
20
  By default `~/.agents/skills` is the single source of truth, linked into each agent's compatible directory (junctions on Windows); where linking is unavailable the adapter falls back to copying. That way updates touch one canonical copy instead of letting duplicates drift apart. Common commands:
21
21
 
@@ -66,6 +66,7 @@ Then just say "**cut a version of this talking-head**", or explicitly pick `gtrk
66
66
  | ⑤ | `/gtrk-mg` | `gtrk mg` | **MG (incl. ov) goes on last** (stacked on the settled, composition-checked base layer) |
67
67
  | ⑥ | `/gtrk-composite` | `gtrk composite` | **Composite layer** (after subtitles, before export): turn chosen time windows into composite particles — one code particle takes over the whole frame for that span (picture changes per sentence, side-by-side contrasts, list cards, subtitle layout) while the talking head and B-roll are drawn into its slots; three entry modes (cover the whole film / let the AI pick / user-given ranges), candidates show up in the client outline's CP row; purely local, zero billing. On export, `gtrk composite bake` bakes them into video locally (the first run needs `gtrk deps install --browser`) |
68
68
  | — | `/gtrk-style-maker` | (no command, builds a show) | A one-time interview that builds your show's style system (skill family + show config, see next section) |
69
+ | 🔍 | `/gtrk-ref-reading` | `gtrk transcript` + `gtrk media` | **Reference reading**: someone else's video → word-level transcript + frame grids labelled with the spoken line + key motion frame by frame → records, system by system, which line each design event answers, in `ANALYSIS.md` / `TIMELINE.md` / `PROGRESS.md`; hand the result to `/gtrk-style-maker` to build a show. The viewing commands are local and free (only the transcription step is billed); **not part of the production SOP** |
69
70
  | ③′ | "**screen-recording PiP**" | `gtrk pip lay` | Mirror the talking-head rough cut's cut points onto a screen recording / second camera recorded in sync: lays a full-frame companion track + a muted picture-in-picture copy of the talking head (ellipse / rounded rectangle / heart / diamond / star mask, optional corner radius); purely local, zero billing; when alignment confidence is low it writes an alignment project for the client to drag into place, then `--resume` |
70
71
  | — | (wrap-up) | `gtrk render` | Render a gtrk project locally → finished mp4 (overlays and MG particles included; particles that miss the cache are cloud-rendered and billed, `--no-particles` skips them) |
71
72
  | ✂️ | `/gtrk-long2short` | `gtrk long2short` | Long-to-short rough cut: semantic segment selection + jump cuts → per-clip client/Jianying/Premiere projects (the raw file is never uploaded); **not part of the production SOP**, usable standalone at any time |
@@ -82,7 +83,7 @@ Then just say "**cut a version of this talking-head**", or explicitly pick `gtrk
82
83
  | 🧭 | `/gtrk-vlog-docu` | orchestrates `gtrk transcript` → `tool audio_tts_clone` → `split` → `matrix` → `mg` → `audio lay` → `subtitle lay` | **Documentary-vlog blueprint**: a batch of on-location footage → footage understanding, register choice and script, one sign-off → live-sound skeleton + narration voice-over + B-roll + subtitle layer + BGM run unattended → a client-ready project; alternates on-location sound with post-production narration, unlike the pure talking-head or pure voice-over chains |
83
84
 
84
85
  > **Skill vs command**: `/gtrk-mg` is the **brain** — it knows it belongs at SOP step ⑤ (MG only after all three B-roll sources have landed and the composition is checked), asks for your confirmation, and resolves which particle type to produce from the show config; `gtrk mg` is the **hands** — purely deterministic lint + track laying. You trigger the skill by talking, and the skill runs the command for you.
85
- > The 19 `/gtrk-X` skills above are **framework skills bundled with the CLI** (installed by `gtrk skills install`; the list is identical to the ones in "Using it with AI agents" and "Layout") — the 7 marked 🧭 are **composite blueprints** (one sentence runs a whole chain; they only orchestrate the single-command skills above and add no commands of their own); `/gtrk-long2short` independently drives long-to-short, `/gtrk-transcript` independently drives video/audio-to-transcript, `/gtrk-tools` covers only the single-shot tool family, `/gtrk-cover` handles covers, and none of the four belong to the production SOP; `/gtrk-ai-drama`·`/gtrk-style-maker`·`/gtrk-cover` are pure authoring skills (no command). Show-specific **visual style and content** come instead from your own show's production skills (created by `/gtrk-style-maker`, bound through the show config's `style.skills`) and are never hardcoded into these framework skills.
86
+ > The 20 `/gtrk-X` skills above are **framework skills bundled with the CLI** (installed by `gtrk skills install`; the list is identical to the ones in "Using it with AI agents" and "Layout") — the 7 marked 🧭 are **composite blueprints** (one sentence runs a whole chain; they only orchestrate the single-command skills above and add no commands of their own); `/gtrk-long2short` independently drives long-to-short, `/gtrk-transcript` independently drives video/audio-to-transcript, `/gtrk-tools` covers only the single-shot tool family, `/gtrk-cover` handles covers, `/gtrk-ref-reading` handles reference reading, and none of the five belong to the production SOP; `/gtrk-ai-drama`·`/gtrk-style-maker`·`/gtrk-cover` are pure authoring skills (no command). Show-specific **visual style and content** come instead from your own show's production skills (created by `/gtrk-style-maker`, bound through the show config's `style.skills`) and are never hardcoded into these framework skills.
86
87
 
87
88
  **How each lane's actual visuals/content get produced** — what the MG looks like, what tone the AI re-enactment has — is not hardcoded into the CLI. It comes from **your own show's production skills** (created interactively with `/gtrk-style-maker`, kept locally). They are bound through the show config's **`style.skills[].produces`** (the value is the lane name), and **general-purpose drivers** such as `gtrk mg` / `gtrk matrix` consume them accordingly. **The direction is: the CLI drives the show skills** — show skills only supply style/content and carry no "which command to run" orchestration; the framework only knows lanes and pipeline interfaces, and the look always belongs to your show. Without a show, the built-in defaults are used and everything still runs end to end.
88
89
 
@@ -180,6 +181,36 @@ Or set `"crashReport": false` directly in `~/.gitruck/config.json`.
180
181
 
181
182
  You can check the current state any time: the “崩溃自动上报” row in `gtrk doctor` shows on / off, and which of the two turned it off. With reporting off, the crash presentation and exit code are **exactly the same** as with it on — the switch only controls whether that one report is sent.
182
183
 
184
+ ### Usage statistics, and how to turn them off
185
+
186
+ gtrk sends anonymous usage statistics so we know which commands get used, how often they fail, and how fast new versions roll out. **On by default; you are told once, when you first configure the CLI** (right after the crash-report line).
187
+
188
+ **What is sent per command, in full**: the command name (its registered name, e.g. `matrix.search`, never any argument), success or failure, on failure an error code or category (e.g. `ENOENT`, never the error message), the elapsed-time range, the caller type (a terminal, or an agent name such as `claude-code`), the CLI version, OS and architecture, Node major version, and whether an API key is configured (yes / no only).
189
+
190
+ **What is never sent**: command arguments and option values, file names and paths, media and project contents, your scripts, your API key, error messages, device identifiers, hostname, account information. The statistics service sees your IP address like any network request; it is used only to tell the country or region and is not stored.
191
+
192
+ **It never slows a command down**: when a command finishes, gtrk only appends one line to `~/.gitruck/usage-queue.jsonl`; a background process sends it and the command exits immediately as usual. Anything that can't be sent stays on your machine (up to 200 entries, 7 days) and goes out next time.
193
+
194
+ **Never sent when**: running from source, running unit tests, or the `CI` environment variable is set.
195
+
196
+ Four ways to turn it off (any one of them, effective immediately):
197
+
198
+ ```bash
199
+ gtrk init --no-usage-stats # persisted in config, off for good (also deletes anything not yet sent)
200
+ ```
201
+
202
+ ```bash
203
+ GITRUCK_USAGE_STATS=0 gtrk patch move … # environment variable, off for one run (takes precedence over config)
204
+ ```
205
+
206
+ ```bash
207
+ DO_NOT_TRACK=1 gtrk … # the common “do not track” convention works too
208
+ ```
209
+
210
+ Or set `"usageAnalytics": false` directly in `~/.gitruck/config.json`.
211
+
212
+ You can check the current state any time: the “使用统计” row in `gtrk doctor` shows on / off, which setting turned it off, and whether the current environment sends at all. With statistics off, command output and exit codes are **exactly the same** as with them on.
213
+
183
214
  ---
184
215
 
185
216
  ## Command reference
@@ -202,6 +233,8 @@ This entry exists in the current development workspace. Check `gtrk matrix --hel
202
233
  | `--platforms <list>` | Comma-separated `youtube,vimeo,tiktok,bilibili`; requires `--online`. Defaults to all four registered platforms. Results depend on service and source availability |
203
234
  | `--online-session <name>` | Nonempty external-search batch name; requires `--online`. Continue within a batch; changing the name starts a new search and may incur new task charges |
204
235
 
236
+ In dispatch consumption, if a round yields **no layable candidates** while the project already has a `split/broll-plan.json` with candidates (for example the previous cloud or local plan), that plan is not overwritten: this round's plan (with per-request errors and review-only candidates) is saved as `split/broll-plan.online-attempt.json`, the `--json` result carries `plan_kept`, and `planPath` still points at the existing plan. The exit code stays non-zero.
237
+
205
238
  ### `gtrk transcript <local video|voice-over audio>`
206
239
 
207
240
  Turns a local video or voice-over audio file into a multi-level Markdown transcript. It accepts local file paths only: video is extracted — and audio input transcoded — to 16 kHz mono audio on your machine, and only that derivative is uploaded. The original file is never uploaded, and URLs or platform video downloads are not supported.
@@ -221,6 +254,31 @@ Live pricing is queried from the website's price table under `asr` before the ru
221
254
 
222
255
  > With `--json` it additionally drops a sentence-timecoded `<name>-transcript.json` next to the source file (`utterances[]{id,text,st,ed}` + `material_id` + `text_hash` + `duration`, field-for-field aligned with the transcript structure `gtrk split` consumes), which the `gtrk project init --transcript` fallback path can consume directly. **Do not re-run ASR here on TTS-synthesized voice-overs** — `gtrk project init --tts-task` fetches the server-side sentence timecodes directly, zero ASR and zero extra billing.
223
256
 
257
+ ### `gtrk media <subcommand>` — local footage viewer (evidence for reference reading)
258
+
259
+ Look at any local video by timecode or by spoken line: frame grids labelled with the transcript, frame-by-frame motion, visual-change candidates. **Purely local, free, offline, no API key**; reads local files only and never downloads links. Driven by `/gtrk-ref-reading`; also handy for checking your own renders.
260
+
261
+ | Subcommand | What it does |
262
+ |---|---|
263
+ | `probe <video>` | Duration, display size (pixel aspect and rotation applied), frame rate and VFR, audio presence |
264
+ | `lines <transcript>` | One line per utterance `u<id> start–end text`; `--find <phrase>` lists every occurrence with word-level times |
265
+ | `frames <video>` | Single frames by `--at` / `--every` / `--frames` / `--every-frame`; with `--transcript` or `--label` a label band is added below each frame |
266
+ | `tile <video>` | One labelled grid (≤60 cells) |
267
+ | `tiles <video>` | Paginated grids (`--cols × --rows`, default 3×3); `--ranges <json>` visits several intervals; `--every-frame` decodes each interval once and keeps every original frame |
268
+ | `boundaries <video>` | Visual-change candidates (`--rate` default 12, `--threshold` default 0.1, `--min-gap` merges neighbours); with `--transcript` each candidate notes which line it falls on. **Mechanical evidence, not shot detection** |
269
+ | `cut <video>` | Saves an evidence clip (`.mp4/.mov/.mkv`) |
270
+
271
+ ```bash
272
+ gtrk media tiles "reference.mp4" --frames 48 --cols 6 --rows 4 --cell 320 --transcript "reading/transcript.json" -o "reading/evidence/overview"
273
+ gtrk media tiles "reference.mp4" --around "can't afford it" --occurrence 1 --every-frame --cols 6 --rows 4 --transcript "reading/transcript.json" -o "reading/evidence/motion/stamp"
274
+ gtrk media boundaries "reference.mp4" --rate 4 --threshold 0.12 --transcript "reading/transcript.json" -o "reading/evidence/boundaries.json"
275
+ ```
276
+
277
+ - **Intervals**: `--start/--end` (seconds or `[hh:]mm:ss.mmm`), or `--around <phrase> [--occurrence n] [--padding s]` to locate by the spoken line (needs `--transcript`; a repeated phrase must name its occurrence — `lines --find` lists them).
278
+ - **Transcripts**: the `gtrk transcript --json` output (v1, with word-level times) works as is; `hypit.transcript@1` is also accepted. The transcript must belong to this video — a duration or file-name mismatch prints a warning on stderr.
279
+ - **Labels** (below the picture, so the original captions and graphics stay visible): source seconds · timecode (plus frame number in frame-by-frame mode) · utterance id / the word being spoken with its times / the whole sentence with the current word highlighted. Moments with no timed word are labelled as such, never inferred as silence. Labels are drawn with libass; an ffmpeg without the `ass` filter fails with a pointer to `gtrk deps install --ffmpeg`.
280
+ - **Output**: `-o` is required — nothing lands in the current directory or next to the source; existing paths are never overwritten, and `--force` only replaces this command family's own earlier output. `frames` / `tiles` directories include an `index.json` recording each cell's file, time, word and utterance. Frame-by-frame is capped at 1800 frames per call.
281
+
224
282
  ### `gtrk oralcut <raw>`
225
283
 
226
284
  | Parameter | Purpose | Default |
@@ -368,7 +426,7 @@ Each source becomes one low-resolution full-window preview candidate. `source-im
368
426
  >
369
427
  > **Material-on-disk self-check**: after writing back the project, the CLI read-only checks whether every `materials[].path` exists. Relative paths resolve against the directory containing the `.gtrk` file (`<output>/gtrk/`). `--json` emits `integrity:{ checked, counts, dangling:[…], danglingReferenced, danglingOrphan, external:[…], noPathIds:[…] }`; `dangling` lists registered materials missing on disk and marks whether the timeline references each one, while missing absolute paths are counted as `external`; http(s) materials are counted without network requests. This check only reports: it does not change `ok`, the exit code, material entries or files. Repair a dangling reference by re-confirming the source clip in the client or deleting the corresponding clip. Runs that never write back (`--lay 0` / refused / missing project) emit no `integrity` field.
370
428
  >
371
- > **Clip background fill (default)**: every candidate clip carries a solid black fill (gtrk contract `background_fill`, so narrow or shrunken clips never reveal the talking-head underneath), and each candidate track patches its own empty spans inside every landed beat envelope with solid black clips — with `--lay 2`, leaving only one track visible still hides the talking-head; audio-driven projects (no talking-head) are not patched. `--json` emits `lay.bed` (`fill`) and `lay.bed_fill` (patches and seconds). Spans with no B-roll at all count as holes: `lay.blackBedHoleSec` / `lay.blackBedHoles` are always emitted, with a non-fatal warning at ≥3 s for one span or ≥15% of one beat; adjust `--score-floor` or patch in the client. The patch material is stored at `assets/builtin/solid-000000-<W>x<H>.png` and reused idempotently.
429
+ > **Clip background fill (default)**: every candidate clip carries a solid black fill (gtrk contract `background_fill`, so narrow or shrunken clips never reveal the talking-head underneath), and each candidate track patches its own empty spans inside every landed beat envelope with solid black clips — with `--lay 2`, leaving only one track visible still hides the talking-head; audio-driven projects (no talking-head) are not patched. `--json` emits `lay.bed` (`fill`) and `lay.bed_fill` (patches and seconds). Spans with no B-roll at all count as holes: `lay.blackBedHoleSec` / `lay.blackBedHoles` are always emitted, with a non-fatal warning at ≥3 s for one span or ≥15% of one beat; adjust `--score-floor` or patch in the client. The patch material is stored at `assets/builtin/solid-000000-<W>x<H>.png` and reused idempotently. Gaps shorter than 1.2 s (1–2-frame seams between clips, the span before an anchored shot) are first absorbed by the neighbouring clip within its source-window headroom (never crossing the search segment, in-segment cuts or black spans); only gaps that cannot be absorbed are patched black, and each is listed in `lay.flash_gaps.kept` and a warning.
372
430
  >
373
431
  > **Solid black bed track (`--black-bed`, legacy)**: one solid black track covers the landed beat envelope beneath candidate tracks and above the talking-head track, and candidate clips carry no fill; holes are counted the same way with the same numbers. A black bed track left in an older project is replaced by clip fills on the next default re-lay.
374
432
 
@@ -420,19 +478,19 @@ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle
420
478
  | `--yes` | Render mode: skip the billing-estimate confirmation | off |
421
479
  | `--json` | Machine-readable: human logs go to stderr, stdout carries only the result JSON | off |
422
480
 
423
- - **Laying** (`gtrk mg --project <dir>`): reads `dispatch.mg` → for each beat takes the source particle from `<project>/mg/<composition_id>.html` → lints → lays it into `beat_track` and atomically writes `struct_meta.mg` back into `.gtrk` (self-produced tracks are registered idempotently in `lay_tracks`; a re-lay strips the previous self-produced items before appending, and user-added tracks are never touched). Whether a particle is a "transparent overlay" or a "full-screen bed" is decided by `opaque`, inferred from the particle HTML's root `background`. Beats with a missing HTML file or a failed lint are counted in `skipped` and do not block the rest.
481
+ - **Laying** (`gtrk mg --project <dir>`): reads `dispatch.mg` → for each beat takes the source particle from `<project>/mg/<composition_id>.html` → lints → lays it into `beat_track` and atomically writes `struct_meta.mg` back into `.gtrk` (self-produced tracks are registered idempotently in `lay_tracks`; a re-lay strips the previous self-produced items before appending, and user-added tracks are never touched). Whether a particle is a "transparent overlay" or a "full-screen bed" is decided by `opaque`, inferred from the particle HTML's root `background`. The lint compares each particle's aspect ratio with the project's `video_size`; a particle with a different ratio (say, one declared 1920×1080 in a portrait project) fails `1-canvas-match` and is not laid. Beats with a missing HTML file or a failed lint are counted in `skipped` and do not block the rest.
424
482
  - **The stripping surface ≠ "what gets laid this run", and ≠ "every registered track"**: `--only <beat>` **strips only the matched particles** (true incremental merge) — every other already-laid particle's clip / material / registration entry is **preserved as is**, together with any manual tweaks you made in opencut (what is preserved is the existing clip itself, not a rebuild from the registration, so transparency `opaque` is not lost); those preserved entries are **not re-linted and their source HTML is not re-copied** (the project is self-contained, so deleting files under `<project>/mg/` does not matter). A full re-lay is still "strip clean, then rebuild the whole track", with **one exception**: particles that are in this dispatch but failed to land (missing HTML / failed lint / zero surviving span after re-projection) keep their previous round's clip on the track (a broken new one must not destroy the working old one); conversely, already-laid entries **no longer present in the dispatch** are still stripped (a plan change ≠ something broke). To strip every other already-laid particle too, authorize it explicitly with `--replace-all`.
425
483
  - **The material table does not accumulate**: strip materials by “self-produced identity × zero references” (self-produced = an `mg-`/`rrv-` prefix, or a registered filename under the CLI-exclusive `assets/mg/`), without trusting the client-rewritable `html_material` prefix. The `mg-` count stays equal to the particles on the track; duplicate and orphan entries are removed. Non-self-produced materials, self-produced materials still referenced by a surviving clip, and HTML copies under `assets/mg/` are preserved.
426
484
  - **"Nothing matched" is not a clear-everything instruction**: when `--only` matches nothing, `dispatch.mg` is empty/missing, or every entry in this run was skipped, **while the track already has laid particles**, the write-back is refused (that is a signal that the dispatch or the selector is broken). Add `--replace-all` if you really mean to clear it. A first-time lay (no existing laid entries on the track) is exempt and completes normally, reporting `laid=0`.
427
485
  - **Slot windows are re-projected on the spot**: before laying and linting, each queue entry's `[track_st, track_ed]` is recomputed from "`transcript` × the current `.gtrk`", and thereafter the lint slot envelope (house rule ⑦) and the laid clip duration both follow the recomputed values (`--only` obeys the same rule; aux particles re-project against **their own** span and are not conflated with the main beat window). The timecodes in `dispatch.mg` are only a **projection-time snapshot**, used as a fallback solely when re-projection is impossible — **after editing the talking-head track you can lay directly without re-running `gtrk split`**. `--json` always emits `reprojection:{mode,degraded,reason?,drifted,max_offset,shrunk,dropped}` (including under `--lint-only`). Entries with **zero surviving span** after re-projection are skipped and counted in `skipped` (no HTML is copied and nothing is laid back from the snapshot); if re-projection is impossible (missing transcript / project not found / no talking-head material on the main track) → it degrades to the snapshot with a warning and a `--json` marker, and the exit code is unchanged; behaviour for **non-v1** projects is unchanged (the laying path's version gate exits non-zero, while `--lint-only` still produces its report). A successful lay appends this run's timecode provenance (`timecode_source` / `reprojected_at`) into `struct_meta.mg`.
428
- - **lint** (`gtrk mg lint <particle.html> [--dispatch <path>]`): a purely local static check of the machine-decidable subset of the house rules for a particle HTML (wrapped in `<template>`, `data-composition-id` + 1920×1080, `gsap.timeline({ paused: true })`, registration in `window.__timelines`, no `Math.random` / `Date.now`, self-contained with no relative external links, root `background` consistent with `opaque`, …); when `--dispatch` is given it also checks that the `composition_id` matches the dispatch. Any fatal item exits non-zero and reports every reason.
486
+ - **lint** (`gtrk mg lint <particle.html> [--dispatch <path>]`): a purely local static check of the machine-decidable subset of the house rules for a particle HTML (wrapped in `<template>`, `data-composition-id` + root `data-width` / `data-height` (positive integers), `gsap.timeline({ paused: true })`, registration in `window.__timelines`, no `Math.random` / `Date.now`, self-contained with no relative external links, root `background` consistent with `opaque`, …); when `--dispatch` is given it also checks that the `composition_id` matches the dispatch, and compares the particle's declared aspect ratio with the project's `.gtrk` `video_size` (`1-canvas-match`: a different aspect ratio is fatal, the same ratio at another size passes, and ratios within 7% count as the same — a 16:9 particle in a 17:9 DCI 4K project passes, accepting a 6.7% horizontal stretch; `--project` does the same). A bare lint has no target project and only checks for positive integers. Any fatal item exits non-zero and reports every reason.
429
487
  - **Expected-id consistency** (`1-cid-expect`, **fatal**): the `data-composition-id` inside the HTML must equal the expected id (when laying, the dispatch entry's `composition_id`; for `mg lint`, the filename — but only when it matches the dispatch or looks like `…-B<digits>[-aux<n>]`, so a renamed copy such as `./tmp.html` is not compared). This guards against "copying `<id>.html`, renaming the file and forgetting the id inside" — laying would write a clip/material named after the file while the file registers a different `__timelines` key and fights the same-named particle over the same style scope.
430
488
  - **House rule ⑦, timeline length estimation** (`7-fill-slot` / `7-no-estimate` / `7-infinite-repeat`, **always non-fatal, never blocks laying**): when the slot envelope is known (per particle when laying; for `mg lint --dispatch` when it matches a dispatch entry) it computes a **static lower bound** on the GSAP timeline — degrading call by call, counting whatever it can parse (`duration×(repeat+1) + repeatDelay×repeat`, with `yoyo` adding no time), while calls with expression positions or non-literal durations are **skipped and not counted** (ignoring some calls still yields a valid lower bound). Estimate < envelope → warning; nothing computable at all → an explicit notice that "length could not be estimated statically, house rule ⑦ was not verified, and it must be accepted against the real engine's seek" (**never silent**: "could not compute" and "computed and passed" are distinguishable in the output); containing `repeat:-1` → a warning that "an infinite loop makes the total length Infinity, so house rule ⑦ cannot be verified statically; please use a finite repeat computed from the slot". The real criterion is always the render engine frame by frame; this item is only a reminder layer.
431
489
  - **House rule ⑧, repeated-primitive merging** (`8-primitive-merge`, **always non-fatal, never blocks laying**): identifies mergeable batches of `line` / `rect` / `path` / `polyline` / `polygon` that are "created inside a loop, or by a named factory called in a loop; landing under the same parent node; and not driven by per-element animation". Only batches whose purely numeric loop trip counts sum to **≥ 8** under the same parent are reported; when bounds involve `.length` or named constants and cannot be computed it still reports "count unknown" without constant folding; elements with per-element `gsap.set` / tweens, or used as a tween's first argument, are excluded. This item only points out "there is a batch of repeated primitives here that can be merged **losslessly**, pixel-identical after merging" — it is **not a risk verdict**: a hit does not mean the particle will reproduce a defect, and a miss does not mean it is safe. The real criterion remains sampling frames from a real render.
432
490
  - **Callback and seek semantics** (`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`, **always non-fatal, never blocks laying**): aligned with the same-named contract section. The engine MUST use `seek(t,false)` / `time(t)` / `progress(p)` when fixing a frame; particles may drive their picture from timeline callbacks but MUST NOT override `tl.seek` or replace `window.__timelines[…]`. These lint items are reminders only and do not require seek shims.
433
491
  - **status** (`gtrk mg status --project <dir>`): summarizes the MG pipeline — total beats in `dispatch.mg` / how many source HTML files exist / how many are laid into `.gtrk`, annotating each beat (missing HTML / produced but not laid / laid).
434
- - **render** (`gtrk mg render <particle.html> --duration <sec> [--out <dir>] [--yes]`): renders a single particle in the cloud, **independent of any project**, into a Jianying-readable qtrle transparent alpha MOV (the fine-cut supplement channel — when the rough cut is already exported to Jianying and one more motion graphic is needed, you can add it without going back to the client app). The chain = lint upfront (envelope = `--duration`; any fatal item is blocked locally, zero submission, zero billing) → **billing-estimate confirmation** (live price lookup; the CLI has no local HTML render engine, so the cloud billed task is the only path for standalone particles; `--yes` skips the prompt) → inline submission to the cloud → `<composition_id>.mov` landed with `task.json`/`result.json` breadcrumbs (recoverable by task_id after a crash). **Scope**: qtrle only for now (`--format webm` is explicitly refused — Jianying cannot read VP8-alpha), 1920×1080 particles only (the contract has no portrait/odd-canvas opening), and `--duration` is required. The output never enters `.gtrk` and never lands in the Jianying draft folder; qtrle is lossless and relatively large, suited to seconds-long particles. Note it shares a word with `gtrk render` (full-video rendering) but is a different thing.
435
- - **fetch** (`gtrk mg fetch <query|block> [--top 3] [--all]` / `gtrk mg fetch --pick <block> --slot <beat> --project <dir>` / `--pick <block> --as <composition_id> --duration <sec> [--out <dir>]`): the **neutral particle source** from the HyperFrames registry — MG without a show skill. Candidate mode is **offline** (the snapshot ships with the package, pinned to a source commit) and lists 2–3 blocks per query with compat flags and poster links; pick mode fetches the block through three sources in order (our mirror first, then jsdelivr, then GitHub raw; 5 s each, **sha256-verified per source**, nothing is written if all three fail) → eight mechanical rewrites (`<template>` wrap / id rename / drop data-start and fit the slot / sink the solid backdrop into a child / swap GSAP to the contract CDN / swap fonts to a CJK font provable in our runtime mirror / fit duration to the slot / letterbox scaling, never stretch) → `gtrk mg lint` (fatal items block the write) → lands at `<project>/mg/<composition_id>.html`. **A skeleton is not a deliverable**: the returned `editable` (copy / number arrays / colors) MUST be rewritten for the beat and the show before laying. The contract currently accepts 1920×1080 particles only; `excluded` blocks are refused, `review` blocks (canvas / house-rule 8 shapes) can be fetched but need a real render check. `GITRUCK_MG_REGISTRY_BASE` overrides the fetch prefix.
492
+ - **render** (`gtrk mg render <particle.html> --duration <sec> [--out <dir>] [--yes]`): renders a single particle in the cloud, **independent of any project**, into a Jianying-readable qtrle transparent alpha MOV (the fine-cut supplement channel — when the rough cut is already exported to Jianying and one more motion graphic is needed, you can add it without going back to the client app). The chain = lint upfront (envelope = `--duration`; any fatal item is blocked locally, zero submission, zero billing) → **billing-estimate confirmation** (live price lookup; the CLI has no local HTML render engine, so the cloud billed task is the only path for standalone particles; `--yes` skips the prompt) → inline submission to the cloud → `<composition_id>.mov` landed with `task.json`/`result.json` breadcrumbs (recoverable by task_id after a crash). **Scope**: qtrle only for now (`--format webm` is explicitly refused — Jianying cannot read VP8-alpha), particle geometry must be positive integers, and `--duration` is required; the MOV comes out at the particle's declared `data-width` / `data-height` (a 1080×1920 portrait particle yields a 1080×1920 MOV). The output never enters `.gtrk` and never lands in the Jianying draft folder; qtrle is lossless and relatively large, suited to seconds-long particles. Note it shares a word with `gtrk render` (full-video rendering) but is a different thing.
493
+ - **fetch** (`gtrk mg fetch <query|block> [--top 3] [--all]` / `gtrk mg fetch --pick <block> --slot <beat> --project <dir>` / `--pick <block> --as <composition_id> --duration <sec> [--out <dir>]`): the **neutral particle source** from the HyperFrames registry — MG without a show skill. Candidate mode is **offline** (the snapshot ships with the package, pinned to a source commit) and lists 2–3 blocks per query with compat flags and poster links; pick mode fetches the block through three sources in order (our mirror first, then jsdelivr, then GitHub raw; 5 s each, **sha256-verified per source**, nothing is written if all three fail) → eight mechanical rewrites (`<template>` wrap / id rename / drop data-start and fit the slot / sink the solid backdrop into a child / swap GSAP to the contract CDN / swap fonts to a CJK font provable in our runtime mirror / fit duration to the slot / letterbox scaling, never stretch) → `gtrk mg lint` (fatal items block the write) → lands at `<project>/mg/<composition_id>.html`. **A skeleton is not a deliverable**: the returned `editable` (copy / number arrays / colors) MUST be rewritten for the beat and the show before laying. Registry neutral blocks come in one geometry only, 1920×1080 (the size is baked into each block), and `--canvas` with any other size is refused; in slot mode, a project whose `.gtrk` `video_size` is not 16:9 (7% tolerance, so 4K landscape and 17:9 DCI still fetch) is refused before anything is downloaded or written — portrait / square projects use `--source text` (no `.gtrk` or an invalid `video_size` skips the check with a notice); `excluded` blocks are refused, `review` blocks (canvas / house-rule 8 shapes) can be fetched but need a real render check. `GITRUCK_MG_REGISTRY_BASE` overrides the fetch prefix.
436
494
 
437
495
  `--json` output: `{ ok, mode:"lay"|"lint"|"status", … }` (each mode carries its own fields, e.g. `laid` / `skipped` when laying, per-beat status for `status`). Laying mode additionally carries **`track_total`** (how many laid particles currently exist on the track), **`kept`** / **`kept_ids`** (how many are **left over from the previous round** and not re-laid this time, plus their `composition_id` list) and **`removed`** (how many old self-produced particles were stripped this run) — `laid` (this run), `track_total` (total on the track) and `kept` (left over) **must be read together**, and `track_total = laid + kept` always holds. Reading `laid` alone makes "lay 1, strip 20" look identical to "patch in 1", and reading only the first two hides the cost that "a few particles on the track are not from this round" (`kept_ids` and `skipped` overlap: something that failed to land this round is still there from the previous one). When not fully green it also carries a machine-readable **`reason`**: `skipped` (some were not laid) / `empty_queue` (**write-back refused**, the project was not modified, with `refused:true` and `blocked[]`) / `no_project` (project missing, nothing laid). Runs that actually wrote back also carry **`integrity`** (the material-on-disk self-check, identical in name and shape to `gtrk matrix`; see the previous section).
438
496
 
@@ -458,12 +516,12 @@ gtrk composite bake --input <snapshot.gtrk> --base <project gtrk dir> [--progres
458
516
  gtrk composite bake --abi
459
517
  ```
460
518
 
461
- - `plan`: writes candidate windows to `struct_meta.composite` in the `.gtrk` (that key only, atomic write-back; the same pattern as `gtrk split` writing `struct_meta.split`); the client outline's CP row draws them as proposal blocks. Also writes a review sheet `composite/plan.md`. Re-running keeps built windows and does not re-propose rejected ones.
519
+ - `plan`: writes candidate windows to `struct_meta.composite` in the `.gtrk` (that key only, atomic write-back; the same pattern as `gtrk split` writing `struct_meta.split`); the client outline's CP row draws them as proposal blocks. Also writes a review sheet `composite/plan.md`. Re-running keeps built windows and does not re-propose rejected ones. The text signals behind the suggested layout (lists / contrasts / numbers / steps) are recognised in Chinese and English; other languages rely on B-roll density only, and the review sheet says so.
462
520
  - `review`: approve / reject / adjust / add windows, written back to the same key; later steps only act on approved windows.
463
521
  - `scaffold`: writes a scene skeleton `composite/scenes/cp-wNN.html` and a context sheet `cp-wNN.context.md` for each approved window; existing scenes are not overwritten.
464
522
  - `shots`: for picking footage — a contact sheet stamped with source time codes, shot cut points, and measured black bars (values for `data-crop`); it does not pick for you and does not touch the project.
465
- - `build`: scene → self-contained particle `gtrk/assets/composite/<id>.html`. Resolution matches the infra `composite-particle-profile` rules byte for byte (frame-grid window, track identity, anchors, subtitle input, `inputs_hash`); style comes from `composite/theme.css`.
466
- - `lint`: static checks plus a per-frame layout check in the local Chrome / Edge (a lower picture's foreground border over an upper picture, a foreground line crossing a picture, a picture leaving the stage) and a **frame-purity** check (each sampled frame is rendered twice — once right after the previous frame, once after a distant frame — and element and slot geometry must match; impure scenes draw the wrong picture at bake chunk starts and after preview seeks), optionally rendering stills. Exit code 0 pass / 1 problems / 3 layout not checked (no browser found; set `GTRK_CHROME`).
523
+ - `build`: scene → self-contained particle `gtrk/assets/composite/<id>.html`. Resolution matches the infra `composite-particle-profile` rules byte for byte (frame-grid window, track identity, anchors, subtitle input, `inputs_hash`); style comes from `composite/theme.css`. Write anchor keywords as they appear in the sentence: matching ignores spaces, punctuation and case on both sides, and English matches whole words (`"cold brew"` works as written; `tea` does not match `teas`).
524
+ - `lint`: static checks plus a per-frame layout check in the local Chrome / Edge (a lower picture's foreground border over an upper picture, a foreground line crossing a picture, a picture leaving the stage, an element inside a container that sets `left` / `top` offsets without being positioned — `unpositioned-offset`; give it `position:absolute` or the `.abs` class) and a **frame-purity** check (each sampled frame is rendered twice — once right after the previous frame, once after a distant frame — and element and slot geometry must match; impure scenes draw the wrong picture at bake chunk starts and after preview seeks), optionally rendering stills. Exit code 0 pass / 1 problems / 3 layout not checked (no browser found; set `GTRK_CHROME`).
467
525
  - `lay`: idempotently lays onto the topmost beat track by producer identity, registers materials, marks windows built; refuses stale particles; never overwrites a same-id particle the user edited in the client.
468
526
  - `bake`: bakes the laid composite particles **into opaque video locally**, written to `gtrk/assets/composite-bake/<key>.mp4`; inputs (slot pictures, subtitles, anchors) are computed from the **current timeline**. Purely local, zero billing.
469
527
  - **Browser**: prefers the pinned chrome-headless-shell (deterministic frames, fastest); otherwise falls back to the local Chrome / Edge (screenshot mode, slower, one fewer worker by default). **Never downloads silently**: install only with `gtrk deps install --browser` or this command's explicit `--install-browser` (about 110 MB). `GTRK_CHROME` selects a browser.
@@ -471,7 +529,7 @@ gtrk composite bake --abi
471
529
  - **Cache**: the key covers the particle, the computed inputs, material file fingerprints (size + mtime), fps, browser build and encode settings; hits are reused. Changing concurrency does not change the key.
472
530
  - **Frame rate**: defaults to the project rate; `--fps` overrides (e.g. a 30fps export). Frame count = `ceil(window × fps)`, covering the whole window.
473
531
  - **Exit codes**: 0 all succeeded (cache hits included) / 1 some composite failed (the rest still bake; reasons per composite) / 2 argument or environment error / 130 cancelled.
474
- - **Machine-readable**: `--progress jsonl` prints one event per line with `type` in `start` / `browser` / `prep` / `progress` / `composite` / `cancelled` / `done`, at most 1 second apart; in this mode **closing stdin cancels** (other modes ignore stdin). `--abi` prints only `{abi, version, browser, overrides}` without reading the project: `browser.pinned` says whether the pinned render component is installed; `overrides` lists the slot user overrides this version can bake (`fit` / `framing` / `crop` / `box` for the picture-in-picture window size and position / `slip_ms` for shifting a referenced clip's frames), so the client can tell whether the adjustments in a project can be baked. `--input <snapshot> --base <dir>`: use the snapshot as the timeline (for the client's unsaved state); relative material paths and the output location resolve against `--base`; the snapshot is never written back.
532
+ - **Machine-readable**: `--progress jsonl` prints one event per line with `type` in `start` / `browser` / `prep` / `progress` / `composite` / `cancelled` / `done`, at most 1 second apart; in this mode **closing stdin cancels** (other modes ignore stdin). `--abi` prints only `{abi, version, browser, overrides, stage}` without reading the project: `browser.pinned` says whether the pinned render component is installed; `overrides` lists the slot user overrides this version can bake (`fit` / `framing` / `crop` / `box` for the picture-in-picture window size and position / `slip_ms` for shifting a referenced clip's frames), so the client can tell whether the adjustments in a project can be baked; `stage: "canvas"` means any stage size can be baked (the composite stage follows the project canvas, so portrait and square work the same way; older versions without this field only handle 1920×1080). `--input <snapshot> --base <dir>`: use the snapshot as the timeline (for the client's unsaved state); relative material paths and the output location resolve against `--base`; the snapshot is never written back.
475
533
  - `gtrk render` / `gtrk project export` bake the project's composites first: a successfully baked span shows the baked video (in Jianying / Premiere, a video clip on that layer), and **MG / OV particles lying entirely inside a composite window are no longer pre-rendered or billed**; a composite that fails to bake (missing footage, no browser, …) falls back to the rough cut with its reason reported, and never blocks export.
476
534
 
477
535
  ### `gtrk project init` / `gtrk audio lay` / `gtrk audio tighten` — audio-first project atoms (voice-over first)
@@ -554,7 +612,7 @@ Standalone single-request capabilities, kept separate from the pipeline's lane c
554
612
  | Tool | Input | Output | Billing | Status |
555
613
  |---|---|---|---|---|
556
614
  | `image_move` | One image; optional `--motion` picks one of 26 camera moves | Camera-move video (geometry derived from the source orientation: landscape 1920×1080 / portrait 1080×1920) | Queried live before the run | Live |
557
- | `image_matting` | One image | Transparent-background png (`--param` can request a backing plate) | Queried live before the run | Live |
615
+ | `image_matting` | One image (phone photos with an EXIF orientation are uprighted to their display orientation before upload; the original is untouched) | Transparent-background png (`--param` can request a backing plate) | Queried live before the run | Live |
558
616
  | `image_blackborder_remove` | One local image | Image with black borders removed | Queried live before the run | Live |
559
617
  | `image_canvas_adapt` | One local image; optional target width/height and `normal` / `rectangle` / `square` | Aspect-adapted image | Queried live before the run | Live |
560
618
  | `image_purify` | One local image; optional `full_screen` / `region` and region boxes (only material you have the rights to process) | Image cleaned of watermarks, logos or overlays | Queried live before the run | Live |
@@ -695,7 +753,7 @@ A QC pass runs automatically afterwards and writes `.qc.json` (`--no-qc` skips i
695
753
  - The distributed ffmpeg is a GPLv3 build, and the corresponding source is provided alongside the binaries (see `SOURCE.md` at the distribution point); **downloads carry no additional usage restrictions**.
696
754
  - `gtrk upgrade [--check]` — upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports.
697
755
  - `gtrk skills install [--agents codex,workbuddy,comate,…] [--all] [--copy] [--dir <skills dir>]` — install/refresh agent skills on their own; by default the generic adapter and the gtrk supplement layer detect hosts automatically.
698
- - `gtrk skills recommend [--scene <id>] [--json]` — third-party skill catalog: without `--scene` lists the ten scenes (hook / mg-explainer / kinetic-text / data-viz / map / ai-drama / collage / caption / principles / technique); with a scene prints entries by tier (purpose / install command / license and dependencies / register command). **Recommend, never bundle**: the catalog ships with the package with a snapshot date, no network, no state; stars and licenses are as of the snapshot, installing is your call. GPL / AGPL / non-commercial / unlicensed / MCP-SaaS-only skills are excluded. The catalog also lists Gitruck's own first-party MG layout-technique family (`--scene technique`, entries marked `origin: first-party`): techniques are not lane producers; the agent picks them per slot at the MG step.
756
+ - `gtrk skills recommend [--scene <id>] [--json]` — third-party skill catalog: without `--scene` lists the ten scenes (hook / mg-explainer / kinetic-text / data-viz / map / ai-drama / collage / caption / principles / technique); with a scene prints entries by tier (purpose / install command / license and dependencies / register command). **Recommend, never bundle**: the catalog ships with the package with a snapshot date; the command itself makes no network requests and keeps no state (usage statistics aside, see “Usage statistics, and how to turn them off”); stars and licenses are as of the snapshot, installing is your call. GPL / AGPL / non-commercial / unlicensed / MCP-SaaS-only skills are excluded. The catalog also lists Gitruck's own first-party MG layout-technique family (`--scene technique`, entries marked `origin: first-party`): techniques are not lane producers; the agent picks them per slot at the MG step.
699
757
  - `gtrk skills add <owner/repo> [--skill <name>]... [--produces MG|AI_DRAMA|FILM_BROLL|script|none] [--column <id>] [--agents ...] [--all] [--copy]` — installs a third-party skill through the generic `skills` adapter and, on success, **appends** `{id, ref: "<owner/repo>#<skill>", produces, status: "third-party"}` (`"first-party"` for first-party entries) to the show config `style.skills` (idempotent per ref, nothing is registered on failure; `--produces` defaults to the catalog value, repos outside the catalog register with `routing:"none"`), after which `gtrk mg` / `/gtrk-ai-drama` resolve it by `produces`.
700
758
 
701
759
  ### Highlight discovery (internal preview)