社群卡片

給社群平台用的圖文貼文和封面。一份原始檔產出三樣東西:每張卡片一張 PNG,尺寸是平台要求的像素;一個圖庫頁面,可以看封面在資訊流裡的大小;LinkedIn 文件還會多一份 PDF。

npx slidehtml cards new solar-post       # 產生 src/cardsets/solar-post/index.tsx
npx slidehtml cards dev solar-post       # 在圖庫裡預覽
npx slidehtml cards check solar-post     # 字型、型別檢查、匯出、QA,最後一行是 PASS 或 FAIL
npx slidehtml cards build solar-post     # 輸出 dist/cards/solar-post.html 和 dist/cards/solar-post/ 裡的 PNG

檔案放在 src/cardsets/<name>/index.tsx。寫完要跑到 PASS,並以原尺寸看過 dist/cards/<name>/ 裡的每張 PNG,再看每張 qa/cards/<name>/feed-NN-<preset>.png,這是封面縮到估算的資訊流寬度後的樣子。

check 需要 Playwright 的 Chromium(npx playwright install chromium)。其中的字型步驟需要 Python 3、fonttools、brotli 和 Noto CJK 的 .ttc 檔案(apt install fonts-noto-cjk fonts-noto-cjk-extra,或設定 NOTO_CJK_DIR)。缺少這些時,check 會以 FAIL 結束。build 不跑字型步驟,也不跑 QA,所以要在 check 之後用,不能取代它。

一組卡片

import type { CardSetDef } from '../../cards'

export const set: CardSetDef = {
  title: '我的卡片',
  preset: 'xhs-portrait',      // 每張卡片的尺寸,單張可以用自己的 `preset` 覆寫
  theme: 'cobalt',
  cards: [
    { t: 'cover', lines: ['三五個字', '說清重點'], mark: [1], hint: '左滑', source: null },
    { t: 'number', value: '2,779', unit: 'TWh', label: '這個數字是什麼', source: '發布者,年份' },
    { t: 'ending', lines: ['最後一張'], cta: '只提一個要求', source: null },
  ],
}

CardSetDef 還可以寫 style、iconStyle、lang(zh 或 en)、handle(每張卡片上的帳號名稱,≤ 14)和 pages(內頁頁碼)。

在圖庫裡,資訊流大小的按鈕會以估算的資訊流寬度顯示每張封面,安全區的按鈕會在卡片上畫出安全區、遮擋條和裁切範圍。

尺寸預設

preset位置像素比例依據資訊流寬度
xhs-portrait小紅書 直向1080×14403:4community180
xhs-square小紅書 方形1080×10801:1community180
xhs-landscape *小紅書 橫向1440×10804:3community180
bili-wide *B站 封面1920×108016:9conflict180
bili-mobile *B站 封面1200×9004:3unconfirmed180
douyin-cover *抖音 封面1080×19209:16community128
channels-portrait *視頻號 直向封面1080×12606:7community128
channels-wide *視頻號 橫向封面1080×60816:9community128
wechat-head *公眾號 頭條900×3832.35:1community350
wechat-thumb *公眾號 次條200×2001:1community60
weibo-square微博 九宮格1080×10801:1community120
weibo-article *微博 文章頭圖980×55016:9community350
ig-portraitInstagram 輪播1080×13504:5community128
ig-tallInstagram 輪播1080×14403:4community128
linkedin-docLinkedIn 文件,同時輸出 PDF1080×13504:5community360
yt-thumb *YouTube 縮圖1280×72016:9official168
og-image *Open Graph1200×6301.91:1official360
x-card *X 連結卡片1200×6281.91:1conflict360

* 只作封面:這個預設上的每張卡片都要過資訊流檢查。資訊流寬度的單位是 390 px 寬手機上的 CSS px,每個值都是估算。

「依據」的意思:

  • official:在平台自己的頁面或它的搜尋摘要裡讀到。yt-thumb 只有比例和最小寬度是官方的,1280×720 和右下角的時長位置來自第三方。og-image 的 Meta 頁面只讀到搜尋摘要。
  • community:第三方指南說法一致,平台沒有確認。
  • conflict:來源互相矛盾,這個值是我們的選擇。B站的來源有 16:9、16:10 和 4:3,所以 src/cardsets/solar-bili 匯出了兩種尺寸。
  • unconfirmed:只有一個來源,或是我們自己的觀察。

每個值的依據寫在程式碼儲存庫的 plans/research-cards.md。平台隨時可能改規格,要依賴某個值之前,先到 App 裡確認。

範本

