會議海報產生器 (HTML)
產生專業的 HTML 海報。使用者備註:$ARGUMENTS
此海報是一個 基於 React 的互動式編輯器 — 單一自包含的 HTML 檔案,位於 poster/ 目錄中。無需建置步驟(React/Babel 透過 CDN 載入)。使用者可以在瀏覽器中直觀地調整版面,然後將設定匯出回 Claude 以進行進一步修改。
專案資料夾結構
<project>/
├── overleaf/ # 來自 Overleaf 的論文原始碼
│ ├── paper.tex
│ ├── figures/
│ └── ...
├── references/ # 用於風格比對的參考海報
│ └── (任何格式:pdf、png、jpg、html、pptx……)
├── poster/ # 產生的自包含海報網站
│ ├── index.html # 海報(React 應用程式)
│ ├── poster-config.json # 版面設定(欄位、卡片順序、高度、字體縮放)
│ ├── logos/ # 機構標誌
│ ├── teaser.png # 複製/轉換的圖表
│ ├── qr.png # 專案頁面 QR 碼
│ ├── qr-posterskill.png # Posterskill QR 碼
│ └── ...
└── .claude/skills/make-poster/
overleaf/包含論文原始碼。請閱讀主要的.tex檔案以及任何它用\input{}引入的檔案。references/包含展示使用者偏好的視覺風格的範例海報。請閱讀/檢視此資料夾中的所有檔案,以匹配其設計語言。poster/是產生的輸出 — 一個自包含的網站。所有圖表和資產都與index.html放在同一層,因此相對路徑可以直接使用。
輸入
- 論文原始碼 - 位於
overleaf/。詢問使用者要讀取哪個.tex檔案(例如paper.tex、main.tex)。然後讀取該檔案以及它用\input{}引入的所有檔案。 - 專案網站 - 如果尚未知道,請詢問使用者 URL。使用 WebFetch 取得作者資訊、託管圖片和連結。
- 參考海報 - 從
references/自動發現。檢視該處的所有檔案並匹配其風格。 - 作者網站(可選)- 使用 WebFetch 取得設計線索(調色盤、排版、標誌)。使用 Playwright 從作者網站下載機構標誌(curl 因重新導向可能失敗):
page.request.get(url)下載原始位元組。 - 格式化要求 - 詢問海報尺寸、方向、欄位數量。
- Git 儲存庫(可選)- 詢問使用者是否有要推送海報的 GitHub 儲存庫。
如果使用者未指定格式化方式,請在繼續前詢問。不要預設尺寸、方向或欄位數量。
流程
步驟 0:分析風格參考
在 references/ 中尋找任何 PDF、PNG 或圖片檔案。將 PDF 轉換為 PNG(在 macOS 上使用 sips -s format png)。檢視每個檔案並記下視覺風格 — 版面、顏色、排版、卡片樣式、圖表放置。匹配參考樣式 — 如果參考海報是淺色/簡潔風格,請勿使用深色主題。
步驟 1:從論文原始碼提取內容
詢問使用者要讀取哪個 .tex 檔案。提取:標題、作者、所屬機構、摘要(2-3 句)、關鍵方法、結果(表格 + 圖表)、關鍵方程式(最多 1-2 個)、結論。
步驟 2:取得專案網站
使用 WebFetch 取得作者姓名、所屬機構、圖表 URL、用於 QR 碼的專案 URL、連接到程式碼/arxiv/影片的連結。
步驟 3:將資產收集到 poster/
圖表: 從 overleaf/figures/ 複製,以高解析度將 PDF 轉換為 PNG:
sips -s format png input.pdf --out poster/output.png -Z 3000
網站圖片: 使用 Playwright 從專案網站下載更高品質的圖片(不要用 curl — 許多網站會重新導向):
resp = page.request.get(url)
with open('poster/filename.png', 'wb') as f:
f.write(resp.body())
標誌: 使用 Playwright 從作者的個人網站下載機構標誌。儲存到 poster/logos/。範本會自動將它們反轉為白色以用於頁首。
QR 碼: 產生並儲存:
curl -sL -o poster/qr.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=PROJECT_URL"
curl -sL -o poster/qr-posterskill.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=https://github.com/ethanweber/posterskill"
步驟 4:測量圖表長寬比
這對於消除空白區域至關重要。 測量每張圖片:
sips -g pixelWidth -g pixelHeight poster/*.png poster/*.jpg
然後根據長寬比將圖片分配到欄位:
- 寬圖(比例 >2:1,例如 teaser、架構圖):放在最寬的欄位
- 方形圖(比例 ~1:1):放在窄欄位
- 直立圖(比例 <1:1):放在最窄的欄位
這可以防止第一大空白問題:寬圖放在窄儲存格中(或反之),留下巨大空隙。
步驟 5:產生海報 HTML
使用位於 ${{CLAUDE_SKILL_DIR}}/template.html 的範本作為起點。該範本是一個 React 應用程式,具有:
架構:
CARD_REGISTRY— 定義每張卡片的內容(標題、顏色、JSX 主體)DEFAULT_LAYOUT— 定義欄位結構和卡片順序DEFAULT_LOGOS— 用於頁首的機構標誌- React 狀態管理版面,並使用 localStorage 持久化
window.posterAPI公開用於程式控制的函式
需要自訂的關鍵項目:
- 使用論文內容更新
CARD_REGISTRY(每個章節是一張卡片) - 使用長寬比最佳化的欄位分配更新
DEFAULT_LAYOUT - 使用使用者的機構標誌更新
DEFAULT_LOGOS - 更新
DEFAULT_FONT_SCALE(從 1.3 開始,使用者可以透過 A-/A+ 按鈕調整) - 更新頁首(標題、作者、所屬機構、會議徽章、QR 碼)
- 更新
@page { size: WIDTHmm HEIGHTmm; }和body { width: WIDTHmm; height: HEIGHTmm; }以符合海報尺寸 - 使用相同的尺寸更新
posterAPI的 fit() 函式
卡片內容模式:
- 圖表卡片:
<div className="fig"><div className="fig-wrap"><img src="file.png" alt="..." /></div><div className="cap"><b>標題說明。</b>描述文字。</div></div> - 文字卡片:
<div className="hl"><p>重點文字</p></div><ul><li>要點 1</li></ul> - 表格卡片:
<table><thead>...</thead><tbody>...</tbody></table>,在獲勝儲存格上使用className="best" - 方程式卡片:
<div className="eq">{'$LaTeX equation$'}</div>(在 JSX 中跳脫反斜線)
消除空白區域的關鍵 CSS 規則:
- 圖片必須使用
width:100%; height:100%; object-fit:contain(不要用 max-width/max-height — 它們會阻止縮放) - 每個欄位必須始終有一張卡片帶有
grow: true(flex:1)來填滿剩餘空間 isCardGrow()函式會自動確保這一點 — 如果沒有卡片設定 grow,則最後一張卡片會獲得 grow
檢視區縮放:
- 在 body 上使用
translate() + scale()來將海報置中並適配任何瀏覽器檢視區 transform-origin: top left至關重要@media print必須設定transform: none !important以獲得正確的列印解析度getBoundingClientRect()會回傳縮放後的值 — 在調整大小處理程式中務必除以currentScaleRef.current
步驟 6:使用 Playwright 自動最佳化版面
產生後,使用 Playwright 測量空白區域並找到最佳欄位寬度:
from playwright.sync_api import sync_playwright
import os
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={'width': 3200, 'height': 2260})
page.goto('file://' + os.path.abspath('poster/index.html'))
page.wait_for_load_state('networkidle')
page.wait_for_timeout(3000)
# 測量空白區域
waste = page.evaluate('window.posterAPI.getWaste()')
print(f"總空白:{waste['total']}px")
for d in waste['details']:
print(f" {d['card']}: H={d['wasteH']} W={d['wasteW']} ({d['pct']}%)")
# 嘗試不同的欄位寬度以最小化空白
best_waste = waste['total']
best_c1, best_c3 = 300, 230
for c1 in range(200, 350, 10):
for c3 in range(160, 280, 10):
page.evaluate(f'window.posterAPI.setColumnWidth("col1", {c1})')
page.evaluate(f'window.posterAPI.setColumnWidth("col3", {c3})')
page.wait_for_timeout(30)
w = page.evaluate('window.posterAPI.getWaste().total')
if w < best_waste:
best_waste = w
best_c1, best_c3 = c1, c3
# 套用最佳值並截圖
page.evaluate(f'window.posterAPI.setColumnWidth("col1", {best_c1})')
page.evaluate(f'window.posterAPI.setColumnWidth("col3", {best_c3})')
page.wait_for_timeout(500)
page.screenshot(path='/tmp/poster_screenshot.png')
# 也嘗試在欄位之間交換卡片
page.evaluate('window.posterAPI.swapCards("cardA", "cardB")')
# ... 再次測量空白 ...
browser.close()
然後讀取 /tmp/poster_screenshot.png 以進行視覺檢查。多次迭代 — 截圖、修正問題、重新截圖,直到海報的空白區域最小。
找到最佳值後,將它們烘焙到 HTML 中的 DEFAULT_LAYOUT、DEFAULT_CARD_HEIGHTS 等。
步驟 7:產生 PDF 並驗證
page.pdf(
path='poster/poster.pdf',
width='841mm', height='594mm', # 符合海報尺寸
margin={'top':'0','right':'0','bottom':'0','left':'0'},
print_background=True
)
將 PDF 轉換為 PNG 並讀取,以驗證它以全解析度渲染:
sips -s format png poster/poster.pdf --out /tmp/poster_pdf_check.png -Z 3000
步驟 8:打開並與使用者迭代
在瀏覽器中打開海報:
open poster/index.html
向使用者說明編輯控制項:
- 預覽 — 關閉編輯 UI 以查看確切的列印效果
- A-/A+ — 全域調整字體大小
- 拖曳欄位分隔線(垂直藍色條)— 左右調整欄位大小
- 拖曳列分隔線(水平藍色條)— 在欄位內上下調整卡片大小
- 點擊交換 — 點擊一張卡片的菱形手柄(變成橘色),然後點擊另一張卡片以交換它們
- 移動/插入 — 點擊一張卡片的手柄,然後點擊虛線橘色放置區以將其移動到該處
- 儲存 — 下載
poster-config.json - 複製設定 — 將版面 JSON 複製到剪貼簿
- 重設 — 還原為預設值
主動提出改進建議: 展示初稿後,建議具體的更改:
- "模型架構卡片有一些空白區域 — 試著將它上面的列分隔線往下拖,給它更少的空間"
- "完成圖表可能更適合放在欄位 2,因為它比較寬 — 試著點擊它的菱形,然後點擊欄位 2 中的一個放置區"
- "您可能想按幾下 A+ 來調大字體"
鼓勵反饋循環: 告訴使用者:
試著在瀏覽器中重新排列海報!當您對版面感到滿意時,點擊右上角工具列中的 複製設定 並貼到這裡 — 我會將這些更改烘焙到預設值中,以便它們持久化。
- 儲存 — 下載
poster-config.json - 複製設定 — 將版面 JSON 複製到剪貼簿以貼給 Claude
- 重設 — 還原為預設值
當使用者貼上設定 JSON 時,更新 HTML 中的 DEFAULT_LAYOUT、DEFAULT_CARD_HEIGHTS、DEFAULT_FONT_SCALE 和 DEFAULT_LOGOS 以匹配。同時將它寫入 poster-config.json。
步驟 9:推送到 GitHub(可選)
如果使用者提供 GitHub 儲存庫 URL:
cd poster
git init
git remote add origin <REPO_URL>
git add .
git commit -m "海報:<論文標題>"
git push -u origin main
重要指南
- 無空白區域。 這是第一要務。使用長寬比感知的欄位分配、圖片上的
width:100%; height:100%; object-fit:contain、自動擴展卡片和 Playwright 最佳化工具。迭代直到空白最小化。 - 保持文字簡潔。 海報是視覺化的 — 使用項目符號,而不是段落。2 分鐘內能理解。
- 匹配參考風格。 如果參考海報是淺色/簡潔風格,請勿使用深色主題。匹配整體美學。
- 字體縮放。 所有文字大小使用
calc(Xpt * var(--font-scale)),以便 A-/A+ 按鈕能運作。從--font-scale: 1.3開始,讓使用者調整。 - 列印最佳化 CSS。
@media print隱藏所有編輯 UI 並設定transform: none !important。@page設定確切尺寸。 - Posterskill QR 碼。 始終在頁首包含一個連結到
https://github.com/ethanweber/posterskill的 QR 碼,並附帶標籤 "使用我的 Claude 技能製作的海報"。 - 無致謝頁尾。 保持海報乾淨 — 預設情況下無頁尾。
- 頁首中的標誌。 從作者的網站下載機構標誌,儲存到
poster/logos/,並將它們列在DEFAULT_LOGOS中。它們會透過 CSS 濾鏡自動反轉為白色。 - 自包含。 無需建置步驟、無需 npm、無需伺服器。單一 HTML 檔案,依賴 CDN。以
file://直接打開即可運作。 - 方程式。 使用 KaTeX(透過 CDN 載入)。在 JSX 字串中跳脫反斜線:
{'$\\mathcal{E}$'}。
圖表處理
- 始終將需要的圖表複製到
poster/中 — 不要在 HTML 中引用overleaf/的路徑。 - 以高解析度將 PDF 轉換為 PNG:
sips -s format png input.pdf --out poster/output.png -Z 3000 - 使用 Playwright 的
page.request.get()下載網站圖片(不要用 curl — 網站經常重新導向)。 - 使用
sips -g pixelWidth -g pixelHeight測量長寬比,並相應地分配到欄位。
使用者設定更新工作流程
使用者可以在瀏覽器中調整海報並將更改分享回來:
- 使用者點擊工具列中的 "複製設定"
- 使用者在聊天中貼上 JSON
- Claude 更新
index.html中的DEFAULT_LAYOUT、DEFAULT_CARD_HEIGHTS、DEFAULT_FONT_SCALE、DEFAULT_LOGOS以匹配 - Claude 也將設定寫入
poster-config.json - 使用者重新整理並點擊 "重設" 以載入新的預設值
程式化 API (window.posterAPI)
可在瀏覽器控制台或透過 Playwright 使用:
swapCards(id1, id2)— 交換兩張卡片(可跨欄位)moveCard(cardId, targetColId, position)— 將一張卡片移動到特定位置setColumnWidth(colId, widthMm)— 設定欄位寬度(null 表示 flex)
…
[已截斷以供翻譯]
