@gitruck/cli 1.3.10 → 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 +26 -0
- package/README.en.md +9 -2
- package/README.md +9 -2
- package/assets/composite-kit/kit.js +36 -7
- package/assets/composite-kit/stage.html +23 -2
- package/dist/index.js +333 -328
- package/docs/reference.en.md +43 -8
- package/docs/reference.md +44 -10
- package/package.json +2 -2
- package/skills/gtrk-composite/SKILL.md +11 -6
- package/skills/gtrk-matrix/SKILL.md +48 -5
- package/skills/gtrk-mg/SKILL.md +404 -406
- package/skills/gtrk-oralcut/SKILL.md +9 -8
- package/skills/gtrk-splitter/SKILL.md +313 -311
package/docs/reference.en.md
CHANGED
|
@@ -260,13 +260,13 @@ Look at any local video by timecode or by spoken line: frame grids labelled with
|
|
|
260
260
|
|
|
261
261
|
| Subcommand | What it does |
|
|
262
262
|
|---|---|
|
|
263
|
-
| `probe <video>` | Duration, display size (pixel aspect and rotation applied), frame rate and VFR, audio presence |
|
|
263
|
+
| `probe <video \| folder>` | Duration, display size (pixel aspect and rotation applied), frame rate and VFR, audio presence. Given a **folder** it looks at that level only (no recursion, hidden files skipped), picks the audio and video files (`mp4 mov mkv avi webm m4v mts` / `wav mp3 m4a flac aac ogg opus`), probes each and sorts by name: `{mode:"probe-dir", files:[{path, kind, duration, codec, width?, height?, fps?, hasAudio}], skipped:[{path, reason}], truncated?}`; a broken file goes to `skipped` without stopping the rest, and only the first 200 are probed |
|
|
264
264
|
| `lines <transcript>` | One line per utterance `u<id> start–end text`; `--find <phrase>` lists every occurrence with word-level times |
|
|
265
265
|
| `frames <video>` | Single frames by `--at` / `--every` / `--frames` / `--every-frame`; with `--transcript` or `--label` a label band is added below each frame |
|
|
266
266
|
| `tile <video>` | One labelled grid (≤60 cells) |
|
|
267
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
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`) |
|
|
269
|
+
| `cut <video>` | Saves an evidence clip (`.mp4/.mov/.mkv`, re-encoded). With `--copy` it **stream-copies** instead: no re-encode, seconds for a long raw recording (e.g. splitting raws over 2 hours); the start falls on the last keyframe before `--start`, the receipt's `seconds` is the actual length and its `note` says so; `-o` must keep the source's extension; audio-only sources work too |
|
|
270
270
|
|
|
271
271
|
```bash
|
|
272
272
|
gtrk media tiles "reference.mp4" --frames 48 --cols 6 --rows 4 --cell 320 --transcript "reading/transcript.json" -o "reading/evidence/overview"
|
|
@@ -277,7 +277,28 @@ gtrk media boundaries "reference.mp4" --rate 4 --threshold 0.12 --transcript "re
|
|
|
277
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
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
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.
|
|
280
|
+
- **Output**: `-o` is required (except `frames`, which defaults to a new folder under `$GTRK_FRAMES_DIR` when that is set) — 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
|
+
|
|
282
|
+
### `gtrk client <subcommand>` — read the project as it is in the editor
|
|
283
|
+
|
|
284
|
+
When the desktop client has this project open, reads the **live state** over the local bridge (which segment is selected, the playhead, unsaved edits, the picture the editor shows); otherwise reads the project files or renders a frame locally. Both paths return the same shape and `source` says which one answered. **The client is never required**: not installed, not running or showing another project, all three subcommands still exit successfully.
|
|
285
|
+
|
|
286
|
+
| Subcommand | What it does | `--json` output |
|
|
287
|
+
|---|---|---|
|
|
288
|
+
| `state` | Project summary: clips on every track with their timeline times, project duration; clips on the main track (the one carrying the voice) get a 1-based `no`. Never prints the whole `.gtrk` | `{source:"client"\|"file", project, duration, tracks:[{track, kind, index, main?, clips:[{no?, clip_id, track_st, track_ed, duration, volume?}]}], selection, playhead, viewport}`; the last three are `null` when read from files |
|
|
289
|
+
| `segment --no <N>` | Timeline times and spoken text of main-track segment N (utterances aligned to timeline times exactly as in the `gtrk split` projection view; cut utterances are left out). Out of range exits non-zero and says how many segments there are | `{source, no, clip_id, track_st, track_ed, text}` |
|
|
290
|
+
| `frame --at <sec>` | One composited frame at that timeline moment (`--width` default 768). Rendered by the client it matches the editor; rendered locally it is free and has no MG particles (`note` says so). Past the end it is pinned to the last frame, with a note | `{source:"client"\|"local-render", at, path, width, height, note?}` |
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
gtrk client state --project . --json
|
|
294
|
+
gtrk client segment --no 12 --json
|
|
295
|
+
gtrk client frame --at 31.5 --json # 31.5 s on the timeline, not 31.5 s into the raw footage
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
- `--project` defaults to the current directory (`gtrk/project.gtrk` or `project.gtrk`).
|
|
299
|
+
- `frame` writes to `$GTRK_FRAMES_DIR` by default, or `gtrk-frames/<project-path-hash>/frame-<sec>.jpg` under the system temp folder — **never into the project folder** (projects get packed up whole). `-o <file.jpg>` picks the path; an existing file needs `--force`.
|
|
300
|
+
- When the bridge was not used, `--json` carries `bridge:{tried, reason}` (`no_file` / `not_running` / `not_open` / `protocol_too_new` / `protocol_too_old` / `timeout` / …) for troubleshooting; human output says on its first line whether it read files or rendered locally.
|
|
301
|
+
- The bridge: on start the client writes `~/.gitruck/client-bridge.json` (port, token, process id, protocol version) and listens on `127.0.0.1` only; the CLI sends the token and gives each request 10 seconds.
|
|
281
302
|
|
|
282
303
|
### `gtrk oralcut <raw>`
|
|
283
304
|
|
|
@@ -352,7 +373,9 @@ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
|
|
|
352
373
|
| `--to <sec\|Nf>` | Target position for `move` | — |
|
|
353
374
|
| `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | The five `trim` semantics (first two relative, next two absolute, `--slip` shifts only the source window) | — |
|
|
354
375
|
| `--cut <sec\|Nf>` | Cut point for `split`. ⚠️ Distinct from the addressing flag `--at` | — |
|
|
355
|
-
| `--muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB) | — |
|
|
376
|
+
| `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | Element-level parameters for `set` (`--volume` is linear gain, not dB, and must be > 0; `--volume 0` fails with `volume_zero_use_muted` — use `--muted` to silence). Track mute is a master switch: if the clip's track is muted, `--no-muted` fails with `track_muted_master` — unmute the track's speaker in the client | — |
|
|
377
|
+
| `--audio-fade-in <sec\|Nf>` / `--audio-fade-out <sec\|Nf>` | `set`: audio fade-in / fade-out length (a video clip's own sound or an audio-track clip; particles and gaps are rejected); seconds or frames, whole milliseconds; 0 deletes the key; rejected outright if the two sides together exceed the clip duration (never scaled for you); `trim` / `split` maintain fades automatically | — |
|
|
378
|
+
| `--audio-track <index>` | `set`: move an audio clip onto an existing audio track; timing, material and effective volume / mute are kept, overlaps and track settings that cannot be preserved are rejected, an emptied source track is removed; moving a clip that is audible onto a muted track fails with `audio_track_target_muted` | — |
|
|
356
379
|
| `--total <sec\|Nf\|max>` | Top-level duration for `set` (project-scoped op, mutually exclusive with element addressing) | — |
|
|
357
380
|
| `--ops <file\|->` | Batch transaction: read once, compute all, validate all, write once; any failure writes **nothing** | off |
|
|
358
381
|
| `--dry-run` | Compute and validate only, do not write | off |
|
|
@@ -368,6 +391,14 @@ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
|
|
|
368
391
|
> ⚠️ A gap cannot be addressed with `--clip ""`: the contract lets multiple gaps share that value, so it is
|
|
369
392
|
> not an address. Use `--track/--at` instead.
|
|
370
393
|
|
|
394
|
+
**Preserving and maintaining transitions** (`transition_in` / `transition_out` / `transition_next`; created in the client — the CLI does not produce transitions in this release and adds no flags):
|
|
395
|
+
|
|
396
|
+
- `split`: the entrance transition stays on the front part; the exit transition and the transition into the next clip go to the back part (`to_clip_id` unchanged); the new cut carries no transition.
|
|
397
|
+
- Every run (a single action or a whole `--ops` batch) maintains the changed tracks once before writing: a dangling `transition_next` is deleted (never re-pointed at the new neighbour), a transition that no longer fits is shortened frame by frame (head first, then tail), and one left under 1 frame is deleted; the receipt's `warnings[]` lists each `transition_dropped` / `transition_shortened`.
|
|
398
|
+
- The granule catalog is fetched at run time from `https://api.ai-mcn.tv:9000/cloud/static/assets/transitions/catalog.json` and cached at `~/.gitruck/cache/transitions/catalog.json` (the shared static-resource cache, also used by the client, refreshed after 24 hours; `composite lay` reads only the cache and never goes online); it is not shipped in the npm package. Offline, with the catalog unavailable, or for a granule missing from it, the transition is kept as is.
|
|
399
|
+
- Pre-existing transition violations unrelated to this edit only go to `preexisting` (`transition_invalid`) and do not block.
|
|
400
|
+
- When a lay command re-lays its own tracks, the number of replaced clips that carried transitions is reported in the log and the `--json` receipt as `replacedTransitionClips`, and each maintenance deletion or shortening is listed in `transitions[]`; `gtrk project export` normalizes the upload body before submitting (the file on disk is untouched; deletions and shortenings go to `result.json` under `transitions`) and prints each cloud `transition_not_carried` warning; `gtrk render` renders hard cuts in this release and counts `transition_not_carried` (`format: "cli_render"`).
|
|
401
|
+
|
|
371
402
|
### `gtrk matrix source-import` — Put selected video URLs into a B-roll beat
|
|
372
403
|
|
|
373
404
|
When the source videos are already known, send them directly to one beat instead of running keyword search:
|
|
@@ -393,6 +424,7 @@ Each source becomes one low-resolution full-window preview candidate. `source-im
|
|
|
393
424
|
| `--lay <n>` | How many candidate tracks to lay (`0` = produce the plan only, lay nothing) | `1` |
|
|
394
425
|
| `--top-k <n>` | Candidate cap per query (overrides the dispatch's shots; server cap is 50) | dispatch value |
|
|
395
426
|
| `--material-class <c>` | Material type `real_shot` \| `concept` (matrix-member endpoint only; overrides the show policy) | show policy |
|
|
427
|
+
| `--neighbors <n>` | Bring back up to n neighboring shots on each side of a matched concept clip, taken from its source film (0–5, matrix-member endpoint only). Results gain `source_ref` (source title, sequence number, start/end in the source; called `source` in the server docs) and `neighbors[]` (with `offset` / `contiguous` / `hit`). `matrix search` prints the run in source order plus a ready-to-run `gtrk matrix fetch` line; dispatch searches write neighbors into the plan and the project, folded in the client panel, and **never auto-laid**. Ignored with a notice on the public endpoint, `--local` and `--online`; invalid values fail before any request | `0` for `matrix search`; `2` for dispatch searches |
|
|
396
428
|
| `--score-floor <f>` | Fill-confidence floor: segments scoring below this are not used and the slot stays empty — in talking-head projects the candidate track **patches empty spots with solid black**. Raising it shrinks the candidate pool, and a span that cannot be filled at all becomes pure black over the talking-head, so check the hole warnings after adjusting | `0.2` |
|
|
397
429
|
| `--black-bed` | Legacy layout: lay one solid black bed track and leave candidate clips without a background fill (for older clients that do not read clip fills); `--no-black-bed` is now the default (no-op) | off |
|
|
398
430
|
| `--force-relay` | Strip and re-lay even when you have already edited a candidate track in the client (by default it refuses and keeps that track) — **this deletes the `broll-raw-*` material registrations of confirmed source clips, orphaning those files on disk** | off |
|
|
@@ -493,7 +525,7 @@ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle
|
|
|
493
525
|
- **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.
|
|
494
526
|
- **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).
|
|
495
527
|
- **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.
|
|
496
|
-
- **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
|
|
528
|
+
- **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** (no network: it reads the locally cached catalog `~/.gitruck/cache/mg-registry/catalog.json`, or the snapshot that ships with the package; pinned to a source commit) and lists 2–3 blocks per query with compat flags and poster links; pick mode first checks the arguments and the landing spot locally, then refreshes the catalog once (unified static-resource delivery: refreshed every 24 hours, falling back to the cache and then the bundled snapshot), then fetches the block through the mirrors the catalog lists (Gitruck Cloud first, reachable from mainland China, then GitHub raw → jsDelivr fastly → jsDelivr gcore → gh-proxy; 8 s per mirror, **every copy is checked against its sha256 and byte count**, nothing is written if all of them fail; fetched blocks are cached under `~/.gitruck/cache/mg-registry/files/`) → 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. Setting `GITRUCK_MG_REGISTRY_BASE` makes it the only mirror root for both the catalog and the blocks (`<root>/catalog.json`, `<root>/files/…`, i.e. the layout of a publish staging folder or the static disk); nothing is written to the local cache.
|
|
497
529
|
|
|
498
530
|
`--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).
|
|
499
531
|
|
|
@@ -502,13 +534,14 @@ Consumes the `dispatch.mg` dispatch landed by `gtrk split`, laying html-particle
|
|
|
502
534
|
> **Aux overlay particles**: if `gtrk split` dispatched an `overlay` particle in some beat's `aux_layers`, it derives a `<beat>-aux<n>` composition entry into `dispatch.mg` — `gtrk mg` lays it too, giving you "a main visual on the base track plus a transparent conceptual diagram stacked on the same span".
|
|
503
535
|
> **Dual-read compatibility**: `dispatch.mg` (also reads the old `rrv_mg`), the source directory `mg/` (also reads the old `rrv/`), the material prefix `mg-` (also reads the old `rrv-`) — projects created before the de-branding need zero migration.
|
|
504
536
|
|
|
505
|
-
### `gtrk composite` — composite layer (plan / review / scaffold / build / lint / lay / shots / bake)
|
|
537
|
+
### `gtrk composite` — composite layer (plan / review / status / scaffold / build / lint / lay / shots / bake)
|
|
506
538
|
|
|
507
539
|
Once the rough cut, B-roll and subtitles are settled, turn chosen time windows into **composite particles**: one code particle takes over the whole frame for that span, and the client draws the talking head and B-roll into its slots. Driven by `/gtrk-composite` (which carries the layout rules and two checkpoints); purely local, zero billing.
|
|
508
540
|
|
|
509
541
|
```bash
|
|
510
542
|
gtrk composite plan --project <dir> [--mode full|auto|ranges] [--range 11,32 | --range u0004-u0009]... [--density 0.25]
|
|
511
543
|
gtrk composite review --project <dir> [--approve W01,W03] [--reject W02] [--adjust W04=80,90.9] [--add 140,150] [--approve-all]
|
|
544
|
+
gtrk composite status --project <dir> [--json]
|
|
512
545
|
gtrk composite scaffold --project <dir> [--only W03] [--force]
|
|
513
546
|
gtrk composite shots --project <dir> --material <material id or file> [--around <sec> --span <sec> | --from <sec> --to <sec>] [--every <sec>]
|
|
514
547
|
gtrk composite build --project <dir> [--only cp-w03] [--theme <css>] [--materials <json>]
|
|
@@ -521,6 +554,7 @@ gtrk composite bake --abi
|
|
|
521
554
|
|
|
522
555
|
- `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.
|
|
523
556
|
- `review`: approve / reject / adjust / add windows, written back to the same key; later steps only act on approved windows.
|
|
557
|
+
- `status`: read-only progress summary — window counts per state, `pending` (approved but not yet laid), laid count, one row per window with its span re-projected onto the current timeline via `source_ranges` (empty with a note when the speech was cut). All zeros when there is no composite key.
|
|
524
558
|
- `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.
|
|
525
559
|
- `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.
|
|
526
560
|
- `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`).
|
|
@@ -543,7 +577,7 @@ Project entry points that start from **a voice-over** instead of a talking-head
|
|
|
543
577
|
|---|---|
|
|
544
578
|
| `gtrk project init --tts-task <task_id>` | **Main path**: references a completed `audio_tts_clone` task — the server hands over the audio and sentence timecodes directly (zero ASR, zero extra billing); the audio download lands in the project's `audio/` |
|
|
545
579
|
| `gtrk project init --audio <voice-over> --transcript <transcript.json>` | **Fallback path**: your own voice-over audio plus its sentence-timecoded transcript as a pair (produced by `gtrk transcript <voice-over> --json`; for TTS-synthesized voice-overs take the main path instead of re-running ASR) |
|
|
546
|
-
| `gtrk audio lay --project <dir> --file <bgm.mp3>` | Appends an audio track to the project; **idempotent same-source replacement** (re-running with the same source replaces instead of piling up tracks; zero-reference protection when stripping the old one); `--volume <0..1>` (default 0.1, bed volume — the contract carries linear gain only, never dB; the client's volume panel shows -20.0, the same scale on both sides), `--offset <ms>` sets the in-point |
|
|
580
|
+
| `gtrk audio lay --project <dir> --file <bgm.mp3>` | Appends an audio track to the project; **idempotent same-source replacement** (re-running with the same source replaces instead of piling up tracks; zero-reference protection when stripping the old one); `--volume <0..1>` (default 0.1, bed volume — the contract carries linear gain only, never dB; the client's volume panel shows -20.0, the same scale on both sides; must be > 0 — `0` does not mute and is rejected, use `gtrk patch set --muted` to silence), `--offset <ms>` sets the in-point |
|
|
547
581
|
| `gtrk audio lay … --beat-align` | **Climax anchoring** (`audio_music_analyze`, billed once): pins the BGM’s emotional peak `H` (the server’s `highlight.time`) onto the cut’s climax `A`; the mapping is always `track_sec = A + (bgm_sec − H)`. **Both sides long enough ⇒ zero tiling** (exactly one clip); only a short side is tiled outward, with seams snapped to downbeats (the two hard track boundaries are cut without snapping). `A` comes from the criterion chain over `struct_meta.split.beats`: elevation → container flip → callback closure → `0.75×total` fallback, and **the CLI reports which rung was used — the fallback is explicitly flagged as a guess**. Without a key / on analysis failure / when the track has no highlight it degrades to no anchoring and the command never fails over it |
|
|
548
582
|
| `gtrk audio lay … --beat-align --climax <track-sec>` | Climax **escape hatch**: always overrides the chain above. Out of range (≤ `--offset` or ≥ the project end) or non-numeric **errors out immediately** rather than falling back silently — an explicitly wrong value should be visible at once. Must be used together with `--beat-align` |
|
|
549
583
|
| `gtrk audio lay … --no-loop` | No tiling: with `--beat-align` it lays only the anchored span and leaves head/tail silence (**the silent seconds are reported**); without `--beat-align` it keeps a single pass instead of looping to fill the project |
|
|
@@ -753,7 +787,8 @@ A QC pass runs automatically afterwards and writes `.qc.json` (`--no-qc` skips i
|
|
|
753
787
|
- **It never downloads silently**: any missing-dependency path only errors out and points at this command (the packages are 30–90 MB and the distributed artifacts carry licence obligations, so a user or agent must trigger it explicitly).
|
|
754
788
|
- Downloads are always https with **strict sha256 verification**; anything that fails verification is discarded and never lands. Extraction uses the **system tar** (bundled with Windows 10+/macOS/Linux), pulling in no third-party decompression dependency.
|
|
755
789
|
- The resolution order is unchanged: `--ffmpeg-path` → `~/.gitruck/ffmpeg` → system `PATH`. The mirror only fills the middle slot and **never overrides an ffmpeg you installed yourself**.
|
|
756
|
-
- Fonts
|
|
790
|
+
- Fonts come from the font catalog of the unified static-resource delivery (`https://api.ai-mcn.tv:9000/cloud/static/assets/fonts/catalog.json`, the same one the desktop client reads): `--font` installs the subtitle font the catalog names (Source Han Sans CN Bold, `sourcehansanscn-bold.otf`), `--font-family <family…>` installs whole families by `font_id` or Chinese / English family name; every file is checked against its sha256 and byte count, and a failed download errors out without leaving a partial file. An installed font is recognised by its normalised file name (the older `SourceHanSansCN-Bold.otf` counts too); `--force` re-downloads it under the catalog's name.
|
|
791
|
+
- Fonts land in `~/.gitruck/fonts` (that folder is the cache; no second copy goes to `~/.gitruck/cache/`) and are supplied to burn-in through the ffmpeg `ass` filter's `fontsdir` — **never installed into the system font table, never written to the registry, never requiring administrator rights**.
|
|
757
792
|
- 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**.
|
|
758
793
|
- `gtrk upgrade [--check]` — upgrade the CLI to the latest version + refresh skills (config preserved); `--check` only reports.
|
|
759
794
|
- `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.
|
package/docs/reference.md
CHANGED
|
@@ -263,13 +263,13 @@ gtrk transcript "D:/素材/采访视频.mp4" --lang zh-CN --out "D:/文字稿/
|
|
|
263
263
|
|
|
264
264
|
| 子命令 | 做什么 |
|
|
265
265
|
|---|---|
|
|
266
|
-
| `probe
|
|
266
|
+
| `probe <视频 \| 目录>` | 时长、显示尺寸(计入像素宽高比与旋转)、帧率与 VFR、有无音轨。传**目录**时只看这一层(不递归、跳过隐藏文件),挑出音视频(`mp4 mov mkv avi webm m4v mts` / `wav mp3 m4a flac aac ogg opus`)逐个探测、按文件名排序:`{mode:"probe-dir", files:[{path, kind, duration, codec, width?, height?, fps?, hasAudio}], skipped:[{path, reason}], truncated?}`;坏文件进 `skipped` 不中断,超过 200 个只探前 200 个 |
|
|
267
267
|
| `lines <转写稿>` | 逐句 `u<id> 起–止 文本`;`--find <台词>` 列出每处出现与字级起止 |
|
|
268
268
|
| `frames <视频>` | 按 `--at` / `--every` / `--frames` / `--every-frame` 取单帧;带 `--transcript` 或 `--label` 时帧下方加标签 |
|
|
269
269
|
| `tile <视频>` | 一张带标签的网格(≤60 格) |
|
|
270
270
|
| `tiles <视频>` | 分页网格(`--cols × --rows`,缺省 3×3);`--ranges <json>` 一次看多段;`--every-frame` 每段连续解码、保留每一原始帧 |
|
|
271
271
|
| `boundaries <视频>` | 视觉变化候选(`--rate` 缺省 12、`--threshold` 缺省 0.1、`--min-gap` 合并近邻);带 `--transcript` 时标注对着哪句话。**是机械证据,不是镜头判定** |
|
|
272
|
-
| `cut <视频>` | 截一段证据片(`.mp4/.mov/.mkv
|
|
272
|
+
| `cut <视频>` | 截一段证据片(`.mp4/.mov/.mkv`,重编码)。带 `--copy` 改为**流拷贝**:不重编码、秒级截长毛片(如超 2 小时的毛片分段),起点落在 `--start` 之前最近的关键帧,回执 `seconds` 是实际时长、`note` 注明关键帧对齐;`-o` 须与源片同扩展名,纯音频也收 |
|
|
273
273
|
|
|
274
274
|
```bash
|
|
275
275
|
gtrk media tiles "参考片.mp4" --frames 48 --cols 6 --rows 4 --cell 320 --transcript "精读/transcript.json" -o "精读/evidence/overview"
|
|
@@ -280,7 +280,28 @@ gtrk media boundaries "参考片.mp4" --rate 4 --threshold 0.12 --transcript "
|
|
|
280
280
|
- **区间**:`--start/--end`(秒或 `[hh:]mm:ss.mmm`),或 `--around <台词> [--occurrence n] [--padding s]` 按台词定位(须配 `--transcript`;台词多处出现时必须指定第几处,`lines --find` 可先列出)。
|
|
281
281
|
- **转写稿**:`gtrk transcript --json` 的产物(v1,含字级时码)原生可用,也认 `hypit.transcript@1`。转写稿须是这条视频的——时长 / 文件名对不上会在 stderr 告警。
|
|
282
282
|
- **标签**(画面下方,不遮原片字幕与图形):源片秒 · 时码(逐帧加帧号)· 句号 / 正在读的字与字级起止 / 所在整句(当前字高亮)。无字时写「此刻无字在读」「句间空隙」,不推断静音。标签用 libass 画,ffmpeg 缺 `ass` 滤镜时报错并指向 `gtrk deps install --ffmpeg`。
|
|
283
|
-
- **落点**:`-o`
|
|
283
|
+
- **落点**:`-o` 必填(`frames` 例外:设了 `$GTRK_FRAMES_DIR` 时缺省落其下的新目录),不落当前目录或源片旁;已存在不覆盖,`--force` 只覆盖本命令族的旧产物。`frames` / `tiles` 的产物目录含 `index.json`,逐格记录文件、时间、字与句号。逐帧单次上限 1800 帧。
|
|
284
|
+
|
|
285
|
+
### `gtrk client <子命令>` — 读编辑器里的工程
|
|
286
|
+
|
|
287
|
+
即剪客户端开着这个工程时,经本机通道读**活状态**(选中哪段、播放头、未存盘的改动、编辑器所见的画面);没开时读工程文件 / 本地渲染出帧。两条路输出同形,`source` 标明走的是哪条。**不依赖客户端**:没装、没开、开的是别的工程,三个子命令照样成功退出。
|
|
288
|
+
|
|
289
|
+
| 子命令 | 做什么 | `--json` 输出 |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| `state` | 工程摘要:各轨片段与轨上时码、工程时长;主轨(口播所在那条)片段带从 1 开始的 `no`。不输出整份 `.gtrk` | `{source:"client"\|"file", project, duration, tracks:[{track, kind, index, main?, clips:[{no?, clip_id, track_st, track_ed, duration, volume?}]}], selection, playhead, viewport}`;读文件时后三项为 `null` |
|
|
292
|
+
| `segment --no <N>` | 主轨第 N 段的轨上时码与口播文字(按转写句与轨上时码对位,同 `gtrk split` 投影视图口径;被剪掉的句不计入)。越界非 0 退出并说明共几段 | `{source, no, clip_id, track_st, track_ed, text}` |
|
|
293
|
+
| `frame --at <秒>` | 时间线这一刻合成后的一帧(`--width` 缺省 768)。客户端渲染时与编辑器所见一致;本地渲染零计费、不含 MG 颗粒(`note` 注明)。超出工程时长钉到末帧并说明 | `{source:"client"\|"local-render", at, path, width, height, note?}` |
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
gtrk client state --project . --json
|
|
297
|
+
gtrk client segment --no 12 --json
|
|
298
|
+
gtrk client frame --at 31.5 --json # 时间线上的 31.5 秒,不是毛片的 31.5 秒
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
- `--project` 缺省当前目录(`gtrk/project.gtrk` 或 `project.gtrk`)。
|
|
302
|
+
- `frame` 的图缺省写到 `$GTRK_FRAMES_DIR`,未设时为系统临时目录下 `gtrk-frames/<工程路径哈希>/frame-<秒>.jpg`,**不写进工程目录**(工程会被整体打包带走);`-o <file.jpg>` 指定落点,已存在须 `--force`。
|
|
303
|
+
- 没走成本机通道时 `--json` 带 `bridge:{tried, reason}`(`no_file` / `not_running` / `not_open` / `protocol_too_new` / `protocol_too_old` / `timeout` / …)便于排障;人读输出首行注明读的是文件还是本地渲染。
|
|
304
|
+
- 本机通道:客户端启动时写 `~/.gitruck/client-bridge.json`(端口、口令、进程号、协议版本),只监听 `127.0.0.1`;CLI 带口令请求、单次 10 秒超时。
|
|
284
305
|
|
|
285
306
|
### `gtrk oralcut <毛片>`
|
|
286
307
|
|
|
@@ -353,8 +374,9 @@ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
|
|
|
353
374
|
| `--to <sec\|Nf>` | `move` 的落点 | — |
|
|
354
375
|
| `--in` / `--out` / `--set-in` / `--set-out` / `--slip` | `trim` 的五种语义(前两个相对、中两个绝对、`--slip` 只换源窗) | — |
|
|
355
376
|
| `--cut <sec\|Nf>` | `split` 的切点。⚠️ 与寻址用的 `--at` 是两个参数 | — |
|
|
356
|
-
| `--muted` / `--volume <gain>` / `--opaque` | `set` 的元素级参数(`--volume` 是线性增益不是 dB
|
|
357
|
-
| `--audio-
|
|
377
|
+
| `--muted` / `--no-muted` / `--volume <gain>` / `--opaque` | `set` 的元素级参数(`--volume` 是线性增益不是 dB,须 > 0;`--volume 0` 报 `volume_zero_use_muted`,静音用 `--muted`)。轨静音是总开关:片段所在轨已静音时 `--no-muted` 报 `track_muted_master`,请在客户端点开轨喇叭 | — |
|
|
378
|
+
| `--audio-fade-in <sec\|Nf>` / `--audio-fade-out <sec\|Nf>` | `set`:音频淡入 / 淡出时长(视频轨原声或音频轨片段,颗粒与空档拒收);秒或帧、整毫秒;设 0 即删键;与另一侧之和超过片段时长即硬拒(不按比例缩);`trim` / `split` 自动维护淡变 | — |
|
|
379
|
+
| `--audio-track <index>` | `set`:将音频片段转入已有音轨;时码、素材和有效音量/静音不变,拒绝重叠或无法保真的轨级设置,移除变空的原轨;原本出声的片段移进静音轨报 `audio_track_target_muted` | — |
|
|
358
380
|
| `--total <sec\|Nf\|max>` | `set` 的顶层总长(工程级 op,与元素寻址互斥) | — |
|
|
359
381
|
| `--ops <file\|->` | 批量事务:一次读、全算、全校验、一次写;任一条失败**零写** | 关 |
|
|
360
382
|
| `--dry-run` | 只算与校验、不写文件 | 关 |
|
|
@@ -367,6 +389,14 @@ gtrk patch set --project <dir> --track audio:1 --at 3.0 --volume 0.5
|
|
|
367
389
|
>
|
|
368
390
|
> ⚠️ 空档(gap)不能用 `--clip ""` 寻址:契约允许多个 gap 共享该取值,它不构成地址;用 `--track/--at`。
|
|
369
391
|
|
|
392
|
+
**转场字段的保真与维护**(`transition_in` / `transition_out` / `transition_next`;由客户端产生,CLI 本期不产出、无新参数):
|
|
393
|
+
|
|
394
|
+
- `split`:入场转场留前段,出场转场与接下一段的转场归后段(`to_clip_id` 不变),新切口不带转场。
|
|
395
|
+
- 每次运行(单发或整个 `--ops` 批)写回前对有变化的轨统一维护:悬空的 `transition_next` 删除(不改挂新邻居),放不下的按帧缩短(先头后尾),不足 1 帧删除;回执 `warnings[]` 逐条给 `transition_dropped` / `transition_shortened`。
|
|
396
|
+
- 颗粒目录运行时从 `https://api.ai-mcn.tv:9000/cloud/static/assets/transitions/catalog.json` 拉取,缓存 `~/.gitruck/cache/transitions/catalog.json`(统一静态资源缓存,与客户端共用,24 小时重拉;`composite lay` 只读缓存不联网),不随 npm 包分发;离线、目录不可用或颗粒不在目录里时转场原样保留。
|
|
397
|
+
- 与本次编辑无关的存量转场违例只进 `preexisting`(`transition_invalid`),不阻断。
|
|
398
|
+
- 铺轨命令重铺自产轨时,被替换片段带转场的条数在日志与 `--json` 回执里出 `replacedTransitionClips`,维护的删缩逐条列在 `transitions[]`;`gtrk project export` 上行前对上行体规整(盘上不动,删缩写进 `result.json` 的 `transitions`),云端 `transition_not_carried` 告警逐条打出;`gtrk render` 本期按硬切出片并计 `transition_not_carried`(`format: "cli_render"`)。
|
|
399
|
+
|
|
370
400
|
### `gtrk matrix source-import` — 指定视频链接进入某个 B-roll beat
|
|
371
401
|
|
|
372
402
|
当你已经选定视频链接,不需要关键词检索时,可以把它们直接送进指定 beat:
|
|
@@ -392,6 +422,7 @@ gtrk matrix source-import --project <工程目录> --beat B07 --urls links.txt -
|
|
|
392
422
|
| `--lay <n>` | 候选铺轨数:平铺 N 条 B-roll 候选轨(`0` = 只出 plan 不铺轨) | `1` |
|
|
393
423
|
| `--top-k <n>` | 每 query 候选数上限(覆盖派单 shots;服务端上限 50) | 派单值 |
|
|
394
424
|
| `--material-class <c>` | 素材类型 `real_shot` \| `concept`(仅矩阵成员口;覆盖栏目策略) | 栏目策略 |
|
|
425
|
+
| `--neighbors <n>` | 命中的概念素材带回原片前后各 n 条相邻片段(0–5,仅矩阵成员口)。结果多出 `source_ref`(出处名、序号、原片起止;服务端文档里叫 `source`)与 `neighbors[]`(`offset` / `contiguous` / `hit` 等)。`matrix search` 人读输出按原片顺序列出整段,并给出现成的 `gtrk matrix fetch` 命令;派单检索把邻居写进 plan 与工程,客户端面板里折叠,**不参与自动铺轨**。公开口、`--local`、`--online` 带了会提示已忽略;非法值发请求前报错 | `matrix search` 为 `0`;派单检索为 `2` |
|
|
395
426
|
| `--score-floor <f>` | 填充置信度地板:segment score 低于此值不采纳、槽位留空——口播工程里留空处由候选轨**补纯黑片**。调高会收缩取材池,整段铺不满即纯黑压口播,调完先看空洞告警 | `0.2` |
|
|
396
427
|
| `--black-bed` | 旧形态:铺一条纯黑底垫轨、候选片段不带底板(给不认片段底板的老版客户端过渡用);`--no-black-bed` 已是缺省(无操作) | 关 |
|
|
397
428
|
| `--force-relay` | 候选轨已被你在客户端编辑过时仍强剥重铺(缺省会拒铺并保留那条轨)——**会删掉已确认原片的 `broll-raw-*` 素材登记、盘上原片成孤儿** | 关 |
|
|
@@ -521,8 +552,8 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
|
|
|
521
552
|
- **回调与 seek 语义**(`x-callback-driven` / `x-engine-api-override` / `x-raf-interval`,**恒非致命、不拦铺轨**):对齐契约同名一节。引擎定帧 MUST 使用 `seek(t,false)` / `time(t)` / `progress(p)`;颗粒可用时间线回调驱动画面,但不得覆写 `tl.seek` 或替换 `window.__timelines[…]`。三项 lint 只作提醒,不要求作者添加垫片。
|
|
522
553
|
- **status**(`gtrk mg status --project <dir>`):汇总 MG 流水线——`dispatch.mg` beat 总数 / 已产源 HTML 数 / 已铺进 `.gtrk` 数,并逐 beat 标注(缺 HTML / 已产未铺 / 已铺)。
|
|
523
554
|
- **render**(`gtrk mg render <颗粒.html> --duration <sec> [--out <dir>] [--yes]`):**脱离工程**把单颗颗粒云渲成剪映可读的 qtrle 透明 alpha MOV(精剪补给口——粗剪导剪映后缺一颗动态图,不回客户端就能补)。链路 = lint 前置(包络 = `--duration`,任一致命项本地拦截、零提交零计费)→ **计费预估确认**(实时查价;CLI 无本地 HTML 渲染引擎,独立颗粒唯一路 = 云渲计费任务,`--yes` 跳过确认)→ 内联提交云端 → `<composition_id>.mov` 落盘 + `task.json`/`result.json` 面包屑(崩溃可凭 task_id 恢复)。**射程**:首发只出 qtrle(`--format webm` 明确拒绝,剪映不吃 VP8-alpha)、颗粒几何须为正整数、`--duration` 必填;MOV 按颗粒声明的 `data-width` / `data-height` 原尺寸出(竖屏 1080×1920 颗粒出 1080×1920 MOV)。产物不进 `.gtrk`、不写剪映草稿目录;qtrle 无损体积偏大,适合秒级颗粒。注意与 `gtrk render`(整片成片渲染)同词不同物。
|
|
524
|
-
- **fetch**(`gtrk mg fetch <检索词|块名> [--top 3] [--all]` / `gtrk mg fetch --pick <块名> --slot <beat> --project <dir>` / `--pick <块名> --as <composition_id> --duration <sec> [--out <dir>]`):**registry 中性颗粒源**——没建栏目也能出 MG
|
|
525
|
-
- **fetch --source text**(`gtrk mg fetch --source text <检索词> [--top 3] [--offline]` / `--pick <模板 id> --slot <beat> --project <dir>` / `--pick <模板 id> --as <composition_id> [--out <dir>]`):**同合云自家的文字特效模板库**——与中性块是两条路。模板是我方 clean-room 重写的**成品**(配色与排版已做过),**不做机械改写、MUST NOT 直接改 HTML**。每颗内嵌产生它的 IR 与双哈希,颗粒因此自带出身证明(三态 `ir` / `detached` / `html`);手改一个字节就掉成 `detached`,云端改写会拒绝它(`gtrk mg lint` 报非致命的 `x-ir-detached
|
|
555
|
+
- **fetch**(`gtrk mg fetch <检索词|块名> [--top 3] [--all]` / `gtrk mg fetch --pick <块名> --slot <beat> --project <dir>` / `--pick <块名> --as <composition_id> --duration <sec> [--out <dir>]`):**registry 中性颗粒源**——没建栏目也能出 MG。候选态**离线**(零网络:读本机缓存的目录 `~/.gitruck/cache/mg-registry/catalog.json`,没有就用随包快照;钉死来源 commit)按检索词列 2–3 件(含 compat 标记与海报链接);取块态先在本地判完参数与落点,再刷新一次目录(统一静态资源下发,24 小时一刷,拉不到用缓存、再用随包),然后按目录里的镜像取块(同合云优先、大陆可达,之后 GitHub raw → jsDelivr fastly → jsDelivr gcore → gh-proxy 回源;每个镜像 8 s,**每份字节都校 sha256 与字节数**,全部失败零落盘;取到的块缓存在 `~/.gitruck/cache/mg-registry/files/`)→ 机械改写八条(`<template>` 包裹 / 改 id / 去 data-start 贴坑位 / 实心底下沉子层 / GSAP 源换契约 CDN / 字体换运行时镜像可证的 CJK 字体 / 时长贴坑位 / 信箱缩放不拉伸)→ `gtrk mg lint` 致命项不过不落盘 → 落 `<project>/mg/<composition_id>.html`。**骨架不是成品**:返回的 `editable`(文案 / 数值数组 / 色值)MUST 按 beat 与栏目改写后再铺。registry 中性块只有 1920×1080 一种几何(尺寸写死在块里),`--canvas` 给其它画幅拒绝;派单模式下工程 `.gtrk` 的 `video_size` 比例不是 16:9(容差 7%:4K 横屏与 DCI 17:9 照取)在下载前拒、不落盘,竖屏 / 方形工程走 `--source text`(找不到 `.gtrk` 或 `video_size` 不合法时不比对、照取并提示);`excluded` 件拒取,`review` 件(canvas / 铁律 8 高危形态)可取但须真渲验收。`GITRUCK_MG_REGISTRY_BASE` 设了就只用它当目录与取块的镜像根(`<根>/catalog.json`、`<根>/files/…`,即统一发布的暂存包 / 静态盘布局),不写本机缓存。
|
|
556
|
+
- **fetch --source text**(`gtrk mg fetch --source text <检索词> [--top 3] [--offline]` / `--pick <模板 id> --slot <beat> --project <dir>` / `--pick <模板 id> --as <composition_id> [--out <dir>]`):**同合云自家的文字特效模板库**——与中性块是两条路。模板是我方 clean-room 重写的**成品**(配色与排版已做过),**不做机械改写、MUST NOT 直接改 HTML**。每颗内嵌产生它的 IR 与双哈希,颗粒因此自带出身证明(三态 `ir` / `detached` / `html`);手改一个字节就掉成 `detached`,云端改写会拒绝它(`gtrk mg lint` 报非致命的 `x-ir-detached`)。目录从同合云取(统一静态资源下发,缓存在与客户端共用的 `~/.gitruck/cache/text-templates/`,24 小时一刷):拉到即以远端为准(不比版本号),拉不到用本机缓存、再用随包那份并**明示**(候选态因此永远离线可用;`--offline` 只读本机缓存与随包);旧缓存 `~/.gitruck/text-templates/` 已废弃、不再读。取块每份字节都校 sha256 与字节数,全部失败零落盘。`GITRUCK_TEXT_TEMPLATE_BASE` 设了就只用它当目录与正文的镜像根(`<根>/catalog.json`、`<根>/files/…`),不写本机缓存。
|
|
526
557
|
**落点与时长由命令钉定**:派单模式的 `composition_id` 取自 `dispatch.mg` 那条(`<工程slug>-<beatId>`,不是 `--slot` 收的 beat id),颗粒内嵌 IR 的 `id` 与 `canvas.duration` 被钉到「期望 id」与「坑位包络 + 0.3s 余量」(铁律⑦,贴模板末尾的层跟着钉),再走 `mg compile` 同一条本地编译链重编——产物仍是 `ir` 态,`1-cid-expect` 天然对得上。独立模式 `--as` 同样改写颗粒内部 id,`--duration` 钉时长;`--slot` 与 `--duration` 互斥。两者都没改、且目标画幅就是模板的 1920×1080 时原字节落盘。
|
|
527
558
|
**画幅**:按目标画幅编(IR 住在 1920 参考系,画幅是编译入参)。派单模式缺省取工程 `.gtrk` 的 `video_size`(显式 `--canvas` 与它不符当场拒;找不到 `.gtrk` 时按 1920×1080 编并提示补 `--canvas`),独立模式取 `--canvas`、不给即 1920×1080;`--json` 带 `canvas` 与 `canvas_from`(`flag` / `project` / `reference`)。
|
|
528
559
|
- **compile**(`gtrk mg compile <ir.json | 颗粒.html> [--canvas <WxH>] [--out <dir>] [--remote]`):把 IR **确定性编译**成颗粒(**0 积分**)。改字、换色、改字号描边阴影、改时长都走它——改 IR 再编,比手改 HTML 干净,且颗粒保持 `ir` 态(云端还能继续调)。缺省在本地编(零请求、断网可用,与服务端编译器逐字节等价);`--remote` 改走服务端,留给排查与对拍。给颗粒 HTML = 按它内嵌的 IR 重置回模板。`--canvas` 是目标画幅:不给时重置沿用那颗自己的画幅、`.ir.json` 按 1920×1080;`--remote` 把同一画幅交给服务端,产物画幅与请求不符(旧服务端不认画幅)时不落盘。
|
|
@@ -535,13 +566,14 @@ gtrk matrix lay --project <目录> [--plan <path>] # ③ 消费(
|
|
|
535
566
|
> **aux 叠层颗粒**:`gtrk split` 若在某 beat 的 `aux_layers` 派了 `overlay` 颗粒,会派生 `<beat>-aux<n>` 合成条目进 `dispatch.mg`——`gtrk mg` 一并铺,实现「同段既有底轨主视觉、又叠透明概念图解」。
|
|
536
567
|
> **双读兼容**:`dispatch.mg`(读旧 `rrv_mg`)、源目录 `mg/`(读旧 `rrv/`)、素材前缀 `mg-`(读旧 `rrv-`)——去品牌化前的既有工程零迁移。
|
|
537
568
|
|
|
538
|
-
### `gtrk composite` — 合成层(plan / review / scaffold / build / lint / lay / shots / bake)
|
|
569
|
+
### `gtrk composite` — 合成层(plan / review / status / scaffold / build / lint / lay / shots / bake)
|
|
539
570
|
|
|
540
571
|
粗剪、B-roll、字幕都定了之后,把选定时间窗做成**合成颗粒**:一段时间内的整个画面由一颗代码颗粒接管,讲者与 B-roll 作为槽位由客户端画进去。由 `/gtrk-composite` 驱动(含编排规则与两个检查点);纯本地、零计费。
|
|
541
572
|
|
|
542
573
|
```bash
|
|
543
574
|
gtrk composite plan --project <工程> [--mode full|auto|ranges] [--range 11,32 | --range u0004-u0009]... [--density 0.25]
|
|
544
575
|
gtrk composite review --project <工程> [--approve W01,W03] [--reject W02] [--adjust W04=80,90.9] [--add 140,150] [--approve-all]
|
|
576
|
+
gtrk composite status --project <工程> [--json]
|
|
545
577
|
gtrk composite scaffold --project <工程> [--only W03] [--force]
|
|
546
578
|
gtrk composite shots --project <工程> --material <素材 id 或文件> [--around <秒> --span <秒> | --from <秒> --to <秒>] [--every <秒>]
|
|
547
579
|
gtrk composite build --project <工程> [--only cp-w03] [--theme <css>] [--materials <json>]
|
|
@@ -554,6 +586,7 @@ gtrk composite bake --abi
|
|
|
554
586
|
|
|
555
587
|
- `plan`:候选窗口写进 `.gtrk` 的 `struct_meta.composite`(只动这一个键、原子写回;与 `gtrk split` 写 `struct_meta.split` 同一套做法),客户端大纲 CP 行据此画提案块;另出审稿稿 `composite/plan.md`。重跑保留已做的、不再提用户不要的。「建议画面」用到的文字信号(列举 / 对照 / 数字 / 分点)识别中文与英文;其他语种只看 B-roll 密度,审稿稿里写明未识别。
|
|
556
588
|
- `review`:采纳 / 不要 / 调起止 / 补窗口,写回同一个键;后续步骤只处理已采纳的窗口。
|
|
589
|
+
- `status`:只读汇总合成进度——各状态窗口数、`pending`(已采纳、还没铺轨的段数)、已铺数,逐窗口一行,起止按 `source_ranges` 投影到当刻时间线(口播被剪掉的窗口起止为空并注明)。没有合成键时全零。
|
|
557
590
|
- `scaffold`:为已采纳窗口落场景骨架 `composite/scenes/cp-wNN.html` 与上下文 `cp-wNN.context.md`;已有场景不覆盖。
|
|
558
591
|
- `shots`:给选片用——带源时间码的联系表、镜头切点、黑边实测(`data-crop` 取值);不替你选、不改工程。
|
|
559
592
|
- `build`:场景 → 自包含颗粒 `gtrk/assets/composite/<id>.html`。解析规则与 infra `composite-particle-profile` 逐字节一致(帧格窗口、轨身份、锚点、字幕输入、`inputs_hash`);风格取 `composite/theme.css`。锚点关键词照句子原文写:匹配时关键词与句子都忽略空格、标点与大小写,英文按整词(`"cold brew"` 直接写,`tea` 不命中 `teas`)。
|
|
@@ -576,7 +609,7 @@ gtrk composite bake --abi
|
|
|
576
609
|
|---|---|
|
|
577
610
|
| `gtrk project init --tts-task <task_id>` | **主路**:引用一个已完成的 `audio_tts_clone` 配音任务——服务端直取产物音频与句级时码(零 ASR、零额外计费),音频下载落工程 `audio/` |
|
|
578
611
|
| `gtrk project init --audio <配音> --transcript <transcript.json>` | **兜底路**:自备配音音频 + 句级时码稿成对给(时码稿由 `gtrk transcript <配音音频> --json` 产出;TTS 合成的配音请走主路,别重跑 ASR) |
|
|
579
|
-
| `gtrk audio lay --project <目录> --file <bgm.mp3>` | 往工程追加一条音频轨;**同源幂等替换**(同一来源重跑替换不堆轨、零引用保护剥旧);`--volume <0..1>`(默认 0.1 垫底音量——契约 volume 只写线性增益、不写 dB;客户端音量面板显示 -20.0
|
|
612
|
+
| `gtrk audio lay --project <目录> --file <bgm.mp3>` | 往工程追加一条音频轨;**同源幂等替换**(同一来源重跑替换不堆轨、零引用保护剥旧);`--volume <0..1>`(默认 0.1 垫底音量——契约 volume 只写线性增益、不写 dB;客户端音量面板显示 -20.0,两侧同一标尺;须 > 0——`0` 不会静音、会被拒,静音用 `gtrk patch set --muted`)、`--offset <ms>` 定入点 |
|
|
580
613
|
| `gtrk audio lay … --beat-align` | **高潮点锚定**(`audio_music_analyze`,计费一次):把 BGM 的情绪峰值 `H`(服务端 `highlight.time`)压到成片高潮点 `A` 上,映射恒为 `轨秒 = A + (BGM 秒 − H)`;**两侧都够长就零平铺**(恰好 1 个 clip),不够长才按小节线平铺补齐、接缝吸附 downbeat(轨的两个硬边界处的截断不吸附)。`A` 取自 `struct_meta.split.beats` 的判据链:升华段 → 容器转折 → 回扣段 → `0.75×全片`兜底,**命中哪一档 CLI 如实报出,兜底档会明示是猜的**。无 Key / 分析失败 / 曲子缺高潮点一律降级为不锚定,命令不失败 |
|
|
581
614
|
| `gtrk audio lay … --beat-align --climax <轨秒>` | 高潮点**逃生门**:一律覆盖上面那条判据链。越界(≤ `--offset` 或 ≥ 工程末尾)或非数**直接报错**,不静默回落 —— 显式给错了值要当场知道。须与 `--beat-align` 同用 |
|
|
582
615
|
| `gtrk audio lay … --no-loop` | 不平铺补齐:开了 `--beat-align` 时只放锚点那一段、头尾留白(**留白秒数如实报出**);未开 `--beat-align` 时保留单次、不循环叠满至工程末尾 |
|
|
@@ -797,7 +830,8 @@ gtrk render <gtrk> [-o <out.mp4>] [--crf <n>] [--codec <c>] [--ffmpeg-path <dir>
|
|
|
797
830
|
- **不会静默自动下载**:任何缺失路径只报错并指向本命令(包体 30–90 MB,且分发物涉及授权,须由用户/agent 显式触发)。
|
|
798
831
|
- 下载一律 https + **sha256 强校验**,校验不过即丢弃、不落地;解包调**系统 tar**(Win10+/macOS/Linux 自带),不引第三方解压依赖。
|
|
799
832
|
- 定位优先级不变:`--ffmpeg-path` → `~/.gitruck/ffmpeg` → 系统 PATH。镜像只填中间那一格,**不越过你自己装的 ffmpeg**。
|
|
800
|
-
-
|
|
833
|
+
- 字体走统一静态资源下发的字体目录(`https://api.ai-mcn.tv:9000/cloud/static/assets/fonts/catalog.json`,与客户端同一份):`--font` 装目录里登记的字幕字体(思源黑体 CN Bold,`sourcehansanscn-bold.otf`),`--font-family <族名…>` 按 `font_id` 或中英族名装整族;每款都校 sha256 与字节数,取不到报错、不落半成品。已装按文件名归一比对(历史命名 `SourceHanSansCN-Bold.otf` 也算),`--force` 才重下并换成目录里的命名。
|
|
834
|
+
- 字体落 `~/.gitruck/fonts`(落点即缓存,不另存一份到 `~/.gitruck/cache/`),烧录时经 ffmpeg `ass` 滤镜的 `fontsdir` 供给——**不装进系统字体表、不写注册表、不要管理员权限**。
|
|
801
835
|
- 分发的 ffmpeg 为 GPLv3 构建,对应源码与二进制同处提供(见分发点 `SOURCE.md`);**下载不附加任何使用限制**。
|
|
802
836
|
- `gtrk upgrade [--check]` — 升级 CLI 到最新版 + 刷新 skill(配置保留);`--check` 只查不装。
|
|
803
837
|
- `gtrk skills install [--agents codex,workbuddy,comate,…] [--all] [--copy] [--dir <skills 目录>]` — 单独安装/刷新 Agent Skills;缺省由通用适配器与 gtrk 补充层自动检测。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitruck/cli",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.11",
|
|
4
4
|
"description": "同合云成片流水线 CLI —— agent 驱动云端任务、产物拉回本地、三方工程文件(客户端/剪映/PR)互通。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Gitruck (同合云)",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"build": "bun build ./src/index.ts --target=node --minify --outfile dist/index.js",
|
|
58
58
|
"typecheck": "tsc --noEmit",
|
|
59
59
|
"prepublishOnly": "node scripts/plugin-manifest-check.mjs && npm run typecheck && npm test && bun run build",
|
|
60
|
-
"test": "node scripts/workspace-pollution-gate.mjs --snapshot && esbuild src/lib/compliance-notice.ts src/lib/config.ts src/lib/crash-report.ts src/lib/usage-analytics.ts src/lib/log.ts src/lib/read-json.ts src/lib/sidecar-write.ts src/lib/user-config.ts src/lib/enum-catalog.ts src/lib/first-run-tutorial.ts src/lib/desktop-client-hint.ts src/lib/command-path.ts src/lib/user-path.ts src/lib/runtime-channel.ts src/lib/self-install.ts src/lib/chunk-upload.ts src/lib/upload-cache.ts src/lib/upload-submit.ts src/lib/render.ts src/lib/cloud.ts src/lib/materialize.ts src/lib/jianying.ts src/lib/clip-brief.ts src/lib/media.ts src/lib/projection.ts src/lib/reproject.ts src/lib/splitdoc.ts src/lib/gtrk-writeback.ts src/lib/project-background.ts src/lib/client-only-state.ts src/lib/gtrk-patch.ts src/lib/frame-domain.ts src/lib/clock-adapter.ts src/lib/gtrk-invariants.ts src/lib/clip-speed.ts src/lib/clip-keyframes.ts src/lib/column-config.ts src/lib/third-party-catalog.ts src/lib/mg-adopt.ts src/lib/mg-registry.ts src/lib/matrix.ts src/lib/online-broll-client.ts src/lib/online-search-journal.ts src/lib/matrix-material.ts src/lib/matrix-fetch.ts src/lib/matrix-lay.ts src/lib/arrange-metering.ts src/lib/arrange-wire.ts src/lib/arrange-apply.ts src/lib/arrange-client.ts src/lib/arrange-gate.ts src/lib/arrange-decision-pin.ts src/lib/arrange-qc.ts src/lib/arrange-qc-bind.ts src/lib/rate-limit-wait.ts src/lib/embed-client.ts src/lib/describe.ts src/lib/highlight-rubric.ts src/lib/highlight-input.ts src/lib/local-index.ts src/lib/character-input.ts src/lib/index-decode.ts src/lib/local-search.ts src/lib/qc.ts src/lib/alignment-qc.ts src/lib/bgm-history.ts src/lib/image-move.ts src/lib/cloud-render-guard.ts src/lib/outdir-guard.ts src/lib/landing-wait.ts src/lib/material-integrity.ts src/lib/project-health.ts src/lib/contact-sheet.ts src/lib/media-transcript.ts src/lib/media-grid.ts src/lib/media-ffmpeg.ts src/lib/solid-png.ts src/lib/mask-raster.ts src/lib/mg-lint.ts src/lib/mg-visual-job.ts src/lib/mg-track-identity.ts src/lib/particle-identity.ts src/lib/text-ir/compile.ts src/lib/text-ir/validate.ts src/lib/text-ir/compile-local.ts src/lib/text-templates.ts src/lib/text-ir-client.ts src/lib/mg-lay.ts src/lib/mg-render.ts src/lib/particle-qtrle.ts src/lib/composite-particle.ts src/lib/composite-lay.ts src/lib/composite-lint.ts src/lib/composite-browser.ts src/lib/composite-plan.ts src/lib/composite-shots.ts src/lib/composite-resolve.ts src/lib/composite-profile.ts src/lib/composite-scene.ts src/lib/composite-bake-plan.ts src/lib/composite-bake.ts src/lib/composite-export.ts src/lib/tool-descriptors.ts src/lib/tool-runner.ts src/lib/tool-batch.ts src/lib/tool-pricing.ts src/lib/transcript.ts src/lib/runtime-assets.ts src/lib/subtitle-lay.ts src/lib/caption-align.ts src/lib/subtitle-line-split-client.ts src/lib/audio-align.ts src/lib/audio-tighten.ts src/lib/cut-snap.ts src/lib/mg-coverage.ts src/lib/ai-drama-lay.ts src/lib/ai-drama-pack.ts src/lib/desk-locate.ts src/lib/pip-lay.ts --bundle --platform=node --format=esm --external:bun:sqlite --outdir=.test-build --out-extension:.js=.mjs && esbuild src/lib/text-ir/compile.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/text-ir-compile.mjs && esbuild src/commands/split.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/patch.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/patch-cmd.mjs && esbuild src/commands/matrix.ts --bundle --platform=node --format=esm --external:bun:sqlite --outfile=.test-build/matrix-cmd.mjs && esbuild src/commands/mg.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/mg-cmd.mjs && esbuild src/commands/mg-text.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/mg-text-cmd.mjs && esbuild src/commands/tool.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/tool-cmd.mjs && esbuild src/commands/transcript.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/transcript-cmd.mjs && esbuild src/commands/project.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/project-cmd.mjs && esbuild src/commands/audio.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/audio-cmd.mjs && esbuild src/commands/subtitle.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/subtitle-cmd.mjs && esbuild src/commands/ai-drama.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/ai-drama-cmd.mjs && esbuild src/commands/feedback.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/feedback-cmd.mjs && esbuild src/commands/music-visualizer.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/music-visualizer-cmd.mjs && esbuild src/commands/long2short.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/long2short-cmd.mjs && esbuild src/commands/oralcut.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/oralcut-cmd.mjs && esbuild src/commands/oralcut-result.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/oralcut-result-cmd.mjs && esbuild src/commands/skills.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/skills-cmd.mjs && esbuild src/commands/qc.ts --bundle --platform=node --format=esm --external:commander --external:bun:sqlite --outfile=.test-build/qc-cmd.mjs && esbuild src/commands/media.ts --bundle --platform=node --format=esm --external:commander --external:bun:sqlite --outfile=.test-build/media-cmd.mjs && esbuild src/commands/doctor.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/doctor-cmd.mjs && esbuild src/lib/convert/ir_to_jsx.ts src/lib/convert/ir_to_am.ts src/lib/convert/ir_to_nv.ts src/lib/convert/am_parse.ts src/lib/convert/nv_parse.ts src/lib/convert/parse.ts src/lib/convert/download.ts src/lib/convert/bake_ops.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build/convert --out-extension:.js=.mjs && esbuild src/lib/mad/selector.ts src/lib/mad/techniques.ts src/lib/mad/beat.ts src/lib/mad/scan.ts src/lib/mad/data.ts src/lib/mad/pool.ts src/lib/mad/cloud-beat.ts src/lib/mad/mad.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build/mad --out-extension:.js=.mjs && esbuild src/commands/composite.ts --bundle --platform=node --format=esm --external:bun:sqlite --external:commander --outfile=.test-build/composite-cmd.mjs && esbuild src/commands/purify.ts --bundle --platform=node --format=esm --external:bun:sqlite --outfile=.test-build/purify-cmd.mjs && node --import ./test/helpers/test-home.mjs --test \"test/*.test.mjs\" && node scripts/workspace-pollution-gate.mjs --verify",
|
|
60
|
+
"test": "node scripts/workspace-pollution-gate.mjs --snapshot && esbuild src/lib/compliance-notice.ts src/lib/config.ts src/lib/crash-report.ts src/lib/usage-analytics.ts src/lib/log.ts src/lib/read-json.ts src/lib/sidecar-write.ts src/lib/user-config.ts src/lib/enum-catalog.ts src/lib/first-run-tutorial.ts src/lib/desktop-client-hint.ts src/lib/command-path.ts src/lib/user-path.ts src/lib/runtime-channel.ts src/lib/self-install.ts src/lib/plugin-presence.ts src/lib/chunk-upload.ts src/lib/upload-cache.ts src/lib/upload-submit.ts src/lib/render.ts src/lib/cloud.ts src/lib/materialize.ts src/lib/jianying.ts src/lib/clip-brief.ts src/lib/media.ts src/lib/projection.ts src/lib/reproject.ts src/lib/splitdoc.ts src/lib/gtrk-writeback.ts src/lib/project-background.ts src/lib/client-only-state.ts src/lib/gtrk-patch.ts src/lib/frame-domain.ts src/lib/clock-adapter.ts src/lib/gtrk-invariants.ts src/lib/clip-speed.ts src/lib/clip-keyframes.ts src/lib/clip-audio-fade.ts src/lib/clip-transitions.ts src/lib/transition-catalog.ts src/lib/column-config.ts src/lib/third-party-catalog.ts src/lib/mg-adopt.ts src/lib/mg-registry.ts src/lib/matrix.ts src/lib/online-broll-client.ts src/lib/online-search-journal.ts src/lib/matrix-material.ts src/lib/matrix-fetch.ts src/lib/matrix-lay.ts src/lib/arrange-metering.ts src/lib/arrange-wire.ts src/lib/arrange-apply.ts src/lib/arrange-client.ts src/lib/arrange-gate.ts src/lib/arrange-decision-pin.ts src/lib/arrange-qc.ts src/lib/arrange-qc-bind.ts src/lib/rate-limit-wait.ts src/lib/embed-client.ts src/lib/describe.ts src/lib/highlight-rubric.ts src/lib/highlight-input.ts src/lib/local-index.ts src/lib/character-input.ts src/lib/index-decode.ts src/lib/local-search.ts src/lib/qc.ts src/lib/alignment-qc.ts src/lib/bgm-history.ts src/lib/image-move.ts src/lib/cloud-render-guard.ts src/lib/outdir-guard.ts src/lib/landing-wait.ts src/lib/material-integrity.ts src/lib/project-health.ts src/lib/contact-sheet.ts src/lib/media-transcript.ts src/lib/media-grid.ts src/lib/media-ffmpeg.ts src/lib/solid-png.ts src/lib/mask-raster.ts src/lib/mg-lint.ts src/lib/mg-visual-job.ts src/lib/mg-track-identity.ts src/lib/particle-identity.ts src/lib/text-ir/compile.ts src/lib/text-ir/validate.ts src/lib/text-ir/compile-local.ts src/lib/text-templates.ts src/lib/text-ir-client.ts src/lib/mg-lay.ts src/lib/mg-render.ts src/lib/particle-qtrle.ts src/lib/composite-particle.ts src/lib/composite-lay.ts src/lib/composite-lint.ts src/lib/composite-browser.ts src/lib/composite-plan.ts src/lib/composite-shots.ts src/lib/composite-resolve.ts src/lib/composite-profile.ts src/lib/composite-scene.ts src/lib/composite-kit-upgrade.ts src/lib/composite-bake-plan.ts src/lib/composite-bake.ts src/lib/composite-export.ts src/lib/tool-descriptors.ts src/lib/tool-runner.ts src/lib/tool-batch.ts src/lib/tool-pricing.ts src/lib/transcript.ts src/lib/runtime-assets.ts src/lib/subtitle-lay.ts src/lib/caption-align.ts src/lib/subtitle-line-split-client.ts src/lib/audio-align.ts src/lib/audio-tighten.ts src/lib/cut-snap.ts src/lib/mg-coverage.ts src/lib/ai-drama-lay.ts src/lib/ai-drama-pack.ts src/lib/desk-locate.ts src/lib/pip-lay.ts src/lib/client-bridge.ts src/lib/client-state.ts src/lib/client-frame.ts --bundle --platform=node --format=esm --external:bun:sqlite --outdir=.test-build --out-extension:.js=.mjs && esbuild src/lib/text-ir/compile.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/text-ir-compile.mjs && esbuild src/commands/split.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build --out-extension:.js=.mjs && esbuild src/commands/patch.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/patch-cmd.mjs && esbuild src/commands/matrix.ts --bundle --platform=node --format=esm --external:bun:sqlite --outfile=.test-build/matrix-cmd.mjs && esbuild src/commands/mg.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/mg-cmd.mjs && esbuild src/commands/mg-text.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/mg-text-cmd.mjs && esbuild src/commands/tool.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/tool-cmd.mjs && esbuild src/commands/transcript.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/transcript-cmd.mjs && esbuild src/commands/project.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/project-cmd.mjs && esbuild src/commands/audio.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/audio-cmd.mjs && esbuild src/commands/subtitle.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/subtitle-cmd.mjs && esbuild src/commands/ai-drama.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/ai-drama-cmd.mjs && esbuild src/commands/feedback.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/feedback-cmd.mjs && esbuild src/commands/music-visualizer.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/music-visualizer-cmd.mjs && esbuild src/commands/long2short.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/long2short-cmd.mjs && esbuild src/commands/oralcut.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/oralcut-cmd.mjs && esbuild src/commands/oralcut-result.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/oralcut-result-cmd.mjs && esbuild src/commands/skills.ts --bundle --platform=node --external:bun:sqlite --format=esm --outfile=.test-build/skills-cmd.mjs && esbuild src/commands/qc.ts --bundle --platform=node --format=esm --external:commander --external:bun:sqlite --outfile=.test-build/qc-cmd.mjs && esbuild src/commands/media.ts --bundle --platform=node --format=esm --external:commander --external:bun:sqlite --outfile=.test-build/media-cmd.mjs && esbuild src/commands/client.ts --bundle --platform=node --format=esm --external:commander --external:bun:sqlite --outfile=.test-build/client-cmd.mjs && esbuild src/commands/doctor.ts --bundle --platform=node --external:bun:sqlite --format=esm --external:commander --outfile=.test-build/doctor-cmd.mjs && esbuild src/lib/convert/ir_to_jsx.ts src/lib/convert/ir_to_am.ts src/lib/convert/ir_to_nv.ts src/lib/convert/am_parse.ts src/lib/convert/nv_parse.ts src/lib/convert/parse.ts src/lib/convert/download.ts src/lib/convert/bake_ops.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build/convert --out-extension:.js=.mjs && esbuild src/lib/mad/selector.ts src/lib/mad/techniques.ts src/lib/mad/beat.ts src/lib/mad/scan.ts src/lib/mad/data.ts src/lib/mad/pool.ts src/lib/mad/cloud-beat.ts src/lib/mad/mad.ts --bundle --platform=node --external:bun:sqlite --format=esm --outdir=.test-build/mad --out-extension:.js=.mjs && esbuild src/commands/composite.ts --bundle --platform=node --format=esm --external:bun:sqlite --external:commander --outfile=.test-build/composite-cmd.mjs && esbuild src/commands/purify.ts --bundle --platform=node --format=esm --external:bun:sqlite --outfile=.test-build/purify-cmd.mjs && esbuild src/lib/static-delivery/index.ts src/lib/static-delivery/node.ts --bundle --platform=node --format=esm --outdir=.test-build/static-delivery --out-extension:.js=.mjs && node --import ./test/helpers/test-home.mjs --test \"test/*.test.mjs\" && node scripts/workspace-pollution-gate.mjs --verify",
|
|
61
61
|
"test:linux": "node scripts/test-linux.mjs",
|
|
62
62
|
"openspec:gate": "node openspec/gate.mjs",
|
|
63
63
|
"mg-registry:snapshot": "node scripts/mg-registry-snapshot.mjs",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gtrk-composite
|
|
3
3
|
description: 合成层包装(合成颗粒)——粗剪、B-roll、字幕都定了之后,把选定时间窗做成「合成」:一段时间内的整个画面由一颗代码颗粒接管(画中画拼贴、逐句换画面、对照并排、并列卡片、字幕排版),讲者与 B-roll 作为槽位画进去。三种入口:整片铺满 / 让 AI 判定哪里值得做 / 用户指定区间;候选窗口显示在客户端大纲的 CP 行。当用户想「做合成 / 合成层 / 整片做一下合成包装 / 哪里适合做合成 / 这段做成画中画拼贴 / 11 秒到 32 秒做个合成 / 逐句换画面 / 把字幕排进画面里」时使用本 skill,驱动 `gtrk composite`(plan → review → scaffold → build → lint → lay → bake),别手搓 HTML 铺进工程。
|
|
4
|
+
metadata:
|
|
5
|
+
in_app_agent: true
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# 合成层包装(gtrk-composite)
|
|
@@ -18,7 +20,7 @@ description: 合成层包装(合成颗粒)——粗剪、B-roll、字幕都
|
|
|
18
20
|
- 字幕最好已上(`gtrk subtitle lay`):合成颗粒可以接管字幕、自己排。
|
|
19
21
|
- `gtrk composite --help` 能跑(CLI 版本含本命令族)。
|
|
20
22
|
|
|
21
|
-
⚠️ **出片口径要先说清**:合成颗粒出片靠本机烘焙(`gtrk composite bake
|
|
23
|
+
⚠️ **出片口径要先说清**:合成颗粒出片靠本机烘焙(`gtrk composite bake`,见「出片:烘焙」一节;客户端导出时自动烘焙)——首次要装烘焙浏览器(约 110 MB),某颗烘焙失败时那一段按粗剪出画。用户要交付成片的话,这件事 MUST 在开工时告诉他。
|
|
22
24
|
|
|
23
25
|
## 入口:三选一(用户已说明就不再问)
|
|
24
26
|
|
|
@@ -36,7 +38,7 @@ description: 合成层包装(合成颗粒)——粗剪、B-roll、字幕都
|
|
|
36
38
|
|
|
37
39
|
### 检查点①(必停):审窗口
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
写回后客户端会自动重新载入工程(没有自动载入时请用户手动重新载入),请用户看大纲的 **CP 行**:虚线框 = 待审,虚线框加浅底 = 已采纳,悬停能看理由与建议。同时把审稿稿的表格摘给他。他在对话里说哪些要、哪些不要、哪些调起止,你用 `review` 写回:
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
44
|
gtrk composite review --project <工程> --approve W01,W03 --reject W02 --adjust W04=80,90.9 --add 140,150
|
|
@@ -77,15 +79,18 @@ gtrk composite scaffold --project <工程> # 为已采纳窗口落场
|
|
|
77
79
|
gtrk composite lay --project <工程> # 全量;--only cp-w03 只替换这颗
|
|
78
80
|
```
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
铺完客户端会自动重新载入(没有自动载入时请用户手动重新载入):CP 行上的提案块变成实色合成块,预览即合成效果。
|
|
81
83
|
|
|
82
84
|
## 出片:烘焙
|
|
83
85
|
|
|
86
|
+
> 这一节是外部 agent(终端里的 Claude Code、Codex 等)的出片步骤。在即剪客户端的 AI 面板里做合成时,铺完轨就告诉用户「导出时会自动烘焙」,不运行 `bake`。
|
|
87
|
+
|
|
84
88
|
铺完、用户确认后、出片前,先在本机把合成烤成视频(`gtrk render` / `gtrk project export` 也会自动先烤,单独跑便于先看结果):
|
|
85
89
|
|
|
86
90
|
```bash
|
|
87
91
|
gtrk deps install --browser # 首次:装钉定版本的烘焙浏览器(约 110 MB)。MUST 先告诉用户再装
|
|
88
92
|
gtrk composite bake --project <工程> # 全部合成;--only cp-w03 只烤这颗
|
|
93
|
+
gtrk composite upgrade-kit --project <工程> # 旧颗粒换上当前工具箱(元数据与场景不动);用户调窗口后边框 / 阴影才跟着走
|
|
89
94
|
```
|
|
90
95
|
|
|
91
96
|
- **缓存即复用**:没改过的颗粒二次运行全部命中;改了场景、素材文件、上游时间线或帧率才重烤。
|
|
@@ -157,10 +162,10 @@ CP.render = (t) => {
|
|
|
157
162
|
- **槽位绑定**:`ref-lane {track}`(某条轨在该时刻的画面,讲者常用);`ref {clip_id}`(某个片段,窗口外定格首末帧);`own {material, src_in_ms, dur_t | dur_f, starts_at: 锚点名 | starts_at_t: 时间线秒}`(自选素材的一段;之前首帧、之后末帧定格);`text`(字幕文本输入,无几何)。
|
|
158
163
|
- **锚点**:`[句 id, 关键词, 第几处(0 起)]`,取关键词首字在时间线上的时刻;场景里 `A("名字")` 得局部秒。关键词所在的字被剪掉时取其后第一个保留的字。匹配时关键词与句子都忽略空格、标点与大小写,英文按整词(`["u0001", "cold brew"]` 直接写;`"tea"` 不会命中 `teas`)。
|
|
159
164
|
- **槽位元素**:`data-slot` 一槽一个;`data-z` 叠放次序;`data-fit` cover / contain;`data-shape` rect / roundrect / circle;`data-crop` 上右下左比例;`data-filter` 只收白名单滤镜。
|
|
160
|
-
- **装饰跟随**:`data-for="<槽位>"` 的元素与槽位同框(`data-pad` 外扩);`.shadow` 在下(背景层),`.frame` / `.ring` 加 `data-layer="front"` 在上——**只给最上层的画面加前景描边**(规则 2
|
|
165
|
+
- **装饰跟随**:`data-for="<槽位>"` 的元素与槽位同框(`data-pad` 外扩);`.shadow` 在下(背景层),`.frame` / `.ring` 加 `data-layer="front"` 在上——**只给最上层的画面加前景描边**(规则 2)。用户在客户端挪、放大窗口后,`data-for` 装饰会跟着覆盖后的窗口走(工具箱 @2 起);所以**围着槽位的边框、阴影、角标一律用 `data-for`**,不要按槽位坐标手摆。场景里自己摆的标签(`place`)要贴着窗口时,用 `CP.boxed("<槽位>", [x, y, w, h])` 取覆盖后的窗口再算位置。旧工程(工具箱 @1 做的颗粒)先跑 `gtrk composite upgrade-kit --project <工程>`,装饰才会跟随。
|
|
161
166
|
- **分层**:缺省是背景层(画在视频之下);`data-layer="front"` 的子树在视频之上(文字、标签、描边、线条)。
|
|
162
167
|
- **定位**:工具箱只给**舞台的直接子元素**绝对定位(`#stage > *`)。放进容器里的子元素(如 `<div id="grid">` 下的一排徽章)不会自动定位,`left` / `top` 不生效、按文档流挤成一列(lint 报 `unpositioned-offset`)——容器内要摆位置的子元素自己写 `position:absolute`,或加工具箱的 `.abs` 类;坐标相对容器(容器自己要写宽高)。
|
|
163
|
-
- **工具箱 `CP`**:`prog(t, 起, 时长, ease)` 进度;`span` 进出;`at(id, [x,y,w,h], 透明度)` 定框;`mix(矩形A, 矩形B, p)` 版式插值;`seq(t, 到点, 下一张到点)` 同一位置逐句换画面的透明度;`place(el, x, y, o)`;`reveal / look / wipe / draw / typeOn`;`caption(el, "subs", t, 高亮词[], 隐藏区间[])`;`cues("subs")` 取字幕条目(局部帧);`fps()`。
|
|
168
|
+
- **工具箱 `CP`**:`boxed(槽位, [x,y,w,h])` 用户窗口覆盖后的框;`prog(t, 起, 时长, ease)` 进度;`span` 进出;`at(id, [x,y,w,h], 透明度)` 定框;`mix(矩形A, 矩形B, p)` 版式插值;`seq(t, 到点, 下一张到点)` 同一位置逐句换画面的透明度;`place(el, x, y, o)`;`reveal / look / wipe / draw / typeOn`;`caption(el, "subs", t, 高亮词[], 隐藏区间[])`;`cues("subs")` 取字幕条目(局部帧);`fps()`。
|
|
164
169
|
- **常用样式**:`.bed`(底色)/ `.bed.dark`;`.kicker` `.h1` `.h2` `.h3` `.body` `.tag` `.num`;`.ptag` / `.ptag.warm`(画面标签);`.cap` / `.cap.dark`(字幕);`.bubble`(对话气泡);`.stamp`(印章);`.card` `.pill` `.rule`。配色与字体都是变量:`--bg --bg2 --ink --muted --line --accent --accent2 --accent3 --alert --font --font-serif`。
|
|
165
170
|
- **纯函数**:场景脚本 MUST NOT 用 `Date`、`Math.random`、`requestAnimationFrame`、`setInterval`、`setTimeout`(lint 会拦)——同一帧号永远画出同一画面,客户端是逐帧 seek 的。
|
|
166
171
|
|
|
@@ -195,7 +200,7 @@ CP.render = (t) => {
|
|
|
195
200
|
| bake 报「找不到可用的浏览器」(退出码 2) | 本机没有钉定浏览器也没有 Chrome / Edge:征得用户同意后 `gtrk deps install --browser` |
|
|
196
201
|
| bake 报「素材缺失:<路径>」 | 素材移动或删除了:恢复文件或重新登记路径后再烤这颗 |
|
|
197
202
|
| lay 报「没铺:时间线上已有同 id 的片段」 | 用户在客户端改过那颗:要重铺先请他在客户端删掉它 |
|
|
198
|
-
| 客户端 CP 行没出现提案块 |
|
|
203
|
+
| 客户端 CP 行没出现提案块 | 请用户重新载入工程(客户端有未保存的改动时不会自动载入外部写入) |
|
|
199
204
|
|
|
200
205
|
## 被图纸快速成片接力调用
|
|
201
206
|
|