Repository navigation
Covers in other ratios, without their title, with a camera and a title of their own: frames --covers --ratios and --no-title, s.cover, titles in several colours - #107
Merged
Conversation
…e of their own
Several long films each hand-wrote the same cover mechanics: a clean background, a camera only for the cover, a
two-colour title, and 9:16 / 3:4 / 4:3 crops with the title set again. They become tools; the crop, framing and type
stay the project's.
- bin/vh frames --covers --no-title: the covers without their title (<id>-clean.png). cover(id, o) takes
{ title: false } and says it obeyed; a page that does not (an older engine copy) gets no picture and a message.
- --ratios 9:16,3:4,4:3: each cover in each ratio as a crop of its picture (whole px, exactly the ratio) around the
project's ratios[r].focus, with ratios[r].cam when given and ratios[r].title in the ratio's own px (or the cover's
title re-set as a starting point); the page is drawn at the pixel ratio the crop needs, so nothing is scaled up.
- canvas-film: s.cover is the cover's id while a cover is drawn (null in the film); a cover title takes a colour per
line, runs of colours in a line, family and weight. ready checks each ratio's title; fonts check draws them.
- The film's frames and the template's 16:9 cover are byte-identical to before. Docs: canvas-film README (with a
migration note), CONTRACT, playbook/10 pointer, bin/vh help, CHANGELOG. CI regressions for each piece.
…, not the same bytes GitHub's macOS runner failed the byte comparison between two separate pages; frames within one page stay byte-identical, which the s.cover case still checks.
# Conflicts: # CHANGELOG.md
…m the page's own size, PSNR failures fail - The default title for a ratio was scaled to fit, then txt() clamped it back up to FILM.minText and it ran off both sides. It is now laid out at the size actually drawn; a line still too wide is broken onto more lines (colours kept), and a title that cannot fit even so stops ready (declared ratios) or the draw (other --ratios), naming the cover and the ratio and asking for ratios[r].title. The cover reply says how many lines it drew; a ready message gives the drawn size. - frames --ratios chose the page's pixel ratio from the HTML's size; a page sized only by window.film.width and height had its crops scaled up. The page is opened again at the ratio its real size needs, and a line says when a crop is still scaled up. - CI: the --no-title PSNR helper returns no value when ffmpeg fails or prints no metric, which fails the case (skipped without ffmpeg); new cases for the text floor and for a page sized by window.film.
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
ZLHad
marked this pull request as ready for review
October 18, 2026 14:02
ZLHad
enabled auto-merge (squash)
October 18, 2026 14:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why · 改了什么、为什么
几支长片各写了一份封面脚本,做的是同一套机械活:出不带字的底图(临时改
COVERS去掉标题,或者拷一份项目把界面画成空的)、只给封面换机位(在cover()里设全局变量)、双色标题(覆盖coverTitle)、从 16:9 的帧裁出 9:16、3:4、4:3 再另排标题。这一版把这些做成工具;裁哪里、怎么取景、用什么字,仍由项目定。bin/vh frames <项目> --covers --no-title:不画标题的封面,out/covers/<id>-clean.png。页面合约的cover(id, o)接受{ title: false },并返回{ title: false }表示照办了;不返回的页面(旧的引擎拷贝)不出图,报出原因,不会给出一张带字的"底图"。--ratios 9:16,3:4,4:3(任意w:h):每张封面每个比例一张out/covers/<id>-9x16.png,短边 1080 ×--dpr。做的是裁切,每行输出都写明:封面画面里正好这个比例、整数像素的最大一块(1920 × 1080 的片子里 9:16 是 603 × 1072),围着项目给的ratios[r].focus,给了ratios[r].cam就用它代替封面的机位;页面按裁切需要的像素比来画(9:16 约 1.8 ×--dpr),画面不放大。标题是项目的ratios[r].title(坐标按这个比例的像素,9:16 是 1080 × 1920),没写就把封面标题居中缩放挪过来当起点。ready按各比例查标题宽不宽得下,bin/vh fonts check也画一遍;最后打出bin/vh cover-preview那一行。draw(t, s)的s.cover是封面 id(片子本身的帧里是null),镜头可以给封面换取景。封面标题的color可以每行一个,一行可以写成一串 run(["…", { text, color }]),先描边后填字;family、weight可选,默认仍是"Film Heavy"900。旧写法画出来和以前一样。covers一行、playbook/10 封面一节一句指路、bin/vh帮助、CHANGELOG。English summary.
frames --covers --no-titledraws clean backgrounds; the contract'scover(id, o)must confirm{ title: false }or the host refuses.--ratiosmakes each cover in other aspect ratios as an honest crop (whole px, exact ratio, around a project-given focus, optional per-ratio camera) captured from a page drawn at the pixel ratio the crop needs, with a title the project lays out in that ratio's own px (or a fitted default as a starting point).s.coverexposes the cover id to shots only while a cover is drawn. Cover titles gain per-line colours, coloured runs within a line, and a configurable family/weight. Film frames are unchanged.How it was verified · 怎么验证的
tools/ci.sh --committed(VH_BASH=/bin/bash、LC_ALL=C,shellcheck、pyflakes 按 CONTRIBUTING 的办法真的跑了)通过;跳过 1 项(本机没装 HyperFrames 运行时)。新增 6 项回归(后两项见下面的 Review fixes),前 4 项在 canvas-film 模板上:--no-title:和带标题的封面相比,标题暗带以上的行是同一幅画面(PSNR ≥ 40 dB;本机是 inf),标题所在的行不同(< 30 dB;本机约 6 dB)。两次分开打开页面不一定逐字节相同(GitHub 的 macOS 机器上就不同),所以比 PSNR;ffmpeg 失败或读不出数值时这一项算失败,没装 ffmpeg 时跳过;--ratios 9:16,3:4,4:3:输出正好 1080 × 1920、1080 × 1440、1440 × 1080,输出写明是裁切;9-16这种写法在开浏览器前就退出 2;window.film.cover改回旧的cover(id) { cover(id); }:--no-title退出 1、报出原因、不写文件;s.cover === "A"时画一块品红:封面(带字和不带字)左上角是品红;片子在 4.9 s 和封面自己的时刻的帧和模板逐字节相同、没有品红。--ratios 16:9,9:16,3:4,4:3(--dpr 1)和--ratios 9:16,3:4,1:1,2.35:1 --dpr 2(2160 × 3840、2160 × 2880、2160 × 2160、5076 × 2160),尺寸都准;看过联系表:9:16 用模板自己写的双色两行标题,3:4、4:3 用默认排法;ready对坏的比例名、超出画框的比例机位、写错的 focus、排不下的比例标题各报一条;bin/vh fonts check在模板上通过。Review fixes · 按 Codex 的评审改的(01b2c77,另合了 main 的 #108)
txt()又把它抬回FILM.minText(下限 80 时,20 个字的标题在 9:16 算出 48 px,实际画 80 px、1600 px 宽,两头裁掉,退出 0)。现在按实际画出的字号排;还放不下的行按wrap()的断法折成几行,颜色跟着字走;折了还放不下(一个词就比画面宽,或者行数多到高度装不下),声明过的比例在ready报错,--ratios临时要的比例在画的时候报错,都写明是哪张封面、哪个比例,让项目写ratios[r].title。cover()的返回多了lines,输出写"re-set for it on 2 lines";ready的超宽提示写实际画出的字号。CI:下限 80 时这个标题在 9:16 和 3:4 都折成两行、退出 0;一个放不下的长词让ready报cover L (3:4) … give it ratios["3:4"].title。window.film.width/height覆盖 HTML 的尺寸,以前 4:3 会在 1× 下画、把 1080 × 810 的裁切放大到 1440 × 1080。现在页面打开后按它真实的尺寸重算,不一样就用对的像素比重开一次(canvas 在页面启动时按devicePixelRatio定大小,所以要重开,不能只改视口);裁切仍被放大时,输出那一行会写出来。CI:一个只在window.film里写 1080 × 1920 的页面,4:3 在 1.333× 下画,出 1440 × 1080,没有"scaled up"。psnr():ffmpeg 失败或读不出数值时返回空值,这一项判失败(以前返回 0.0,被"标题暗带 < 30"当成通过)。两条新 CI 在改之前的代码上都会失败(已经确认过)。改完以后模板 9 个时刻的帧和 16:9 封面 A 仍和 main 逐字节相同。
Review focus · 请重点看
frames --covers下面(--no-title、--ratios),没有另开bin/vh covers,所以 CLAUDE.md 的命令表不用改。clip.scale缩到目标尺寸,出来不对就反向再截一次,还不对就报错。9:16 因此比理论上的 607.5 × 1080 少 8 px 高(603 × 1072)。PRX乘上缩放);一次跑里同时要 16:9 和别的比例时,16:9 也在较高的像素比下画、再缩回去,所以和单独--covers出的那张不是逐字节相同(画面一样)。ratios[r].title就不出标题,可以讨论。Checklist · 自查
tools/ci.sh --committedpasses · 通过CHANGELOG.md→ Unreleased · 已记进 CHANGELOGCLAUDE.mdunchanged (no new command) · 没改 CLAUDE.md,不用 sync-agents