@gitruck/cli 1.3.9 → 1.3.11
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.
- package/AGENT.md +41 -2
- package/CHANGELOG.md +44 -0
- package/README.en.md +22 -0
- package/README.md +22 -0
- package/assets/composite-kit/kit.js +36 -7
- package/assets/composite-kit/stage.html +23 -2
- package/dist/index.js +341 -334
- package/docs/reference.en.md +57 -18
- package/docs/reference.md +59 -21
- package/package.json +3 -3
- package/skills/gtrk-composite/SKILL.md +11 -6
- package/skills/gtrk-food-recap/SKILL.md +1 -1
- package/skills/gtrk-live-slicing/SKILL.md +2 -2
- package/skills/gtrk-long2short/SKILL.md +4 -3
- package/skills/gtrk-matrix/SKILL.md +48 -5
- package/skills/gtrk-mg/SKILL.md +404 -398
- package/skills/gtrk-narration/SKILL.md +3 -2
- package/skills/gtrk-oralcut/SKILL.md +28 -16
- package/skills/gtrk-splitter/SKILL.md +313 -298
- package/skills/gtrk-style-maker/SKILL.md +1 -1
- package/skills/gtrk-style-maker/references/craft-output-spec.md +2 -2
- package/skills/gtrk-talking-head/SKILL.md +8 -3
- package/skills/gtrk-tools/SKILL.md +5 -4
- package/skills/gtrk-vlog-docu/SKILL.md +1 -1
package/AGENT.md
CHANGED
|
@@ -138,7 +138,8 @@ gtrk transcript <本地视频.mp4> --json # 转成一个含总结/时
|
|
|
138
138
|
**先跑 `gtrk deps status` 确认真缺**,再跑 `install`——不要看到报错就无脑装(先查后拉)。
|
|
139
139
|
- 包体 30–90 MB(按平台),走同合云镜像;下载自动过 sha256 校验,解包用系统 tar,无第三方依赖。
|
|
140
140
|
- **不越过用户自装的 ffmpeg**:定位仍是 `--ffmpeg-path` → `~/.gitruck/ffmpeg` → 系统 PATH。
|
|
141
|
-
-
|
|
141
|
+
- 字体从统一静态资源下发的字体目录取(`cloud/static/assets/fonts/catalog.json`,与客户端同一份),`--font` 只装目录登记的字幕字体,
|
|
142
|
+
落 `~/.gitruck/fonts`(落点即缓存),经 `ass` 滤镜 `fontsdir` 供给——**不动用户的系统字体表**。已装按文件名归一比对,历史命名 `SourceHanSansCN-Bold.otf` 也算已装。
|
|
142
143
|
- 平台未覆盖时(如 linux-arm64)会明确报错并指引手工安装,**不会错装其他架构的包**。
|
|
143
144
|
|
|
144
145
|
6. **skill 新鲜度(agent 纪律 · fix-skill-install-staleness)**:随包 `/gtrk-*` skill 是
|
|
@@ -333,6 +334,25 @@ gtrk media boundaries <参考片> --rate 4 --threshold 0.12 --transcript <稿> -
|
|
|
333
334
|
- 台词多处出现时命令会报错列出每处——用 `--occurrence` 拍板,别改用模糊的 `--start/--end` 绕过。
|
|
334
335
|
- 读完要建栏目 → 交 `/gtrk-style-maker`:精读出的系统只作「作品逆向」的证据,经用户认领才成栏目维度;参考片的帧与片段不进栏目 skill 的 assets。
|
|
335
336
|
|
|
337
|
+
### 2.3.2 读编辑器里的工程:`gtrk client`(客户端开着读活状态,没开读文件)
|
|
338
|
+
|
|
339
|
+
用户说「第 12 段」「我选中的这段」「现在这一帧」时,先读工程而不是猜:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
gtrk client state --project <dir> --json # 轨道摘要 + 选中 + 播放头(主轨片段带序号 no)
|
|
343
|
+
gtrk client segment --no 12 --project <dir> --json # 第 12 段的轨上时码与口播文字
|
|
344
|
+
gtrk client frame --at 31.5 --project <dir> --json # 时间线 31.5 秒那一刻的画面(返回图片路径)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**agent 纪律:**
|
|
348
|
+
|
|
349
|
+
- `frame --at` 收的是**时间线**时刻(`track_st` 那一套)。看「剪后这一刻长什么样」用它;MUST NOT 拿 `track_st` 去 ffmpeg seek 毛片——粗剪过的工程,毛片同一秒是另一处画面。要看源片某一刻才用 `gtrk media frames <源片> --at <秒>`。
|
|
350
|
+
- `source` 不是 `client` 时,`selection` / `playhead` 为 `null`:用户没开客户端,「选中的这段」无从得知——问用户是第几段,别猜。
|
|
351
|
+
- 本地渲染的帧不含 MG 颗粒(`note` 写明);判底轨构图够用,判颗粒效果要用户在客户端里看。
|
|
352
|
+
- 截帧图是临时文件:缺省落 `$GTRK_FRAMES_DIR` 或系统临时目录,用完即删;不复制进工程目录、不落 agent 自有目录。
|
|
353
|
+
|
|
354
|
+
列毛片同目录的音视频用 `gtrk media probe <目录>`;超长毛片分段用 `gtrk media cut <毛片> --start <秒> --end <秒> --copy -o <同扩展名文件>`(流拷贝、秒级,起点按关键帧对齐)。
|
|
355
|
+
|
|
336
356
|
---
|
|
337
357
|
|
|
338
358
|
## 2.4 元素级编辑:`gtrk patch`(改工程唯一入口)
|
|
@@ -366,7 +386,8 @@ gtrk patch set --project <dir> --total max # 改顶层总长(
|
|
|
366
386
|
| | `--set-in` / `--set-out` | 同上,但给**绝对时码** |
|
|
367
387
|
| | `--slip <delta>` | **只换源窗**:轨上落点与时长都不动。⚠️ trim-in 有两种业界语义,所以必须你显式选一种 |
|
|
368
388
|
| `split` | `--cut <sec\|Nf>` | 切点。两段各须 ≥1 帧;新片段 id 为 `<orig>-2` 递增 |
|
|
369
|
-
| `set` | `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | 元素级参数。`--volume` 是**线性增益不是 dB
|
|
389
|
+
| `set` | `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | 元素级参数。`--volume` 是**线性增益不是 dB**、须 > 0——`--volume 0` 报 `volume_zero_use_muted`(各消费方把 `volume: 0` 读成原音量),静音用 `--muted`。**轨静音是总开关**:片段所在轨已静音时 `--no-muted` 报 `track_muted_master`(`patch set` 不改轨级参数,请在客户端点开轨喇叭);`--audio-track` 把原本出声的片段移进静音轨报 `audio_track_target_muted` |
|
|
390
|
+
| | `--audio-fade-in <sec\|Nf>` / `--audio-fade-out <sec\|Nf>` | 音频淡入 / 淡出时长(视频轨原声或音频轨片段;颗粒与空档拒收)。秒或帧、整毫秒;**设 0 即删键**;与另一侧之和**超过片段时长即硬拒**并报本侧最多可设多少(不替你按比例缩);不接受带符号的相对值。`trim` / `split` 会自动维护淡变(剪短放不下时按比例缩并在回执出 `audio_fade_clamped`) |
|
|
370
391
|
| | `--total <sec\|Nf\|max>` | 顶层总长。**工程级 op,与元素寻址互斥** |
|
|
371
392
|
|
|
372
393
|
**通用**:`--dry-run` 只算不写;`--json` 回执到 stdout(人读日志转 stderr);
|
|
@@ -398,6 +419,22 @@ gtrk patch set --project <dir> --total max # 改顶层总长(
|
|
|
398
419
|
- 顶层 `duration` 键不在场时用 `--total` ⇒ 缺席自带「按末端机械算出」语义,新增该键会改消费与计费口径
|
|
399
420
|
- 只给 `--track` 不给 `--at` ⇒ v1 射程是**元素级**,不写轨对象上的键
|
|
400
421
|
|
|
422
|
+
**转场字段的保真与维护**(`transition_in` / `transition_out` / `transition_next`:用户在客户端加;CLI 本期**不产出**转场,`patch set` 也没有转场参数):
|
|
423
|
+
|
|
424
|
+
- **保真**:任何命令都原样带着转场走;CLI 新铺的片段一律不带转场键。
|
|
425
|
+
- **`split`**:入场转场留前段;出场转场与「接下一段」的转场归后段(`to_clip_id` 不变);新切口不带转场。
|
|
426
|
+
- **写回前统一维护**(单发与整个 `--ops` 批都只在**末尾一次**,批内先移走再移回不算数):对本次有变化的轨跑一遍契约 resolve——
|
|
427
|
+
`transition_next` 不再紧邻它指向的片段(下一段被移走 / 删掉)⇒ **删**,MUST NOT 改挂到新邻居;剪短后放不下 ⇒ 按帧缩短(先头后尾),不足 1 帧即删。
|
|
428
|
+
回执 `warnings[]` 逐条给 `transition_dropped{clip_id, track, slot, reason}` / `transition_shortened{clip_id, track, slot, reason, before, after}`——
|
|
429
|
+
**改了用户在客户端设的东西,要如实转告用户**。
|
|
430
|
+
- **颗粒目录从后端拉、不随包**:工程带转场时才拉 `https://api.ai-mcn.tv:9000/cloud/static/assets/transitions/catalog.json`(统一静态资源目录外壳 schema 2,只取目录、不取着色器 / 缩略图 / 预览),
|
|
431
|
+
缓存在统一静态资源缓存 `~/.gitruck/cache/transitions/catalog.json`(与客户端共用,24 小时一刷;旧的 `~/.gitruck/transitions/` 已废弃、不再读)。`composite lay` 只读这份缓存、不联网。离线 / 目录不可用 / 颗粒不在目录里 ⇒ 那个转场**原样保留不删**(悬空的也留着,联网后下一次维护再处理),命令照常工作。
|
|
432
|
+
- **存量问题不卡你**:与本次编辑无关的轨上的转场违例只进 `preexisting`(`transition_invalid`),不阻断;目录里没有的颗粒永不阻断。
|
|
433
|
+
- **铺轨命令**(`matrix` / `mg` / `ai-drama` / `pip` / `audio` / `composite lay`)重铺自产轨时,被替换掉的片段若带用户的转场,日志与 `--json` 回执出
|
|
434
|
+
`replacedTransitionClips`(只在 > 0 时出现);同轨邻居因此悬空的转场同样维护,逐条列在回执 `transitions[]`。
|
|
435
|
+
- **`project export`** 上行前对上行体规整一次(盘上 `.gtrk` 不动),删缩的写进 `result.json` 的 `transitions`;本期云端各 NLE 格式不承接转场,
|
|
436
|
+
回执的 `transition_not_carried` 告警逐条打出——导到剪映 / Pr 里是硬切。**`gtrk render`** 本期同样按硬切出片,并计 `transition_not_carried`(`format: "cli_render"`)。
|
|
437
|
+
|
|
401
438
|
---
|
|
402
439
|
|
|
403
440
|
## 2.5 双源画中画:`gtrk pip lay`(屏录 / 第二机位 · 纯本地零计费)
|
|
@@ -426,6 +463,7 @@ gtrk pip lay --project <口播工程目录> --companion <屏录.mp4> [--shape el
|
|
|
426
463
|
```bash
|
|
427
464
|
gtrk composite plan --project <工程> [--mode full|auto|ranges] [--range 11,32 | --range u0004-u0009]... [--density 0.25]
|
|
428
465
|
gtrk composite review --project <工程> [--approve W01,W03] [--reject W02] [--adjust W04=80,90.9] [--add 140,150] [--approve-all]
|
|
466
|
+
gtrk composite status --project <工程> [--json]
|
|
429
467
|
gtrk composite scaffold --project <工程> [--only W03] [--force]
|
|
430
468
|
gtrk composite shots --project <工程> --material <素材 id 或文件> [--around <秒> --span <秒>]
|
|
431
469
|
gtrk composite build --project <工程> [--only cp-w03] [--theme <css>] [--materials <json>]
|
|
@@ -437,6 +475,7 @@ gtrk composite bake --project <工程> [--only cp-w03] [--fps 30] [--workers 4]
|
|
|
437
475
|
- **候选写 `struct_meta.composite`**(只动这一个键、原子写回),客户端大纲 CP 行画提案块——与 `gtrk split` 写 `struct_meta.split`、beat 色带呈现同一套做法。要用户看提案块,先请他在客户端**重新载入工程**。
|
|
438
476
|
- **解析规则不自造**:`build` 按 infra `composite-particle-profile` 解析(帧格窗口、`lane_clip_id`、锚点局部帧、字幕输入、`inputs_hash`),对拍 infra 金样逐字节一致;窗口不在帧格上会被吸附并报挪动量。
|
|
439
477
|
- **机检**:`lint` 退出码 0 通过 / 1 有问题 / 3 排版未机检(本机找不到 Chrome / Edge,可设 `GTRK_CHROME`)。**3 不是通过**:照实告诉用户,用静帧人眼查。`lint` 含帧纯度检查(`impure-frame`:同一帧号随渲染顺序画出不同画面),不过的颗粒烘焙段首会画错。
|
|
478
|
+
- **进度**:`status` 只读汇总——各状态窗口数、`pending`(已采纳、还没铺轨的段数)、已铺数,逐窗口起止按当刻时间线重新投影。
|
|
440
479
|
- **铺轨**:按 `producer=gtrk:composite@1` 认领自产轨(不按轨号);过期颗粒(上游改过)拒铺;用户在客户端改过的同 id 颗粒不覆盖。
|
|
441
480
|
- **出片**:`gtrk composite bake` 在本机把合成烤成不透明视频(缓存命中即复用,纯本地零计费);`gtrk render` / `gtrk project export` 会自动先烤,成功的段以烘焙视频出画,整段落在合成窗口内的 MG / OV 不再预渲、不计费。
|
|
442
481
|
- 浏览器优先用钉定版本 chrome-headless-shell,没有时退回本机 Chrome / Edge(更慢)。**MUST NOT 自作主张下载**:征得用户同意后 `gtrk deps install --browser`(约 110 MB)或 `bake --install-browser`。
|
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,50 @@
|
|
|
11
11
|
|
|
12
12
|
## 未发布
|
|
13
13
|
|
|
14
|
+
- 新:工程片段的**转场**(即剪客户端写进 `.gtrk` 的 `transition_in` / `transition_out` / `transition_next`)CLI 全程认得、本期不产出。任何命令都原样带着转场走,新铺的片段不带转场。`gtrk patch split` 入场转场留前段、出场与接下一段的转场归后段(此前两半都复制同一个转场,前段那个立刻悬空、切口凭空多出一个入场);每次 `gtrk patch`(单发或整个 `--ops` 批)写回前对改动过的轨统一维护:下一段被移走后不再紧邻的「两段之间」转场删除(不改挂到新邻居),剪短后放不下的按帧缩短(先头后尾),回执逐条给 `transition_dropped` / `transition_shortened`;与本次编辑无关的存量转场问题只报不拦。`matrix` / `mg` / `ai-drama` / `pip` / `audio` / `composite lay` 重铺自产轨时,被替换掉的片段若带你在客户端加的转场,日志与 `--json` 回执给出 `replacedTransitionClips`。`gtrk project export` 上行前把工程规整一遍(悬空、越界的删缩并列进 `result.json` 的 `transitions`,盘上工程不动),免得云端整单拒收;云端各格式本期不承接转场,导到剪映 / Pr 里是硬切,回执里的 `transition_not_carried` 逐条打出。`gtrk render` 本期按硬切出片并计 `transition_not_carried`(无转场工程滤镜串逐字节不变)。转场颗粒目录不随 npm 包分发:工程带转场时才从后端拉 `cloud/static/assets/transitions/catalog.json`,缓存在与客户端共用的统一静态资源缓存 `~/.gitruck/cache/transitions/catalog.json`(24 小时一刷);离线、目录不可用或颗粒不在目录里时转场原样保留,命令照常工作。⚠️ **编辑含转场的工程需本版本及以上**:旧版不报错,但切分会复制转场、移动后留下悬空转场、重铺静默删掉用户的转场、上云被拒收(link-gtrk-clip-transitions)。
|
|
15
|
+
|
|
16
|
+
- 改:`gtrk mg fetch` 的 MG 区块与文字模板(`--source text`)改走统一静态资源下发,目录格式与本机缓存同即剪客户端共用一套(unify-static-resource-delivery)。
|
|
17
|
+
- 文字模板:目录缓存从 `~/.gitruck/text-templates/` 挪到 `~/.gitruck/cache/text-templates/`(旧位置不再读,首次联网自动重拉);拉到远端目录即用,不再按版本号择新(服务器回滚就是换回旧目录);正文按内容寻址取,每份都校 sha256 与字节数,命中本机缓存不打网。候选不再列「预览」(封面从未发布过)。
|
|
18
|
+
- MG 区块:候选态照旧零网络(读本机缓存的目录,没有就用随包快照);取块前先刷新一次目录(24 小时一刷,缓存在 `~/.gitruck/cache/mg-registry/`),镜像改为同合云优先、取不到再经 GitHub raw / jsDelivr fastly / jsDelivr gcore / gh-proxy 回源;目录里块被下架或改判 excluded 时按刷新后的目录拒取。
|
|
19
|
+
- `GITRUCK_TEXT_TEMPLATE_BASE` / `GITRUCK_MG_REGISTRY_BASE` 现在指镜像根:`<根>/catalog.json` 与 `<根>/files/…`(即统一发布的暂存包 / 静态盘布局,不再是 `blocks/<名>/<文件>`),设了就只用它,不写本机缓存。
|
|
20
|
+
- `--json` 回执:取块与候选多了 `catalog`(目录版本与来源);命中本机缓存时 `fetched_from` / `source` 是 `cache`、`url` 是 `null`;全部镜像失败的报错改为逐个镜像列原因(不再是「三源皆不可用」)。
|
|
21
|
+
|
|
22
|
+
- 改:`gtrk deps install --font` / `--font-family` 改从统一静态资源下发的字体目录装(`cloud/static/assets/fonts/catalog.json`,与客户端同一份目录、同一套命名),不再读字体库 `manifest.json`。`--font` 装的是目录顶层登记的字幕字体(思源黑体 CN Bold,落 `~/.gitruck/fonts/sourcehansanscn-bold.otf`);每款都校 sha256 与字节数,取不到时逐个镜像说明原因、不落半成品;字体文件不另存一份到 `~/.gitruck/cache/`。已装按文件名归一比对,历史命名 `SourceHanSansCN-Bold.otf` 也算已装、照旧跳过;`--force` 重下时换成目录里的命名。`gtrk deps status` 的字体一行改报目录版本、族数 / 款数与字幕字体装没装(unify-static-resource-delivery)。
|
|
23
|
+
|
|
24
|
+
- 新:`gtrk matrix --neighbors <n>`(0–5)。矩阵成员检索概念素材时,命中镜头连同它在原片里前后各 n 个镜头一起带回,适合接成一串蒙太奇。
|
|
25
|
+
- `matrix search` 加上它后,有邻居的结果下面会按原片顺序列出整段(不相接处标 `⋯`),并给出现成的 `gtrk matrix fetch` 命令,邻居可直接拉原片。
|
|
26
|
+
- 派单检索缺省带 2:邻居写进工程,在客户端 B-roll 面板里折叠,由你单张挑选,不参与自动铺轨;`--neighbors 0` 关闭。
|
|
27
|
+
- 服务端返回的出处字段 `source` 在 CLI 里改叫 `source_ref`(link-clip-search-neighbors-cli)。
|
|
28
|
+
|
|
29
|
+
- 改:`gtrk audio lay --volume 0`(含 `0.0` / `-0`)现在直接拒绝、不写工程。它不会静音——客户端、`gtrk render` 与云端都把 `volume: 0` 读成原音量,BGM 照样满音量;不想要 BGM 就别铺,铺好后要静音用 `gtrk patch set --muted`,要很轻的垫底给个小正数。其它越界值照旧按默认 0.1 回落并告警。
|
|
30
|
+
- 改:`gtrk patch set --volume 0` 现在直接拒绝(`volume_zero_use_muted`),提示改用 `--muted`。契约 §4 不以线性 0 表达静音,客户端、`gtrk render` 与云端工程导出 / 时间线渲染都把 `volume: 0` 当旧客户端 0 dB 残档读成原音量,此前这条命令「成功」却听不出变化;`--ops` 批量里出现同样整批不写。
|
|
31
|
+
- 改:`gtrk patch set` 的静音改按「轨是总开关」判,与客户端、`gtrk render` 一致——轨或片段任一静音即静音,片段上的 `muted: false` 打不开已静音的轨。⚠️ **原来在静音轨上「成功」的 `set --no-muted` 现在报错** `track_muted_master`(以前写进 `muted: false`、回执说已取消静音,实际照样静音):`patch set` 不改轨级参数,请在客户端点开该轨喇叭。静音轨上 `set --muted` 显式写 `muted: true`(之后轨解除静音,这段仍静)。`set --audio-track` 转轨按有效静音保真:从静音轨移到不静音的轨,片段写上 `muted: true`;把原本出声的片段移进静音轨报 `audio_track_target_muted`、工程不动。音量照旧按「片段覆盖轨」(link-gtrk-track-muted-precedence)。
|
|
32
|
+
- 新:工程片段的**音频淡入淡出**(即剪客户端写进 `.gtrk` 的 `audio_fade_in` / `audio_fade_out`)CLI 全程认得。`gtrk patch` 剪短片段时淡变放不下就按比例缩、回执出 `audio_fade_clamped`,切开片段时前段只留淡入、后段只留淡出(此前切点处会凹一下);新参数 `gtrk patch set --audio-fade-in / --audio-fade-out`(秒或帧,0 即删键,两侧之和超过片段时长直接拒)。`gtrk render` 按淡变出声(按成片时间计、变速片段不换算,无淡变工程滤镜串逐字节不变)。`gtrk audio tighten` 遇到带淡变的音频片段拒绝并点名、工程不动;`gtrk audio lay` 同源重铺把带淡变的旧片段替换掉时如实告知条数。`gtrk project export` 把云端返回的产物级告警全部打出并写进 `result.json` 的 `warnings`(含剪映 / Pr 等格式对淡变的降级说明,顺带变速保调降级告警也不再被吞)。⚠️ **编辑或渲染含音频淡变的工程需本版本及以上**:旧版不报错,但切分会让两半都带两侧淡变、剪短不缩、`audio tighten` 逐段复制、渲染没有淡变(link-gtrk-clip-audio-fade)。
|
|
33
|
+
|
|
34
|
+
- 修:`gtrk render` 不认音频轨的静音——客户端里点了 BGM 轨的喇叭、或用 `gtrk patch set --muted` 静了某段音频,本地渲染出来照样有声,与客户端导出不一致。现在音频轨的轨级与片段级 `muted` 都生效:轨静音是总开关(片段上写着 `muted: false` 也不出声,与客户端一致),片段静音只静那一段;静音部分不再读素材音频,成片总长不变。所有音源都被静音时照常出无声成片,并打「本片无音源」提示。没有静音音频轨的工程,渲染结果与之前相同(fix-render-audio-track-muted)。
|
|
35
|
+
- 修:同一台机器既装了 gtrk 插件(Claude Code / Codex 插件市场)又跑了安装器,Agent 里的 Skill 会出现两份——插件自己的引导让人跑的 `npx -y @gitruck/cli@latest install` 会再装一份。现在:`gtrk install --no-skills` 只装 CLI 和配置、不装 Skill,插件的引导(Claude Code 会话开头提示、Codex 详情、README 插件一节)都改用它;安装器认得已启用的 gtrk 插件,默认安装时按宿主让路——Claude Code 有插件就照装给其他 Agent、撤掉 Claude Code 里那几条链接,Codex 有插件就这一步不装(它直接读 `~/.agents/skills`,再装一份就是两份),让路算成功,`gtrk upgrade` 不再误报「skill 没刷成」;点名 `--agents` 时照装,会重复就提示一行。已经重复的只报不删:`gtrk doctor` 新增「Skill 来源」一行,新命令 `gtrk skills uninstall` 移除安装器装的那份(第三方 Skill 与插件那份不动);Codex 插件在场时过期提示改指移除。(fix-plugin-installer-duplicate-skills)
|
|
36
|
+
- 新:Codex 插件市场与 Cursor 插件清单——仓库根即插件,随包 20 个 `gtrk-*` Skill 照旧取 `skills/`。Codex:`codex plugin marketplace add Gitruck/cli` 后 `codex plugin add gtrk@gitruck`(只装 Skills,CLI 与 API Key 用 `npx -y @gitruck/cli@latest install --no-skills` 另装);Cursor 清单 `.cursor-plugin/plugin.json` 供插件市场审核。发版闸 `plugin-manifest-check` 改为 Claude Code / Codex / Cursor 三份清单的 version 都须与 package.json 一致。
|
|
37
|
+
- 新:`gtrk client state / segment / frame`——读编辑器里的工程。即剪客户端开着这个工程时经本机通道读活状态(选中哪段、播放头、编辑器所见的画面);没开时读工程文件、本地渲出一帧(零计费、不含 MG 颗粒),两条路输出同形、`source` 标明是哪条,客户端缺席不影响任何子命令。`frame --at` 收的是**时间线**时刻:粗剪过的工程拿轨上时码去 seek 毛片会取到另一处画面,`gtrk-splitter` / `gtrk-mg` 的抽帧步骤因此改用它。`gtrk media probe` 收目录(列出这一层的音视频与参数),`gtrk media cut --copy` 流拷贝截段(秒级、起点按关键帧对齐),`gtrk media frames` 没给 `-o` 时认 `$GTRK_FRAMES_DIR`。`gtrk-splitter` / `gtrk-mg` / `gtrk-oralcut` 标 `in_app_agent`:要 agent 执行的命令全是 gtrk(装 CLI 那一步标为外部 agent 的前置),测试闸守住。
|
|
38
|
+
- 修:`gtrk qc --gtrk` 与 `gtrk render` 渲后质检的报告里从来没有换段备选——`gtrk-mg` 出片后 QC 闭环第 2 步「读它给的排序备选」无从读起,只能手找候选段。现在段内跳切与判为严重的过短镜头条目带 `alternatives`:同一 beat 里还没上轨的候选段(从工程登记的 `split/broll-plan.json` 取),每条给 `clip_id`、段区间与排序依据,按运动量 → 切点密度 → 分数排序,列前 3 段(多于 3 段另报总数);候选缺运动或切点信号时 `alternatives_note` 注明口径受限。「未上轨」按段判:此前按 `clip_id` 判,一个 beat 只有一条素材、底下好几段的工程会被判成零备选。该 beat 的段都已上轨时给空列表并说明;没读到 plan 时不给列表、只给说明。判为严重的过短镜头此前不带 beat / 槽位坐标,现在带上,紧贴拼接处的极短镜头(一两帧)也能归到槽位(add-material-motion-signal 4.2)。
|
|
39
|
+
|
|
40
|
+
- 新增:`gtrk tool image_purify --redraw` 图片去水印「重绘模式」——整张图交给图片编辑模型重新生成,铺满全图的半透明、网格水印也能去掉;与 `--purify-scope region` 同用时只替换框内。单独计价,运行前报价按重绘档;也可 `--params-json '{"purify_method":"redraw"}'`。不加 `--redraw` 时请求与之前逐字节相同。价格表里挂在父项下的分档(`tiers`,如重绘、区分说话人、云配音各音色档)现在也能按自己的 key 查到实时价格(link-add-image-purify-redraw-mode-cli)。
|
|
41
|
+
- Skill 措辞订正(ClawHub 安全扫描指出的自相矛盾与告知缺口):`gtrk-matrix` 的描述把「素材本体不上云」改准为视频本体不上云、选中上轨的图片会上云转运镜(正文早已写明);`gtrk-narration` / `gtrk-food-recap` / `gtrk-vlog-docu` 的「不执行任何网络下载」收窄为不下载二创源片与主体素材,素材矩阵的 BGM / 空镜可按签名直链落地(与旅拍图纸同口径,此前与各自的 BGM 伴奏下载步骤字面冲突);`gtrk-narration` 开工问询补一句内容离机告知(转写上传音轨、建索引上传抽帧图);`gtrk-style-maker` 安装用户 skill 前先问装到哪些 Agent(缺省只装当前这个),适配器钉在 `skills@1.7.4`。下载禁令的射程同步写进解说链规格(fix-narration-download-ban-scope)。
|
|
42
|
+
- `gtrk-oralcut` 剪完不再一律往下接力:只要剪辑工程、草稿或去停顿时,剪完停在交工,一句话交代下一步,说一声就接着做;看不出要不要成片时也先停。要成片、完整包装,或点名 B-roll、字卡、BGM、字幕之一时,照旧接着拆分镜派单。按 `/gtrk-talking-head` 跑粗剪时交回图纸,停在检查点①(adjust-oralcut-relay-by-request-scope)。
|
|
43
|
+
- `gtrk-splitter` 派单后不再一律往下铺:直接调用只要拆分稿或派单时,落地后停下,一句话交代下一步(下一步会往工程里加 B-roll 候选轨),说一声就接着做;看不出要不要往成片做时也先停。要成片、点名要铺 B-roll 等,或是被 `/gtrk-oralcut` 按「要成片」接力过来时,照旧交棒铺 B-roll(adjust-splitter-relay-by-request-scope)。
|
|
44
|
+
- `gtrk-mg` 出片后 QC 报出可换段的画面问题时,不再直接把你选定的 B-roll 换成排序第一的备选:先列出哪几处、拟换成哪段,以及连带影响(B-roll 重铺、受影响的 MG 颗粒重铺并覆盖手调、重渲可能计费),你同意后只换同意的那几处;改 plan 前留 `broll-plan.before-qc-<时间戳>.json` 与 `project.before-qc-<时间戳>.gtrk` 两份副本,拷回原文件名即回退、不再计费。事先说过「QC 报的问题直接换」也只免换段那一问,重铺(本地素材走云端编排计费)与重渲照旧先报预估、等你同意(fix-mg-qc-swap-needs-approval)。
|
|
45
|
+
- `gtrk-mg` 出片后 QC 报出可换段的画面问题时,不再自己换 B-roll:转述缺陷后把换段交回 `gtrk-matrix`,先列拟换方案、等你同意、留副本这些规矩照旧。重铺完会先停下,请你在客户端看换过的那几处画面,以及上面的 MG 有没有挡住主体;你认可新底轨之后才回到 MG,没点名的颗粒一颗不重铺,手调保留。事先说过「QC 报的问题直接换」也不免这一次认可(adjust-mg-qc-swap-handoff-to-matrix)。
|
|
46
|
+
- `gtrk-matrix` 出片 QC 换段时,换进来的段接过被替换段的排序分、占它原来的位置,重铺后只有你同意换的那几处变。此前照「原样搬」保留检索相似度,本地素材的 plan 会被段序校验整单拒绝;重排后再铺,同一 beat 的其余镜头会整体挪位,还可能挤进一段没上轨的备用段。原检索相似度记进与副本同一时间戳的 `split/qc-swap-<时间戳>.json`;换进段来自另一条素材、位置保不住时,会先告诉你哪几处跟着挪。另订正一处说法:钉选(`pinned`)只保证落得上,不保证落在第几槽(fix-qc-swap-slot-order)。
|
|
47
|
+
- `gtrk-talking-head` 快速成片开剪前先停一次:有没有文稿、B-roll 从哪来、有没有屏录或第二机位(多条毛片时再加一问是不是同一期),一张表问完才跑粗剪——粗剪是这条链第一个计费的命令。请求里已经说清的不再问;目录里没看到文稿或屏录只作提示,不再当成答案;检查点①也不再补问这几项(fix-talking-head-kickoff-gate)。
|
|
48
|
+
- 修:`gtrk oralcut` 两条不同目录下的同名毛片(如换卡后重复的 `C0001.MP4`)同一秒开剪时,后落的剪映草稿会整份覆盖先落的那份,且没有任何提示。现在开剪前就在剪映草稿根里占好草稿文件夹,撞名时后到的那份改叫 `…-2` 并提示,原草稿逐字节不动;同一目录下同名毛片同秒并行时,产物目录同样追加 `-2`。显式 `--out` 重跑同一目录时,产物目录照旧复用,剪映草稿另起 `-2`,不再覆盖可能已在剪映里改过的旧草稿。顺带修正草稿信息里的名称与位置:此前每份 oralcut 草稿都写成草稿根本身(名称为「JianyingPro Drafts」),现在是草稿自己的文件夹。`gtrk oralcut-result` 取回时落回原跑批占好的文件夹;`gtrk project export` 落草稿时也不再覆盖同名草稿(fix-oralcut-jianying-draft-collision)。
|
|
49
|
+
- 修:`gtrk long2short` 与 `gtrk tool video_translate_dub` 的剪映草稿名不带时间戳,不同目录下的同名毛片哪怕先后跑,后跑的也会把先跑的草稿整份覆盖(long2short 两次条数不同时,一组草稿里还会混着两条毛片的片段),且没有提示。现在提交前就定下草稿名:同一条毛片在同一产物目录重跑,照旧覆盖上一次的草稿;撞上别的毛片的草稿时改落 `…-2`(long2short 整组改名,如 `talk-long2short-2_clip0`)并提示,原草稿逐字节不动。升级前跑过的产物目录第一次重跑会多出一份 `-2`。`gtrk project export` 的剪映草稿信息里的名称与位置也改正为草稿自己的文件夹(此前写成草稿根本身,名称为「JianyingPro Drafts」)(fix-long2short-dub-export-draft-collision)。
|
|
50
|
+
- 修:`gtrk oralcut` 与 `gtrk long2short` 跑之前不打印价格——skill 一直写着「跑前 CLI 自动查实时价并打印」,实际这两条命令从来没接价格查询。现在抽音频之前查一次官网实时价格,往 stderr 打一行「计费提示」:单价,加上按原片时长算的本次预估积分(以服务端结算为准);`--json` 结果与 `result.json` 增加 `pricing`。查不到时打「实时价格暂不可用,以服务端结算为准」,照常往下跑。两条命令新增 `--dry-run`:只探测并报价,不抽取、不上传、不计费、不建任何目录,适合长片或开工问询时先报价。`gtrk-oralcut`、`gtrk-long2short`、`gtrk-talking-head`、`gtrk-live-slicing`、`gtrk-narration` 的计费说明同步改写,`gtrk-live-slicing` 里写死的单价已删(fix-oralcut-long2short-price-line)。
|
|
51
|
+
|
|
52
|
+
## 1.3.10(2026-10-26)
|
|
53
|
+
|
|
54
|
+
- **改**:`gtrk tool video_canvas_adapt` 的 `--clip-start` / `--clip-end` 改为**秒**(可带小数),原为帧序号。服务端同步改为按秒截取(此前文档站写秒、后端按帧号截,传 `5` 只截到 5 帧);区间为空或起点不小于视频时长时,服务端建单前即拒(错误码 6016,不扣费),CLI 对 `--clip-end` 不大于 `--clip-start` 也当场拦下。旧版 CLI 传的帧号会被当成秒(link-video-canvas-adapt-start-end-unit)。
|
|
55
|
+
- 修:`gtrk tool image_classic_template --template-mode image`(只要拼图、不画标题)不传 `--main-title` 也被当场拦下。现在与服务端同口径:`--main-title` 只在封面模式(缺省 / `full` / `text`)必填,`image` 时可省、payload 不带标题。标题含 emoji 等封面字体画不出的字符,服务端建单前即拒(错误码 6046,不扣费),CLI 原样转述(fix-cover-title-font-coverage)。
|
|
56
|
+
- 文档:README 补两种装法——通用 skills CLI(`npx skills add Gitruck/cli`)与 Claude Code 插件市场;`gtrk mg edit` 的计价说明同步为 6 积分/候选、前 200 个之后 8。
|
|
57
|
+
|
|
14
58
|
## 1.3.8(2026-10-18)
|
|
15
59
|
|
|
16
60
|
- 新增参考片精读:`gtrk media` 看片命令族(`probe` / `lines` / `frames` / `tile` / `tiles` / `boundaries` / `cut`,纯本地、不计费)。取帧网格下方标出源片秒、时码与正在念的字;`--around` 按台词定位;`boundaries` 给视觉变化候选(机械证据,不是镜头判定)。配套随包 skill `/gtrk-ref-reading`:按「改不改变讲者的位置、大小或可见区域」把参考片的每个视觉系统归到 MG 或合成风格;`/gtrk-style-maker` 的作品逆向可接视频参考。
|
package/README.en.md
CHANGED
|
@@ -84,6 +84,27 @@ Media processing requires FFmpeg. Check with `gtrk deps status`; when missing, e
|
|
|
84
84
|
|
|
85
85
|
</details>
|
|
86
86
|
|
|
87
|
+
<details>
|
|
88
|
+
<summary>Install from a Skills directory or a plugin marketplace (Claude Code / Codex)</summary>
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Generic skills CLI (skills.sh)
|
|
92
|
+
npx skills add Gitruck/cli
|
|
93
|
+
|
|
94
|
+
# Claude Code plugin marketplace
|
|
95
|
+
/plugin install gtrk --marketplace Gitruck/cli
|
|
96
|
+
|
|
97
|
+
# Codex plugin marketplace
|
|
98
|
+
codex plugin marketplace add Gitruck/cli
|
|
99
|
+
codex plugin add gtrk@gitruck
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Each of these installs the Skills only. You still need to install the gtrk CLI and set your API key:
|
|
103
|
+
- If you installed from a plugin marketplace, run `npx -y @gitruck/cli@latest install --no-skills`. The plugin already provides the Skills; without `--no-skills` you get a second copy.
|
|
104
|
+
- If you used the skills CLI, run `npx @gitruck/cli@latest install` as usual.
|
|
105
|
+
|
|
106
|
+
</details>
|
|
107
|
+
|
|
87
108
|
## See what it can make
|
|
88
109
|
|
|
89
110
|
These are real examples from the [product page](https://ai-mcn.tv/en/gtrk). Click a cover to watch the result, or compare the talking-head edit with its original footage.
|
|
@@ -195,6 +216,7 @@ gtrk ai-drama lay --project ./my-video --desk-project <project-id>
|
|
|
195
216
|
| Covers in multiple aspect ratios | [Cover workflow](https://hocassian.feishu.cn/wiki/AD5bwUAHris75vkWl4DcsvPJntb) |
|
|
196
217
|
| A spectrum video for a song | [Music visualizer Skill](skills/gtrk-music-visualizer/SKILL.md) |
|
|
197
218
|
| Break down a reference video's packaging and pacing | [Reference-reading Skill](skills/gtrk-ref-reading/SKILL.md) · `gtrk media` |
|
|
219
|
+
| Let your agent see the project as it is in the editor (selected segment, the frame at a given moment) | `gtrk client state / segment / frame` (live state when the desktop client has the project open, the project files otherwise) · [Command reference](docs/reference.en.md#gtrk-client-subcommand--read-the-project-as-it-is-in-the-editor) |
|
|
198
220
|
| A visual style for your show | [Style-maker Skill](skills/gtrk-style-maker/SKILL.md) |
|
|
199
221
|
| Third-party animation, typography or creative Skills | [Skill map](https://hocassian.feishu.cn/wiki/SxRtwJ0G7inTbQkwckFcZmClnrd) |
|
|
200
222
|
|
package/README.md
CHANGED
|
@@ -84,6 +84,27 @@ gtrk upgrade
|
|
|
84
84
|
|
|
85
85
|
</details>
|
|
86
86
|
|
|
87
|
+
<details>
|
|
88
|
+
<summary>从 Skills 目录或插件市场安装(Claude Code / Codex)</summary>
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# 通用 skills CLI(skills.sh)
|
|
92
|
+
npx skills add Gitruck/cli
|
|
93
|
+
|
|
94
|
+
# Claude Code 插件市场
|
|
95
|
+
/plugin install gtrk --marketplace Gitruck/cli
|
|
96
|
+
|
|
97
|
+
# Codex 插件市场
|
|
98
|
+
codex plugin marketplace add Gitruck/cli
|
|
99
|
+
codex plugin add gtrk@gitruck
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
以上几种方式都只装 Skills,gtrk CLI 和 API Key 还要另外安装和配置:
|
|
103
|
+
- 从插件市场装的,用 `npx -y @gitruck/cli@latest install --no-skills`。插件已经带了 Skill,不加 `--no-skills` 会再装一份。
|
|
104
|
+
- 用 skills CLI 装的,照常用 `npx @gitruck/cli@latest install`。
|
|
105
|
+
|
|
106
|
+
</details>
|
|
107
|
+
|
|
87
108
|
## 看看它能做什么
|
|
88
109
|
|
|
89
110
|
下面选用与[产品专页](https://ai-mcn.tv/gtrk)一致的真实案例。点击封面观看成片,口播示例也可打开原片对比。
|
|
@@ -195,6 +216,7 @@ gtrk ai-drama lay --project ./my-video --desk-project <project-id>
|
|
|
195
216
|
| 做一套多尺寸封面 | [封面工作流](https://hocassian.feishu.cn/wiki/AD5bwUAHris75vkWl4DcsvPJntb) |
|
|
196
217
|
| 把一首歌做成频谱视频 | [音乐可视化 Skill](skills/gtrk-music-visualizer/SKILL.md) |
|
|
197
218
|
| 拆解一条参考视频的包装与节奏 | [参考片精读 Skill](skills/gtrk-ref-reading/SKILL.md) · `gtrk media` |
|
|
219
|
+
| 让 Agent 看编辑器里此刻的工程(选中哪段、某一刻的画面) | `gtrk client state / segment / frame`(客户端开着读活状态,没开读文件)· [命令参考](docs/reference.md#gtrk-client-子命令--读编辑器里的工程) |
|
|
198
220
|
| 给自己的栏目建立视觉风格 | [风格体系 Skill](skills/gtrk-style-maker/SKILL.md) |
|
|
199
221
|
| 接入第三方动画、排版或创作 Skills | [Skill 地图](https://hocassian.feishu.cn/wiki/SxRtwJ0G7inTbQkwckFcZmClnrd) |
|
|
200
222
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
/* 合成颗粒工具箱 composite-kit@
|
|
1
|
+
/* 合成颗粒工具箱 composite-kit@2(html@1 引擎)——`gtrk composite build` 构建时内联进每颗颗粒,颗粒自包含、不外链。
|
|
2
2
|
* 随 @gitruck/cli 分发(assets/composite-kit/);改行为即升版本号(颗粒 <meta name="generator"> 与 CP.VERSION 记着它)。
|
|
3
3
|
*
|
|
4
4
|
* 场景脚本只写一件事:`CP.render = (t) => { ... }`(t = 局部秒)。其余由这里负责:
|
|
5
|
-
* - 宿主协议:hello → meta;init → 帧率 / 锚点 / 图层 /
|
|
5
|
+
* - 宿主协议:hello → meta;init → 帧率 / 锚点 / 图层 / 字幕,回 ready(features 声明 decor-follows-box);
|
|
6
|
+
* apply(frame, boxes?) → 画这一帧并回报槽位几何;lint → 排版自检;
|
|
6
7
|
* - 分层:舞台缺省属 back,`data-layer="front"` 的子树属 front(visibility 继承);
|
|
7
8
|
* - 槽位几何:`[data-slot]` 的包围盒 + data-z / data-fit / data-shape / data-radius / data-filter / data-crop(上右下左);
|
|
8
9
|
* - 装饰跟随:`data-for="<槽位>"` 的元素与槽位同框(data-pad 外扩),用于边框、阴影、角标;
|
|
10
|
+
* @2 起 apply 带用户的窗口覆盖 boxes(槽位 → { scale_pm, dx_px, dy_px })时,装饰定在覆盖后的窗口上
|
|
11
|
+
* (以槽位框中心缩放、中心位移;外扩不缩放),槽位自身与回报的几何不套覆盖(宿主自己套);boxes 只管这一次 apply;
|
|
12
|
+
* 场景自己摆的标签用 `CP.boxed(id, rect)` 取覆盖后的窗口(extend-composite-decor-follows-box);
|
|
9
13
|
* - 字幕:接管字幕后由颗粒自己排(`CP.caption`),文字来自 init.texts;
|
|
10
14
|
* - 逐句换画面与版式切换:`at` / `mix` / `seq` / `place`;
|
|
11
15
|
* - 排版自检 `lint`:下层画面的 front 描边压上层画面、front 线条穿过画面、画面越出舞台。
|
|
@@ -22,6 +26,8 @@
|
|
|
22
26
|
let ANCHORS = (META.resolved && META.resolved.anchors_f) || {};
|
|
23
27
|
let LAYER = "all";
|
|
24
28
|
let TEXTS = {};
|
|
29
|
+
/** 本次 apply 带来的窗口覆盖;每次 apply 重置,不留存到下一次(逐帧纯函数)。 */
|
|
30
|
+
let BOXES = {};
|
|
25
31
|
|
|
26
32
|
const clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
|
|
27
33
|
const lerp = (a, b, p) => a + (b - a) * p;
|
|
@@ -52,13 +58,25 @@
|
|
|
52
58
|
el.style.transform = dx || dy || s !== 1 ? "translate(" + dx + "px," + dy + "px) scale(" + s + ")" : "";
|
|
53
59
|
return el;
|
|
54
60
|
}
|
|
55
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* 槽位在本次 apply 的窗口覆盖下的框(与宿主套 box 同一公式:以框中心缩放 scale_pm / 1000、中心位移 dx_px / dy_px);
|
|
63
|
+
* 没有覆盖时原样返回。
|
|
64
|
+
*/
|
|
65
|
+
function boxed(id, r) {
|
|
66
|
+
const b = BOXES[id];
|
|
67
|
+
if (!b) return r;
|
|
68
|
+
const s = b.scale_pm / 1000, w = r[2] * s, h = r[3] * s;
|
|
69
|
+
const cx = r[0] + r[2] / 2 + b.dx_px, cy = r[1] + r[3] / 2 + b.dy_px;
|
|
70
|
+
return [cx - w / 2, cy - h / 2, w, h];
|
|
71
|
+
}
|
|
72
|
+
/** 槽位与跟随它的装饰一起定框;o 同时作用于两者。装饰按覆盖后的窗口外扩 data-pad(外扩不随缩放)。 */
|
|
56
73
|
function slot(id, x, y, w, h, o = 1) {
|
|
57
74
|
const el = document.querySelector('[data-slot="' + id + '"]');
|
|
58
75
|
box(el, x, y, w, h); el.style.opacity = String(clamp(o));
|
|
76
|
+
const [dx, dy, dw, dh] = boxed(id, [x, y, w, h]);
|
|
59
77
|
for (const d of document.querySelectorAll('[data-for="' + id + '"]')) {
|
|
60
78
|
const p = Number(d.dataset.pad || 0);
|
|
61
|
-
box(d,
|
|
79
|
+
box(d, dx - p, dy - p, dw + 2 * p, dh + 2 * p); d.style.opacity = String(clamp(o));
|
|
62
80
|
}
|
|
63
81
|
}
|
|
64
82
|
/** 槽位按矩形 [x, y, w, h] 定框(slot 的数组写法)。 */
|
|
@@ -215,12 +233,22 @@
|
|
|
215
233
|
return issues;
|
|
216
234
|
}
|
|
217
235
|
|
|
236
|
+
/** apply.boxes → 只留形状合法的项(宿主已换算成像素形整数;这里只防坏值,不再校验取值域)。 */
|
|
237
|
+
function readBoxes(raw) {
|
|
238
|
+
const out = {};
|
|
239
|
+
if (!raw || typeof raw !== "object") return out;
|
|
240
|
+
for (const [id, b] of Object.entries(raw)) {
|
|
241
|
+
if (b && [b.scale_pm, b.dx_px, b.dy_px].every(Number.isFinite) && b.scale_pm > 0) out[id] = { scale_pm: b.scale_pm, dx_px: b.dx_px, dy_px: b.dy_px };
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
|
|
218
246
|
function fitStage() { stage.style.transform = "scale(" + innerWidth / W + ")"; }
|
|
219
247
|
addEventListener("resize", fitStage); fitStage();
|
|
220
248
|
|
|
221
249
|
const CP = (window.CP = {
|
|
222
|
-
VERSION: "composite-kit@
|
|
223
|
-
META, W, H, $, A, has: (k) => k in ANCHORS, clamp, lerp, ease, prog, span, box, look, slot, at, mix, seq, place, typeOn, cueAt, caption,
|
|
250
|
+
VERSION: "composite-kit@2",
|
|
251
|
+
META, W, H, $, A, has: (k) => k in ANCHORS, clamp, lerp, ease, prog, span, box, look, slot, at, mix, seq, place, typeOn, cueAt, caption, boxed,
|
|
224
252
|
reveal, wipe, draw, cues: (slotId) => TEXTS[slotId] || [], fps: () => FPS,
|
|
225
253
|
render: () => {},
|
|
226
254
|
/** init 之后调用一次(字幕等输入已就位):按输入建一次性的 DOM。必须幂等。 */
|
|
@@ -235,8 +263,9 @@
|
|
|
235
263
|
if (m.type === "hello") reply({ type: "meta", meta: META });
|
|
236
264
|
else if (m.type === "init") {
|
|
237
265
|
FPS = m.fps || FPS; ANCHORS = m.anchors || ANCHORS; LAYER = m.layer || "all"; TEXTS = m.texts || {};
|
|
238
|
-
CP.setup(); applyLayer(); reply({ type: "ready", layer: LAYER });
|
|
266
|
+
CP.setup(); applyLayer(); reply({ type: "ready", layer: LAYER, features: ["decor-follows-box"] });
|
|
239
267
|
} else if (m.type === "apply") {
|
|
268
|
+
BOXES = readBoxes(m.boxes);
|
|
240
269
|
CP.render(m.frame / FPS);
|
|
241
270
|
reply({ type: "frame", seq: m.seq, frame: m.frame, slots: measure(), layer: LAYER });
|
|
242
271
|
} else if (m.type === "lint") {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<iframe id="front" class="layer" title="front"></iframe>
|
|
15
15
|
<script>
|
|
16
16
|
/* 合成颗粒出片台(composite-kit@1;`gtrk composite lint --stills` 与 `gtrk composite bake` 共用):与客户端预览同一套规则——
|
|
17
|
-
* 两层图形 iframe(back / front)夹一块槽位画布。颗粒走宿主协议(init / apply → frame
|
|
17
|
+
* 两层图形 iframe(back / front)夹一块槽位画布。颗粒走宿主协议(init / apply → frame);apply 带本颗的窗口覆盖 boxes。
|
|
18
18
|
*
|
|
19
19
|
* 槽位取帧(与客户端 `composite-slot-frames.ts` 的 `resolveSlotSource` 同口径):
|
|
20
20
|
* ref = 片段在时间线该时刻的画面(之前首帧、之后末帧),源时刻 = clip_st + (T − track_st) × speed;
|
|
@@ -178,6 +178,26 @@ function sourceFor(b, T, f) {
|
|
|
178
178
|
* box = 以槽位中心缩放 scale_pm/1000 倍、中心位移 dx_px / dy_px 舞台像素(旧写法 dx_pm / dy_pm 为舞台宽高的千分比),圆角同乘缩放;
|
|
179
179
|
* crop = 替换颗粒的 data-crop([上, 右, 下, 左] 比例)。
|
|
180
180
|
*/
|
|
181
|
+
/**
|
|
182
|
+
* 随 apply 发给颗粒的窗口覆盖(extend-composite-decor-follows-box):本颗绑定里带 box 的槽位 → 像素形整数
|
|
183
|
+
* (旧千分比形按舞台宽高换算、四舍五入;与客户端预览同一口径)。声明 decor-follows-box 的颗粒据此把 data-for 装饰
|
|
184
|
+
* 摆到覆盖后的窗口上;旧颗粒忽略它。绑定在烘焙前已过 `composite-profile` 校验,这里不再判取值域。
|
|
185
|
+
*/
|
|
186
|
+
function boxesOf(entry) {
|
|
187
|
+
const [w, h] = Array.isArray(entry.stage) ? entry.stage : [1920, 1080];
|
|
188
|
+
const out = {};
|
|
189
|
+
for (const [id, b] of Object.entries(entry.bindings || {})) {
|
|
190
|
+
const box = b && b.box;
|
|
191
|
+
if (!box) continue;
|
|
192
|
+
const px = "dx_px" in box;
|
|
193
|
+
out[id] = {
|
|
194
|
+
scale_pm: box.scale_pm,
|
|
195
|
+
dx_px: px ? box.dx_px : Math.round((box.dx_pm / 1000) * w),
|
|
196
|
+
dy_px: px ? box.dy_px : Math.round((box.dy_pm / 1000) * h),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
181
201
|
function applySlotOverrides(g, b) {
|
|
182
202
|
let out = g;
|
|
183
203
|
if (b.box) {
|
|
@@ -253,7 +273,8 @@ window.renderAt = async (T) => {
|
|
|
253
273
|
const f = Math.min(Math.max(F - entry.window_f[0], 0), entry.window_f[1] - entry.window_f[0] - 1);
|
|
254
274
|
const s = ++seq;
|
|
255
275
|
const pf = waitFor("front:frame:" + s), pb = waitFor("back:frame:" + s);
|
|
256
|
-
|
|
276
|
+
const boxes = boxesOf(entry);
|
|
277
|
+
for (const fr of [back, front]) fr.contentWindow.postMessage({ ch: "gtrk-composite", type: "apply", seq: s, frame: f, boxes }, "*");
|
|
257
278
|
const [geo] = await Promise.all([pf, pb]);
|
|
258
279
|
const Tf = (entry.window_f[0] + f) / FPS;
|
|
259
280
|
const used = [];
|