Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
24 changes: 9 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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 <pkg>` 会**静默不装**(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 无关)。
Expand Down Expand Up @@ -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 上要几十秒。
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
2 changes: 1 addition & 1 deletion .minimax-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
65 changes: 35 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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 <your-project>/.claude/skills/
cp -r skills/html2video-for-mcode <your-project>/.claude/skills/
```

Then install the two dependencies **in your video project** (not in the skill directory):

```bash
cd <your-video-project>
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/<id>.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
Expand Down Expand Up @@ -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
Expand All @@ -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 <value> <project>` 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

Expand Down
Loading
Loading