From 723cecd93c08b7ddb9bc51b5c9bbe7e2253a42ae Mon Sep 17 00:00:00 2001 From: Hahaha Date: Fri, 16 Oct 2026 19:29:17 +0800 Subject: [PATCH] fix: address Feishu submission PLUGIN-202610030177 review (1.9.20) --- .claude-plugin/plugin.json | 2 +- .github/workflows/ci.yml | 24 +++---- .gitignore | 1 + .minimax-plugin/plugin.json | 2 +- CHANGELOG.md | 8 +++ README.md | 65 ++++++++++--------- README.zh-CN.md | 44 +++++++------ package-lock.json | 47 ++++++++++++++ package.json | 15 +++++ plugin.json | 6 +- skills/html2video-for-mcode/SKILL.md | 43 ++++++++---- skills/html2video-for-mcode/evals/evals.json | 8 +-- .../references/authoring.md | 6 +- .../references/image-sources.md | 29 ++++++--- .../html2video-for-mcode/references/render.md | 6 +- .../references/symptoms.md | 2 +- .../references/tts-and-timing.md | 2 +- skills/html2video-for-mcode/scripts/asr.mjs | 16 +++-- .../html2video-for-mcode/scripts/capture.mjs | 2 +- .../scripts/fetch-official-images.mjs | 2 +- skills/html2video-for-mcode/scripts/tools.mjs | 2 +- .../tests/endpoint-allowlist.test.mjs | 20 ++++-- 22 files changed, 234 insertions(+), 118 deletions(-) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 5dd9b65..c7118a0 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "html2video-for-mcode", - "version": "1.9.18", + "version": "1.9.20", "description": "Turn a topic, outline, or script into a narrated MP4: HTML slides with staged entrance animations, TTS voiceover, ffmpeg assembly, and ASR verification.", "skills": [ "./skills/html2video-for-mcode/SKILL.md" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c842d0e..d85cfe9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,12 @@ # html2video-for-mcode · CI (Linux + Windows) # 仓库根是插件包根(skills/html2video-for-mcode/ 才是技能目录 —— marketplace 提交面, 2026-10-03 起), -# 两个作业都 working-directory 到技能目录, 让 node_modules 落在 tests/ 旁边, 与旧"仓库根=技能目录" -# 布局的发现几何完全一致。fork 上的 scoped smoke workflow 要等宿主维护者批准才会首跑, +# 两个作业在技能目录运行测试;依赖从根级锁文件安装到仓库根 node_modules,沿祖先链发现。 +# fork 上的 scoped smoke workflow 要等宿主维护者批准才会首跑, # 这里在自己的仓库里以同样的依赖组合(ffmpeg + Playwright Chromium, 两个平台各跑一遍) # 把 tests/ 下全部测试真实执行 —— 尤其是三条需要**文件符号链接**能力的 canary: Windows 无 # 开发者模式时建不了文件链接, 本地一直只能跳过, Linux 与 Windows 管理员 runner 上是它们真正运行的场合。 # -# 依赖放置的坑(实测): 技能目录不带 package.json, 而 npm 11 在无清单目录里 -# `npm install --no-save ` 会**静默不装**(exit 0, node_modules 为空)。 -# 所以先 `npm init -y` 造临时清单 → 装(不落 lockfile) → 删清单。 +# Playwright uses the committed root package-lock.json; npm ci installs the exact dependency tree. # ffmpeg 走系统包(choco/apt)让它在 PATH 上: 测试会把脚本放进临时项目目录当 cwd 跑, # 只有 PATH 发现对"任意 cwd"都成立(node_modules 发现依赖 cwd/上两层锚点, 深层布局会够不到 —— # 脚本自身的 node_modules 发现走祖先链, 与 cwd 无关)。 @@ -43,13 +41,11 @@ jobs: - name: Install ffmpeg run: sudo apt-get update && sudo apt-get install -y --no-install-recommends ffmpeg - - name: Install playwright (throwaway manifest, nothing committed) + - name: Install locked playwright dependencies working-directory: ${{ env.SKILL_DIR }} run: | - npm init -y >/dev/null - npm install --no-save --no-package-lock playwright - rm package.json - npx playwright install --with-deps chromium + npm ci --prefix ../.. --ignore-scripts --no-audit --no-fund + npx --no-install playwright install --with-deps chromium # glob 交给 shell 展开: 以后新增测试文件自动进 CI(旧枚举写法漏过 8 个文件)。 # 单测超时 300s: 渲染冒烟里的 capture / build-video 在 CI 上要几十秒。 @@ -75,14 +71,12 @@ jobs: shell: bash run: choco install ffmpeg -y --no-progress - - name: Install playwright (throwaway manifest, nothing committed) + - name: Install locked playwright dependencies shell: bash working-directory: ${{ env.SKILL_DIR }} run: | - npm init -y >/dev/null - npm install --no-save --no-package-lock playwright - rm package.json - npx playwright install chromium + npm ci --prefix ../.. --ignore-scripts --no-audit --no-fund + npx --no-install playwright install chromium - name: All tests (security · policy · css blocks · render smoke · symlink canaries) shell: bash diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/.minimax-plugin/plugin.json b/.minimax-plugin/plugin.json index 1437f0f..dcc3d47 100644 --- a/.minimax-plugin/plugin.json +++ b/.minimax-plugin/plugin.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "name": "html2video-for-mcode", "displayName": "HTML 2 Video for mcode", - "version": "1.9.19", + "version": "1.9.20", "description": "Turn a topic, outline, or script into a narrated MP4: HTML slides with staged entrance animations, a TTS voiceover, burned-in subtitles, ffmpeg assembly, and an ASR pass that verifies the voiceover. / 把主题、大纲或文稿做成一条带口播的 MP4:HTML 幻灯片分步入场动画、TTS 配音、内嵌字幕、ffmpeg 合成,外加 ASR 反向校验口播与文稿一致。", "author": "Wzdhehe", "icon": "icon.png", diff --git a/CHANGELOG.md b/CHANGELOG.md index b00cb86..15417d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.9.20 — 2026-10-16 + +- Address Feishu submission PLUGIN-202610030177: point homepage/repository to the real Wzdhehe source and identify this as a community plugin. +- Default to typography; require explicit opt-in and user-confirmed permission before downloading news images, screenshots, or portraits. Record permission evidence and attribution; remove blanket reuse claims. +- Pin npm install examples and CI dependencies; require explicit user consent before global installs or upgrades. +- Reject ASR command-line keys (including equals syntax); use MINIMAX_API_KEY or an existing mmx login. Preserve endpoint and credential-isolation checks. +- Align all three manifests at 1.9.20. + # Changelog ## 1.9.19 — 2026-10-10 diff --git a/README.md b/README.md index 8b7b6fb..023b1a1 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ replacement), the generated-body template with its content fingerprint, and the | 3. Script | Per-slide narration split into clauses; every slide carries at least two information layers on separate animation stages (order is free) | | 4. TTS | Voice synthesis (mcode connector, or `mmx-cli` elsewhere), then measure every clip with ffprobe | | 5. Timing | Derive each slide's duration and each animation's entrance time from the **measured** audio — nothing is hand-written | -| 6. Assets | Official sources first, image framing primitives, compliance manifest | +| 6. Assets | User-confirmed licensed assets, image framing primitives, authorization manifest | | 7. HTML | Staged entrance animations bound to the measured timings; layout recipes for 17 slide types | | 8. Render | Deterministic frame-stepping capture (animations land in the video), ffmpeg assembly with subtitles, optional background music. Before spending encode time, `preview-page.mjs` writes a play page so the deck can be screened in a browser | | 9. Verify | ASR transcription compared against the script; contrast, theme, and static-slide gates | @@ -86,46 +86,54 @@ replacement), the generated-body template with its content fingerprint, and the ## Install -**As a plugin (MiniMax Code):** install `plugins/Wzdhehe/html2video-for-mcode` from the -[MiniMax-Code-Plugins catalog](https://github.com/MiniMax-AI/MiniMax-Code-Plugins/tree/main/plugins/Wzdhehe/html2video-for-mcode) — that hosted -directory is the publication unit, and the copy reviewed there is the one users get. +**Source and ownership:** this is an independently maintained community plugin by Wzdhehe, +not an official MiniMax plugin. The source and marketplace submission package are hosted at +[Wzdhehe/html2video-for-mcode](https://github.com/Wzdhehe/html2video-for-mcode). +The repository root contains `plugin.json`, `.claude-plugin/plugin.json`, +`.minimax-plugin/plugin.json`, and `skills/html2video-for-mcode/`. +Marketplace availability depends on review; this repository does not imply approval or listing. -**As a plugin (mcode marketplace):** this repository's root is itself a plugin package — -`plugin.json` (the portable manifest the runtime reads), `.claude-plugin/plugin.json` (mcode 0.4+), -and `.minimax-plugin/plugin.json` (the marketplace submission manifest, with the listing icon and -category). It carries the same `skills/html2video-for-mcode/` subtree the hosted catalog reviews, -kept byte-identical by the release tooling. - -**As a standalone skill (any AgentSkills host):** copy the skill directory out of that hosted -plugin (or out of this repository — the same bytes) into your host's skills directory: +**As a standalone skill (any AgentSkills host):** from a checkout of this repository: ```bash -# from a checkout of the MiniMax-Code-Plugins repository: -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode ~/.claude/skills/ -# or from a checkout of this repository (the same subtree): cp -r skills/html2video-for-mcode ~/.claude/skills/ # project-level -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode /.claude/skills/ +cp -r skills/html2video-for-mcode /.claude/skills/ ``` Then install the two dependencies **in your video project** (not in the skill directory): ```bash cd -npm i playwright && npx playwright install chromium +npm i --save-exact playwright@1.63.0 && npx --no-install playwright install chromium # ffmpeg: winget install Gyan.FFmpeg / brew install ffmpeg / apt install ffmpeg -# or: npm i ffmpeg-static ffprobe-static +# or: npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0 ``` + +**Installation and credentials:** prefer project-local dependencies and retain the generated +`package-lock.json`; repeat installs with `npm ci`. All npm package examples below use exact +versions. Before any global install or upgrade, explain the package, version, and system-wide +change and obtain explicit user consent. Only then may you run `npm install -g mmx-cli@1.0.26`. +Use an existing `mmx auth login` session or provide `MINIMAX_API_KEY` through the environment. +Never ask users to paste keys into chat, command arguments, source files, or project files. + +**Asset authorization:** default to typography and CSS/SVG charts. News images, article screenshots, +and real-person portraits are disabled by default. Before downloading or using any external asset, +have the user confirm permission for the intended use and record its source, license or permission +evidence, attribution requirements, and user confirmation in `assets/MANIFEST.md`. +An official site or a user-supplied file does not by itself establish reuse permission. +If permission is missing or unclear, use typography instead. + ## Requirements -- **Node.js 18+** (plain ESM, no build step). +- **Node.js 20+** (plain ESM, no build step). - **ffmpeg / ffprobe** on `PATH`, or `ffmpeg-static` / `ffprobe-static` in the project. Scripts probe `PATH → project node_modules → skill parents → common install locations`. - **Playwright Chromium** for capture. Install it in the video project — scripts resolve it from the project directory, the working directory, or the global npm root. - **Voice synthesis**, one of: mcode platform connectors, `mmx-cli` - (`npm i -g mmx-cli && mmx auth login --api-key sk-...`), or your own TTS written to + (with an existing `mmx auth login` session), or your own TTS written to `audio/.mp3`. Both mcode connectors and `mmx-cli`/REST spend a **MiniMax account's paid, quota-metered balance** — the account is a required, billable service charged per character/minute. - **Reverse ASR verification** via `scripts/asr.mjs`, which transcribes the voiceover and compares @@ -223,23 +231,24 @@ No telemetry, no analytics, no hidden endpoints, no installers, no native binari without changing anything. - No credentials are stored or embedded: with the default mmx provider the script never touches a key at all (mmx holds its own login); on the `--provider api` path it reads a key from - `MINIMAX_API_KEY` or `--api-key` at runtime and never writes it anywhere. + `MINIMAX_API_KEY` at runtime (command-line keys are rejected) and never writes it anywhere. - `KIT_PROJECT_DIR` is internal plumbing, set automatically by the CLI entry points so shared helpers can locate the project directory; you never need to set it yourself. +For development in a repository checkout, run `npm ci --ignore-scripts` at the repository root; +CI uses the committed lockfile for the same dependency tree. + ## Verification The Skill ships an executable test suite (`skills/html2video-for-mcode/tests/`, plain `node:test` — no extra dependencies): ```bash -# in the MiniMax-Code-Plugins monorepo (the plugin PR context), from the repository root: -node --test "plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode/tests/*.test.mjs" # in a standalone clone of this repository, from its root (the skill sits under skills/): node --test "skills/html2video-for-mcode/tests/*.test.mjs" ``` -285 tests in fifteen files: `safe-paths` (malicious slide ids / paths, canary intactness, symlink +The suite covers: `safe-paths` (malicious slide ids / paths, canary intactness, symlink escapes including a **dangling** link that must be caught rather than skipped), `no-clobber` (refusing to overwrite), `endpoint-allowlist` (key never leaves the official hosts — plus a local server that proves the gate sits before the request, and provider selection: `mmx speech transcribe` default vs `--provider api` fallback, with an mmx-shim integration pair @@ -262,14 +271,10 @@ the new mechanism: a live region **plus a stale copy of the generated body outsi `ok`, and the `ok` note for a project override now says whether it sits before the region (loses the cascade) or after it (wins)) and `render-smoke` (init → timings → static gate → capture → build, end to end, **plus a pixel-level proof that upgrading a stale project really changes the rendered picture**), plus the capture layout-geometry self-check (content overflow / top-edge clipping named with numbers) and the safe-center scaffold contract. Two newer suites cover the second review round and the delivery-quality fixes: `review-round2` (canary tests proving output containment, a local server proving a rejected destination receives **zero** requests, single-quoted/unquoted HTML attributes, ASR request errors counted as failures, ffmpeg discovered from the project) and `cover-transition` (cover image present, `attached_pic` stream embedded, first frame not black, no black frame at any cut point in both hard-cut and cross-dissolve modes, total duration unchanged) and `review-round3` (the seven functional defects: `check-timing --calibrate` must not write back half-measured boundaries, `--topic ` must not treat the value as the project directory, `--json` is position-independent, `--min WxH`, `--get` all-failed exits non-zero, `capture --mode/--dsf` and `grab-frames --at` reject bad values at the entry point, the subtitle-band gate only fires on positioned elements, `--dry-run` prints the plan and exits 0, and a bare-string `transition` must mean the same thing to the gate and the renderer — plus the stale-CSS gates on `check-slides` / `capture` / `build-video`, and the chart-structure gate: percentage-height bars sitting bare in a flex column get flagged (they collapse via flex-shrink; wrap them in `.chart-plot-cell`)) and `subtitles-invalidate` (deleting clauses, or `--no-subs`, and rebuilding must remove the old subtitles from the video — asserted at pixel level; plus keyframe-shape invariants, full-brightness / cross-still-leak checks on the spliced stills, and cover / still-mode-base must-stay-subtitle-free checks (the 2026-09-22 subtitle regressions)). Everything runs with ffmpeg, ffprobe and -Chromium installed (on `PATH`, or in this repo's / your project's `node_modules` — `npm i -ffmpeg-static ffprobe-static playwright`). Without them, every test that needs one of them **skips +Chromium installed (on `PATH`, or in this repo's / your project's `node_modules` — `npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0 playwright@1.63.0`). Without them, every test that needs one of them **skips with its stated reason** (a tool is absent, or the filesystem forbids creating a junction) — nothing pretends to pass, and the pipeline scripts themselves exit with `找不到 ffmpeg` instead of running -half a pipeline. The scoped workflow -`.github/workflows/html2video-for-mcode-smoke.yml` — which lives in the **MiniMax-Code-Plugins -monorepo**) and runs on the plugin PR and on main — -installs them and runs everything for real. +half a pipeline. The repository workflow `.github/workflows/ci.yml` runs the suite on Linux and Windows. ## Troubleshooting diff --git a/README.zh-CN.md b/README.zh-CN.md index e80750f..886eed6 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -38,7 +38,7 @@ my-video/ | 3. 脚本 | 每张 slide 的口播拆成逐句 clauses;每张至少两个信息层、分属不同动画 stage(先后顺序自由) | | 4. TTS | 配音合成(mcode connector,其他环境用 `mmx-cli`),随后用 ffprobe 实测每段时长 | | 5. 对时 | 每张时长、每层入场时刻**全部由实测音频推出**,不手写任何秒数 | -| 6. 配图 | 官方素材优先、图片框原语、合规清单登记 | +| 6. 配图 | 用户确认授权的素材、图片框原语、授权清单登记 | | 7. HTML | 分步入场动画绑定实测时刻;17 种版式配方 | | 8. 渲染 | 确定性逐帧步进捕获(动画真正进视频)、ffmpeg 合成与字幕、可选 BGM。真正编码前先用 `preview-page.mjs` 出的放映页在浏览器里过一遍 | | 9. 校验 | ASR 转写与脚本比对;对比度、主题、渲染前静态闸门 | @@ -54,39 +54,43 @@ my-video/ ## 安装 -**作为插件(MiniMax Code)**:从 [MiniMax-Code-Plugins 目录](https://github.com/MiniMax-AI/MiniMax-Code-Plugins/tree/main/plugins/Wzdhehe/html2video-for-mcode)安装 -`plugins/Wzdhehe/html2video-for-mcode` —— 宿主目录就是发布单元,评审过的那份才是用户拿到的。 +**来源与归属**:这是由 Wzdhehe 独立维护的社区插件,并非 MiniMax 官方插件。 +真实源码与市场提交包位于 [Wzdhehe/html2video-for-mcode](https://github.com/Wzdhehe/html2video-for-mcode)。 +仓库根包含 `plugin.json`、`.claude-plugin/plugin.json`、`.minimax-plugin/plugin.json` +及 `skills/html2video-for-mcode/`。市场是否上架以审核结果为准,本仓库不代表已获审核通过。 -**作为插件(mcode 插件市场)**:本仓库根本身就是一个插件包 —— `plugin.json`(可移植清单,运行时读它)、 -`.claude-plugin/plugin.json`(mcode 0.4+)、`.minimax-plugin/plugin.json`(市场提交清单,含图标与类目); -`skills/html2video-for-mcode/` 子树与宿主目录评审的那份逐字节一致(由发布工具同步保证)。 - -**作为独立技能(任意 AgentSkills 宿主)**:从宿主插件目录(或本仓库 —— 同一份字节)复制技能目录: +**作为独立技能(任意 AgentSkills 宿主)**:从本仓库检出后复制: ```bash -# 从 MiniMax-Code-Plugins 仓库的检出: -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode ~/.claude/skills/ -# 或从本仓库的检出(同一份子树): cp -r skills/html2video-for-mcode ~/.claude/skills/ # 项目级安装 -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode <你的项目>/.claude/skills/ +cp -r skills/html2video-for-mcode <你的项目>/.claude/skills/ ``` 然后把两个依赖装到**你的视频项目里**(不是技能目录里): ```bash cd <你的视频项目> -npm i playwright && npx playwright install chromium +npm i --save-exact playwright@1.63.0 && npx --no-install playwright install chromium # ffmpeg: winget install Gyan.FFmpeg / brew install ffmpeg / apt install ffmpeg -# 或: npm i ffmpeg-static ffprobe-static +# 或: npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0 ``` +**安装与凭据**:优先在视频项目内安装,保留生成的 `package-lock.json`,后续使用 `npm ci`。 +所有 npm 安装示例均锁定精确版本。全局安装或升级前,必须说明包名、版本及系统范围影响, +并取得用户明确同意;仅在同意后才可执行 `npm install -g mmx-cli@1.0.26`。 +Key 仅通过环境变量 `MINIMAX_API_KEY` 或已有 `mmx auth login` 登录提供,禁止放进聊天、命令参数或项目文件。 + +**素材授权**:默认使用纯排版及 CSS/SVG 图表,不默认抓取新闻图片、报道截图或真人肖像。 +下载或使用任何外部素材前,须由用户确认具备用于本次用途的授权,并在 `assets/MANIFEST.md` +记录来源、许可或授权证据、署名要求和用户确认。官方来源或用户提供均不自动代表可再利用;授权不明则使用纯排版。 + ## 依赖要求 -- **Node.js 18+**(纯 ESM,无构建步骤)。 +- **Node.js 20+**(纯 ESM,无构建步骤)。 - **ffmpeg / ffprobe**:在 `PATH` 上,或项目里装 `ffmpeg-static` / `ffprobe-static`。脚本按 `PATH → 项目 node_modules → 技能上两级 → 常见安装位置` 探测。 - **Playwright Chromium**:截图用。装在视频项目里即可 —— 脚本会从项目目录、工作目录、npm 全局逐个解析。 -- **配音**:三选一 —— mcode 平台 connector、`mmx-cli`(`npm i -g mmx-cli && mmx auth login --api-key sk-...`)、或你自己的 TTS(把音频写到 `audio/.mp3`)。mcode connector 与 `mmx-cli`/REST 消耗的都是 **MiniMax 账号的付费配额** —— 该账号是必需的计费服务,按字数/时长计费。 +- **配音**:三选一 —— mcode 平台 connector、`mmx-cli`(使用已有的 `mmx auth login` 登录)、或你自己的 TTS(把音频写到 `audio/.mp3`)。mcode connector 与 `mmx-cli`/REST 消耗的都是 **MiniMax 账号的付费配额** —— 该账号是必需的计费服务,按字数/时长计费。 - **反向 ASR 校验**:`scripts/asr.mjs` 把配音转写回来与脚本比对(数字、专名、语种)。默认走 `mmx speech transcribe`(mmx-cli ≥ 1.0.26,与配音同一套 mmx 登录,不需要另行配 Key);没有 mmx-cli 时用 `--provider api` + `MINIMAX_API_KEY` 直连 REST。两条路径消耗的都是同一个**付费、按配额计费的 MiniMax 账号**,每次转写按音频时长计费。 ## 快速开始 @@ -137,21 +141,21 @@ Windows / macOS / Linux。脚本全部是 Node ESM,不依赖特定 shell。Windo - 抓取的素材下载到项目的 `assets/` 目录,并需在 `assets/MANIFEST.md` 登记来源与许可。 - **写入只发生在你传入的项目目录内。** `script.json` 派生出的每个路径(slide 的 `id` / `html` / `audio`、`bgm.file`)都先过校验:id 必须匹配 `^[A-Za-z0-9_-]{1,64}$`,路径必须 resolve 在项目目录内,符号链接逃逸同样拒绝 —— 手改或被注入的 `script.json` 无法让流水线读写或递归删除项目目录之外的东西。**唯一声明过的例外**:`prep-image.mjs --crop` 的输入与输出都由命令行**显式给出**(与你直接跑 ffmpeg 同一信任级),这两个路径不限于项目内 —— 覆盖已存在输出仍需 `--force`。所有**派生**路径的流水线写入(项目 + id、`preview/`、`build/`、`out/`、`asr.mjs --out`)都完整收监。 - **不会静默覆盖任何东西。** `init-project.mjs` 对非空目标目录直接拒绝(重新初始化需 `--force`,且只重置它自己生成的 5 个文件);`fetch-official-images.mjs` 与 `prep-image.mjs` 覆盖已存在文件需 `--force`,下载默认收在工作目录内。`--upgrade-css` 更新 tokens.css 里**唯一的 tokens 受管区**(技能生成的整段主体:主题令牌 / `--fs-*` 字号 / fx 关键帧与工具类 / `.fx-stagger`,三个工具箱子块嵌在其中)时按 rev 原地替换。区外还留着的旧副本**按条清理**:逐字来自模块原文的规则会被删掉(它们在层叠上会压过受管区),你自己的规则(包括紧挨副本的一两条覆写)保留并报出;写前先备份 `tokens.css.bak`。你自己的规则要写在**受管区之后**,否则受管区的值优先。`--check-css` 只查不改。 -- **不存储、不内嵌任何凭据**:默认 mmx 提供方下脚本完全不接触 Key(mmx 自己持有登录);`--provider api` 路径运行时从 `MINIMAX_API_KEY` 或 `--api-key` 读取,且从不写出到任何文件。 +- **不存储、不内嵌任何凭据**:默认 mmx 提供方下脚本完全不接触 Key(mmx 自己持有登录);`--provider api` 路径运行时从 环境变量 `MINIMAX_API_KEY` 读取(拒绝命令行 Key),且从不写出到任何文件。 - `KIT_PROJECT_DIR` 是内部变量,由 CLI 入口自动设置,让共用助手能定位项目目录;用户永远不需要自己设置。 +仓库开发环境请在仓库根运行 `npm ci --ignore-scripts`;CI 同样使用已提交的锁文件。 + ## 验证 技能自带可执行测试(`skills/html2video-for-mcode/tests/`,纯 `node:test`,无额外依赖): ```bash -# MiniMax-Code-Plugins monorepo(插件 PR 语境), 在仓库根执行: -node --test "plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode/tests/*.test.mjs" # 本仓库的独立 clone, 在仓库根执行(技能在 skills/ 子目录下): node --test "skills/html2video-for-mcode/tests/*.test.mjs" ``` -十五个文件共 285 例:`safe-paths`(恶意 slide id / 路径、canary 完好性、符号链接逃逸 —— 含**悬空**链接必须被拦下,而不是当"不存在"跳过)、`no-clobber`(覆盖拒绝)、`endpoint-allowlist`(Key 不离开官方域,并用本地服务器证明闸门在请求之前;外加提供方选择:`mmx speech transcribe` 缺省与 `--provider api` 后备,mmx shim 集成对断言参数映射与临时目录中转/清理)、`fetch-policy`(SSRF、`file://`、重定向与文件名规则、**IPv4-mapped IPv6 十六进制形式**)、`connect-binding`(DNS 失败即拒(fail-closed),SSRF 否决挂到**建连那次** lookup —— 出网走 `policyGet`、浏览器流量走本地否决代理;rebinding 用例以"目标收到 **0 个请求**"为判据)、`preview-page`(快照注入实测延迟、`base` 顺序、自包含无外链、越界拒绝、无计时器、**竖版画布、iframe 强制相对解析**)、`tokens-fx`(模板里每个入场动画的关键帧必须声明 `opacity`、`no-fx` 必须重置基础态、`--upgrade-css` 幂等)、`chart-kit`(模板里真带着图表工具箱:keyframes / 注册属性 /「关动效 = 终态」不变量)、`table-kit`(表格原语的可读性硬指标:正文号、行高 ≥72px、涨跌走令牌、矩阵高亮列覆盖表头)、`css-kit`(**整段受管区**:陈旧 / 缺失 / 重复 / 定界符被改坏 / 区外还留着旧副本, 五种都要检出并原地修好 —— 区外副本会在层叠上压过受管区, 这正是本轮重写的起因; 项目端覆写按条保留、老格式裸文本原地包裹而不重复、`--check-css` 退出码、CRLF 不误报、病态互踩一次到位、超大输入拒绝 —— 外加复查在新机制自己身上揪出的两个假绿灯: 受管区是最新的、但区外还留着一份**主体副本**时以前报 `ok`(现在按主体形状识别并报 `legacy-outside`); 项目覆写的 `ok` 提示会点名它**在受管区之前还是之后**(之前则层叠上输, 之后才赢))与 `render-smoke`(init → 对时 → 静态闸门 → 截图 → 成片全链,**still 复截后静态回退必须点名警告**,外加**升级前后画面真的变了的像素级证明**), 以及 capture 的布局几何自检(溢出/顶部被裁点名数字)与骨架 safe center 契约。`review-round2`(输出收监 canary:项目内符号链接不得写到项目外;本地服务器证明被拒目标收到 0 个请求;单引号属性;ASR 请求失败必须计入失败;项目内 ffmpeg 发现)与 `cover-transition`(封面 + `attached_pic` 流 + 首帧非黑 + 硬切/溶解两种模式下切页点均无黑帧且总时长不变)与 `review-round3`(七个功能缺陷:`--calibrate` 不许写回半份实测、`--topic <值> <项目目录>` 不许把值当目录、`--json` 位置无关、`--min WxH`、`--get` 全失败退非零、`capture --mode/--dsf` 与 `grab-frames --at` 在入口拒绝非法值、字幕带闸门只对定位元素生效、`--dry-run` 打完计划必须退 0、裸字符串 `transition` 在闸门与渲染器里同义;以及 check-slides / capture / build-video 的陈旧 CSS 闸门, 外加图表结构闸门: 百分比柱体裸放 flex column 会被点名(flex-shrink 压扁, 应包进 .chart-plot-cell))与 `subtitles-invalidate`(删掉 clauses 或 `--no-subs` 重建后, 成片里不得再有旧字幕 —— 像素级断言; 外加字幕关键帧形状不变量、静帧满亮/跨句残留判据、以及封面/静帧基底不得烙字幕(2026-09-22 字幕回归);全套用例需要装好 ffmpeg、ffprobe 与 Chromium(`PATH` 上,或本仓/项目 `node_modules` 里 —— `npm i ffmpeg-static ffprobe-static playwright`):缺了它们,需要这些工具的用例会**带着明确原因跳过**(缺工具、文件系统不允许建 junction),不会假装通过;渲染脚本本身则会明确报 `找不到 ffmpeg` 退出,不会假装跑完半条流水线。scoped workflow `.github/workflows/html2video-for-mcode-smoke.yml`(**位于 MiniMax-Code-Plugins monorepo**)会在插件 PR 与 main 上装齐依赖并把全部用例真跑一遍。 +测试覆盖:`safe-paths`(恶意 slide id / 路径、canary 完好性、符号链接逃逸 —— 含**悬空**链接必须被拦下,而不是当"不存在"跳过)、`no-clobber`(覆盖拒绝)、`endpoint-allowlist`(Key 不离开官方域,并用本地服务器证明闸门在请求之前;外加提供方选择:`mmx speech transcribe` 缺省与 `--provider api` 后备,mmx shim 集成对断言参数映射与临时目录中转/清理)、`fetch-policy`(SSRF、`file://`、重定向与文件名规则、**IPv4-mapped IPv6 十六进制形式**)、`connect-binding`(DNS 失败即拒(fail-closed),SSRF 否决挂到**建连那次** lookup —— 出网走 `policyGet`、浏览器流量走本地否决代理;rebinding 用例以"目标收到 **0 个请求**"为判据)、`preview-page`(快照注入实测延迟、`base` 顺序、自包含无外链、越界拒绝、无计时器、**竖版画布、iframe 强制相对解析**)、`tokens-fx`(模板里每个入场动画的关键帧必须声明 `opacity`、`no-fx` 必须重置基础态、`--upgrade-css` 幂等)、`chart-kit`(模板里真带着图表工具箱:keyframes / 注册属性 /「关动效 = 终态」不变量)、`table-kit`(表格原语的可读性硬指标:正文号、行高 ≥72px、涨跌走令牌、矩阵高亮列覆盖表头)、`css-kit`(**整段受管区**:陈旧 / 缺失 / 重复 / 定界符被改坏 / 区外还留着旧副本, 五种都要检出并原地修好 —— 区外副本会在层叠上压过受管区, 这正是本轮重写的起因; 项目端覆写按条保留、老格式裸文本原地包裹而不重复、`--check-css` 退出码、CRLF 不误报、病态互踩一次到位、超大输入拒绝 —— 外加复查在新机制自己身上揪出的两个假绿灯: 受管区是最新的、但区外还留着一份**主体副本**时以前报 `ok`(现在按主体形状识别并报 `legacy-outside`); 项目覆写的 `ok` 提示会点名它**在受管区之前还是之后**(之前则层叠上输, 之后才赢))与 `render-smoke`(init → 对时 → 静态闸门 → 截图 → 成片全链,**still 复截后静态回退必须点名警告**,外加**升级前后画面真的变了的像素级证明**), 以及 capture 的布局几何自检(溢出/顶部被裁点名数字)与骨架 safe center 契约。`review-round2`(输出收监 canary:项目内符号链接不得写到项目外;本地服务器证明被拒目标收到 0 个请求;单引号属性;ASR 请求失败必须计入失败;项目内 ffmpeg 发现)与 `cover-transition`(封面 + `attached_pic` 流 + 首帧非黑 + 硬切/溶解两种模式下切页点均无黑帧且总时长不变)与 `review-round3`(七个功能缺陷:`--calibrate` 不许写回半份实测、`--topic <值> <项目目录>` 不许把值当目录、`--json` 位置无关、`--min WxH`、`--get` 全失败退非零、`capture --mode/--dsf` 与 `grab-frames --at` 在入口拒绝非法值、字幕带闸门只对定位元素生效、`--dry-run` 打完计划必须退 0、裸字符串 `transition` 在闸门与渲染器里同义;以及 check-slides / capture / build-video 的陈旧 CSS 闸门, 外加图表结构闸门: 百分比柱体裸放 flex column 会被点名(flex-shrink 压扁, 应包进 .chart-plot-cell))与 `subtitles-invalidate`(删掉 clauses 或 `--no-subs` 重建后, 成片里不得再有旧字幕 —— 像素级断言; 外加字幕关键帧形状不变量、静帧满亮/跨句残留判据、以及封面/静帧基底不得烙字幕(2026-09-22 字幕回归);全套用例需要装好 ffmpeg、ffprobe 与 Chromium(`PATH` 上,或本仓/项目 `node_modules` 里 —— `npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0 playwright@1.63.0`):缺了它们,需要这些工具的用例会**带着明确原因跳过**(缺工具、文件系统不允许建 junction),不会假装通过;渲染脚本本身则会明确报 `找不到 ffmpeg` 退出,不会假装跑完半条流水线。本仓库的 `.github/workflows/ci.yml` 会在 Linux 与 Windows 上运行全部测试。 ## 排错 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d160dc0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,47 @@ +{ + "name": "html2video-for-mcode", + "version": "1.9.20", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "html2video-for-mcode", + "version": "1.9.20", + "devDependencies": { + "playwright": "1.63.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..87d66fd --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "html2video-for-mcode", + "version": "1.9.20", + "private": true, + "type": "module", + "scripts": { + "test": "node --test" + }, + "devDependencies": { + "playwright": "1.63.0" + }, + "engines": { + "node": ">=20" + } +} diff --git a/plugin.json b/plugin.json index 79d9003..4f312a8 100644 --- a/plugin.json +++ b/plugin.json @@ -1,14 +1,14 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "html2video-for-mcode", - "version": "1.9.18", + "version": "1.9.20", "description": "Turn a topic, outline, or script into a narrated MP4: HTML slides with staged entrance animations, TTS voiceover, ffmpeg assembly, and ASR verification.", "author": { "name": "Wzdhehe", "url": "https://github.com/Wzdhehe" }, - "homepage": "https://github.com/MiniMax-AI/MiniMax-Code-Plugins/tree/main/plugins/Wzdhehe/html2video-for-mcode", - "repository": "https://github.com/MiniMax-AI/MiniMax-Code-Plugins", + "homepage": "https://github.com/Wzdhehe/html2video-for-mcode", + "repository": "https://github.com/Wzdhehe/html2video-for-mcode", "license": "MIT", "keywords": [ "video", diff --git a/skills/html2video-for-mcode/SKILL.md b/skills/html2video-for-mcode/SKILL.md index 5852711..363aeab 100644 --- a/skills/html2video-for-mcode/SKILL.md +++ b/skills/html2video-for-mcode/SKILL.md @@ -7,6 +7,23 @@ description: Turn a script/outline/topic into a finished MP4 with Chinese voiceo Turn a topic/outline into a publishable MP4 (default 1920×1080, switchable to 1080×1920 vertical): HTML slides (staged entrance animations) + Chinese TTS narration + ffmpeg assembly + reverse ASR verification. +Community plugin maintained by Wzdhehe. Source: https://github.com/Wzdhehe/html2video-for-mcode. +This is not an official MiniMax plugin; marketplace acceptance is subject to review. + +**Installation and credentials:** prefer project-local dependencies and retain the generated +`package-lock.json`; repeat installs with `npm ci`. All npm package examples below use exact +versions. Before any global install or upgrade, explain the package, version, and system-wide +change and obtain explicit user consent. Only then may you run `npm install -g mmx-cli@1.0.26`. +Use an existing `mmx auth login` session or provide `MINIMAX_API_KEY` through the environment. +Never ask users to paste keys into chat, command arguments, source files, or project files. + +**Asset authorization:** default to typography and CSS/SVG charts. News images, article screenshots, +and real-person portraits are disabled by default. Before downloading or using any external asset, +have the user confirm permission for the intended use and record its source, license or permission +evidence, attribution requirements, and user confirmation in `assets/MANIFEST.md`. +An official site or a user-supplied file does not by itself establish reuse permission. +If permission is missing or unclear, use typography instead. + ## The four iron rules (violate any one and the output is guaranteed to be reworked) 1. **All durations come only from ffprobe measurements; never write them by hand.** Each slide's duration = that segment's measured TTS duration + tail padding (default 0.8s). Don't estimate, don't round, don't hard-code. @@ -28,7 +45,7 @@ Turn a topic/outline into a publishable MP4 (default 1920×1080, switchable to 1 | **Canvas and platform (aspect ratio)** | Landscape 1920×1080 (default, suits Bilibili/official sites) or vertical 1080×1920 (Douyin/WeChat Channels/Xiaohongshu); vertical needs a stacked layout | | Approximate duration | Default ~60s (6–10s per slide × 8 slides); short-video platforms can compress it to 30s; offer a range for the user to pick | | **TTS voice and speed (rough direction)** | ①**Gender/voice direction**: male / female / neutral × warm / crisp / magnetic / lively; ②**speed**: normal (**default 1.1**, ≈5.3 Chinese characters/sec) / a bit slower / a bit faster. A rough direction is enough — Phase 2 auditions 3 candidate voices, and **plays the same sentence at all three speeds (1.05/1.15/1.25) alongside them so the two are decided together** (see tts-and-timing.md); once decided, write it into `speed` in `script.json` and restate it | -| **Images and asset boundaries** | First ask **whether to use images at all**: pure typography, no images (number cards + large type + quotes) / allow official images pulled from the web (default) / only user-provided assets. **For negative-event subjects (blow-ups/penalties/lawsuits/controversies), add: do you want announcement or news-report screenshots as illustrations** (default suggestion: yes, 1–2; discipline in image-sources.md path D). The specifics — "which ones to use, what still needs to be supplied" — are left to the Gate 3 asset confirmation | +| **Images and asset boundaries** | Ask whether to use typography and CSS/SVG charts (default), user-provided assets, or external assets. News images, article screenshots, and real-person portraits are disabled by default. Before downloading or using an asset, require the user to confirm permission for the intended use, including portrait consent where applicable. Record evidence and confirmation in MANIFEST; unclear permission means typography fallback. Gate 3 confirms the final selection. | ## Contents and tools @@ -47,30 +64,30 @@ The skill ships with **12 command-line scripts + 8 internal modules** (call them | `scripts/preview-page.mjs [--open] [--no-script]` | Generates the **play page** `preview/play/index.html` (single file, no CDN/server — double-click to view over file://; the snapshot copies read the project's slides/ via ``, so share the project directory or at least `play/`, not `index.html` alone): **with animations on, ←→/touch swipe step through the entrance level by level** — each press of → reveals the next level (a sub-heading or small chart animates in on the spot), and only after the last level does it turn the page; with animations off it just turns pages. X toggles animations on/off, P toggles narration on/off (all toggles are buttons in the bottom bar, and the label text literally reads "动效开/动效关" "口播开/口播关" — animations on/off, narration on/off; the top bar keeps only the page number), O overview, F fullscreen. **Frame switching is double-buffered with no white flash; UI text adapts between Chinese and English per the `lang` in script.json**. **It does only one thing: "show the frame"** — no timer/progress bar/read-along highlight/replay button (to see timing, watch the finished video). Space/PageDown/PageUp/Home/End/Esc all work (the footer lists every key; pressing →/← at the first/last frame flashes an "already first/last" hint instead of doing nothing). Overview thumbnails travel inside `play/thumbs/` (copied from `preview/*.png` at generation; slides without a capture get a counted placeholder and a terminal warning). External automation should use the **`window.playPage` API** (`state` getter + `go/next/prev/setFx/setNarr/setTrans/overview`) instead of simulating keys and scraping `innerText`. Snapshots inject the measured delays from `timings.json` (the level-by-level animation shares its source with the finished video); the narration panel decides automatically from the data whether to load at all, collapses into a bottom drawer with default-collapsed state in narrow windows/on phones, and the canvas adapts to landscape or vertical | | `scripts/build-video.mjs [--asr] [--dry-run] [--transition cut|xfade]` | Encodes each slide → concatenates → aligns the audio track → muxes → self-checks + emits `out/subs.srt`; `--asr` splits the audio **by sentence** + generates a checklist; `--dry-run` only prints the ffmpeg commands that would run (for troubleshooting). **Transitions default to a hard cut** (no black frame between segments; the first segment dissolves in from the cover and the last fades out), and `--transition xfade` or `transition` in `script.json` switches to a 0.4s cross-dissolve (the dissolve eats the extra frames kept at the end of each segment, so the total duration is unchanged). When subtitle stills exist it splices as "frame-sequence segments + subtitle segments" (the segment lengths must sum exactly to the slide's duration) | | `scripts/grab-frames.mjs [--ids 05,11] [--at 0.5] [--both]` | **Finished-video frame extraction check**: compute each slide's absolute start from `timings.json` and pull frames from `out/final.mp4` into `build/introspect/` — problems like a caption covered by subtitles, the last-level element missing from the frame, or too little still time at the end are "invisible in a still, only visible in the finished video", so go through them slide by slide before publishing | -| `scripts/asr.mjs [--provider mmx\|api] [--api-key K] [--verify-timing] [--from ] [--allow-any-endpoint]` | Calls ASR to transcribe and verifies sentence by sentence whether the audio says what the script says (mismatched numbers/traditional characters count as ✗); `--verify-timing` uses character-level timestamps to measure sentence onset. Defaults to `mmx speech transcribe` (mmx-cli ≥ 1.0.26, same login as TTS — no key handling here); `--provider api` calls REST directly instead, and then the key is only ever sent to official domains | +| `scripts/asr.mjs [--provider mmx\|api] [--verify-timing] [--from ] [--allow-any-endpoint]` | Calls ASR to transcribe and verifies sentence by sentence whether the audio says what the script says (mismatched numbers/traditional characters count as ✗); `--verify-timing` uses character-level timestamps to measure sentence onset. Defaults to `mmx speech transcribe` (mmx-cli ≥ 1.0.26, same login as TTS — no key handling here); `--provider api` calls REST directly instead, and then the key is only ever sent to official domains | Internal modules (imported by the scripts above, never run on their own): `tools.mjs` (ffmpeg/ffprobe probing + path jail `safeId/safeRel/inside`), `url-policy.mjs` (ASR endpoint allowlist + SSRF/redirect policy — DNS fails closed, and the veto rides the connection's own lookup: `checkedLookup`/`policyGet` for downloads, a loopback veto proxy for browser traffic — plus download filenames), `nofx-css.mjs` (single source of truth for the `no-fx` rules), `chart-css.mjs` (single source of truth for chart animations and chart primitives), `table-css.mjs` (table primitives: `.tbl/.kv/.matrix/.rank`), `css-kit.mjs` (the **managed-region mechanism**: rev delimiter comments + `findAllBlocks` + in-place replacement + the status vocabulary `ok`/`stale`/`duplicate`/`broken`/`legacy-outside`/`missing`, shared by `--upgrade-css`/`--check-css`/check-slides/preview-page/capture/build-video), `tokens-template.mjs` (the single source of the generated tokens.css body + its content hash `TOKENS_REV`), `limits.mjs` (the 2 MB scan cap that applies to both tokens.css and slide HTML). The whole generated body is wrapped in a `tokens` managed region **with the three toolkit blocks nested inside**, so after any source module changes, `--upgrade-css` propagates exactly into old projects; `BLOCK_IDS` in css-kit is the single list of region ids. -Requirements: Node 18+ (scripts use fileURLToPath for compatibility, so they don't depend on Node 20.11's import.meta.dirname), `npm i playwright && npx playwright install chromium` (inside the project directory). ffmpeg/ffprobe are auto-detected: PATH → node_modules (ffmpeg-static/ffprobe-static) → common install locations; if they can't be found you get item-by-item diagnostics instead of a cryptic error. +Requirements: Node 20+ (required by pinned Playwright 1.63.0), `npm i --save-exact playwright@1.63.0 && npx --no-install playwright install chromium` (inside the project directory). ffmpeg/ffprobe are auto-detected: PATH → node_modules (ffmpeg-static/ffprobe-static) → common install locations; if they can't be found you get item-by-item diagnostics instead of a cryptic error. ## Installing into other Agent environments -This skill is the standard "one folder + SKILL.md at the root" shape (the frontmatter `name` / `description` are already written to spec), so dropping it into the corresponding skills directory is enough for it to be discovered. **Copy the reviewed skill directory out of the hosted plugin — not from any other source**: the hosted directory is the publication unit, and a copy taken from anywhere else has not been reviewed. +This skill is the standard "one folder + SKILL.md at the root" shape (the frontmatter `name` / `description` are already written to spec), so dropping it into the corresponding skills directory is enough for it to be discovered. **Copy the skill directory from the real source repository, Wzdhehe/html2video-for-mcode.** ```bash -# from a checkout of the MiniMax-Code-Plugins repository: -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode ~/.claude/skills/ # Claude Code (personal scope) / OpenClaw / other AgentSkills hosts +# from a checkout of Wzdhehe/html2video-for-mcode: +cp -r skills/html2video-for-mcode ~/.claude/skills/ # Claude Code (personal scope) / OpenClaw / other AgentSkills hosts # project-scope install -cp -r plugins/Wzdhehe/html2video-for-mcode/skills/html2video-for-mcode /.claude/skills/ +cp -r skills/html2video-for-mcode /.claude/skills/ ``` After installing, you only need to add two **dependencies** (in your video project, not in the skill directory): ```bash cd -npm i playwright && npx playwright install chromium # for screenshots +npm i --save-exact playwright@1.63.0 && npx --no-install playwright install chromium # for screenshots # ffmpeg, pick one: winget install Gyan.FFmpeg / brew install ffmpeg / apt install ffmpeg -# or: npm i ffmpeg-static ffprobe-static +# or: npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0 ``` **Why the skill still runs when installed elsewhere**: `scripts/tools.mjs` resolves `playwright` through a list of anchors — "the skill's own location → the project directory → the working directory at call time → npm global"; ffmpeg/ffprobe are likewise probed in four tiers (PATH → the project's node_modules → two levels up from the skill → common install locations). So "skill in `~/.claude/skills/`, dependencies in the project" is a supported setup (measured: the skill still renders images even when it lives outside the project tree). @@ -90,7 +107,7 @@ The script layer (screenshots / rendering / compositing / validation / images) i | Image assets | Built-in browser inspecting the official site's DOM (preferred; take the image URL to disk with `scripts/fetch-official-images.mjs --url`) / official brand kit | Same image paths as on the left (in this environment use `fetch-official-images`, which ships its own Playwright headless browser for rendering pages); for abstract illustrations use `mmx image generate --prompt "..." --aspect-ratio 16:9 --n 3` (use `9:16` for vertical projects; **abstract concept images only — generating logos / screenshots / real people's faces is forbidden**), then register it per `image-sources.md` | | Research | `web_search` / `web_fetch` (built in); for SPA/JS-rendered pages open them in the **built-in browser** to read the body text (usage discipline in references/research.md) | `mmx search ""` / `mmx text chat`; for SPA pages render the body text with the project's Playwright **headless browser** (minimal command in research.md) | -**First-time mmx-cli setup** (non-mcode environments): `npm install -g mmx-cli` (TTS works on any version; ASR needs ≥ 1.0.26 for `speech transcribe`) → `mmx auth login --api-key sk-xxx` → verify with `mmx quota`. A 401 is usually a region mismatch: `mmx config set --key region --value cn|global`. On the script side, ASR reuses that same mmx login; set `MINIMAX_API_KEY` (+ `MINIMAX_REGION=cn|global`) only if you force the direct-REST path (`--provider api`). +**First-time mmx-cli setup** (non-mcode environments): prefer an existing installation. If it is missing or older than 1.0.26, explain the global change and obtain explicit user consent before `npm install -g mmx-cli@1.0.26`. The user signs in with `mmx auth login` locally; verify with `mmx quota`. For REST, read only `MINIMAX_API_KEY` from the environment. Do not supply a key in command arguments or ask for it in chat. A 401 may be a region mismatch: `mmx config set --key region --value cn|global`. **Discipline does not change with the environment**: durations still come from ffprobe measurements, subtitles still come from `clauses[]`, voices still have to be auditioned and language-verified (mcode sandbox: `mcode-tools upload_temp_url` + `connector__matrix__listen_audio`; other environments: `asr.mjs` above), and no Gate is skipped. **Search and body-text extraction are not limited to the tools in the table above either**: if other search skills/plugins are installed locally (web search, web reading, etc.), or any headless browser (the project's Playwright counts), use whichever one can get the body text — only the tool changes; source grading, two-source cross-checking and scope annotation are not negotiable. @@ -181,14 +198,14 @@ Optional but recommended (especially when the user has reported "audio and visua Follow the image SOP in `references/image-sources.md` (core principle: **for images with an incomplete subject / cut off halfway / wrong aspect, search again for the full view first — don't force a crop**). Key points: 1. Write the requirements list (which slides need images, and what kind). -2. **Priority: official channels (brand kit / simple-icons / official documentation screenshots) → open the official site in the built-in browser or Playwright and inspect the DOM for official assets (highest measured success rate) → Wikipedia CC → pure-typography fallback (number cards + large type + quotes, no images). Negative-event subjects (blow-ups / penalties / lawsuits / controversies) won't have assets on the official site, so switch to **announcement and news-report screenshots**: exchange/regulatory announcements, company statements, or screenshots of mainstream media report pages (top-tier authorities and portals like Tencent News/Sina are both fine; self-media excluded), and the frame must keep the outlet name and date (commands and discipline in image-sources.md path D).** The old image-downloader (Bing) is off by default: on niche Chinese-language subjects it returned irrelevant images 5/5 times. +2. **Authorization before acquisition:** default to typography and CSS/SVG charts. Only after the user confirms permission for the intended use may you fetch an official brand kit, official-site image, or individually licensed image. News images, report screenshots, and real-person portraits require explicit opt-in and documented permission before downloading; they are never automatic fallbacks for negative-event topics. Record license evidence, attribution, and user confirmation in MANIFEST. 3. Add positive keywords when searching for images (panorama/full view/front view/wide shot), and screen with thumbnails before downloading: subject centered, aspect close, no watermark, no unrelated logos, ≥1200px; if one doesn't fit, swap it — don't settle. 4. Once you have an image, first run `node <技能>/scripts/prep-image.mjs --check <图>` to check dimensions and crop risk; if the subject touches the edge, swap the image. -5. Compliance-check every asset: no watermark, trademarks only in a fair-use context, photos from licensable sources, screenshots (official docs or news/announcements) must keep their source and date and be registered in MANIFEST. +5. Compliance-check every asset: no watermark, trademarks only with user-confirmed permission for the intended use, photos with documented authorization, screenshots (official docs or news/announcements) must keep their source and date and be registered in MANIFEST. 6. Save to `assets/`, one line per asset in `assets/MANIFEST.md` (content/source/license). 7. **Generating logos, screenshots, avatars or QR codes out of thin air is forbidden; putting watermarked images into assets is forbidden; dropping a bare `` is forbidden (it must be wrapped in `.img-frame`).** -**Gate 3** (after asset collection is done and both the facts and candidate images are in hand): give the user the asset-list table + a preview of each asset (thumbnail/description), and ask three things: ① **which ones to use** — have the user pick slide by slide (annotate recommended usage, e.g. "slide 02 with the hero image"); whatever they cross out is dropped; ② **is there anything to add** — links (official pages/report pages/data pages), screenshots, logos, pictures, data files, reference narration scripts can all be handed to the agent directly; **user-provided assets have the highest priority** (they save searching and the source is reliable): images go to `assets/`, pass `prep-image --check`, and are registered in MANIFEST as "source: user-provided"; links are saved to disk per image-sources.md paths A/B/D or used as Gate 0 fact sources; ③ "are the asset sources and licensing fine". **Only write the HTML after the user has signed off.** +**Gate 3** (after asset collection is done and both the facts and candidate images are in hand): give the user the asset-list table + a preview of each asset (thumbnail/description), and ask three things: ① **which ones to use** — have the user pick slide by slide (annotate recommended usage, e.g. "slide 02 with the hero image"); whatever they cross out is dropped; ② **is there anything to add** — links (official pages/report pages/data pages), screenshots, logos, pictures, data files, reference narration scripts can all be handed to the agent directly; **user-provided assets have priority after the user confirms permission for the intended use**: images go to `assets/`, pass `prep-image --check`, and are registered in MANIFEST as "source: user-provided"; links are saved to disk per image-sources.md paths A/B/D or used as Gate 0 fact sources; ③ "are the asset sources and licensing fine". **Only write the HTML after the user has signed off.** ### Phase 4 · HTML (staged entrance is implemented here) diff --git a/skills/html2video-for-mcode/evals/evals.json b/skills/html2video-for-mcode/evals/evals.json index a368dcf..9523284 100644 --- a/skills/html2video-for-mcode/evals/evals.json +++ b/skills/html2video-for-mcode/evals/evals.json @@ -40,7 +40,7 @@ "id": 5, "name": "asset-gate-browser-route", "prompt": "做一条介绍某中国 AI 公司的视频, 需要他们的 logo、CEO 照片和产品截图。素材这块你怎么弄?", - "expected_output": "按优先级执行: 官方渠道(brand kit/simple-icons/官方文档截图)优先; 缺的用内置浏览器或 Playwright 打开官网 inspect DOM 提取官方 CDN 资源(2026-09 实测中国 AI 公司 6/6 相关); image-downloader(Bing)默认不用(中文题材实测系统性返回无关图); 每个素材查合规(水印/商标语境/照片授权/截图出处), 落盘 assets/ 并逐条登记 MANIFEST.md; 素材清单+预览过 Gate 3, 明确问用户来源与授权是否 OK, 过了才写 HTML。禁止凭空造图; 无合适素材降级纯排版。", + "expected_output": "默认纯排版与 CSS/SVG 图表。用户明确选择外部素材时,下载前先确认每份素材用于本次用途的授权;CEO 肖像还需确认相应肖像使用许可。官方来源或用户提供不自动等于授权。确认后才从 brand kit、官网或单独许可来源获取;逐条在 MANIFEST 记录来源、许可/授权证据、署名要求、用户确认。Gate 3 确认最终选择后写 HTML。授权不明则用文字引语/图表,不自动抓新闻图片、报道截图或真人肖像,不以概括性法律豁免代替授权。", "files": [] }, { @@ -75,7 +75,7 @@ "id": 10, "name": "image-sourcing-sop", "prompt": "配一张学校大门的实景图, 搜到的图主体都在画面边缘或者只有半截, 比例也不对。怎么办?", - "expected_output": "按 references/image-sources.md 的 SOP: 核心原则是'先重搜全貌图, 别硬裁硬用'。query 加正向词(全景/全貌/正面/远景)排除词(特写/近景/一角/半截); 下载前缩略图筛(主体居中/比例接近/无水印无无关logo/≥1200px), 不合适就换; 拿到图跑 prep-image.mjs --check; 图片一律套 .img-frame, 用 --img-pos 控制主体可见区或 .contain 留白, 不要裸放 img 或硬裁(裁切硬限: 裁掉≤20%、不放大补边); 都不行就换题材(数字卡/大字/引言)。", + "expected_output": "先由用户确认本次用途的素材授权,再按 references/image-sources.md 检查构图:优先找全貌图,检查主体、比例、清晰度;用 prep-image --check 校验,套 img-frame/contain 控制展示,裁切不超过20%,不得裁掉水印或署名来绕过限制;授权不明或构图不合适则退回纯排版。", "files": [] }, { @@ -96,14 +96,14 @@ "id": 13, "name": "non-mcode-environment-via-mmx", "prompt": "我在 Claude Code 里, 没有 mcode 的 connector。这个技能还能跑吗? TTS 和 ASR 怎么办?", - "expected_output": "能跑 —— 脚本层(截图/渲染/合成/校验/配图)完全环境无关, 只有 TTS/音乐/ASR 依赖平台。TTS 用 mmx-cli: mmx speech synthesize --text ... --voice --speed 1.1 --out audio/01.mp3(音色 mmx speech voices); ASR 用技能自带 node scripts/asr.mjs <项目>(同一把 API Key 直调 /v1/speech_to_text, 自动比对 checklist, 数字/繁体字不符判 ✗); 音乐生成 mmx-cli 没有 → 用户自备或跳过; 配图可用 mmx image(仅限抽象图, 禁生成 logo/截图/真人头像)。首次配置 npm i -g mmx-cli + mmx auth login, 401 时设 region。纪律不变: 时长实测、字幕来自 clauses、音色要试听验语种、Gate 不跳。", + "expected_output": "能跑 —— 脚本层(截图/渲染/合成/校验/配图)完全环境无关, 只有 TTS/音乐/ASR 依赖平台。TTS 用 mmx-cli: mmx speech synthesize --text ... --voice --speed 1.1 --out audio/01.mp3(音色 mmx speech voices); ASR 用技能自带 node scripts/asr.mjs <项目>(默认复用 mmx 登录转写;REST 后备只读环境变量 MINIMAX_API_KEY,自动比对 checklist,数字/繁体字不符判 ✗); 音乐生成 mmx-cli 没有 → 用户自备或跳过; 配图可用 mmx image(仅限抽象图, 禁生成 logo/截图/真人头像)。优先复用已有 mmx 登录;如需安装或升级,说明全局影响并取得用户明确同意后才 npm i -g mmx-cli@1.0.26,随后由用户本机 mmx auth login;禁止把 Key 放进命令参数或聊天, 401 时设 region。纪律不变: 时长实测、字幕来自 clauses、音色要试听验语种、Gate 不跳。", "files": [] }, { "id": 14, "name": "asr-rest-and-timing-verify", "prompt": "ASR 校验怎么跑? 我想顺便确认动画到底有没有对上口播。", - "expected_output": "build-video --asr 先按句切出 asr/part--.mp3; 然后 MINIMAX_API_KEY=sk-xxx node scripts/asr.mjs <项目> 直调 REST 转写, 自动与 checklist 预期文本比对并回填(数字/繁体字不符 → ✗ 非 0 退出; 超 500s/50MB 自动转码)。要确认对轴: node scripts/asr.mjs <项目> --verify-timing 用接口的字级时间戳(verbose_json + timestamp_level=word)实测每句开口, 与 timings.json 的 clauses[].start 对比; 偏差大就校准后重渲染。也可先用 check-timing.mjs(静音法, 离线免费)。", + "expected_output": "build-video --asr 先按句切出 asr/part--.mp3; 然后使用已有 mmx 登录运行 node scripts/asr.mjs <项目>;REST 后备需先通过环境提供 MINIMAX_API_KEY,再加 --provider api;禁止 --api-key 或 --api-key= 参数,禁止将 Key 放进聊天或项目文件。转写后, 自动与 checklist 预期文本比对并回填(数字/繁体字不符 → ✗ 非 0 退出; 超 500s/50MB 自动转码)。要确认对轴: node scripts/asr.mjs <项目> --verify-timing 用接口的字级时间戳(verbose_json + timestamp_level=word)实测每句开口, 与 timings.json 的 clauses[].start 对比; 偏差大就校准后重渲染。也可先用 check-timing.mjs(静音法, 离线免费)。", "files": [] }, { diff --git a/skills/html2video-for-mcode/references/authoring.md b/skills/html2video-for-mcode/references/authoring.md index 307d1bc..2f42736 100644 --- a/skills/html2video-for-mcode/references/authoring.md +++ b/skills/html2video-for-mcode/references/authoring.md @@ -74,11 +74,13 @@ Type discipline: at most two levels on screen at once per slide (title + one sec ## Asset acquisition (Phase 3 · Gate 3) +Default to typography and CSS/SVG charts. Before downloading or using external assets, require user confirmation of permission for the intended use and log evidence, attribution, and confirmation in MANIFEST. News images, screenshots, and real-person portraits require explicit opt-in. Official hosting and user-provided files do not establish permission. + Process: list the requirements (which slides need images, and what) → source by the priority order below → compliance self-check → write to disk under `assets/` and register in `MANIFEST.md` → **present Gate 3 to the user**. **Sourcing priority (step down level by level, never force it):** -1. **Official channels (first choice)**: logos from the official brand kit or simple-icons (curl-able); product screenshots taken from official help/docs; data from official reports. Strongest compliance; for factual subjects try to stop at this level. +1. **Official channels (first choice)**: logos from the official brand kit or simple-icons (curl-able); product screenshots taken from official help/docs; data from official reports. Check the individual license and user-confirmed authorization before downloading. 2. **Extract from the official site with a built-in browser / Playwright (measured and recommended, 2026-09)**: open the official site or official news page with the agent's built-in browser or Playwright, inspect the DOM and extract ``/`` assets (verify the src is an official CDN domain, then write to disk with `fetch-official-images.mjs --url --out-dir assets` —— the same host/size/filename validation set). Measured on Chinese AI-company subjects: 6/6 all relevant, far better than image-search engines. If the user chose "official assets only / pure layout" during kickoff alignment, skip this whole level. 3. **Pure-layout fallback (the fallback that is always available)**: large type + number cards + colour + the expressive power of the layout itself. Better to omit than to fake —— when no suitable asset exists, use this level; the frame still holds up. @@ -86,7 +88,7 @@ Process: list the requirements (which slides need images, and what) → source b **Compliance self-check (run through it for every asset):** -- No watermarks. For a watermarked candidate: use a different image, or crop inside the watermark; if you cannot crop it out, do not use it. +- No watermarks. Replace a watermarked candidate with an authorized asset; do not crop out watermarks or attribution to bypass restrictions. - Trademarks/logos are used only in the legitimate reference context of "talking about that brand", never as decorative filler. - Photos must come from licensable sources (official press images, CC-licensed, free stock libraries); for celebrity/people photos with no verifiable licence, prefer a text-only quotation card. - Screenshots state their source (official doc name + date). diff --git a/skills/html2video-for-mcode/references/image-sources.md b/skills/html2video-for-mcode/references/image-sources.md index abb189a..40e1dbb 100644 --- a/skills/html2video-for-mcode/references/image-sources.md +++ b/skills/html2video-for-mcode/references/image-sources.md @@ -3,14 +3,23 @@ > Source: distilled from end-to-end testing on 2026-09-17 (hard user requirement). The core principle in one sentence: > **When an image is incomplete / cut off / badly proportioned, first search for one that shows the whole subject — do not force-crop it and do not force-use it.** -## 1. Image sourcing paths (by priority) +## Authorization comes before downloading + +Default to typography and CSS/SVG charts. News images, article screenshots, and real-person +portraits are disabled by default. Before downloading or using any external asset, ask the user +to confirm authorization for the intended use, including portrait consent where applicable. +Record the source URL, license or permission evidence, required attribution, and user confirmation +in MANIFEST. Official hosting, accessibility, source citation, and user-provided files do not +automatically establish reuse permission. If permission is unclear, use typography. + +## 1. Image sourcing paths (only after authorization) | Path | How | Use for | Tested | |---|---|---|---| -| **A · Official channels** | Official brand kit / simple-icons (curl works); take product shots from official help/docs; use official reports for data | logos, product shots, data | ✅ Strongest compliance; for factual topics stay at this tier whenever possible | -| **B · Direct from the official site (highest success rate)** | `node /scripts/fetch-official-images.mjs ` lists candidate images (including CSS background images and lazy-loaded ones) → pick indexes → `--get 1,3 --out-dir assets` to download. **When the site needs login / scroll-loading, or the script cannot open it, use the agent's built-in browser to inspect the DOM, grab the image URLs, then `--url [,...] --out-dir assets` to write them to disk** (the same host / redirect / size / filename validation, and no Playwright needed); the tool flags suspicious "off-site domain" assets, and can feed straight into `prep-image.mjs --check` | brand logos, product shots, hero images, CEO portraits, news images | ✅ tested on minimaxi.com, 6/6 all relevant | -| **C · Wikipedia Commons / CC** | Search historical figures, landmarks, public institutions | historical topics | ✅ download once, reuse forever; zero compliance risk | -| **D · Screenshots of announcements and authoritative coverage** | **Negative-event topics** (collapse / penalty / lawsuit / controversy): the official site will never carry this material, so A/B are guaranteed to fail — the correct source is **the primary carrier of the event itself**: exchange filings, regulatory documents, company official statements / apology letters > media coverage pages (Tier 3 media are acceptable from either region — international: Reuters, AP, Bloomberg, FT, WSJ, BBC, CNBC, The Verge; Chinese: Xinhua, CCTV, The Paper 澎湃, Caixin, Tencent News 腾讯新闻, Sina, NetEase — self-media excluded). Open with the built-in browser or Playwright and **screenshot** (command below) | collapse, regulatory penalty, lawsuit, scandal / controversy | ✅ reporting-based citation; the screenshot must keep the outlet name and date visible | +| **A · Official channels** | Official brand kit / simple-icons (curl works); take product shots from official help/docs; use official reports for data | logos, product shots, data | Check the specific asset license and obtain user confirmation | +| **B · Direct from the official site (highest success rate)** | `node /scripts/fetch-official-images.mjs ` lists candidate images (including CSS background images and lazy-loaded ones) → pick indexes → `--get 1,3 --out-dir assets` to download. **When the site needs login / scroll-loading, or the script cannot open it, use the agent's built-in browser to inspect the DOM, grab the image URLs, then `--url [,...] --out-dir assets` to write them to disk** (the same host / redirect / size / filename validation, and no Playwright needed); the tool flags suspicious "off-site domain" assets, and can feed straight into `prep-image.mjs --check` | authorized brand logos, product shots, hero images | ✅ tested on minimaxi.com, 6/6 all relevant | +| **C · Wikipedia Commons / CC** | Search historical figures, landmarks, public institutions | historical topics | Check the individual license, attribution, and intended-use conditions | +| **D · Announcements and coverage screenshots (explicit opt-in only)** | For negative-event research, read primary filings, regulatory notices, company statements, and accountable reporting as fact sources. Do not turn them into visual assets automatically. Screenshot or download only after the user confirms permission for the intended use; otherwise cite the facts in typography. | authorized screenshots only | Keep source and date; log permission evidence and user confirmation | | ~~Legacy · Bing image search~~ | image-downloader skill | — | ❌ for niche Chinese-language topics 5/5 were irrelevant (anti-bot interstitial pages + "you may also like" recommendation cards), **off by default** | **Discipline when inspecting with the built-in browser** (take this route when the site needs interaction or the script cannot open it): @@ -22,11 +31,11 @@ **On the legacy Bing route**: this skill ships **no** Bing crawler of its own (shipping one would mean shipping a known-failing path). If image-downloader happens to be installed, use it **only when** the topic is an English-language mainstream brand or a generic real-world scene and you are willing to hand-filter every image; for Chinese-language topics, niche companies and the China context, always take path B. **Do not write a throwaway crawler just to fetch an image** — start with the existing tools, and if they come up empty, fall back to pure layout. -**Screenshot discipline for Path D** (negative-event topics, news/announcement screenshots): +**Screenshot discipline for Path D (only after permission confirmation)** (negative-event topics, news/announcement screenshots): 1. **Source tiering**: exchange filings / regulatory documents > company official statements (including apology letters and clarification announcements) > media coverage — **rank by primary-ness and editorial accountability, not by country**: Tier 1 primary documents (SEC EDGAR filings, HKEX / SSE / SZSE announcements, regulatory notices, FDA / FTC decisions) outrank Tier 2 company statements, which outrank Tier 3 mainstream media; and within Tier 3, international outlets (Reuters, AP, Bloomberg, FT, WSJ, BBC, CNBC, The Verge) and Chinese outlets (Xinhua, CCTV, The Paper 澎湃, Caixin, Tencent News 腾讯新闻, Sina, NetEase) are **equally qualified sources** — do not insist on a single "most authoritative" one. What is actually excluded is only self-media, aggregator accounts and content farms (unverifiable, often agenda-driven). 2. **Screenshots must retain verifiable information**: the outlet/institution name, the headline and the publication date must be inside the frame — a screenshot with the source information cropped out is unusable. Close cookie banners and recommendation feeds before shooting; capture the article body area only. -3. **Saving and logging**: store screenshots in `assets/`, and log one MANIFEST line per file: "content / source URL / publication date / licence (fair use for reporting)"; in the HTML use `.img-frame.contain` + `.img-cap` to state the source and date (e.g. "Image: XX News report · 2026-09"). +3. **Saving and logging**: store screenshots in `assets/`, and log one MANIFEST line per file: "content / source URL / publication date / license or permission evidence / required attribution / user confirmation for intended use"; in the HTML use `.img-frame.contain` + `.img-cap` to state the source and date (e.g. "Image: XX News report · 2026-09"). 4. **Negative financial topics are also bound by compliance.md**: still add the closing disclaimer line, give no trading advice in the narration and no price predictions; third-party logos / people appearing in screenshots follow the existing trademark / portrait rules. 5. Screenshot command (wait for lazy-loading, then capture the article body area; the same applies to the host's built-in browser screenshot): @@ -47,7 +56,7 @@ Abstract information (numbers, comparisons, quotes) **does not need an image**: **Query design** - ✅ Add positive words: **panorama / full view / front-on / wide shot / official** - ❌ Add exclusion words: **close-up / macro / corner of / half-cut** -- For people add `official portrait`; for products add `press photo` / `official` +- Search real-person portraits only after explicit user opt-in and confirmation of portrait/reuse permissions; for authorized product images add `press photo` / `official`. **Glance over the thumbnails first, ask four questions:** 1. Is the subject centred and prominent? (subject hugging the edge → replace immediately) @@ -112,7 +121,7 @@ After cropping you **must** eyeball whether the subject is intact — better to ## 7. Compliance and logging (consistent with authoring.md) - Every asset lands in `assets/` and is logged in `assets/MANIFEST.md`: filename / content / source URL or channel / licence -- No watermarks (if there is one, replace the image; cropping out a watermark requires confirming the cropped area is ≤20% and the subject is intact) +- No watermarks (if there is one, replace the image; do not crop out watermarks or attribution to bypass restrictions) - Trademarks/logos only in the context of "talking about that brand", never as decoration - Photos must come from a licensable source; a person's photo with no traceable licence is better replaced by a plain text quote card - Screenshots must state their origin (official document name + date) @@ -127,6 +136,6 @@ After cropping you **must** eyeball whether the subject is intact — better to | Overseas tech companies | A (official brand kit) + B | curl logos straight from simple-icons | | Universities / campuses | B (school official site, "official account" images) | real-scene images must be "front-on / full view"; the subject easily hugs the edge | | Historical figures / old photos | C (Wikipedia CC) | mind the copyright term | -| Collapse / regulatory penalty / lawsuit / scandal | D (announcement and coverage screenshots) | official sites carry no such material; screenshot mainstream media coverage or the announcement page and keep the outlet name and date visible; negative financial topics are also bound by compliance.md | +| Collapse / regulatory penalty / lawsuit / scandal | typography by default | Treat coverage as research sources; news images and screenshots need explicit opt-in and permission confirmation before downloading. | | Earnings data / comparisons | no image | number card + table layout | | Abstract concepts (growth / connection / future) | no image | gradient + big type + icons | diff --git a/skills/html2video-for-mcode/references/render.md b/skills/html2video-for-mcode/references/render.md index 6ce5296..2765e73 100644 --- a/skills/html2video-for-mcode/references/render.md +++ b/skills/html2video-for-mcode/references/render.md @@ -169,7 +169,7 @@ Before build-video ends it enforces: the final video's ffprobe duration differs | Font ugly first, then correct (FOUT) | External font + font waiting not going through capture | Localize assets/fonts; make sure you use capture.mjs rather than manual screenshots | | Animation not in the video | Used still mode | Re-run that slide with `--mode motion` | | Animation layer timing wrong | Animation delays hand-written in the HTML | Delete them, rely on --t1/--t2/--t3 injection | -| chromium fails to launch | Browser not installed | `npx playwright install chromium` (on Linux CI add `--with-deps`) | +| chromium fails to launch | Browser not installed | `npx --no-install playwright install chromium` (on Linux CI add `--with-deps`) | | A slide's segment length is wrong | Frame directory is from old timings | Delete `build/frames//` and re-run capture; after changing TTS you must re-run plan-timings | | Backslash paths break concat on Windows | — | build-video already converts to forward slashes; be careful when hand-assembling list.txt | | Some elements enter at 0s, others on time | Old tokens.css: delays overridden by the `.fx-*` shorthands | Switch to the new tokens.css (`--fx-delay`); see authoring.md for the implementation principle | @@ -182,6 +182,6 @@ Before build-video ends it enforces: the final video's ffprobe duration differs ## Environment differences notes - **ffmpeg/ffprobe detection**: every script uniformly goes PATH → project/repo node_modules (ffmpeg-static/ffprobe-static) → common install locations (winget Links / scoop / C:\ffmpeg\bin); when not found they list the checks one by one and exit with code 2 (distinct from 1 for business errors). -- **Windows**: `python`/`node` naming, path separators — this whole suite is implemented in Node, no bash arrays, no octal traps, it just runs. ffmpeg: `winget install Gyan.FFmpeg` or `npm i ffmpeg-static ffprobe-static`. -- **Linux sandbox (mcode)**: chromium is installed by `npx playwright install chromium`; a Chinese font package is needed; `--with-deps` supplies shared libraries. +- **Windows**: `python`/`node` naming, path separators — this whole suite is implemented in Node, no bash arrays, no octal traps, it just runs. ffmpeg: `winget install Gyan.FFmpeg` or `npm i --save-exact ffmpeg-static@5.3.0 ffprobe-static@3.1.0`. +- **Linux sandbox (mcode)**: chromium is installed by `npx --no-install playwright install chromium`; a Chinese font package is needed; `--with-deps` supplies shared libraries. - Supersampling: capture `--dsf 2` emits 3840×2160 frames, and build-video detects the size mismatch and auto-downsamples with lanczos, giving sharper text edges; render time is about ×4, so use it only for the final master. `--dsf` accepts 1–4 and **defaults to 1**; anything else (0, 2.5, `abc`) is rejected at the entry point with a clear message. diff --git a/skills/html2video-for-mcode/references/symptoms.md b/skills/html2video-for-mcode/references/symptoms.md index 6bc85b1..8dd7f1f 100644 --- a/skills/html2video-for-mcode/references/symptoms.md +++ b/skills/html2video-for-mcode/references/symptoms.md @@ -29,5 +29,5 @@ Use it two ways: as trigger examples (the user describes one of these and you re > When a symptom points at a script, run it with `--quiet`/`--ids` to narrow first; every diagnostic script prints the exact next command on failure. | a script exits 0 with no output at all (printed nothing, did nothing) | you **imported** the CLI instead of running it — `node -e "import(…)"` never runs `main` by design; run `node