
免费
邮戳分享卡
像航空信一样的链接预览图:每个标题一张 1200x630 PNG,脚本盖章,不用图像模型。
安装
把“邮戳分享卡”技能安装到 ~/.claude/skills/postmark-card。 下载下面每个文件,保存到这个文件夹: https://skilllift.pages.dev/packs/postmark-card/SKILL.zh.md → SKILL.md https://skilllift.pages.dev/packs/postmark-card/references/style.md → references/style.md https://skilllift.pages.dev/packs/postmark-card/assets/card.html → assets/card.html https://skilllift.pages.dev/packs/postmark-card/assets/emblems.json → assets/emblems.json https://skilllift.pages.dev/packs/postmark-card/assets/keep-words.json → assets/keep-words.json https://skilllift.pages.dev/packs/postmark-card/scripts/render.mjs → scripts/render.mjs https://skilllift.pages.dev/packs/postmark-card/scripts/rules.mjs → scripts/rules.mjs https://skilllift.pages.dev/packs/postmark-card/scripts/check.mjs → scripts/check.mjs 然后读一遍 SKILL.md,告诉我它是做什么的,并提醒我开一个新会话。
解压到 ~/.claude/skills
同一个技能,不同的需求
左边是预览。右边由另一个 Agent 按不同需求制作,它只有安装好的技能,没看过预览。
这是按虚构需求做的一次测试。系统字体不同时,字形可能略有差异。
用脚本生成 1200x630 的航空信风格链接预览图,每个标题一张 PNG,不需要图像模型。可以给一个标题,也可以给 CSV 或 JSON 标题列表,支持中文和英文。适合博客、通讯、课程、发布活动需要分享图或 og:image,尤其是要成批出图、风格统一的时候;用户点名要这个风格时也用它。
交付前必须通过
node <技能文件夹>/scripts/check.mjs <文件夹>退出码为 0,每条 WARN 都看过- 每张 PNG 和
view-600/里的副本都看过 - 每个标题都是用户的原话,否则已列为推断内容
- 断行读起来都自然,包括检查脚本放行的地方
- 图案和每个标题都相配;拿不准的用了
envelope - 名字和用户写的一致,否则已把替代名列为假设
- 已报告跳过和拒绝的行,以及每一处推断的日期、标签和颜色
- 编造的示例都把
notice设成了fictional - 没有编造客户、数字、期号或资历
阅读完整 SKILL.md
---
name: postmark-card
description: 用脚本生成 1200x630 的航空信风格链接预览图,每个标题一张 PNG,不需要图像模型。可以给一个标题,也可以给 CSV 或 JSON 标题列表,支持中文和英文。适合博客、通讯、课程、发布活动需要分享图或 og:image,尤其是要成批出图、风格统一的时候;用户点名要这个风格时也用它。
version: 1.0.0
---
# 邮戳分享卡
版式都在 `assets/card.html` 里,不能改。你只提供文字,`scripts/render.mjs` 负责画邮票、邮戳、边框和纸张,按固定字号档位排标题,再输出 PNG。能改的只有用户自己的名字和两个颜色。`scripts/check.mjs` 会把每张卡和引擎逐字节比对,还会检查图片的实际像素。
准确的色值和尺寸写在 `references/style.md`,只有回答相关问题时才需要看。
## 要问的信息
简报里没有的,一次问完,然后开始做。
| 字段 | 含义 | 上限 | 简报信息不够时 |
|---|---|---|---|
| title(必填) | 标题,每张卡一个。照用用户的原话。`\|` 指定断行,`~` 让两个词不分开,这两个符号都不会印出来 | 100 单位:拉丁字符算 1,汉字算 2。最多五行 | 没人要求就不要自己写。若被要求代写,列为推断内容 |
| name(必填) | 这张卡是谁寄的:个人或刊物名,印在“寄件人”下面 | 28 单位,一行 | 用“编辑部”,并列为假设。检查脚本接受它,会打印一条提示。“你的名字”这类占位词会被拒绝 |
| ink | 标题、邮戳和一半边框的颜色,十六进制 | 对纸张至少 4.5:1,对 accent 至少 1.8:1 | 不填,默认 `#1b2a49`。给了两个颜色时,深的那个是 ink。给的是“深青色”这样的颜色词,就自己定一个十六进制值,并列为推断内容。不要根据公司名去猜品牌色 |
| accent | 邮票、小字和另一半边框的颜色,十六进制 | 对纸张至少 3:1 | 不填,默认 `#c4311f`。颜色词的处理同上 |
| date | 邮戳上的日期,格式 `YYYY-MM-DD` | 必须是真实日期 | 有发布日期就用它;没有就不填,自动用今天,并列为推断内容 |
| label | 邮戳一圈的文字:栏目或系列名。它只是装饰,不要指望别人一定会读 | 中文 8 个字,拉丁字符 14 个 | 不填,卡片印“已寄出”。不要编期号 |
| notice | 卡片顶部的声明标签:`fictional` 或 `sample`。印固定用词(虚构、示例),语言跟随卡片,600 宽时也读得清 | 只能是这两个词 | 真实内容不填。编造的示例用 `fictional`,用真实素材做演示用 `sample`。要给卡片加声明就用它,不要写在 label 里 |
| topic | 这份刊物或列表讲什么,用来选图案,不会印出来。优先级高于标题里的词 | 40 个字符 | 用用户自己的说法,比如 `烹饪`;不知道就不填 |
| emblem | 邮票里的图案,默认 `auto` | 只能用下面列出的名字 | 保持 `auto`。没有明确匹配就用中性的 `envelope` |
| emblem_why | 选了文字支持不了的图案时写明理由,不会印出来 | 60 个字符 | 用户没指定图案就不填 |
| lang | `auto`、`en` 或 `zh`,决定卡片小字的语言 | | 保持 `auto`:每张卡跟随自己的标题,适合双语列表。想让一批卡统一语言,就传 `--lang`。汉字数乘以 2 不少于拉丁字母数时,算中文卡 |
在 CSV 或 JSON 列表里,`title`、`date`、`label`、`notice`、`emblem`、`emblem_why`、`topic` 可以每行单独设置。名字和颜色整批统一。双语刊物如果有两个名字,分成两批生成。
### 图案
运行 `node <技能文件夹>/scripts/render.mjs --emblems` 可以看到这份列表和用途:
`envelope` 中性,什么主题都行 · `compass` 指南、策略 · `book` 阅读、教学 · `bulb` 想法 · `key` 安全 · `anchor` 海洋 · `leaf` 自然、木材 · `hammer` 手工、工具 · `gear` 工程、机械 · `code` 编程、软件 · `pot` 烹饪、食谱 · `cup` 咖啡、茶 · `mountain` 户外 · `heart` 健康、关爱 · `mic` 播客、演讲 · `note` 音乐 · `bars` 数据、结果 · `coin` 金钱、理财 · `globe` 世界、语言 · `plane` 旅行 · `sailboat` 帆船
`auto` 这样决定:topic 里的词优先。标题里的词只用来在 topic 打平时做决定,或者在 topic 没有匹配时决定。词必须完整匹配,所以“秘书”不会被当成“书”。打平或没有匹配时用 `envelope`。
**没有合适的图案,就用 `envelope`。** 它永远可用,也是唯一中性的图案:`cup` 表示咖啡或茶。严肃题材(去世、灾难、战争、裁员)只能用 `envelope`,给什么理由都不行。
### 断行
断行是自动的,常见词组(如“新手指南”、Instant Pot)不会被拆开。如果某处断行还是别扭,不用改写标题,在标题里标记就行:
- `为什么橡木|会变形` 在这里断行,竖线不会印出来。
- `新手~教程` 这里不断行,汉字之间不留空格;两边有拉丁字母时印一个空格。
- 要印这两个符号本身,写 `\|` 或 `\~`。
## 步骤
下面的 `<技能文件夹>` 指这份文件所在的文件夹,装在哪里都一样。两个脚本在任何目录下都能运行。
1. 只需安装一次:`npm install playwright`,再运行 `npx playwright install chromium`。如果 Playwright 装在别处,把 `NODE_PATH` 指向那个 `node_modules`。
2. 生成:
```
node <技能文件夹>/scripts/render.mjs --title "为什么橡木会变形" --name "纹理木作通讯" --topic 木工 --out cards/
node <技能文件夹>/scripts/render.mjs --list titles.csv --name "纹理木作通讯" --ink "#23352b" --accent "#b5541c" --out cards/
node <技能文件夹>/scripts/render.mjs --titles "第一个标题;第二个标题;第三个标题" --name "纹理木作通讯" --out cards/
```
列表是什么形式,就用对应的方式:
- **粘贴的文字:**用 `--titles`。多行时每行一个标题,行首的项目符号和序号会去掉。写在一行时按分号拆开(全角半角都行)。标题本身带分号时,请改成每行一个。
- **文件:**用 `--list`,支持 `.csv`、`.json`、`.txt`。没有表头的 CSV 每行一个标题。有表头时必须有 `title` 列(也可以写“标题”),其余列按需添加。JSON 可以是字符串数组、对象数组,或 `{"titles":[...]}`。`.txt` 每行一个标题。
3. 看脚本的输出。被拒绝的行会写明原因,其他行照常生成。改好被拒绝的行,再运行一次。
4. 运行 `node <技能文件夹>/scripts/check.mjs cards/`,把报告的问题全部修掉。必须退出码为 0;用户决定放弃某些行时,去掉这些行重新生成。每条 WARN 也要看,它标出的是读起来多半别扭的断行。
5. 每张 PNG 都要亲眼看:全尺寸看一遍,再看 `cards/view-600/` 里的同名副本,那是别人实际看到的大小。确认断行读起来自然,图案配得上标题,邮票上的字和邮戳文字读得清,名字没有写错。
6. 交付 PNG,并列出跳过的行、被拒绝的行、推断的字段和所做的假设。
退出码。`render.mjs`:0 全部生成;1 有行被拒绝;2 整体被拒绝(配色不合格、选项错误或列表无法读取)。`check.mjs`:0 通过;1 有问题;2 用法错误。
每张卡不到 1 秒,已含浏览器启动时间(实测 3 张 0.7 秒)。一次只跑一批。脚本只开一个浏览器,结束时会关闭。
## 特殊输入的处理结果
| 输入 | 结果 |
|---|---|
| 很短的标题(一个汉字、“Hi”) | 用最大一档字号排成一行,不会添东西去填满 |
| 长标题 | 字号逐档降到 48px,最多五行。在 600 宽的预览里是 24px,仍然读得清。某一档的最佳断行读起来别扭时,可能改用小一档的字号 |
| 超过 100 单位,或五行放不下 | 这一行被拒绝,错误码 TITLE_TOO_LONG 或 TITLE_DOES_NOT_FIT。脚本不会替你截断。请提出更短的标题,经用户同意再用 |
| 单个词比标题区还宽(按 48px 算) | 这一行被拒绝,错误码 TITLE_DOES_NOT_FIT。词内只在连字符和斜杠处断开 |
| 中英文混排 | 正常排版:两种文字各用各的字体,三个词以内的拉丁短语留在同一行,小字语言跟随 `lang` |
| 文件里是分号分隔的列表 | 这一行被拒绝,错误码 ROW_MALFORMED,提示改成每行一个标题或用 `--titles` |
| CSV 里有逗号和引号 | 按标准规则解析:`"橡木、白蜡,和""为什么"""` 印出来是 橡木、白蜡,和"为什么" |
| 逗号没加引号,导致一行的单元格过多 | 这一行被拒绝,错误码 ROW_MALFORMED,不会丢掉半个标题 |
| CSV 引号没有闭合 | 整个文件被拒绝,并给出行号 |
| 空行或空标题 | 跳过并报告,不算失败 |
| 标题含不安全的文件名字符(`../../etc/passwd: a/b*?`) | 标题照原样印;文件名变成 `etc-passwd-a-b.png`,一定留在输出文件夹里 |
| 想要带序号的文件名 | 生成后自己改名。检查脚本读取每个文件内部的记录,改名和移动都能通过;重新保存或压缩会丢掉记录,检查不通过 |
| Windows 保留名,或没有任何文字数字 | 文件名加 `card-NNN` 前缀 |
| 标题重复 | 按行序依次加 `-2`、`-3` |
| 标题里有 HTML | 当普通文字印出来,不会执行 |
| 括号不成对,或英文双引号是单数 | 这一行被拒绝,错误码 TITLE_BRACKET。多半是 CSV 写错了;如果是有意的,请改写 |
| 表情符号 | 这一行被拒绝,错误码 TITLE_EMOJI。活字印刷没有彩色字形 |
| 配色不合格 | 一张都不生成。提示里会给出最接近的合格配色。问用户,或者用这组配色并说明 |
| “标题”“你的名字”这类占位词 | 这一行被拒绝 |
| 电脑上没有中文字体 | 这一行被拒绝,错误码 FONT_MISSING。请安装 Noto Serif CJK SC |
提示里的行号是 CSV 的行号,或 JSON 数组里从 1 开始数的位置。
## 遇到这些情况
- **简报信息不够:**复述用户给的事实,绝不编造,把每一处推断都列出来。按上面的表逐个字段处理。
- **没人能回答:**用上面的默认值继续做,交付时列出假设。
- **用户想要别的长度:**尺寸固定为 1200x630,标题字号由档位决定。标题越短字越大,不能手动指定字号。改写标题要经用户同意。
- **没有真实链接:**卡片上不放链接,所以不需要。如果要加 `og:image` 标签,等用户有了真实地址再写,绝不编一个。
- **用户想换版式、字体或加标志:**这个技能做不到,直接说明。
## 交付物
输出文件夹里有:每张卡一个 `<标题>.png`,尺寸正好 1200x630;`cards.json`,记录生成、跳过和拒绝的情况;`view-600/`,只用来查看的副本,不要发布。对外发布时只用最外层的 PNG。每张 PNG 的文本块里存着标题、名字、日期和排版记录,这些内容本来就印在卡上,任何人都能读取。
## 交付前检查
- [ ] `node <技能文件夹>/scripts/check.mjs <文件夹>` 退出码为 0,每条 WARN 都看过
- [ ] 每张 PNG 和 `view-600/` 里的副本都看过
- [ ] 每个标题都是用户的原话,否则已列为推断内容
- [ ] 断行读起来都自然,包括检查脚本放行的地方
- [ ] 图案和每个标题都相配;拿不准的用了 `envelope`
- [ ] 名字和用户写的一致,否则已把替代名列为假设
- [ ] 已报告跳过和拒绝的行,以及每一处推断的日期、标签和颜色
- [ ] 编造的示例都把 `notice` 设成了 `fictional`
- [ ] 没有编造客户、数字、期号或资历
## 不适合的情况
- 用户需要照片、产品图或在卡片上放标志。
- 严肃的公告或法律通知,航空信的轻快感不合适。
- 需要 1200x630 以外的尺寸,或从右往左书写的文字。只测试过中文和英文。
## 运行要求
Node.js 22 或更高版本,Playwright 和 Chromium。生成时不需要图像模型,也不联网。字体用系统自带的:拉丁文用 Rockwell 或相近的粗衬线体,中文标题用宋体(Songti SC)或 Noto Serif CJK SC,中文小字用无衬线体。字号档位是在本机实际测量的,换一台电脑换了字体,断行可能不同,但检查规则不变。