t用途欄位與上限形狀
cover大字封面lines 1–3 行,mark,sub ≤ 24,motif,hint ≤ 8細長、直向、方形
wide寬比例封面lines 1–2 行(16:9 每行 ≤ 8,wechat-head 每行 ≤ 4),mark,sub ≤ 20,motif,align橫向、寬版、橫幅
number一個數字就是重點value ≤ 7,unit ≤ 6,label ≤ 22,note ≤ 40,bars除橫幅外都可以
chart一張圖和它證明的一句話title ≤ 22,takeaway ≤ 40,chart除橫幅外都可以
compare2–3 項並排對比title ≤ 22,items(label ≤ 12,value ≤ 7,unit,num,note ≤ 22,focus),verdict ≤ 36除橫幅外都可以
quote一句有署名的話text ≤ 44,by ≤ 24除橫幅外都可以
list要點title ≤ 22,items(head ≤ 14,body ≤ 40,icon):直向 3–5 條,方形和 4:3 為 3 條細長、直向、方形、橫向
steps有先後的步驟title ≤ 22,steps(head、body):直向 3–4 步,方形 3 步細長、直向、方形
text圖表說不清的論點title ≤ 22,paras 1–3 段,每段 ≤ 70細長、直向、方形
image截圖、照片或裝飾圖image,title ≤ 22,caption ≤ 40細長、直向、方形
ending最後一張lines 1–2 行,每行 ≤ 8,mark,takeaways 0–3 條,每條 ≤ 24,cta ≤ 22,sources 0–3 條,每條 ≤ 44細長、直向、方形

封面的 motif 有三種:{ kind: 'bars', values }、{ kind: 'icon', icon },以及貼紙式的 { kind: 'emoji', e: '🎤', around: ['✨', '💡'] }。任何文字欄位也都可以直接打 emoji,見 guide 的 Emoji 一節。

每張卡片還有 source(≤ 44,或 null)、kicker(≤ 14)、tone(paper、ink、accent、wash)、preset 和 cover。

形狀:細長是 9:16,直向到 6:7 為止,橫向是 4:3,寬版到 2:1 為止,橫幅比這更寬(wechat-head)。範本用在沒有對應版式的形狀上,QA 會指名報錯。

chart 可以是 line(1–3 條線)、bars(≤ 12 根)或 rank(直向 ≤ 8 列,方形和寬版 ≤ 5 列,名稱 ≤ 6)。

規則

  • 上限這樣算:一個漢字算 1,一個英文字母或數字算 0.5。QA 會數標題、內文欄位、kicker 和 source。大標題不計數,它的字級由最長一行決定,太小時 QA 判 FAIL。內文不會自動縮小,放不下就刪字或拆卡片。
  • 封面大標題每行放得下的字數:小紅書約 6 個漢字,抖音和其他三欄宮格約 5 個,wechat-thumb 只有 2–4 個。每一處換行都自己決定。不要重複貼文標題,平台通常已經把它印在封面旁邊。
  • 第一張是封面,標了 * 的預設上每張都是封面。封面必須有大標題,所以只能用 cover、wide 或 number。要在這種預設上放別的範本,給那張卡片寫 cover: false。
  • 事實必須有出處。在 source 寫明發布者,計算出來的數字要標明。只有不陳述事實的卡片才寫 null。QA 只能在卡片含有數字時發現缺出處,用文字寫的事實要自己查。查不到出處的事實不要寫。
  • quote 的 by 必須是真實的署名,不要替別人編話。
  • image.kind 遵守專案的圖片規則:screenshot 是你自己作品的截圖,可以當證據;photo 只營造氛圍,並印出 credit;decor 只做裝飾。

QA 檢查什麼

文字是否超出卡片、進入安全區或壓在遮擋條下面。檔案裡的文字是否小於 10 px,全螢幕開啟時在手機上是否太小。最後一行是否只剩一個字。文字重疊、內容溢位、內容被裁掉、圖表被壓得太扁。內容上限。有數字沒出處、宣告了出處卻沒印在卡片上、照片沒有署名、圖片沒載入。把 PNG 縮到資訊流寬度後測量大標題的字級和對比度,以及大標題在置中裁切後是否還在。原尺寸的對比度。是否退回系統字型。從檔案讀取每張 PNG 的準確像素。PDF 頁數(需要安裝 pdfinfo)。圖庫在手機上是否橫向捲動,頁面錯誤和網路請求。

結果在 qa/cards/<name>/report.json。

已知限制

  • 這裡沒有一個中國平台的規格得到官方確認。小紅書、抖音、視頻號和 B站都沒有找到公開的官方頁面,試過的微信文件頁面回傳 404。
  • 資訊流寬度是估算,來自算術或觀察。大標題的最小字級(資訊流大小下 16 CSS px,wechat-thumb 為 14)是判斷,不是標準。安全區、遮擋條和置中裁切都是工作假設。
  • 沒有在真實 App 裡發布測試過。第一次發布後要到 App 裡看一眼。
  • QA 能發現一行只剩一個字,發現不了一個詞被拆到兩行,所以每張卡片還是要有人看。