@remixmate/cli 0.9.37 → 0.9.38
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/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixmate/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.38",
|
|
4
4
|
"description": "AI media generation skills for Claude Code / Codex — 12 skills covering image, video, voice, digital human, web screenshot, web recording, script, template registry, rendering, Jianying export, and video deconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -441,11 +441,22 @@ Apply the following principles when producing the DSL:
|
|
|
441
441
|
1. **Narrative-first**: opening hook → point expansion → CTA close.
|
|
442
442
|
2. **Assets are declared, not executed**: every asset starts as `AssetRef` with `status: planned`; no generation API call from this skill.
|
|
443
443
|
3. **Narration drives duration**: each scene's duration should match its narration reading time (≈ 3–4 zh chars/sec, or ~2 words/sec for English).
|
|
444
|
-
4. **
|
|
444
|
+
4. **One complete thought per line — do NOT pre-split at subtitle width.** Separate lines inside `audio.narration.text` with `\n`, and put **one full clause or sentence** on each line (roughly 15–30 Chinese characters, or an equivalent number of English words). A `\n` is a hard cut in the *audio*: TTS treats each line as its own segment and returns a timestamp for it, so lines should fall where a human would actually pause for breath.
|
|
445
|
+
|
|
446
|
+
**Do not cut mid-phrase to make lines "subtitle-sized".** The renderer splits each line into on-screen subtitles itself, and it does that better than you can from the text alone: it measures the real glyph widths for the actual font size and frame (`HNSW` is not as wide as four Chinese characters), knows how many characters fit on one line of *this* template and aspect ratio, and picks cut points by punctuation strength (sentence end → colon → comma → enumeration comma → space). It also guarantees no wrapping. Pre-splitting takes all of that away and just makes the captions choppy.
|
|
447
|
+
|
|
448
|
+
Measured on a shipped video (2026-09-21): narration written as 6–8 character lines produced 57 subtitle screens in 121.5s — a median of 2.10s each, 33% of them under 1.5s, with `AI Agent` alone on a screen. The renderer's own splitter never even fired.
|
|
449
|
+
|
|
450
|
+
Write:
|
|
445
451
|
```
|
|
446
|
-
"text": "
|
|
452
|
+
"text": "最近刷爆科技圈的 AI Agent 到底厉害在哪\n真正的分水岭不是文案更精准,而是自主执行能力"
|
|
447
453
|
```
|
|
448
|
-
|
|
454
|
+
not:
|
|
455
|
+
```
|
|
456
|
+
"text": "最近刷爆科技圈的\nAI Agent\n到底厉害在哪\n不是文案更精准\n也不是对话更流畅"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Use full-width punctuation in Chinese narration** (`,。:;?!`), not half-width (`,.:;?!`). Half-width punctuation in Chinese text renders with no trailing space — `第一步,目标感知:只给最终目标` reads cramped on screen.
|
|
449
460
|
5. **Moderate scene count**: 30-second videos work well with 4–6 scenes, 60-second videos with 6–10.
|
|
450
461
|
6. **Leave room for templates**: pick generic layouts; do not assume a specific template implementation.
|
|
451
462
|
7. **Image model allowlist**: every `type: image` + `source: gen-image` `AssetRef`'s `payload.model` **must** be one of the values in the table below. **Never** use display names, short forms, or made-up ids (e.g. `seedream`, `seedream-5`, etc.).
|
|
@@ -20,10 +20,35 @@ from typing import Optional
|
|
|
20
20
|
CHARS_PER_SECOND = 5.0
|
|
21
21
|
|
|
22
22
|
_PRIMARY_BREAK = re.compile(r"(?<=[。!?;\n])")
|
|
23
|
-
|
|
23
|
+
# 次级断点**不含顿号 `、`**。顿号是并列项之间的分隔,在它上面下刀就是把一串并列
|
|
24
|
+
# 拦腰切开(`调研、策划、` / `开发、分析,…`)。这一层只数字符、分不出标点的语义
|
|
25
|
+
# 强度,所以干脆不碰它 —— 真需要再切时交给渲染端,那边是分级的(句末 > 冒号 >
|
|
26
|
+
# 逗号 > 顿号 > 空格),只有前面几级都切不动才会降到顿号。
|
|
27
|
+
_SECONDARY_BREAK = re.compile(r"(?<=[,,::])")
|
|
24
28
|
_PRIMARY_TAIL = re.compile(r"[。!?;\n]\s*$")
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
# ─── 这两个上限管的是「喂给 TTS 的行」,不再是「一屏字幕」 ────────────────
|
|
31
|
+
#
|
|
32
|
+
# 曾经是 16 / 6,那是渲染端还不会分屏时的产物:谁都不会再切,所以必须在这里
|
|
33
|
+
# 就把旁白预切成一屏放得下的大小。现在渲染端(core 的 `chunkSubtitleSegments`)
|
|
34
|
+
# 会按**实际字号与实际可用宽度**算容量、按**标点语义强度分级**切分,这件事它
|
|
35
|
+
# 做得比这里好得多:
|
|
36
|
+
# · 这里只能数字符数,数不出 `HNSW` 比 4 个中文字窄一半;
|
|
37
|
+
# · 这里的 `_SECONDARY_BREAK` 是平的,冒号和顿号同权,会把并列项拦腰切开;
|
|
38
|
+
# · 这里一个全局 16 要同时服务 16:9(一行放 44 字)和 9:16(一行放 22 字)。
|
|
39
|
+
#
|
|
40
|
+
# 于是 16 的唯一效果变成了**抢在渲染端之前把句子剁碎**。2026-09-21 线上成片实测:
|
|
41
|
+
# 121.5s 里 57 屏、中位 2.10s 一屏、33% 短于 1.5s,「AI Agent」独占一屏 —— 全都是
|
|
42
|
+
# 这个 16 的产物,渲染端的分屏阈值(20)一次都没被触发。
|
|
43
|
+
#
|
|
44
|
+
# 现在这里只负责一件事:**在真实语音停顿处断行**,让 Minimax 按停顿返回时间戳。
|
|
45
|
+
# 句末(`_PRIMARY_BREAK`)永远断;逗号那一级只在句子长到一行 TTS 太长时才用。
|
|
46
|
+
# 30 是「一个中文长句」的量级 —— 越过它说明这句本来就该有个呼吸点。
|
|
47
|
+
#
|
|
48
|
+
# ⚠️ 别再把它当字幕宽度调:想改一屏显示多少字,改 core 的
|
|
49
|
+
# `DEFAULT_SPLIT_MAX_UNITS` / `LINE_FILL_LIMIT`,那边才看得见字号和画幅。
|
|
50
|
+
MAX_SEGMENT_CHARS = 30
|
|
51
|
+
# 合并下限保持 6:TTS 行太短会让合成的语气断掉(和字幕闪烁是两回事)。
|
|
27
52
|
MIN_SEGMENT_CHARS = 6
|
|
28
53
|
|
|
29
54
|
# 字幕显示时需要去掉的末尾标点(中英文句末 + 逗号等)
|
|
@@ -157,10 +182,15 @@ def _strip_trailing_punct(text: str) -> str:
|
|
|
157
182
|
|
|
158
183
|
|
|
159
184
|
def segment_narration(text: str) -> list[str]:
|
|
160
|
-
"""Split narration
|
|
185
|
+
"""Split narration into **TTS lines**, cutting at speech pauses.
|
|
161
186
|
|
|
162
187
|
Use before TTS: ``"\\n".join(segment_narration(text))`` sends to Minimax
|
|
163
|
-
so it returns per-
|
|
188
|
+
so it returns per-line timestamps.
|
|
189
|
+
|
|
190
|
+
⚠️ 这里切的**不是字幕屏**。字幕分屏归渲染端(core 的
|
|
191
|
+
``chunkSubtitleSegments``),它知道字号、画幅和标点的语义强度;这里只知道
|
|
192
|
+
字符数。这一层切得越细,留给渲染端的余地越小 —— 见 ``MAX_SEGMENT_CHARS``
|
|
193
|
+
的注释。
|
|
164
194
|
"""
|
|
165
195
|
if not text:
|
|
166
196
|
return []
|