关于 paper2poster
paper2poster 是论文转海报流程中的渲染技能,面向需要从 paper2assets 输出生成学术海报的用户。它选择论文图示、排版并填充固定画布,随后输出 HTML、PDF、PNG 和可编辑 PPTX,也可生成分节讲解音频。
主要功能
- 01从论文素材中语义筛选图示
- 02生成并迭代调整海报布局
- 03支持横向与纵向固定画布
- 04输出 HTML、PDF、PNG 和 PPTX
- 05生成分节讲解音频
适用场景
- 01将论文素材整理为学术海报
- 02从已有 HTML 海报导出可编辑演示文稿
- 03为海报生成 PDF、PNG 及讲解音频
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ researchstudio --skill paper2poster安装后在 Claude Code 中输入/paper2poster确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/fonts/Arimo-LICENSE.txtassets/headers_portrait/pv1.htmlpv2.htmlpv3.htmlpv4.htmlpv5.htmlpv6.htmlpv7.htmlassets/headers/v1.htmlv2.htmlv3.htmlv4.htmlv5.htmlv6.htmlv7.htmlassets/katex/auto-render.min.jskatex.min.csskatex.min.jsLICENSEassets/layouts_portrait/full.htmlhalf.htmlassets/layouts/3col.htmlfull.htmlhalf.htmlmethoddriven.htmlmethoddriven4.htmlassets/math/katex.htmlmathjax.htmlassets/mathjax/LICENSEVERSION详细介绍
paper2poster — paper_spec.md → HTML 海报 → PDF/PNG + 可编辑的 PPTX
此技能是一个 3 技能流程中的渲染阶段。它假定 paper2assets 已生成输入 <outdir>/。给定该输出目录,它会挑选图表、渲染 HTML 海报,反复调整布局以适配固定页面(横向 60×36in 或纵向 A0 33.1×46.8in),为各章节生成讲解音频,将 HTML 交给捆绑的 html2pptx 子技能(位于 html2pptx/)生成可编辑的 .pptx,并导出 PDF + PNG。移交给 html2pptx 是标准的最终步骤,而非可选步骤——一次运行即可生成 poster.{html,pptx,pdf,png},因为用户希望同一轮操作中获得可编辑的演示文稿,不会另行调用 html2pptx。
<outdir>/ (produced by paper2assets)
manifest.json assets/figures/ assets/logos/ assets/qr/ assets/meta/{paper_spec.md, text.txt, figures.json, metadata.json}
│
▼ Step 1 — verify prerequisites
▼ Step 2: select figures from upstream semantics
│ → assets/meta/figure_selection.json
│ (Method / high-confidence optional Motivation / Result)
▼ Step 2.5 — optional per-figure visual box cut (asymmetric noise the
│ paper2assets deterministic chain couldn't catch — most
│ figures need no further work here)
│
▼ Step 3 — compose (layout × style × header) + substitute (references/compose_poster.py → poster.html)
│ → <outdir>/poster.html (lean: 6 core sections, Necessary only)
│
▼ Step 4 — iterative fill loop (check_poster.py slack + polish)
│ → <outdir>/poster.html (every section FULL, every figure ≥90% on one axis)
│
▼ Step 5 — generate_audio.py → <outdir>/assets/audio/<id>.mp3 (free Edge TTS, from <outdir>/assets/meta/narration.json)
│ → the Listen buttons + Full Listen play these clips by id
│
▼ Step 5.9 — fit_logos.py → pack the header institution logos to fill their zone
│ (browser-measure + greedy shape-pack; baked into poster.html)
│
▼ Step 6 — render_poster.py → <outdir>/poster.pdf + <outdir>/poster.png (applies + bakes the expand into poster.html)
│
▼ Step 7 — html2pptx skill → <outdir>/poster.pptx (reads the baked poster.html; users want the editable pptx in one run)
│ (render FIRST — bakes the expand into poster.html; html2pptx then reads it, isolated under assets/_pptx_build/)
│ then check_poster.py verify-final
│
▼ Step 7.5 — check_poster.py deliverables (MANDATORY final gate)
│
└─→ Step 8 — Report absolute paths (html + pptx + pdf + png)
画布尺寸按方向在模板中固定(横向 60×36in,5:3;纵向 A0 33.1×46.8in,0.708);不要更改。
必须通过的收尾检查(绝不可超出以下范围)
最终海报必须满足两项硬性要求。它们不是警告,不是建议,也不是“留待下一轮润色”的事项——如果海报违反其中任意一项,必须重新迭代,才能宣布任务完成:
-
每张卡片中的图表至少在一个轴向(宽度或高度)填充其所在区域的 90–100%。
check_poster.py polish会将此问题报告为FIG/NARROW。如果图表在宽度和高度上的填充都不足 90%,它就像一枚被遗落在卡片里的小印章,是明显的缺陷。用一个数字表示:fillRatio = max(w_fig / w_section, h_fig / h_section)必须处于[0.90, 1.00]。修复顺序(调整上限 → 精简图表所属章节的正文 → 缩短图注 → 重新平衡栏宽)见references/staged_fill.md。分阶段填充循环结束时,任何图表都不得低于 90%。 -
每个章节的状态都必须为
FULL(fullRatio 0.90–1.00)。check_poster.py slack会报告此项。OVERFLOW(>1.10)、SPILLAGE(1.00–1.10)、SPARSE(0.70–0.90)和EMPTY(<0.70)都是不可接受的收尾状态。
两项检查必须同时通过:修复其中一项但导致另一项失败的修改必须回滚。持续迭代,直至 slack 显示每个章节均为 FULL,且 polish 不再报告任何 FIG/NARROW 警告,然后渲染 PDF/PNG 并运行 verify-final + deliverables。
何时查阅哪些参考资料
| 步骤 | 遇到此步骤时,阅读 |
|---|---|
| 第 3 步 — 组合模板 | references/compose_poster.py(组合布局 × 样式 × 页眉 → 独立的 poster.html;横向和纵向) |
| 第 3 步 — 替换占位符 | references/template_substitution.md(占位符映射、主题颜色随机化、各章节强调色、垂直尺寸规则、精简渲染策略) |
| 第 3 步 — 内容模式 | references/content_patterns.md(12 种语义组件系列——三种强调框、关键统计数据、统计条、对比项、编号步骤、标签、重点表格、公式、时间线和横幅——用于打破符合条件的章节正文中大段纯文本的单调感) |
| 第 3 步 — 润色 | references/visual_polish.md(排版、颜色/对比度、行内强调规则、统计网格、图表上限、强调框、拱形横幅、印刷规范) |
| 第 4 步 — 分阶段填充 | references/staged_fill.md(slack 命令、迭代式测量→选择→应用→审查循环、修改方法目录、精简规则) |
| 第 5.9 步 — 排列页眉标志 | references/fit_logos.py(在浏览器中测量各标志区域 + 通过贪心算法排列形状以填满区域;将各行写入 poster.html——在填充循环后、渲染前运行) |
| 第 5 步 — 音频(生成) | scripts/generate_audio.py 根据 <outdir>/assets/meta/narration.json 脚本(由上游 paper2assets 生成;使用免费的 Edge TTS)合成 <outdir>/assets/audio/<id>.mp3,供“收听”按钮使用。参见 references/audio_narration.md。 |
工作流
并行安全(请先阅读——绝不可违反)
此技能经常会同时用于许多篇论文——批处理驱动程序会为每篇论文启动一个 claude -p 会话,每个会话都有自己的 <outdir>(例如 papers/foo_portrait/、papers/bar_portrait/……并发运行)。因此:
- 绝不要运行
ps、pkill、kill、killall,也不要以其他方式查看或终止其他进程。 你看到的任何其他claude/python/chromium/soffice进程,都属于处理其他论文的同级海报任务。它们不是你的重复进程,也不会与你争用文件。终止它们会破坏其他论文的运行。 - 只读写你所获分配的
<outdir>内的文件。 绝不要触碰其他论文的目录或共享模板/配置目录。 - 如果
<outdir>/poster.html在读取和编辑之间似乎“意外发生了变化”,那是因为你自己之前的工具调用导致的(写入、运行替换脚本或先前的编辑)——不是因为有其他进程在争用。重新读取文件并继续。不要调查“还有谁在修改它”——没有其他人。 <config>/skills/paper2poster/assets/*.html下的共享模板是只读输入——将其复制到你的<outdir>中,绝不要直接修改。
违反上述任何一项,都是导致任务快速失败(约 400 秒)的最常见原因:Agent 会陷入不存在的“进程冲突”问题,而不是制作海报。
步骤 0 — 缓存检查(必须首先执行,在任何其他工作之前)
渲染海报会运行第 2 阶段的迭代分步填充循环(约需 15–30 分钟的 Claude token),并覆盖 <outdir>/poster.html——破坏用户可能做过的任何行内编辑、手动替换的图表或布局调整。开始前,检查交付文件是否已存在:
if [[ -f "$outdir/poster.html" \
&& -f "$outdir/poster.pdf" \
&& -f "$outdir/poster.png" ]]; then
if python ~/.claude/skills/paper2poster/scripts/select_figures.py "$outdir" \
&& python ~/.claude/skills/paper2poster/scripts/check_poster.py \
preflight "$outdir/poster.html"; then
echo "[paper2poster] CACHED in $outdir: semantic preflight passed, reusing."
echo " poster.html $(stat -c%s "$outdir/poster.html") bytes"
echo " poster.pdf $(stat -c%s "$outdir/poster.pdf") bytes"
echo " poster.png $(stat -c%s "$outdir/poster.png") bytes"
[[ -f "$outdir/poster.pptx" ]] && echo " poster.pptx (html2pptx output present)"
[[ -d "$outdir/assets/audio" ]] && echo " assets/audio/ (narration present)"
exit 0
fi
echo "[paper2poster] cached deliverables are semantically stale; upgrading " \
"Paper2Assets and rebuilding instead of reusing them."
fi
只有当三个核心交付文件都存在,且选择器检查和语义预检均通过时,才报告并停止。旧版、部分生成、代际混杂或归属错误的缓存海报,必须继续执行步骤 1,升级其 Paper2Assets 包,并重新渲染。仅有缓存的 PDF/PNG 文件,绝不能证明动机图正确。
仅在以下情况重新渲染:
- 用户更改页眉模板,包括切换到或切换自明确的无机构页眉 → 重新排版并导出,而不是复用缓存
poster.{html,pdf,png}中有一个文件缺失 → 从相应步骤继续(缺少poster.html→ 从步骤 2 的填充循环开始;仅缺少poster.pdf/poster.png→ 只运行步骤 6 渲染)- 用户明确提出要求(“重建海报”“重新生成”“重新渲染”“从头开始”“重新排版”)。在这种情况下,先删除
<outdir>/poster.html,以免触发缓存检查。
步骤 1 — 验证 paper2assets 前置条件
没有要求机构名称/徽标? 请先选择明确的无品牌页眉:
横向版使用居中对齐的 v6/左对齐的 v7,纵向版使用居中对齐的 pv6/左对齐的 pv7。请阅读 references/branding_free_headers.md。对于这些模板,请跳过下方的徽标恢复步骤,保留任何共享徽标资源,并在需要时仍然恢复二维码资源。这些模板的结构刻意不含机构/徽标槽位;替换或调整版面时不要添加这些内容。此例外也适用于后续所有获取徽标和机构信息的说明。如果请求的页眉与缓存海报不同,则不适用常规缓存快捷方式。
必需参数:由 paper2assets 技能生成的 <outdir>/ 路径,或源 *.pdf 的路径。开始任何操作前,请确认所需文件均存在:
ls <outdir>/assets/meta/paper_spec.md <outdir>/assets/meta/text.txt <outdir>/assets/meta/figures.json <outdir>/assets/meta/metadata.json
如果缺少四个必需文件中的任何一个,请自动调用 paper2assets 技能处理源 PDF,以生成/填充 <outdir>/,然后继续。figures.json 可以合法地是空列表;选择器和预检会验证每条非空记录及其磁盘上的资源。
可选目录 <outdir>/assets/logos/ 和 <outdir>/assets/qr/ 可能不存在——但不要仅仅因为目录缺失,就悄悄删除徽标/二维码 HTML 块。目录缺失通常有两个可恢复的原因:
- 跳过了 paper2assets 的步骤 6,或
- 调用 paper2assets 的步骤 6 时使用了错误的 CLI 标志(paper2assets SKILL.md 步骤 6 中记录的
--spec/--outdir <outdir>/assets/logos陷阱,导致大多数论文的徽标落在<outdir>/assets/logos/logos/<slug>.png,而不是<outdir>/assets/logos/<slug>.png)。
当 <outdir>/assets/logos/ 缺失或为空时的恢复流程:
# A. Auto-fix the nested-dir bug if present
if [ -d <outdir>/assets/logos/logos ]; then
mv <outdir>/assets/logos/logos/* <outdir>/assets/logos/ 2>/dev/null
rmdir <outdir>/assets/logos/logos
fi
# B. Retry fetch_logos.py from this skill (it's a paper2assets script
# but safe to call from paper2poster as a recovery step).
python ~/.claude/skills/paper2assets/scripts/fetch_logos.py \
--from-spec <outdir>/assets/meta/paper_spec.md --outdir <outdir>
# C. Same for qr/ if missing
python ~/.claude/skills/paper2assets/scripts/make_qr.py \
--from-metadata <outdir>/assets/meta/metadata.json --outdir <outdir>
只有在重试之后,如果 logos/ 仍为空(机构名称未能解析到任何维基百科信息框——这会发生在“Anonymous Institution”投稿和不知名实验室的情况下),才将未使用的 <img class="logo"> 元素从海报 HTML 中移除,作为最后的后备措施。二维码缺失时也同样处理。
第 2 步 — 选择图示
在编排或替换海报前,先运行确定性语义选择器:
python scripts/select_figures.py <outdir>
它会写入 <outdir>/assets/meta/figure_selection.json。将此清单视为主要图示占位符的唯一事实来源:
selections.method.file->{{METHOD_FIGURE}}selections.motivation.file->{{TEASER_FIGURE}}(非 null 时)selections.result.file->{{SECONDARY_FIGURE}},或用作 Key Result 部分中的主图
每个非 null 条目还包含稳定的 figure_id、说明文字、语义置信度和证据。不要凭视觉猜测将选中的文件替换为其他图像。check_poster.py preflight 会独立重新计算确定性选择;若清单过期、角色不匹配,或 Method/Motivation 重复使用,则会直接失败。
选择器会使用 Paper2Assets 中新增的语义字段 semantic_roles[] 和 section_relevance[]。选择过程具有确定性,且所选图示互不重叠:
- Method 图示要求
method >= 0.55,并排除 Result/Ablation/Qualitative 图集占主导或分数接近的情况。这样可避免仅仅提到“our method”的说明文字取代真正的系统概览图。 - **Motivation 图示可选,且仅在置信度高时选用。**它要求
motivation >= 0.62,排除所有带有method、result或ablation >= 0.55的候选项,并且始终与 Method 图示互不重叠。如果其值为 null,请移除整个 Motivation<figure>块。绝不要用 Method 或 Result 图像填补该空间。 - Result 图示要求
result或qualitative >= 0.55,排除明显以 Method 为主的图示,并且与 Method 和 Motivation 图示互不重叠。**仅当存在符合条件的实证图示时,才以每张海报至少 2 个图示为目标。**不要为了达到目标而用语义无关的图像填充海报。 - 图示丰富模式 → 3 列布局。如果论文包含 超过 3 个高信号图示(多个结果图、定性样例图集、架构图 + 组件图),请全部选用(软上限约为 6 个),不要停在 2 个;并使用3 列布局(
--layout 3col,第 3 步),更宽的列可以容纳更大的图示,符合大多数作者提供的 GT 海报的做法。将图示分布到全部 3 列;Method 图示仍作为锚点。只选真正有信息量的图示,绝不要为了凑数而填充。
**必须升级旧版资源包。**如果 figures.json 不包含完整的 figure_semantics.v2 生产者契约(包括不完整/原型语义字段),选择器会以非零状态退出,预检也会失败。请复用现有资源并运行 Paper2Assets build_package.py --skip-extract --paper-spec ...,然后重新运行选择器。不得将手动/原始模型选图作为备用方案,因为这会重现此关卡旨在防止的 Motivation 不匹配问题。
引用每个选中的图示时,请注明其文件路径,并在依赖该图示前确认文件存在。
步骤 2.5 — 按图进行视觉框选裁切(可选,用于确定性处理链未能清除的不对称噪声)
paper2assets 已对每张图运行确定性清理流程(top-check → decaption → autotrim)。大多数选中的图无需进一步处理。
如果选中的图存在确定性处理链无法清除的不对称噪声——例如多图页面在一侧渗入噪声(相邻面板的一条竖向区域)、明显的残留标题行未被严格的 decaption 阈值过滤,或你想排除的一块图内容——则进行一次视觉 box 处理:
- 读取该图。
- 确定紧贴内容的像素边界框
(X0, Y0, X1, Y1)。 - 应用:
此操作会写入一次性的python ~/.claude/skills/paper2assets/scripts/crop_figure.py box <outdir>/assets/figures/<file>.png --box X0 Y0 X1 Y1<file>.png.bak(如果 paper2assets 之前已创建备份,则保留现有备份),并更新figures.json。 - 重新读取结果。每张图最多尝试 3 次;如果裁切过度,则使用
cp从.bak恢复。
大多数论文无需执行此步骤——如果选中的图经过 paper2assets 的确定性处理流程后看起来干净,就跳过。
步骤 3 — 渲染 HTML 海报
先选择适配方向的组合轴,再进行组合。
两种方向都共享 assets/ 下的四个独立轴:布局 × 样式 × 页眉 × 主题。横向海报还增加第五个轴 Scan-to-Read,而纵向海报有意不设独立的扫描轴:
- **结构:**横向使用
assets/layouts/{full,half,3col}.html;纵向使用assets/layouts_portrait/{full,half}.html。 - 视觉样式:
assets/styles/*.css;横向启用全部 11 种样式,纵向排除underline和double-rule,启用其余 9 种。 - **标题栏:**横向使用
assets/headers/{v1,v2,v3,v4,v5,v6,v7}.html;纵向使用assets/headers_portrait/{pv1,pv2,pv3,pv4,pv5,pv6,pv7}.html。*6/*7变体为可选项,不含机构名称和徽标。 - 颜色/主题:
references/apply_theme.py提供 9 套配色,两种方向共用。 - **Scan-to-Read:**仅适用于横向,来自
assets/scan/*.html。
references/compose_poster.py 会将所选样式注入 {{STYLE_CSS}},将所选页眉注入 {{HEADER}},将仅适用于横向的扫描模块注入 {{SCAN_SECTION}},并将解析后的主题注入所选布局。它会写入一个独立完整的 poster.html,因此 check_poster.py / render_poster.py / 分阶段填充循环无需改变,也不会产生 N×M×K×J 个庞大模板。
现在也支持组合纵向海报(--orientation portrait、assets/layouts_portrait/{full,half}.html),包含 STYLE + COLOR + HEADER 轴:9 种适用样式、包括 mono 在内的 9 种主题,以及浅色默认页眉下的 5 种 A0 标题格式 pv1–pv5。underline 和 double-rule 仅适用于横向,因为它们的水平线会在纵向窄栏中造成误导性的分区。纵向海报没有独立的 Scan-to-Read 区块或 --scan 轴,但包含组合页眉及其页眉自带的 QR 码位置。纵向海报的分区必须使用内容模式组件(references/content_patterns.md),并遵循与横向相同的至少涵盖 5 个不同语义类别的要求。A0 窄栏更容易退化成普通项目符号列表或表格,因此纵向海报更需要丰富的组件选择。
轴 0 — 方向:
landscape(默认)——ICML / NeurIPS / CVPR 标准尺寸 60×36 英寸,宽高比为 5:3。外层为 4 列网格。除非用户明确选择纵向,否则始终使用横向。portrait——ACL / NAACL / AAAI 2025 标准 A0 纵向尺寸,33.1×46.8 英寸,宽高比为 0.708。half布局使用 2 列主体;full布局使用 4 个纵向堆叠的内容区块。仅当流程设置了POSTER_ORIENTATION=portrait时使用。不要根据方法图的宽高比自动判断方向——图形形状决定某一方向内部使用的布局轴(full或half),而非海报方向本身。横向海报中的高纵横比方法图应放入half模板的单列中;不应因此将整张海报切换为纵向。 如果未设置POSTER_ORIENTATION(或将其设为landscape),则使用横向模板。仅此而已。
轴 1 — 布局(由 Method 图形的形状决定):
-
full(横向--layout full;纵向layouts_portrait/full.html)— 当 Method 图形横向较宽时使用:横向时AR ≥ 2.5,纵向时AR ≥ 1.2。当figures.json中为{column=full}时也使用。横向时,此布局采用一个 4 列外部网格,其中间两列合并为一个.mid-wide区块。纵向时,此布局采用四个堆叠的内容区:Problem | Motivation;全宽的.method-hero;比例为1.5fr 1fr 1fr的 Key Results | Ablation | Headline Numbers;以及全宽的 Takeaway。用于填充项目符号的纵向伪区块: 主视觉区的 LEFT 项目符号单元格由
<div class="section method-text" data-section="method-text">…</div>包裹,这是一个视觉上透明、但会参与分阶段填充循环的伪区块。slack.py 将其填充率计算为bullets_content_h / row_h。当图形使行高超过项目符号内容所需高度时,判定结果会显示method-text SPARSE,LLM 随即扩充项目符号,直到填满单元格。这就是为什么 AR 阈值可以保持宽松的 1.2,而不是更稳妥的 1.8 — 伪区块会自动吸收中等纵横比图形造成的空白。 -
half(横向--layout half;纵向layouts_portrait/half.html)— 当前方向下的默认布局。当 Method 图形的 AR 适中或偏高,且figures.json中为{column=half}时使用;或者当 Method 图形为**Figure:** none时使用。横向时,Method 是 4 列中的 1 列内的半宽卡片。纵向时,Method 是 2 列中的 1 列内的卡片。
从 figures.json 读取 Method 图形的 width 和 height,计算 AR = width / height,然后:
- 横向:若 AR ≥ 2.5 或为
{column=full},则选full;否则选half。 - 纵向:若 AR ≥ 1.2 或为
{column=full},则选full;否则选half。(主视觉区的项目符号单元格是一个会通过分阶段填充循环自动填满的伪区块;中等纵横比的图形也适用。)
图形丰富时的覆盖规则(横向 — 优先于 full/half)。 如果步骤 2 选出了超过 3 个图形,则无论 Method 图形的 AR 如何,都使用 3 列布局(--layout 3col)— 其 3 个等宽列(1fr 1fr 1fr)可以容纳更多、更大的图形,与占主导地位的作者 GT 布局一致。Method 图形卡片在中间列保持醒目;其他图形分布在各列中。通过组合,3col 现在可以搭配任意风格和任意页眉(旧的“仅限 solid”限制已取消)。只有当海报包含 ≤ 3 个图形时,以上 full/half 选择才适用。
方法驱动式覆盖(仅在用户明确要求使用“方法驱动式”海报时启用)。 使用 --layout methoddriven。方法部分占据中间的宽幅区块(.mid-wide,合并后的中心列):顶部放置一张优先级最高的大型方法图,然后将方法拆分为实心圆角子部分卡片(.section.msub,data-section="method-1"…"method-N"),用于组织各个子部分;移除基准测试风格的填充卡片(左侧栏放置问题/动机,右侧栏放置关键结果/标题/要点)。此模式为可选项:--layout random 不会选择它,其他所有布局/样式均保持不变。规则:
methoddriven和methoddriven4中的子部分标题都使用带描边的方形 **A、B、C、D……**徽标(.msub-h .n)。卡片内部的数字步骤保持独立;不要把标题徽标改回实心数字圆形。添加/重新排序卡片时,按阅读顺序延续字母,同时保留data-section="method-1"…"method-N",以供测量和 Reel 交互使用。- 配色默认采用
multi-accent:与主题--accent色相相同,但每张卡片的深浅不同(.msub.d1…d4,由主题衍生,并随 9 个主题的轴变化)。如需使用不同色相,可在<body>上添加类mhue。 - 方法图优先——它会填满栏的宽度(因此宽幅横幅在宽度上可满足 90% 的图像填充门槛;无需豁免),且仅受一个宽松的高度限制
--method-fig-max约束,该限制可通过填充循环调整(默认值42cqh)。提高/降低--method-fig-max,即可在图像大小和卡片空间之间权衡。<figcaption>会排在图像下方。 - 子部分卡片会根据方法图调整布局——填充循环会为每篇论文选择合适的排列方式(不固定为 2×2)。
.msubs是可组合跨度的网格;为单张卡片添加标签并调整顺序,即可组合出所需布局:.msub.wide→ 占满整行的长横排(第一张卡片在顶部,最后一张卡片在底部).msub.tall→ 跨两行的高卡片(另外两张普通卡片排列在另一列)- 为
.msubs添加cols-3→ 三列等宽的三卡并排布局 - 示例:高卡片+2 张(一张
.tall+ 两张普通卡片);顶部/底部横排+2 张(开头/末尾放置一张.wide+ 两张普通卡片);2×2(四张普通卡片);三卡并排(.cols-3+ 三张卡片)。可自由添加/移除卡片。
- 将卡片安排在方法图剩余的空间内。 运行
pack预检查;使用slack测量每个.msub(每张都必须显示 FULL 0.90–1.00)。如果卡片内容稀疏/溢出或布局不平衡,重新选择排列方式(添加/移除.wide/.tall,更改卡片数量,或切换到.cols-3),或微调--method-fig-max,不要只通过扩充文案来解决。对于包含多张卡片的任何一行,平衡卡片内容,否则较短的卡片下方会留下空白(完善 Gate C / CARD-TRAILING)。
轴 2 — 样式(POSTER_STYLE,默认随机):
前三种是完整主题(会为页眉和页面背景重新设置主题);样式 4–11 是仅作用于区块的卡片处理样式,适配纯色主题(强调色页眉、扁平白色 Logo 徽标),只改变分区卡片的外观。
solid— 经典外观:标题栏填充强调色(强调色背景、白色文字),章节h2= 彩色强调文字,并带细下划线。章节采用低调的暖色卡片,顶部带强调色条纹。framed— 编辑风格外观:圆角标题栏采用描边框(白色背景、强调色边框和标题),章节h2= 边到边的强调色实心横幅;白色章节卡片带中性色细边框。simple— 极简白色外观:白色标题栏,下方只有一条细线;标题为近黑色的普通样式;无边框章节卡片之间仅用顶部细线分隔。left-bar— 卡片左侧有粗强调色竖条;标题采用普通强调色样式。elevated— 带柔和深色阴影和圆角的悬浮白色卡片。neo-brutal— 硬朗的黑色边框,搭配错位的强调色投影;标题采用大写字母。tag— 标题呈现为行内强调色胶囊。underline— 粗强调色线条紧贴标题。tinted— 卡片背景带淡淡的强调色。double-rule— 标题居中,两侧各有一条细强调色线。legend-frame— 粗强调色边框,居中标题位于顶部边缘并打断边框(类似 fieldset/legend 的样式)。
默认样式策略: --style 默认为 random,因此 compose_poster.py 会从该方向符合条件的样式目录中确定性地选取样式。横向版会从全部 11 种样式中随机选择。纵向版会从 9 种样式中随机选择,并拒绝显式指定的 underline 或 double-rule。可通过 POSTER_STYLE=<name> 或 --style <name> 覆盖为符合条件的样式。切勿要求模型“随机选择一种样式”;应使用合成器的随机模式。仅适用于区块的样式采用 solid 标题主题。纵向版还会合成 9 种主题和 5 种 A0 标题格式(pv1–pv5,assets/headers_portrait/),且均采用浅色默认标题栏。纵向版格式现在在结构上各不相同:pv1 均衡布局 Venue+QR | centered title | institutions;pv2 为全宽居中刊头,下方是 Venue+QR | institutions 导航条;pv3 为 left-top-aligned title | institutions | Venue+QR,让机构标识与论文信息相邻;pv4 是 pv1 的居中镜像布局,即 institutions | centered title | Venue+QR;pv5 是 pv3 的镜像布局,即 Venue+QR | institutions | right-top-aligned title。在 pv2/pv3/pv5 中,一条竖线将功能菜单与机构标识分隔开,同时这两个区域仍可由 fit_logos.py 独立测量。
轴 5 — 颜色/主题(POSTER_THEME,默认 random): 9 组学术强调色(blue · teal · green · burgundy · purple · rust · slate · plum · mono)——即论文图库重新着色时使用的调色板。每组都会替换 {--accent, --accent-soft}(以及音频的 --play-highlight-blue);结果登记处的 --callout(深红色)在所有主题中保持不变。采用浅色默认标题栏(--tb-bg: var(--accent-soft),深色标题)时,每种主题都会为标题栏着上浅色调,并在白色卡片上为 <h2> 文字和下划线着色——呈现浅色风格,而非深色实心横条。--theme random 会根据种子确定性地抽取一种主题,取代此前“模型手动编辑 :root”这一步。主题仅在 references/apply_theme.py(THEMES)中定义一次;横向版和纵向版共用(均通过 compose_poster.py)。
轴 3 — 标题栏(POSTER_HEADER,默认随机):
明确不含机构的模板: v6 / v7(横向版)、pv6 / pv7
(纵向版)按设计不包含机构名称和任何标题栏徽标。
选择居中(*6)或左对齐(*7);两者均保留作者姓名、会场
文本以及该方向常规的 QR 码行为。请填写 {{AUTHORS_PLAIN}},而非带单位标记的 {{AUTHORS}}。它们不纳入随机选项池。
完整规范见 references/branding_free_headers.md。
v1— 会场(左)· 标题(居中)· 机构徽标(右)。对称的三区带。v2— v1 的镜像:机构徽标(左)· 标题(居中)· 会场(右)。v3— 标题横跨全宽居中,下方设置一条等高徽标带(会议标识 + 机构)。v4— 标题(左)· 会场 + 机构徽标堆叠排列(右)。常见的 GT 布局。v5— 经典款:会场文本徽章(左)· 标题(居中)· 机构徽标 + 论文/代码二维码(右)。唯一在标题栏中包含二维码的页眉。仅限选择启用(POSTER_HEADER=v5)——选择此版式时,请停用独立的scan-to-read区域(将两个{{QR_*}}均设为空),以免二维码重复。
如果存在 assets/logos/_venue.png,v1–v4 会显示会议徽标(由步骤 6 的 fetch_conf_logo.py 获取);否则会在同一标签块中显示会场/年份文本作为后备方案;v5 则有意使用会场文本徽章。所有版式均适用于 2–6 个机构(空的 LOGO_n 槽位会自动隐藏)。徽标尺寸会调整为填满其所在区域(单个会场徽标 + 两行机构网格),徽标标签块会通过 --tb-chip-bg / --tb-chip-shadow 配合所选样式主题:纯色 → 强调色带上的纯白色平面标签块(无阴影);带边框 → 白色卡片上的纯白色平面标签块;简约 → 透明标签块(无边框),徽标直接显示在白色页眉上。默认情况下,传入 --header random — compose_poster.py 会根据配置的种子,从全部五种版式(v1–v5)中确定性地选取一种;v5 会通过 {{HDR_QR_*}} 在自己的标题栏中填入二维码(参见二维码约定)。可通过 POSTER_HEADER={v1|v2|v3|v4|v5} 覆盖。
**默认字体策略:**海报正文默认使用 Arial,--font-latin 可选择 8 种适用于 Mac/Windows PowerPoint 的字体系列名称:Calibri | Aptos | Cambria | Arial | "Times New Roman" | Verdana | Georgia | "Trebuchet MS"。这些专有操作系统字体在 Linux 渲染器或每个 HTML 客户端上都无法保证已安装。在测量浏览器几何尺寸之前,check_poster.py / render_poster.py 会将浏览器渲染固定为 assets/fonts/ 下精简、独立且采用开放许可的字体子集,而 html2pptx 仍会将所请求的原生字体系列写入 .pptx。Arial 使用随附的 Arimo Regular/Bold,因为 Arimo 的字宽度量与 Arial 兼容;其他选项则保留渲染器实际回退类别中的 DejaVu 或 Noto 开放字体。全新的 Arial 海报、旧版 Arial/DejaVu 保真度块,或本地字体优先的 Arimo 块,都会通过定向媒体门控迁移为随附字体优先的 Arimo:媒体身份必须保持不变,所有研究图表在迁移后都必须达到绝对最低值 90%,且任何轴都不得首次超过 101%。完成这一次修复后,Arimo 布局将成为持久 HTML、PDF、PNG 和 Reel 检查的严格基线。可选的 POSTER_FONT 环境变量使用相同选项,但默认值设在模板中。若要使用 Inter,请将 --font-latin 改回 Inter, …,并运行 html2pptx Inter 嵌入步骤,使 .pptx 包含该字体;每个模板中都保留 4 个 Inter @font-face 代码块,专供此覆盖选项使用。
构图目录(横向和纵向):
| 维度 | 选项 | 源文件 | 选择方式 |
|---|---|---|---|
| 布局 | 横向 full · half · 3col / 纵向 full · half | assets/layouts/<layout>.html · assets/layouts_portrait/<layout>.html | 方法图 AR / 图表数量(维度 1)→ --layout |
| 样式 | 横向:全部 11 种。纵向:solid · framed · simple · left-bar · elevated · neo-brutal · tag · tinted · legend-frame(9 种) | assets/styles/<style>.css | POSTER_STYLE(默认在当前方向的样式目录中随机选择)→ --style |
| 页眉 | 横向 v1–v5 / 纵向 pv1–pv5;选择不含机构名称/标志的样式:v6·v7 / pv6·pv7 | assets/headers/<v>.html · assets/headers_portrait/<pv>.html | POSTER_HEADER(默认随机选择,仅限带品牌的选项)→ --header |
| 扫描 | 仅限横向:single · dual(关键词分组 — 推荐)· aside(默认)· hero · contact · directory · banner · twin · chips | assets/scan/<variant>.html | 解析二维码 → --scan dual,否则 --scan single(维度 4)→ --scan;纵向没有扫描维度 |
| 颜色/主题 | blue · teal · green · burgundy · purple · rust · slate · plum · mono(9 种强调色) | references/apply_theme.py(THEMES) | POSTER_THEME(默认 random,根据种子确定性选择)→ --theme。通过组合应用于横向和纵向。 |
compose_poster.py 会验证每个选项;若名称无效,则会中止并列出可用选项。旧的单体 poster_*_{solid,framed}.html / poster_portrait_*.html 模板已弃用 — compose_poster.py(布局 × 样式 × 页眉 × 扫描 × 颜色,A0 使用 --orientation portrait)是唯一可用方式;源文件现在全部位于 assets/{layouts,layouts_portrait,styles,headers,headers_portrait,scan}/。
生成 poster.html 时,绝不可通过输出通道输出其完整内容 — 这是硬性要求。 模板约 100 KB(约 30–40k 个 token);使用 Write 工具内联写入会超出每轮输出 token 上限(CLAUDE_CODE_MAX_OUTPUT_TOKENS,默认值为 32000),并导致运行失败 — 而测量填充循环每轮都会再次付出这一代价。请以间接方式生成,确保大部分模板内容不会经过你的输出:
-
组合模板(磁盘到磁盘,不产生输出令牌 — 不要使用
Write):# landscape — assemble layout × style × header into ONE self-contained poster.html python references/compose_poster.py \ --layout <full|half|3col> --style random --header random \ --scan <single|dual> --theme random \ --out <outdir>/poster.html # portrait — composed too (STYLE + COLOR + HEADER axes; 5 A0 title formats pv1-pv5, # no scan section): reads assets/layouts_portrait/ + assets/headers_portrait/ python references/compose_poster.py --orientation portrait \ --layout <full|half> --style random --header random --theme random \ --out <outdir>/poster.htmlcompose_poster.py会解析结构钩子({{STYLE_CSS}}、{{HEADER}}和仅用于横版的{{SCAN_SECTION}}),并处理颜色轴(将:root强调色变量重写为解析出的主题);所有内容{{...}}占位符都会保留到下一步。--scan: 仅当make_qr.py生成了两个 QR 槽位(去重后仍保留两个确实不同的 URL)时,传入组关键字dual,否则传入single— compose 会在组内以确定性方式选取合适的变体(因此,双 QR 布局不会落到只有 1 个链接的纸张上,因为论文/项目/代码 URL 会合并为一个 QR);也可以使用--scan random或显式指定变体名称。纵版没有独立的扫描区段,因此会忽略此轴,但其pv1–pv5页眉仍会正常组合。QR 数量保护(双重保险): 如果传入单 QR 上下文(single,或显式指定hero/contact/banner),但metadata.json实际上在磁盘上包含两个 QR 文件,compose_poster.py会自动升级为dual组,确保第二个(项目/代码)QR 不会被悄然丢弃 — 如果解析出了代码 QR,仍请显式传入dual。--theme: 默认的random会根据种子以确定性方式从 9 种学术主题中选取一种 — 不要手动编辑:root颜色;使用--theme <name>或POSTER_THEME覆盖为指定主题。--header: 默认为random(横版 v1-v5/纵版 pv1-pv5)。--math: 数学排版引擎,默认使用katex(字形更纤细,类似 posterskill)— 只需在compose_poster.py中修改MATH_ENGINE_DEFAULT,或按次运行时使用--math mathjax/POSTER_MATH=mathjax。两个引擎都已离线打包(assets/katex/、assets/mathjax/),并由渲染器和 html2pptx 接管(其数学处理流程与引擎无关),因此切换引擎无需更改模板/pptx。每种布局(横版 + 纵版)都会在{{MATH_HEAD}}钩子处注入。确定性选择与 30 篇以上论文的批量处理。 普通运行中,随机轴依次使用
--seed(如果已提供)、POSTER_SEED,否则使用解析后的绝对--out路径。解析路径很重要:不同论文的输出目录不再仅仅因为每条命令都指定了--out poster.html就得到相同的种子。大批量处理时,传入连续的从零开始的--variant-index值,以及一个共享的--variant-seed;采样器会以确定性方式对联合随机轴组合空间排序,且不重复,同时保持各轴的边际分布均衡。横版用 11 张海报覆盖全部 11 种样式;纵版用 9 张海报覆盖其符合条件的 9 种样式;5 张海报即可覆盖全部 5 种纵版页眉;9 张即可覆盖全部 9 种主题。布局应由 Method 图决定;仅当布局本身也应参与均衡采样时,才传入--layout random:python references/compose_poster.py --orientation portrait \ --layout full --style random --header random --theme random \ --variant-index 17 --variant-seed portrait-wave-20260810 \ --selection-out <outdir>/selection.json \ --out <outdir>/poster.html每个组合后的 HTML 还会在
<script id="paper2poster-composition" type="application/json">中以 JSON 嵌入解析出的组合结果,并将主要轴标记为<body data-poster-...>属性。--selection-out会将相同的可审计选择结果写入单独的 JSON 文件,供图库和采样测试使用。 -
使用
Edit工具替换占位符,每次处理一个{{...}}词元(或一个区段块)— 每次Edit只会输出小型占位符及论文专属内容,不会输出周围的模板。切勿重建并使用Write写入整个文件。 如果需要替换很多内容,可以采用等效的 Opus 风格方案:复制references/build_poster.py中现成的骨架(其中包含实际占位符名称、用于精简版渲染的按嵌套层级移除可选部分的逻辑,以及检查是否残留{{...}}的步骤),将这篇论文的内容填入其SUBS字典,然后在组合好的poster.html上运行该脚本——模板会在运行时从磁盘读取,绝不会出现在输出中。两种方式都可以;原则相同:完整的 HTML 绝不能出现在工具调用的输出中(这是小型模型在处理大型海报时中止的最常见原因)。
现在阅读 references/template_substitution.md——其中包含完整的占位符映射、由代码驱动的主题颜色(9 选 1,由 compose / apply_theme.py 应用——不要手动编辑 :root)、各分区的强调色调色板、垂直尺寸规则(在 Portrait Half 中,每列最底部的分区必须且只能有一个 grow),以及精简版初始渲染策略:六个核心分区中仅保留 Necessary;三个可选分区(Contribution、Dataset / Benchmark、Ablation Study)以及每个 Additional 段落在此阶段都应有意暂缓添加。
解耦式页眉 + QR 占位符约定。 横版 v6/v7 遵循与 v1–v4 相同的正文扫描规则。竖版 pv1–pv5 提供 {{LOGO_1}}…{{LOGO_4}} 以及页眉 QR 占位符;pv6/pv7 仅提供 QR 占位符,不含 logo 或机构占位符。所有竖版页眉均省略独立的 Scan-to-Read 区域和扫描轴。只有在引用的 QR 文件存在时才填入竖版 QR 插槽。组合后的页眉会取代旧标题栏,因此占位符集合有所变化:
- 会议: 横版
v1–v4使用{{VENUE_NAME}}+{{VENUE_YEAR}}和可选的{{VENUE_LOGO}}。只有在assets/logos/_venue.png存在时才将VENUE_LOGO设为该路径,否则设为"";为空时,页眉会在会议徽标中绘制会议名称/年份文本。旧版{{VENUE}}标记已弃用。横版v5和竖版pv1–pv5有意保留{{VENUE_LINK}}和{{VENUE_TAG}},用于紧凑型文本徽章。 - 机构 logo(仅限品牌页眉): 横版提供
{{LOGO_1}}…{{LOGO_6}};竖版提供{{LOGO_1}}…{{LOGO_4}}。为每个已提供的机构填入路径;所有未使用的插槽都设为""(空/未填充的徽标会自动隐藏)。 - QR 的位置仅取决于页眉——QR 恰好只显示在一个位置,且绝不会出现在标题区域中,
v5除外:- 页眉
v1/v2/v3/v4/v6/v7→ 标题区域不包含 QR(这些页眉根本没有 QR 插槽)。始终通过{{QR_PAPER}}/{{QR_CODE}}填充独立的 Scan to Read.section(data-section="scan-to-read",紧跟 Takeaway 之后),并将页眉的{{HDR_QR_PAPER}}/{{HDR_QR_CODE}}设为""。机构数量无关紧要——旧的“≤ 2 个机构 → 页眉 QR”规则已弃用;QR 绝不会加入 logo 行。该区域的内部布局使用--scan轴(步骤 3):如果能解析到代码 QR,则传入--scan dual,否则传入--scan single,这样双 QR 布局就不会出现在只有一个 QR 的论文上。除{{QR_PAPER}}/{{QR_CODE}}外,所选变体还可能提供显示 URL 占位符{{URL_PAPER}}/{{URL_CODE}}/{{URL_PROJECT}}(来自metadata.json的短 URL 文本,例如arxiv.org/abs/2106.09711)和{{CONTACT}}——填入所有存在的占位符,其余设为"";每个占位符为空时都会自动隐藏。例外——--layout 3col: 在 3col 布局中会抑制独立的 Scan-to-Read 区域(其 1/3 宽的列对于该区域的小型内容来说过宽,显示时会显得空荡),因此 3col 海报有意不包含 QR。使用--layout 3col进行组合时,请将{{QR_PAPER}}/{{QR_CODE}}(以及其他扫描内容占位符)留空——它们反正会被渲染到隐藏区域中。 - 页眉
v5(经典版)是唯一在标题栏中放置 QR 的页眉——使用v5时,始终填充{{HDR_QR_PAPER}}/{{HDR_QR_CODE}},并将区域中的{{QR_*}}留空,这样 QR 只显示一次(位于v5页眉中),且scan-to-read区域会自动隐藏。 - 渲染时保证(CSS——双重保险,你不依赖构建过程填对位置): 只要标题栏包含一个已填充的 QR,所有布局都会隐藏
.section[data-section="scan-to-read"](body:has(.titlebar img.qr-img[filled]) , body:has(.titlebar .qr-tile .chip.qr img[filled]) -> [data-section="scan-to-read"]{display:none})。因此,即使页眉 QR 和区域 QR 都被填充,独立的 Scan-to-Read 区域也会在渲染时被抑制,QR 绝不会重复显示。 - 每个 QR 占位符在为空或对应的
assets/qr/*.png不存在时都会自动隐藏——只有文件存在时才设置路径。
- 页眉
- Logo 自动裁边:
fetch_logos.py/fetch_conf_logo.py现在会栅格化(SVG→PNG)并裁去透明/近白色边框,让徽标紧贴图案——自动执行,尽力而为,无需在此处采取任何操作。 替换完成后,应用视觉润色层 —— 阅读references/visual_polish.md以了解排版、颜色、行内强调词汇(<strong>/.hi/.num)、统计网格、图注、标注和架构组件,以及打印规范(画布按方向锁定:横版 60×36in /cqw/aspect-ratio: 5 / 3;竖版 33.1×46.8in /cqw/aspect-ratio: 33.1 / 46.8—— 切勿编辑)。
现在阅读 references/content_patterns.md,并打散大段文字。 这不是可选的参考资料 —— 这是对视觉质量的硬性要求。目录包含 12 个语义化组件族:callout-primary、callout-soft、callout-bar、key-stat、stat-strip、vs-compare、numbered-steps、chips、highlight-table、equation、timeline 和 banner。四种 timeline 渲染算作一个族。这些模式之所以存在,是因为在符合条件的章节中仅使用普通的 <p> + <ul> 会让海报读起来像无差别的文本。规则:
- 每个符合条件的章节正文必须至少包含一个模式组件。 Gate H 仅豁免结构性标题/标题栏卡片、扫描卡片、竖版 Full 的
method-text伪章节、已包含.headline-hero的 Headline Numbers 卡片,以及纯图表卡片。在任何其他可见卡片中仅使用普通的<p>+<ul>即为失败。 - 整张海报中,至少使用 5 个不同的语义族。 一张使用了 9 次
.p-callout-soft的海报仍然读起来单调。Timeline 变体不单独计数。在各章节间变换族,让相邻章节看起来视觉上不同。 - 每个章节最多编写 2 个组件(这是视觉质量规则;Gate H 不会机器强制执行此上限),这样一张卡片不会变成一堆相互竞争的标注。
- 让组件匹配内容形态: 从目录的"适合的内容形态"列中选择 —— 以一个数字为主的章节用
key-stat,Theirs/Ours 章节用vs-compare,流程用numbered-steps,分类法/数据集/基线列表用chips,等等。
图表/logo/QR 资产位于 <outdir>/assets/{figures,logos,qr}/(由 paper2assets 放置在此),而 poster.html 通过 src="assets/figures/…"、src="assets/logos/…"、src="assets/qr/…" 引用它们。figures.json、fetch_logos.py 和 make_qr.py 清单中的 path/file 值已经带有 assets/ 前缀,因此将它们原样放入 src 即可使相对路径从海报自身位置解析,无需进一步操作。
步骤 4 —— 迭代填充以精确适配页面
首先,进行列打包预检查(在任何填充轮次之前进行一次计算)。 运行 python3 scripts/check_poster.py pack <outdir>/poster.html。它会标记任何图表最小高度 + 最小文本已超出列高的列 —— 负余量的列是不可行的,填充循环会在那里振荡约 20 轮(实测中最大的时间消耗:一次 opus 运行在其中一列上烧掉了约 15 分钟)。在填充之前重新打包被标记的列 —— 将一个文本章节或图表移至更宽松/更宽的列,或者(如果总余量为负)删除/缩小一个图表或删减文本 —— 并且仅在每列余量 ≥ 0 时才进入循环。详情:references/staged_fill.md → "Column-pack pre-check"。
精简的初始渲染通常会留下一些未填满的区块。用迭代循环扩充内容,直到每个区块都显示为 FULL(fullRatio 达到卡片高度的 90–100%,含内边距)。每一轮:先运行 check_poster.py autofit <outdir>/poster.html —— 它会确定性地闭合机器能精确计算的连续杠杆缺口(每个 .grow 卡片行的 row-gap 缺口以及 scan-to-read QR 高度,使用报告已计算出的 needPx,并受列预算约束),并打印出仍需要由你编辑内容/图表的剩余区块 —— 然后用 check_poster.py slack --with-polish 测量,读取每个区块的判定结果,挑选与当前缺陷最匹配的一到两种修改方法,应用它们,然后重新测量以复核并决定保留或回滚。方法没有固定顺序 —— 测量结果告诉你哪里出了问题,由你来选择补救措施。每个偏离区间的判定都提示了对应的补救措施:
EMPTY(<70%)→ 添加补充文本,或为该列添加可选区块。SPARSE(70–90%)→ 润色增强现有行文(用规格中Additional的材料填充),使卡片填满。SPILLAGE(100–110%)→ 润色精简内容(收紧行文,使其占用更少行数)。OVERFLOW(>110%)→ 移除补充文本,或移除可选区块,以收回垂直空间。
当两种方法相互独立(位于不同列)时,你可以在同一轮中同时应用;当它们涉及同一列时,一次只应用一种,以便回滚决策保持明确无歧义。当有多种方法可以填补同一缺口时,优先选择价值最高的内容(真实数字、Method 图、具名贡献),而不是填充性文字。
机器校验的退出闸门。 只有当此命令退出码为 0 时,循环才算完成:
python ~/.claude/skills/paper2poster/scripts/check_poster.py slack \
<outdir>/poster.html --with-polish --strict
--with-polish 在一个渲染页面上同时运行填充闸门(slack)和视觉润色闸门(FIG/NARROW 等)—— 只需启动一次浏览器而非两次 —— 并且在 --strict 下两者都必须通过,因此这一条命令即可替代原先分开的 slack + polish 调用。只要它退出码非零,就不要停止迭代。--strict 与你每轮读取的测量相同,但带有硬性退出码 —— 不存在“可接受的 SPARSE”或“图表太紧无法修复”这类逃避。持续应用修改方法(对于顽固的图表,使用 references/staged_fill.md 中的列宽微调/垂直空间方法),直到闸门通过。
快速收敛,并限制循环次数(对小模型至关重要)。 slack 报告为每个偏离区间的区块给出精确的 needPx 增量 —— 例如 key-result SPARSE grow +50px [+18..+83]。按这个数字用连续 CSS 杠杆(margin-bottom / .col gap / 图表 max-height)进行编辑,不要靠整行文字去猜,从而超出 0.05 宽的 FULL 区间。跟踪最近的测量结果,一旦某个区块在 SPARSE↔SPILLAGE 之间来回摆动,立即切换杠杆。并且循环是有上限的:如果 约 12 轮 / 约 20 分钟后两个闸门仍未通过,则渲染测量结果最佳的状态,将该阶段标记为 DEGRADED 并附上残余的偏离区间区块 id,然后继续 —— 绝不要无限打磨。这是由脚本强制执行的:slack 会在 <poster_dir>/assets/meta/.fill_budget.json 中统计连续未收敛的测量次数,一旦超过 --max-iterations(默认 80)就以退出码 3 退出并显示 CIRCUIT BREAKER 横幅 —— 这是磁盘上的上限,能在上下文压缩后依然存活,因此丢失的轮次计数不会让你继续打磨。收敛的测量会清除该计数,而完全没有产生几何数据的调用(导航超时、MathJax 未稳定)不计入其中。将退出码 3 视为硬性停止(渲染最佳状态,标记 DEGRADED)。退出闸门保持严格;只有迭代次数被限制。完整规则见 references/staged_fill.md 顶部的 “Convergence protocol”。
当 .grow 区块持续处于 EMPTY 或 SPARSE 状态,即便已用尽其自身的 Additional/可选内容,也不要继续拉长这一个区块,而应完善同一列中其他(非 grow)区块的内容:将它们的 Additional 段落移入渲染后的卡片,把项目符号从精简形式扩展为详细形式,或加入针对论文的自定义区块。这样,.grow 区块就会自然吸收剩余空间,而不会让单张卡片因填充内容而膨胀。
当某列的预算已用尽(slackRatio ≈ 0),但分布不均——一张卡片处于 SPARSE 状态,而同列其他卡片显示为 FULL,因此无论添加还是删除内容都无济于事——请使用相邻区块再平衡方法:将 FULL 卡片中一条预留且切题的内容移到 SPARSE 卡片中(净交换,不改变该列总高度,只调整其高度预算分布)。只有确实适合目标区块的内容才能移动。
现在阅读 references/staged_fill.md——其中包含 check_poster.py slack 命令、JSON 报告格式、测量→选择→应用→复核循环、修改方法列表以及删减顺序。
先运行预检(check_poster.py preflight),以便在测量前发现残留 LaTeX/数学内容中的原始 </缺失图片。对于语义化 Paper2Assets 素材包,这也是必需的图片归属检查关卡:如果 Motivation、Method 或 Result 图片与 assets/meta/figure_selection.json 不一致,如果 Motivation 的置信度低于要求或其角色被否决为 Method/Result/Ablation,或者 Method 与 Motivation 使用了同一张图片,检查就会失败。旧版或不完整的素材包会在 Paper2Assets 升级其语义元数据前检查失败。
调试辅助。 当填充循环行为异常——slackRatio 显示一种情况,实际观察却是另一种情况——请将 check_poster.py slack --json-out <outdir>/assets/meta/poster_debug.json 的输出写入文件,在浏览器中打开 poster.html,然后按 d。每一列/区块/图片都会显示轮廓;徽标会同时显示实际渲染高度、估算高度及二者差值。
Step 5 — 为 Listen 按钮合成旁白音频
paper2assets 生成了旁白脚本(<outdir>/assets/meta/narration.json);paper2poster 会将其转换为 Listen 按钮播放的 mp3——TTS 在 paper2poster 中进行(paper2assets 不会):
python ~/.claude/skills/paper2poster/scripts/generate_audio.py \
<outdir>/assets/meta/narration.json --outdir <outdir>/assets/audio
- 默认后端 = 免费的 Edge TTS——通过
edge-ttspackage 使用 Microsoft Edge 在线语音:无需 API 密钥,无需配置文件,只需网络连接。默认语音为en-US-AndrewNeural;narration.json包含"provider": "edge"。每次运行时可通过--provider azure(需要~/.azure/speech.json和AZURE_API_KEY)或--voice <name>覆盖。请参阅references/audio_narration.md。 - **优雅跳过:**如果未安装
edge-tts或网络不可用,脚本会显示明确提示并退出,不写入任何内容——海报的 HTML/PDF 仍会正常渲染,只是 Listen 按钮不会播放声音。请显示该提示;不要伪造音频。 - **保持
PLAYLIST同步:**模板中的PLAYLIST(以及每个区块的data-sectionid)必须与<outdir>/assets/audio/中的片段 id 一致。Listen 按钮和 Full Listen 会根据 id 播放assets/audio/<id>.mp3;如果某个 id 没有对应文件,高亮会闪现后停止播放。因此,如果渲染时移除了某个区块(例如dataset-benchmark)或插入了自定义区块,请确保PLAYLIST与现有音频文件保持同步。如果<outdir>/assets/audio/整个目录不存在,按钮会正常地不执行任何操作,海报的视觉呈现仍可正常使用。
第 5.9 步 — 调整页眉 Logo 排列以填满其区域(fit_logos.py)
填充循环收敛后、渲染前,调整页眉的机构 Logo 排列,使其无论数量或形状如何都能填满所在区域:
python references/fit_logos.py --poster <outdir>/poster.html
fit_logos.py 会以真实画布尺寸在无头模式下打开海报,测量每个 Logo 区域(.logo-grid / .logo-block),通过贪心搜索行划分方案,尽可能增大所有机构 Logo 共用的统一高度(它们会一起放大,绝不会出现有的大、有的小);Logo 可以重新排序。机构资源安全:自动完成仅会读取 assets/logos/logos.json 中经过批准的条目;它不会对 assets/logos/ 中的所有图片执行 glob。当前条目包含 approved: true 和 decision: "approved";不含这些字段的旧版 logos[] 条目仍保持兼容,因为旧版清单只存储已接受的资源。明确拒绝的条目和孤立图片(例如校园照片或封面图)都会排除,即使它们仍保留在磁盘上或过时的 HTML 中。当 logos.json 不存在时,调整程序会对资源发现采取默认拒绝策略:仅排列 poster.html 中已明确指定的机构资源,不会从磁盘添加任何内容。单独管理的场地资源不受此许可名单限制:如果 assets/logos/_venue.png 存在,调整程序会将其接入会议标签(.chip.conf),以便 :has(img) CSS 生效并自动隐藏场地年份文字——绝不会重复显示标识。对于横向 v1–v4 页眉,程序还会将二维码从标题栏中移出,并放入独立的扫码阅读区域(如果较旧的渲染版本省略了该区域,则会在 Takeaway 后重新创建);横向 v5 和所有纵向页眉则会保留标题栏中的二维码。程序会将区域重排为多行,并直接在磁盘上改写 poster.html(不会通过输出通道输出完整 HTML)。每个 Logo 的高度都完全相同,并会尽可能放大以填满区域(一个 Logo 会填满整个区域;多个 Logo 会均匀分配到高度相同的各行中)。最宽的标识和较矮的页眉栏会限制统一高度,因此没有固定的填充目标——排列程序会尽可能增大共用高度。render_poster.py(第 6 步)现在会在渲染前自动运行 fit_logos.py,因此导出的 PDF/PNG 总会包含排列好的 Logo;你仍可单独运行它来预览。
第 6 步 — 将海报渲染为 PDF + PNG(优先执行——应用并固化扩展)
python ~/.claude/skills/paper2poster/scripts/render_poster.py <outdir>/poster.html
请在第 7 步(html2pptx)之前运行此脚本,以便在 html2pptx 读取 poster.html 之前将扩展固化到其中——这样,可编辑的 poster.pptx 就会与 PDF/PNG 一致,而不是使用扩展前的布局。脚本会从 HTML 中读取 @page { size: <W> <H> },将随附的 Inter 网页字体镜像到 <outdir>/assets/fonts/,将任何选定的系统字体栈固定为获得许可且可移植的浏览器字体,在启用打印模拟的情况下打开 Chromium,等待 MathJax 渲染完成,应用渲染时扩展,并将扩展写回 poster.html,然后生成 <outdir>/poster.pdf 和 <outdir>/poster.png(默认缩放比例为 0.35×)。因此,海报 HTML 和 assets/fonts/ 可保持自包含,便于跨平台共享。
渲染时“扩展”(自动启用)。 在写入 PDF/PNG 之前,render_poster.py 会对自然状态的海报进行一次只读快照,然后临时增大每个内容未填满的卡片内部各行之间的行间距,直至接近 POSTER_EXPAND_THRESHOLD(默认值为 0.98)。这样,在 0.90 FULL 门槛下收敛的海报,视觉上也会显得饱满——没有尾部空白——而无需重新运行填充循环,将门槛收紧到耗时约为原来 2 倍的水平。每项调整都会止于其底部内边距上限;如果改变了卡片的列高/容器高度,则立即回退。图形/图像卡片也可以参与调整,但不会信任实时 DOM 中的规则:渲染器会将临时规则写入 poster.html,重新加载实际文件,并且只有在级联仍能使规则生效、所有原始分区/父级矩形和可见媒体框保持固定、媒体源/固有尺寸/绘制尺寸保持固定,并且每个受跟踪的图形仍至少在一个轴向上填满其分区的 ≥90% 且无溢出时,才会保留该规则。如果验证失败,则移除该父级范围内的所有临时规则,重写样式块、重新加载,并重复此过程直至达到固定点;如果稳定或验证失败,则移除所有可选规则。然后,最终规则集还必须在再次加载完全相同的文件后通过验证,才能进行捕获。只有经过验证且持久有效的页面才会用于可编辑 HTML、其 D 覆盖层、PDF/PNG 和下游 html2pptx,从而确保所有视图使用相同的布局。样式烘焙只会在步骤 4 之后写入一个幂等的 <style id="poster-expand-baked"> 块,因此分阶段填充循环仍会测量自然的顶部对齐布局,且其 0.90 FULL 门槛仍然有效。
保留下来的规则还必须通过在全新 BrowserContext 中打开页面的验证,不能只通过热重载验证。交付的 HTML 会保护旧版周期性几何适配器,确保它们测量未缩放的固定画布并恢复精确的查看器变换;冷启动打开的页面稳定后,会冻结脚本执行,再进行 PDF/PNG 捕获,以防延迟计时器生成仅存在于实时页面中的导出结果。
两个调节参数(环境变量)——通常只需调整这两个布局旋钮:
| 环境变量 | 默认值 | 控制项 |
|---|---|---|
POSTER_FULL_THRESHOLD | 0.90 | 分阶段填充循环的 FULL 门槛(步骤 4)。布局会持续优化,直至每个分区的自然顶部对齐填充率达到此值。提高该值(例如设为 0.94)可让排版更紧凑,但循环耗时约为原来的 2 倍;每个元素的 slack 报告可防止任一门槛导致振荡。 |
POSTER_EXPAND_THRESHOLD | 0.98 | 渲染时扩展目标(此步骤)。每张卡片都会向此值扩展,但受底部内边距上限和列高保护机制限制。设为 0 可禁用扩展,输出自然的顶部对齐布局。 |
这样的配对是有意为之:0.90 可使布局快速收敛,随后在渲染时免费地通过 0.98 让最终交付物显得饱满。两者均从环境变量读取,因此可在单次运行时覆盖任一值,无需修改代码。
实用标志(通常无需更改默认值):
- 使用
--thumb-scale 0.5可生成更大的缩略图,使用0.2可生成更小的缩略图。 - 如果海报包含复杂的 LaTeX,可使用
--mathjax-timeout-ms 15000。
这是一个软性路径。 CDN 被阻止、MathJax 获取失败或 Web 字体加载缓慢时,会向 stderr 输出警告,并生成可能显示原始 $...$ 而非排版后数学公式的 PDF。请原样呈现警告,但不要因此重新运行脚本——应修复上游问题。
前置条件: playwright 和 Chromium。如果脚本因 ImportError 退出,请运行它打印的安装命令,然后重新运行。
渲染后,运行最终尺寸检查:
python ~/.claude/skills/paper2poster/scripts/check_poster.py verify-final \
<outdir>/poster.pdf --from-html <outdir>/poster.html
FAIL 表示上游 HTML 或 render_poster.py 调用有误(例如,@page 被删掉)。请呈现错误并停止——不修复 HTML 就重新运行,会得到相同的失败结果。
步骤 7 — 将 poster.html 转换为 poster.pptx(html2pptx — 标准最终交付)
用户几乎总是希望在同一次运行中获得可编辑的 PowerPoint——不得将其视为可选步骤,也不得等待用户另行提出请求。步骤 6 完成渲染并将展开内容写入 poster.html 后,将其交给随附的 html2pptx 子技能(随此技能一并提供,位于 html2pptx/;不再是单独的 git 子模块)。在 Claude 会话中,请说:
“使用 html2pptx 技能将
<outdir>/poster.html转换为<outdir>/poster.pptx。海报默认使用 Arial 字体,Mac 和 Windows PowerPoint 均已预装,无需嵌入字体——跳过嵌入步骤。仅当此海报使用可选的 Inter 覆盖字体渲染时,才运行 html2pptx 的 Inter 嵌入步骤(使用其自带的scripts/font_embedder.py),以便将字体一并打包进 .pptx。”
该技能通过 Playwright 提取 DOM,构建原生 .pptx(可编辑文本 + 原生形状 + 图像,而非幻灯片中的 PNG),渲染 soffice 校验 PNG,并运行 Claude 视觉保真度审查(默认开启)。使用 --outdir <outdir>/assets/_pptx_build/ 运行,使所有 html2pptx 产物(DOM json、校验 PNG、soffice 渲染结果)都保存在 assets/ 下,然后将演示文稿移至最终交付文件的顶层:cp <outdir>/assets/_pptx_build/poster.pptx <outdir>/poster.pptx。最终交付文件:<outdir>/poster.pptx(打包根目录);构建产物单独保存在 <outdir>/assets/_pptx_build/ 下。由于它读取的是步骤 6 中已写入展开内容的 poster.html,pptx 中会保留与 PDF/PNG 相同的展开布局。
执行顺序。 html2pptx 必须在步骤 6 的渲染和写入操作之后运行,以便读取展开后的 poster.html。它的 soffice 校验渲染结果写入 <outdir>/assets/_pptx_build/,因此不会覆盖打包根目录中的 poster.pdf / poster.png(这正是将其放在最后安全运行的原因)。
失败不阻断流程。 如果 html2pptx 确实无法运行(例如缺少 soffice 或 Python 依赖),请明确记录 WARNING,并继续执行步骤 7.5——pptx 生成失败不得阻断核心文件 poster.{html,pdf,png} 的交付。请明确报告警告;切勿悄然省略 pptx。
步骤 7.5 — 最终交付检查(完成前必须执行)
python ~/.claude/skills/paper2poster/scripts/check_poster.py deliverables <outdir>
这是确定性的关卡,不是建议。仅当 <outdir> 中的全部四个核心产物都存在且达到最低文件大小要求时,才会以 0 退出:
paper_spec.md(来自 paper2assets)poster.html(来自步骤 3–4)poster.pdf(来自步骤 6)poster.png(来自步骤 6)
如果退出码非零,命令会列出缺失文件以及生成这些文件的确切命令——运行这些命令,然后重新执行此检查。持续重复,直到退出码为 0。然后确认步骤 7 生成的 poster.pptx 也存在;如果 html2pptx 发出警告,请在报告中说明,不得悄然省略。
此关卡可捕获的失败模式——模型通常会在步骤 4 的填充循环通过 slack/polish 硬性关卡后就结束任务,完全跳过渲染步骤,并以“所有关卡都通过了 = 任务已完成”为由自圆其说。这是错误的:填充循环只会验证 HTML;它不会生成或验证 PPTX/PDF/PNG。同一个 Claude 模型处理同一篇论文,有时会执行步骤 6–7,有时会跳过;没有任何内部可依赖的预警信号。未运行此检查,不得宣告完成。
第 8 步 — 报告
告知用户所有产物的绝对路径:
<outdir>/assets/meta/paper_spec.md(由 paper2assets 生成)<outdir>/poster.html<outdir>/poster.pptx(可编辑的 PowerPoint,由第 7 步生成——如果 html2pptx 发出警告,请明确说明)<outdir>/poster.pdf<outdir>/poster.png<outdir>/assets/audio/(由第 5 步的generate_audio.py根据narration.json在此生成;如果 edge-tts/网络不可用,则此目录不存在,此时“收听”按钮不起作用)
不要将文件内容直接贴到聊天中——规格说明和 HTML 很长,而 PPTX/PDF/PNG 是二进制文件。如果聊天界面支持附加图片,请在消息中显示 PNG。说明用户可以直接在浏览器中打开 poster.html;海报会自动适配浏览器窗口大小(无需滚动)。按 s 进入全屏,按 a 切换“收听”按钮,按 d 切换调试叠加层。
完整流程是 paper2assets → paper2poster(现在会在最后通过捆绑的 html2pptx 生成可编辑的 .pptx);仍然可以在 Claude 会话中针对上一阶段的 <outdir>/,单独调用每个技能。
工具
scripts/
├── check_poster.py ← CLI: slack / preflight / polish / verify-final / deliverables
├── select_figures.py ← figures.json semantics → deterministic figure_selection.json
├── render_poster.py ← CLI: print-emulated PDF + scaled PNG thumbnail (mirrors bundled fonts)
├── generate_audio.py ← CLI: narration.json → assets/audio/<id>.mp3 (free Edge TTS default; --provider azure)
└── utils/ ← internal modules (canvas parser, Playwright + settle, etc.)
check_poster.py slack 和 render_poster.py 都会从输入 HTML 中读取 @page { size: W H }——模板已设置此项,因此无需在命令行中传入画布大小。
注意:图形裁剪工具(crop_figure.py、extract_pdf.py、fetch_logos.py、make_qr.py)位于 paper2assets 技能中。如果需要对某个图形进行一次性的视觉 box 重新裁剪,而 paper2assets 的确定性流程无法处理,可通过 ~/.claude/skills/paper2assets/scripts/ 调用这些工具(见第 2.5 步)。
模板
所有模板都位于 assets/ 中。它们共用占位符标记、音频标记、按键绑定脚本和设计标记;只有画布尺寸和列网格会因方向/布局而异。第 3 步会根据方向触发条件选择模板(POSTER_ORIENTATION=portrait → 纵向;否则为横向——请勿根据图形的纵横比自动检测方向),然后根据 Method 图形形状选择(横向:纵横比 ≥ 2.5 或 {column=full} → full,否则为 half;纵向:纵横比 ≥ 1.2 或 {column=full} → full,否则为 half)。
横向(60×36in,5:3):
layouts/half.html— 适用于半宽 Method 图形的 4 列网格。默认横向布局;Method 是与其他部分并列的半宽卡片。layouts/full.html— 适用于宽幅/全宽 Method 图形(纵横比 ≥ 2.5 或{column=full})的 4 列外部网格,中间两列合并为.mid-wide。.mid-wide区块跨越网格第 2–3 列,并将 Method(占据中间区域全宽,宽图最小宽度规则确保其至少达到可用宽度的 75%)置于上方,下方为承载 Dataset + Key Result 的 2 列.mid-sub。
纵向(33.1×46.8in A0,0.708):
layouts_portrait/half.html— 适用于高幅/中等纵横比 Method 图形的 2 列网格。默认纵向布局;左列承载 Problem / Motivation / Method(含图形);右列承载 Dataset / Key Results / Ablation / Headline Numbers / Takeaway。每列恰好有一个.grow,始终位于该列的底部区块:左列是 Method,右列是 Takeaway。layouts_portrait/full.html— 适用于宽幅 Method 图形(纵横比 ≥ 1.2 或{column=full})的 四内容带杂志式夹心布局。阅读顺序:标题栏 → 第 1 带(Problem | Motivation,等宽 2 列)→ 第 2 带(.method-hero视觉中心,全宽:左侧为竖排旋转的 SIDE-TITLE + 项目符号,右侧为宽图——杂志编辑风格)→ 第 3 带(Key Results 1.5fr | Ablation 1fr | Headline Numbers 1fr,不对称 3 列数据带)→ 第 4 带(全宽 Takeaway 点题)。Method 视觉中心位于画面中部,而非顶部——这符合海报叙事惯例(Problem/Motivation 铺垫 WHY,随后 Method 说明 HOW,再由 Results/Numbers 展示成果,最后以 Takeaway 落下胜利句点)。底部 3 列带有意采用不均衡的比例(1.5/1/1),使数据展示呈现层级而非并列关系。Takeaway 占据整个画布宽度——视线最终落在它上面,作为收尾。method-hero 内的项目符号单元格由一个 伪区块(<div class="section method-text" data-section="method-text">)包裹;观看者看不到它,但slack.py会对其进行测量——如果图形撑高该行,使其高度超过项目符号内容所需的空间,分阶段填充循环就会将method-text识别为 SPARSE,LLM 随即扩充项目符号,直到单元格填满,从而避免“窄项目符号单元格紧邻高图形 → 留白”的问题。默认布局不包含可选区块(Contribution、Dataset/Benchmark)——只有论文确实需要时,才按模板主体底部的内联注释配方将其粘贴进去。
如果要添加模板:请保持其与具体会议无关,保留 {{...}} 占位符词汇、data-section 属性和 PLAYLIST 标记,并为相应方向保留画布/cqw/aspect-ratio 锁定设置。
assets/fonts/ 中捆绑了 Inter Regular / SemiBold / Bold / ExtraBold 字体,提供 .woff2(网页)和 .ttf(嵌入 pptx)两种格式——HTML 模板的 @font-face 规则使用相对路径 fonts/Inter-*.woff2,而 render_poster.py 会将它们复制到各自的 <outdir>/fonts/ 中,使交付物可独立使用。
内容指南
- 章节语义:
- 问题——论文要解决的具体缺口或失效模式。
- 动机——为什么这件事现在很重要;以往方法有哪些不足。
- 贡献——论文明确提出的贡献(通常是引言中列出的“我们的贡献”):新产物、数据集、算法、定理或见解。
- 方法——所提方法的工作原理(贡献的技术实现)。
- 关键公式/表述——论文的核心公式:目标函数、损失函数、支配方程,或定义该方法的关键表达式。任何包含实质性数学内容的海报都至少要包含一个关键公式(大多数机器学习/理论论文都符合),并使用
equationwidget 渲染(MathJax 排版$…$/$$…$$)。模型可自行决定放置位置——将公式纳入方法,或在数学内容至关重要时单独设置一个精简的表述卡片。从paper_spec.md(paper2assets 生成的 MethodKey equation子字段)/text.txt中提取 LaTeX;切勿捏造。仅当论文确实不含公式(纯系统/实证研究)时才可省略。 - 数据集/基准测试——数据集、数据划分、规模,以及论文提出的任何新基准测试。如果论文只是使用标准公开基准测试而没有展开说明,则此部分可选。如果论文提出了数据集或基准测试,则应将其视为首要贡献。
- 关键结果——最重要的实验发现和定性结论。
- 消融研究——量化哪些组件/设计选择至关重要。列出排名前 1–3 的条目(最多 3 项)。如果论文没有消融研究,请说明这一点并省略数字。
- 醒目数据——1–4 个最突出的量化结果。数字本身就是视觉内容;不要使用图表。必须采用模板的主数字+辅助数字布局——包含
.hero-val+.hero-label+.hero-note的<div class="headline-hero">,以及包含至少 2 个.stat-mini磁贴的<div class="supporting">行(每个磁贴包含.val+.lbl)。在此处使用项目符号,或只放主数字而没有辅助磁贴,都会导致海报不合格(会被润色检查 HEADLINE/HERO 和 HEADLINE/SUPPORTING 捕获)。 - 结论——用一句话说明“这意味着什么”。
- 表格与图:表格(来自
captions.json)不能用作方法部分的图(仅figures/中的 PNG 可用)。其中的数字应融入醒目数据和关键结果的必要文本。 - 每个保留的图都必须配有一行说明。
<figure>(方法、动机部分,或填充过程中插入的任何次要图)必须始终包含非空的<figcaption>,且说明应取自captions.json——没有标签的裸图属于缺陷(check_poster.py preflight会对空说明发出警告)。如果某个图没有可用的说明来源,则应根据论文文本撰写简短、客观的一行说明,或删除该图;切勿发布没有说明的图。 - **优先使用 3 列以上的表格。**将只有“方法|指标”两列的表格拉伸至整个章节宽度,会显得内容稀疏(留有宽大的空白区域)。当论文报告多个指标时,应为每个指标设置一列,使表格内容更充实并充分利用宽度。参见
content_patterns.mdP12。 - **禁止捏造。**每个数字、结论和图注都必须能追溯到
text.txt(由 paper2assets 生成)或figures.json。不确定时,宁可省略,也不要编造。
边界情况
| 情况 | 操作 |
|---|---|
<outdir>/ 不存在,或缺少必需的 paper2assets 输出 | 自动对源 PDF 调用 paper2assets 技能,以生成/填充 <outdir>/,然后继续。 |
figures.json 为空 | 继续;Method 的图片设为 none。 |
| 所选图片文件在磁盘上不存在 | 视为 none。 |
Method 图片为 none | 按选定的方向使用 --layout half 进行排版,然后移除 Method <figure> 块。 |
设置了 POSTER_ORIENTATION=portrait(唯一触发条件——不要根据图片宽高比自动切换方向) | 使用 layouts_portrait/{full,half}.html——A0 纵向画布(33.1×46.8 英寸)。Half 为 2 列;Full 为下文所述的四带布局。 |
| 横向布局中的 Method 图片宽高比 ≥ 2.5(横向较宽) | 使用 --layout full 进行排版——宽幅流程图/架构图无论源文件的列属性如何,都使用合并中间区域的布局。 |
| 纵向布局中的 Method 图片宽高比 ≥ 1.2 | 使用 layouts_portrait/full.html——四个内容带。阅读顺序:Problem|Motivation(顶部 2 列)→ .method-hero 核心区(全宽,左侧为垂直旋转的 SIDE-TITLE + 项目符号,右侧为宽幅图片)→ Key Results|Ablation|Headline(非对称 3 列,比例为 1.5/1/1)→ Takeaway 全宽重点结论。项目符号单元格是一个伪版块,会自动填充行高。 |
横向布局中的 Method 图片为 {column=full} | 使用 --layout full 进行排版(合并中间区域的布局)。 |
纵向布局中的 Method 图片为 {column=full} | 使用 layouts_portrait/full.html(四个内容带的杂志式夹心布局,中间为带垂直旋转 SIDE-TITLE 的 Method 核心区)。 |
Method 图片为 {column=half} 且横向布局中的宽高比 < 2.5 | 使用 --layout half 进行排版。 |
| 纵向布局中的 Method 图片宽高比 < 1.2(较高) | 使用 layouts_portrait/half.html——图片位于单列,文本在上方,没有主视觉带。 |
<outdir>/assets/logos/ 为空 | 移除未能解析出所属机构的所有 <img class="logo"> 元素——不要在 src 中留下字面的 {{LOGO_N}} 标记。 |
<outdir>/assets/qr/code.png 不存在 | 从标题栏移除代码 QR 的 <img>;只保留论文 QR 也可以。 |
| 标题数字少于 4 个 | 移除未使用的 .stat div(保留至少 2 个辅助信息卡片)。 |
| 没有清晰的基线与我们方法的对比 | 将 <table class="results"> 替换为包含 Key Result Necessary 的 <p>。 |
poster.html 已存在 | 直接覆盖,无需询问。 |
| 论文没有消融研究 | 用一行 Necessary 说明没有消融实验;Additional 留空;移除 Ablation Study .section 块,并从 PLAYLIST 中删除 "ablation-study"。 |
| 论文仅使用标准公开基准(没有新数据集) | Dataset / Benchmark 为可选项。默认在精简渲染时省略 .section 块;如果某列有剩余空间,分阶段填充循环可以添加一张仅含一行“Standard benchmarks: …”的卡片。如果省略该块,则从 PLAYLIST 中删除 "dataset-benchmark"。 |
| 论文提出了新的数据集或基准 | 在初始轮次中渲染 Dataset / Benchmark 部分(将其视为与 Method 同等重要的一级内容);在 PLAYLIST 中保留 "dataset-benchmark"。 |
关键规则
- 绝不编造数字。 从
text.txt(paper2assets 的输出)中提取。每项统计数据、差值和表格单元格都必须能在规范中找到依据。 - 绝不要通过输出通道发送完整的
poster.html。 它约有 100 KB;完整文件的Write(或以任何方式内联输出整个模板)都会超过每轮输出令牌上限(CLAUDE_CODE_MAX_OUTPUT_TOKENS,默认值为 32000),导致运行中止——这是较小模型处理大型海报时最常见的失败原因。应间接生成(通过 shellcp复制模板,再用针对占位符的Edit修改;或使用build_poster.py生成器——参见步骤 3),并确保填充循环中的每项更改都是局部Edit,绝不整份重写。 - 填充循环期间,绝不要再次
Read整个poster.html(这是上述规则在输入上下文方面的对应要求)。 文件约有 100 KB,每轮都重新读取会淹没较小模型的上下文窗口 → 自动压缩 → 填充状态丢失 → 循环反复折腾,始终无法收敛。请依据slack报告操作——它现在会打印一个EDIT TARGETS区块,其中包含每个超出范围的章节的原文;直接从中复制Edit的old_string,绝不要重新读取整个文件。参见staged_fill.md规则 6。 - 先精简渲染,再依据测量结果填充。 替换占位符时不要猜测内容是否适配。先仅渲染核心章节的
Necessary内容——Problem、Motivation、Method(包含关键公式)、Key Result、Headline Numbers、Takeaway——然后让check_poster.py slack决定添加什么。默认删除 Contribution(仅当论文的核心创新点就是其贡献列表时才保留)。降低 Ablation Study、Dataset / Benchmark 和填充性 Takeaway 的优先级——只有在包含真正重要的一手内容时才渲染(仅当论文引入数据集时才保留 Dataset;仅当 Ablation 有实际消融行时才保留)。填充循环应优先添加关键公式、真实数据、Method 图以及次要/定性图,而不是 Ablation、Dataset 或凑数的文本,也不要恢复 Contribution。 - 每张海报至少安排 2 张图。 只有 Method 图会让右侧的实证内容变成一堵由文字和数字组成的墙。步骤 2 会在论文有次要图时选取一张——除了 Method 示意图,还至少需要一张实证视觉材料。只有在其他图都不具备实际信息时,才可以接受仅有 1 张图的海报(这种情况很少见)。
- 包含关键公式。 对于包含有意义数学内容的论文,每张海报都必须通过
equation组件展示至少一个关键公式/表达式(目标函数、损失函数或控制方程),并将其融入 Method,或作为精简的 Formulation 卡片呈现。对于由公式驱动的论文,不呈现任何公式属于质量问题(这是与作者版相比最常见的缺陷)。从规范/text.txt中提取 LaTeX;绝不要编造符号。 - 章节不得没有内容。 如果某章节渲染后没有真实内容,就省略它,而不是显示空章节——绝不要在占位符上方保留标题,也不要只放一个「N/A」。这也是 FULL 填充门槛的另一面:降低优先级的章节(Ablation、填充性 Takeaway、论文未引入数据集时的 Dataset)应直接删除,而不是填充凑数。每个保留的章节都必须包含真实且针对该论文的内容。
- 严格执行逐章节适配门槛。 只有在每个章节均为
FULL(fullRatio 为 0.90–1.00),且每张卡片中的图至少有一个轴填满其边框的 90–100%(polish报告中没有FIG/NARROW)时,才停止分阶段填充循环。不允许按列放宽 SPARSE 标准——SPARSE卡片并未完成;它表示该卡片尚未填充完毕。 - 填充循环通过 ≠ 任务完成。 通过 slack/polish 门槛意味着 HTML 布局良好,不代表交付物已经生成。步骤 6(渲染 PDF/PNG)和步骤 7(html2pptx)是独立步骤;模型常把「填充循环已收敛」误认为「任务完成」,因此经常跳过这两步。步骤 7.5 中的
check_poster.py deliverables门槛不可妥协:报告前必须运行,并持续循环直到退出码为 0。 .grow卡片也受门槛约束,并非例外。 flexbox 拉伸.grow卡片以填补列中剩余空间后,旧版工具可能会将其判定为 FULL,但卡片仍可能有一条明显的尾部空白。对它同样应用 fullRatio 门槛——填入内容(Additional/额外项目符号),或将其非.grow同级卡片中的内容移过来,而不是留着空白。- 多卡片内容一致性(反复出现的缺陷——请仔细阅读)。 只要某个章节呈现一行横向排列的小型统计/数字卡片,每张卡片在视觉上都必须采用相同形态——大数字的行数相同,标签的行数也相同。高度不一致会显得很糟:一张卡片的数值高于相邻卡片,或标签出现 2 行/3 行的阶梯状基线。此规则适用于各种情况——不仅是
.headline-hero .supporting中的.stat-mini卡片,还包括.p-stat-strip单元格、Motivation/Method/Key Results中任何临时添加的数字卡片行,以及将来的所有卡片组件。- 模板现在已在结构上提供保护:
.headline-hero .supporting使用align-items: flex-start(所有.val数字都会顶部对齐,无论标签高度如何,位置始终一致);.stat-mini .lbl设置了min-height: 2.4em(每个标签都预留 2 行空间,因此 1 行和 2 行标签占用相同的垂直空间)。这样,换行的标签就不会再把数值挤偏。但 CSS 只是预留了空间——你仍必须确保每个标签都不超过 2 行;否则 3 行标签会溢出预留的 2 行空间,导致整行再次错位。不要把 CSS 当作撰写不一致标签的借口。 - 大数字: 要么所有卡片的数值都占一行,要么都换成两行。绝不要在同一行中混用 1 行和 2 行。可缩短最长的数值(例如
−84% FLOPs Δ→−84%),或改写较短的数值使其也换行——通常前一种更好。 - 标签: 一行中的所有标签都应保持相同的行数,每个标签最多 2 行(预留空间恰好是 2 行)。要么都占 1 行(适用于
pts、params、mAP等短词),要么都占 2 行;绝不要混用并造成阶梯状效果。如果某个标签自然会变成 3 行,而其他标签只有 2 行,就缩短较长的标签(删去修饰词、优先使用缩写、采用M/B等单位简写,准确率可用acc)——不要给较短的标签凑字数。 - 宣布完成前先检查。 目视检查渲染海报中的每一行多卡片布局。如果数值的 y 坐标不同,或标签呈阶梯状排列,则该行不符合一致性要求——宣布完成前必须修正内容。
- 模板现在已在结构上提供保护:
- 不要编辑画布锁定设置。 两个模板中的 60×36in/
cqw/aspect-ratio: 5 / 3规则,能确保浏览器预览、打印 PDF 和 PNG 缩略图在不同缩放比例下保持相同布局。 - 图像清理流程由 paper2assets 负责(top-check → decaption → autotrim)。 不要在此处重新运行确定性流程——它已经完成。步骤 2.5 中的视觉
box裁剪仅用于处理残留的不对称噪点。