From 2966f19b96e3be754bf7425671191ab775b41035 Mon Sep 17 00:00:00 2001 From: zhanglinghao Date: Wed, 7 Oct 2026 00:50:49 +0800 Subject: [PATCH 1/4] bin/vh textcheck: canvas text covered by the picture, too faint, or out of the frame npx hyperframes check measures DOM text only; text a script draws into a canvas is pixels to it. A canvas film's own script found reads with too little contrast that frame review had missed. This turns that method into a command any canvas film can run with one line in the composition: window.__vh = { draw(t), texts? }. - tools/textcheck: hooks fillText/strokeText before the page's scripts, draws each read's frame with and without it plus the read alone as a mask: share shown, contrast with the picture and with its edge, out of frame, under a DOM caption. Canvas text outside the registry and captions over a bright picture warn. No npm dependency: CDP over --remote-debugging-pipe, a static server on 127.0.0.1. - bin/vh textcheck finds the browser: CHROME_PATH, HyperFrames' headless shell, then Chrome or Chromium. - engines/README (the contract), playbook/02 layer 2, CHANGELOG, CLAUDE.md command list and AGENTS.md; tools/ci.sh runs it on a fixture with one read per case. --- AGENTS.md | 2 +- CHANGELOG.md | 9 + CLAUDE.md | 2 +- bin/vh | 21 +- engines/README.md | 18 ++ playbook/02-verification.md | 1 + tools/ci.sh | 37 +++- tools/textcheck/browser.mjs | 76 +++++++ tools/textcheck/fixture/index.html | 63 ++++++ tools/textcheck/page.js | 327 +++++++++++++++++++++++++++++ tools/textcheck/textcheck.mjs | 270 ++++++++++++++++++++++++ 11 files changed, 821 insertions(+), 5 deletions(-) create mode 100644 tools/textcheck/browser.mjs create mode 100644 tools/textcheck/fixture/index.html create mode 100644 tools/textcheck/page.js create mode 100644 tools/textcheck/textcheck.mjs diff --git a/AGENTS.md b/AGENTS.md index df4c0e2..e3a7ed3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -108,7 +108,7 @@ OpenVideoHarness/ ├── CLAUDE.md / AGENTS.md 入口(本文件;AGENTS.md 由 bin/vh sync-agents 生成,内容相同) ├── README.md / README.zh-CN.md 给人看的说明;CONTRIBUTING.md 是改本仓库时的规则;install.sh 一键安装 ├── LOCAL.md 本机环境(不入库;模板是 LOCAL.example.md) -├── bin/vh 命令行:doctor · setup · types · effort · new · style · recipes · hf-init · install-skill · sync-agents · tts · voices · captions · beats · music · sfx · mix · mux · qa · readcheck · storyboard · rhythm · cover-preview · sheet · check · gif · review · desk +├── bin/vh 命令行:doctor · setup · types · effort · new · style · recipes · hf-init · install-skill · sync-agents · tts · voices · captions · beats · music · sfx · mix · mux · qa · readcheck · textcheck · storyboard · rhythm · cover-preview · sheet · check · gif · review · desk ├── tools/ bin/vh 背后的脚本;audio/README.md 是声音命令的参数手册,desk/README.md 是审阅台的读取约定;ci.sh 是仓库自检 ├── skills/open-video-harness/ 轻量 skill:在任何目录把做视频的请求引到本仓库 ├── video-types/ 9 类视频(09 实验中):工作流、审美、禁止项、Prompt 增量块、自查重点、案例 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f6059b..bb79c71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Unreleased +**`bin/vh textcheck`: canvas text covered by the picture, too faint, or out of the frame** +- Why: `npx hyperframes check` measures DOM text only; text a script draws into a `` is pixels to it. A 457 s canvas film's own script measured its 106 reads this way and found 3 with too little contrast that frame review had missed. This makes that check a command any canvas film can run. +- A composition opts in with one line, `window.__vh = { draw: (t) => …, texts }` (`texts` optional). Before its scripts run, the check hooks the canvas's `fillText` and `strokeText`, so the film's own text functions stay as they are: kinetic type drawn one character at a time, a line drawn in parts, and a "·" or an arrow drawn as a shape still match the read. +- For each registered read (`--texts`, else `window.__vh.texts`, else the `out/texts.json` readcheck reads), at 3 times across its window: the frame as drawn, the frame without that read and the read alone as a mask give the share of its glyphs that show (under 70%: covered), and its contrast with the picture under it and with what is right around it, so an outline, a shadow or a plate counts (both under 3:1: too faint). Outside or cut by the frame and under a DOM caption also fail; so does a frame function that throws. Exit 1 on any of those, 2 when it could not check. +- Warnings only: canvas text outside the registry (scanned every second, each line judged once where it is most opaque), reads missing from some samples or never drawn as canvas text, DOM captions (`data-read="subtitle"`) over a bright picture (the share of the pixels under their lines within 3:1 of the caption's colour), and a frame that is not the same when drawn twice. Crops and every number go to `out/check/textcheck/`. +- No npm dependency: Node drives a headless Chrome over the DevTools protocol through a pipe, and serves the project folder on 127.0.0.1. The browser: `CHROME_PATH`, HyperFrames' chrome-headless-shell, then Chrome or Chromium. Pixels are copied into the check's own canvas before reading, because after a few `getImageData` calls Chrome moves a canvas off the GPU and the film then draws every later frame on the CPU, many times slower. +- On a copy of the 457 s film with the line added (107 reads, about 30 s on an M3 Max): one read drawn above the frame at its sample time, one read that is an image, ten reads missing from their first sample, two dim notes outside the registry under 3:1, one line outside the frame and one cut by its edge, two captions over a bright picture. +- engines/README (HyperFrames, 画面文字检查): the contract and what it cannot see (text in images, WebGL or an offscreen canvas); playbook/02 layer 2: the method and the command; tools/ci.sh runs it on a fixture with one read per case, skipped where no Chrome is found. + **Lessons from four films go into the docs** - Why: the maintainer asked that the general lessons kept in the agent's memory notes and in project LESSONS.md files move into the docs, leaving out what is personal to one channel. They come from 《发送之后》, a news film (FZ1073), the 3-minute tech-history film and the review rounds of 2026-10-04/05. - playbook/09 §10 (new): how narration, title cards and labels read as written by a person. Let the fact carry the heaviest beat; vary sentence length; the sentence shapes models reach for (parallelism, triplets, "不是……而是……"); spoken words; explanations go into labels; one common way to end (from this case to this kind of case, back to the person) in plain words; a caption-only script goes out with the gate ② storyboard (or stops on its own when the human owns `script`). A default, overridden by a concept that wants another voice; any film with narration or cards reads it. `templates/SCRIPT.md` points there from both of its comments; the concept card's 首尾 line goes down to the last line or last picture (a 3-minute film changed its ending three times at gate ③). diff --git a/CLAUDE.md b/CLAUDE.md index 12b8731..8283e62 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -105,7 +105,7 @@ OpenVideoHarness/ ├── CLAUDE.md / AGENTS.md 入口(本文件;AGENTS.md 由 bin/vh sync-agents 生成,内容相同) ├── README.md / README.zh-CN.md 给人看的说明;CONTRIBUTING.md 是改本仓库时的规则;install.sh 一键安装 ├── LOCAL.md 本机环境(不入库;模板是 LOCAL.example.md) -├── bin/vh 命令行:doctor · setup · types · effort · new · style · recipes · hf-init · install-skill · sync-agents · tts · voices · captions · beats · music · sfx · mix · mux · qa · readcheck · storyboard · rhythm · cover-preview · sheet · check · gif · review · desk +├── bin/vh 命令行:doctor · setup · types · effort · new · style · recipes · hf-init · install-skill · sync-agents · tts · voices · captions · beats · music · sfx · mix · mux · qa · readcheck · textcheck · storyboard · rhythm · cover-preview · sheet · check · gif · review · desk ├── tools/ bin/vh 背后的脚本;audio/README.md 是声音命令的参数手册,desk/README.md 是审阅台的读取约定;ci.sh 是仓库自检 ├── skills/open-video-harness/ 轻量 skill:在任何目录把做视频的请求引到本仓库 ├── video-types/ 9 类视频(09 实验中):工作流、审美、禁止项、Prompt 增量块、自查重点、案例 diff --git a/bin/vh b/bin/vh index 1d6e044..f20a5cd 100755 --- a/bin/vh +++ b/bin/vh @@ -57,6 +57,10 @@ # FAIL under one brisk read (CJK/7 + other/20 + 0.8 s, at least 1.5 s; exit 1), WARN under the target of the BRIEF's # Pace (exit 0); subtitles within reading speed. data-read="subtitle"|"label" and data-pace="…" mark clips # readcheck --budget : how many characters fit in a span · readcheck --export [--out f]: the composition's timed text +# textcheck [--texts f.json] [--min-visible 0.7] [--min-contrast 3] [--samples 3] [--scan-step 1] [--caption-step 0.5] [--out dir] [--soft-gl] +# text drawn into a canvas, which npx hyperframes check cannot see: a read covered by the picture (under 70% of it +# shows), under 3:1, outside or cut by the frame, or under a DOM caption (exit 1); canvas text outside the registry +# and captions over a bright picture warn. The composition opts in with window.__vh = { draw(t), texts? } (engines/README.md) # sheet