免费

手记作品集

像一本正在用的工作手记:大号衬线墨字、手写批注、自己画出来的小花,估价器只用你自己的价格。

安装

把“手记作品集”技能安装到 ~/.claude/skills/margin-notes-portfolio。
下载下面每个文件,保存到这个文件夹:
https://skilllift.pages.dev/packs/margin-notes-portfolio/SKILL.zh.md → SKILL.md
https://skilllift.pages.dev/packs/margin-notes-portfolio/references/style.md → references/style.md
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/engine.html → assets/engine.html
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/engine.css → assets/engine.css
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/engine.js → assets/engine.js
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/starter.json → assets/starter.json
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts-license.txt → assets/fonts-license.txt
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/fraunces.woff2 → assets/fonts/fraunces.woff2
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/newsreader.woff2 → assets/fonts/newsreader.woff2
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/newsreader-italic.woff2 → assets/fonts/newsreader-italic.woff2
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/caveat.woff2 → assets/fonts/caveat.woff2
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/zh-display.json → assets/fonts/zh-display.json
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/zh-body.json → assets/fonts/zh-body.json
https://skilllift.pages.dev/packs/margin-notes-portfolio/assets/fonts/zh-hand.json → assets/fonts/zh-hand.json
https://skilllift.pages.dev/packs/margin-notes-portfolio/scripts/check.mjs → scripts/check.mjs
https://skilllift.pages.dev/packs/margin-notes-portfolio/scripts/build.mjs → scripts/build.mjs
https://skilllift.pages.dev/packs/margin-notes-portfolio/scripts/drive.mjs → scripts/drive.mjs
https://skilllift.pages.dev/packs/margin-notes-portfolio/scripts/audit.mjs → scripts/audit.mjs
https://skilllift.pages.dev/packs/margin-notes-portfolio/scripts/lib.mjs → scripts/lib.mjs
https://skilllift.pages.dev/packs/margin-notes-portfolio/references/example.en.json → references/example.en.json
https://skilllift.pages.dev/packs/margin-notes-portfolio/references/example.zh.json → references/example.zh.json
然后读一遍 SKILL.md,告诉我它是做什么的,并提醒我开一个新会话。

解压到 ~/.claude/skills

同一个技能,不同的需求

左边是预览。右边由另一个 Agent 按不同需求制作,它只有安装好的技能,没看过预览。

预览
预览
新需求,由另一个 Agent 制作
新需求,由另一个 Agent 制作

这是按虚构需求做的一次测试。系统字体不同时,字形可能略有差异。

为独立开发者、产品设计师、其他独立从业者或小工作室做一个有个性的作品集网站:一个离线 HTML 文件,靠哈希路由从一段 JSON 渲染出全部页面。样子像一本正在用的工作手记:暖色纸底,一种浓墨色的大号衬线标题,手写批注,自己画出来的箭头和小花,胶带、便利贴和一张身份卡片。带作品筛选、案例预览标签、只按用户自己价目计算的估价器、常见问题标签和诚实的演示表单。支持中文或英文。当有人想要一个有性格的个人或工作室作品集,或者点名要这个风格时使用。

交付前必须通过

  • check.mjs 以 0 退出且跑了视觉检查(或者你已说明没跑)。
  • 手机和桌面的每个路由都看过,drive.mjs 的各状态也看过。
  • 每个客户、评价、数字和日期都来自用户,或者 meta.fictional 为 true。
  • 示例内容一点不剩。
  • 发布前报告已写进你的消息,或者 check.mjs --publish 以 0 退出。
  • 已告诉用户表单是演示,不会发送。
阅读完整 SKILL.md
---
name: margin-notes-portfolio
description: 为独立开发者、产品设计师、其他独立从业者或小工作室做一个有个性的作品集网站:一个离线 HTML 文件,靠哈希路由从一段 JSON 渲染出全部页面。样子像一本正在用的工作手记:暖色纸底,一种浓墨色的大号衬线标题,手写批注,自己画出来的箭头和小花,胶带、便利贴和一张身份卡片。带作品筛选、案例预览标签、只按用户自己价目计算的估价器、常见问题标签和诚实的演示表单。支持中文或英文。当有人想要一个有性格的个人或工作室作品集,或者点名要这个风格时使用。
version: 1.0.0
---

# 手记作品集

你只写一个 JSON 文件,其余都由引擎画出来。不要改 `assets/engine.*`,也不需要读它们:每个字段、路由和自动行为,这份文件都写清楚了。`scripts/check.mjs` 发现引擎被改动就会报错。

精确的样式数值在 `references/style.md`。`references/example.zh.json`(中文)和 `references/example.en.json`(英文)是完整的成品,可以用来看结构,但里面的文字不能沿用,检查脚本会抓出残留。

## 需要问用户什么

一次问完,放在一条消息里,简报里已有的就不要再问。

必须知道:姓名;用几个字说清做什么;这个人是真实的还是虚构的;语言(一个文件一种语言,`en` 或 `zh`)。

值得问:1 到 12 个项目以及实际发生了什么;服务和真实价格;照片;邮箱;真实的客户评价及其来源。

用户已经给过的信息,不要再让他填一遍。

## 信息不全时怎么办

- **简报很单薄:** 只把用户自己的事实换更好的说法重述。绝不编造客户、评价、奖项、数字、雇主、日期或成果,缺的字段直接不写。把所有你推断出来的句子列在最后的回复里。
- **没人能回答:** 用已有信息继续做,其余不写,最后列出你的假设。
- **某个板块没内容:** 整个键都不要写。路由、导航和页脚链接会自动消失。不要写“敬请期待”。只有姓名、角色、标题和一句联系方式的页面也完全有效,能通过检查。
- **没有照片:** 不写 `person.portrait`。草稿会画一幅原创的涂鸦自画像,并明确标注这是占位。这能通过默认检查;`--publish` 会失败,直到有了照片,或者用户选择保留涂鸦、你把 `person.keepDoodle` 设为 `true`。要告诉用户。绝不生成或使用写实人像。
- **项目没有图片:** 不写 `cover`。显示的项目都没有封面时,卡片是横格索引卡;有的有封面时,没有的那张会得到一块同样形状的手绘面板。两种都能通过检查。
- **没有真实链接或邮箱:** 不写 `url`、`links` 或 `email`。真实人物的网站上绝不用编的地址。虚构人物可以用 `.example` 结尾的地址,联系页就能用。邮箱和链接都没有时,访客联系不到这个人:报告会写明,`--publish` 会失败。
- **经历或隐私内容很薄:** 一条经历至少要有角色、机构、时间中的两项,更薄的不会显示,一条都不剩时路由也不存在。隐私页没有内容时就不写,或者把 `privacy` 写成 `{"auto":true}`,显示两句对这个单文件页面成立的大白话。一旦托管或加了统计,就要去掉。
- **不知道价格:** 服务存在但没有数字,用 `{"type":"request"}`;用户不想显示价格,就不写 `price`。绝不替用户估价。
- **长度不合适:** 下面的上限是硬性的,超了就删字。项目多就多写,版式从 1 到 40 个都能适应。
- **虚构示例:** 如果这个人不是真的,把 `meta.fictional` 设为 `true`。每个路由顶部会出现且只出现一条虚构标注。不要再写别的声明,检查脚本会判重复。真实人物设为 `false`。

## 步骤

1. 写 `content.json`,从 `assets/starter.json` 开始,它的 `lang` 是 `en`,中文站要改成 `zh`。没内容的键直接删掉。
2. 图片放在旁边,用相对路径引用。
3. 构建草稿:`node scripts/build.mjs content.json index.html`(约一秒)。会嵌入图片,以及文字用到的中文字体分片。草稿会显示占位标注。
4. 检查:`node scripts/check.mjs index.html`(约一分钟:先静态规则,再把每个路由和状态在 1280、768、390 宽度下,开动效和减弱动效,模拟触屏,都走一遍)。改 `content.json`,重新构建,直到通过。
5. 实际操作并亲眼看:`node scripts/drive.mjs index.html shots/`(约两分钟),会保存每个路由和状态的截图。手机和桌面的每个路由、估价器、一个表单状态、灯箱都要打开看。脚本通过不代表可以不看。断行不好就改文字。
6. 看 `build.mjs` 和 `check.mjs` 打印的发布前报告:占位、缺联系方式、示例邮箱、虚构人物。
7. 交付。报告里还有内容,就按草稿交付,并把这份清单原样转给用户。清单为空时才运行 `node scripts/build.mjs content.json index.html --publish`,再运行 `node scripts/check.mjs index.html --publish`,清单上还有东西就会失败。发布版会隐藏占位标注。说明哪些没写、哪些是推断、表单只是演示。

**Playwright:** 视觉检查需要它。`check.mjs` 找不到时会以 3 退出:运行 `npm install playwright` 和 `npx playwright install chromium`,或把 `NODE_PATH` 指向装有它的 `node_modules`。`--static-only` 会跳过视觉检查,用了就要在报告里说明。同一时间只开一个浏览器。

## 内容文件

长度单位是字符,写法为“英文 / 中文”,超限即失败。除标明必填的字段外,都可以不写。标有“行内”的字段支持 `**粗体**`、`*斜体*` 和 `[文字](链接)`。

### meta(必填)
| 字段 | 含义 | 上限 | 信息不足时 |
|---|---|---|---|
| `lang` | `en` 或 `zh`,决定界面语言。混入另一种语言会失败。 | | 必填,跟随用户的语言。 |
| `fictional` | 人物和作品是编的就写 `true`,页面会加一条标注。 | | 必填。不确定就问,没人答就写 `true`。 |
| `title` | 浏览器标签和首页标题。 | 70 / 40 | 必填,姓名加角色。 |
| `description` | 搜索描述。 | 160 / 90 | 必填,用他的事实写一句。 |
| `currency` | 三位币种代码,如 CNY、AUD,所有价格都用它。 | 3 | 只要有价格数字就必填,不要猜。 |
| `priceStyle` | `written`(默认)或 `symbol`。人民币中文页,written 显示 8000 元起,symbol 显示 ¥8,000 起。其他页面都用货币符号。 | | 不写。 |
| `ink` | `blue`(默认)、`green`、`oxblood`、`plum`,标题用的那一种墨色。 | | 不写。 |
| `fictionalNote` | 替换标注的措辞。 | | 不写。 |
| `verified` | 用户确实提供的、含有说法或数字的原文短语列表。 | | 见下面“证明”。 |

### person(必填)
| 字段 | 含义 | 上限 | 信息不足时 |
|---|---|---|---|
| `name` | 身份卡上的名字,必填。 | 48 / 24 | 用他的原话。 |
| `short` | 名字太长时左上角用的短名。 | 24 / 12 | 名字不长就不写。 |
| `role` | 手写在标题上方,也在卡片上,必填。 | 70 / 36 | 用他的原话。 |
| `location` | 卡片上的所在地。 | 40 / 20 | 没给就不写。 |
| `status` | 贴在头像旁的便利贴,如“春天的档期还能约”。 | 60 / 30 | 不写,绝不编造档期。 |
| `email` | 卡片、联系页,以及“用邮件应用发送”按钮。 | | 没给就不写。 |
| `links` | `{label, url}` 列表,显示在联系页。 | | 没给就不写。 |
| `portrait` | `{src, alt, focal}`,真实照片,裁成柔和的不规则形状,可点开看全图。 | alt 140 / 70 | 不写就显示涂鸦。 |
| `keepDoodle` | 只有用户选择用涂鸦代替照片时才写 `true`,`--publish` 才能通过。 | | 不写。 |

所有图片对象:`src` 是相对路径(png、jpg、webp、gif、svg),`alt` 必填,`focal` 选填,如 `"50% 25%"`,裁切时保住这个点,`caption` 选填,140 / 70。灯箱里永远显示完整图片。

### home(必填)
| 字段 | 含义 | 上限 | 信息不足时 |
|---|---|---|---|
| `headline` | 特大号衬线标题,必填。 | 60 / 26 | 用他自己的描述写一句平实的话,或者就写名字。 |
| `mark` | 标题里加手绘下划线的那部分,须与标题原文一致。 | 18 / 8 | 拿不准就不写。 |
| `lede` | 标题下的一段。行内 | 220 / 110 | 重述他那句自我介绍。 |
| `note` | 带箭头的手写批注,可以用第一人称。 | 70 / 34 | 宁可不写,也不要编个人细节。 |
| `workNote` | “精选作品”旁的批注。 | 60 / 26 | 不写。 |
| `featured` | 首页展示的项目 slug。 | | 不写,默认取前四个。 |

### work:项目列表
| 字段 | 含义 | 上限 | 信息不足时 |
|---|---|---|---|
| `slug` | 小写字母、数字、连字符。路由 `#/work/slug`。必填。 | 60 | 用拼音或英文。 |
| `title` | 必填。 | 60 / 26 | 他起的名字。 |
| `summary` | 卡片和案例顶部的一两句话。行内 | 180 / 90 | 只写他的事实。 |
| `client`、`year`、`role` | 有就显示。`year` 决定排序。 | 40 / 20、12、60 / 30 | 没给就不写。真实人物的网站上绝不写编的客户。 |
| `tags` | 最多五个,用于筛选。 | 20 / 10 | 写一两个朴素的类别。 |
| `tools` | 案例里显示的工具列表。 | | 没给就不写。 |
| `url`、`urlLabel` | 真实的线上链接。 | | 没有就不写。 |
| `note` | 案例标题旁的批注。 | 70 / 34 | 宁可不写,不要编。 |
| `cover` | 图片对象,用于卡片和案例顶部。 | | 不写,见上文。 |
| `previews` | 预览标签。每项 `{label, text?, items?, image?, images?}`,只有一项时不显示标签条。 | label 20 / 10,text 900 / 450,items 240 / 120 | 没东西可看就不写。 |
| `sections` | `{heading, body}`,`body` 是内容块列表。 | heading 60 / 26 | 只写他告诉你的。两段短的好过四段凑的。 |
| `outcome` | 结尾的便利贴:实际发生了什么。行内 | 500 / 250 | 不知道就不写,绝不编成果。 |

**内容块**(`body` 列表):一个字符串,或 `{type, text, note, items, image}`。类型:`p`(行内,900 / 450)、`h`、`quote`、`list` 和 `steps`(`items`,每项 240 / 120)、`code`(1500)、`image`、`flower`(手绘分隔)。任何块都可以带 `note`:手写批注,70 / 34,宽屏在页边,手机在块下方。每段大约一条,没有真实的旁白就不写。

### services:服务列表
`slug`、`title` 必填(48 / 20)。`summary` 行内(180 / 90)。`price`(见下)。`priceNote`(120 / 60)。`body` 内容块。`includes`、`excludes`、`steps` 列表(每项 200 / 100)。`note`(70 / 34)。路由 `#/services`、`#/services/slug`。信息不足时只写他列出的,他没说的 `excludes` 不写。

### 价格
服务和估价器共用,统一由一个格式化函数显示:
| `price` | 英文 | 中文 |
|---|---|---|
| `{"type":"fixed","amount":2400}` | $2,400 | ¥2,400 |
| `{"type":"from","amount":14000}` | From $14,000 | ¥14,000 起 |
| `{"type":"per","amount":180,"unit":"张","min":1,"max":12}` | $180 per screen | ¥180 / 张 |
| `{"type":"request"}` | Price on request | 价格面议 |

上表中文列是 `meta.priceStyle: "symbol"` 的写法。人民币页面默认显示 2400 元、14000 元起、180 元 / 张。要原样显示用户的写法,就加 `text`(24 / 14),如 `{"type":"from","amount":8000,"text":"8,000 元起"}`:列出这个价格的地方都用它,里面必须有同样的数字。合计仍用默认写法。

数字必须是用户给的。正文里写的价格必须和这里某个数字一致,否则检查失败。

### estimator:估价器
`groups`:`{id, label(48 / 20), select: "one"|"many", items}` 的列表。每项 `{id, label(48 / 20), note(90 / 45), price}`,price 必填。另有 `title`、`lede`(220 / 110)、`note`(160 / 80,替换“不是报价”那句)、`handNote`(70 / 34)。路由 `#/estimate`。

这些行为不用你写:勾选之后才出现合计。固定价和按量价精确相加。只要有一项 `from`,合计就显示为“X 起”。面议项目绝不计入,而是在已标价合计旁逐项列名;如果只勾了面议项目,就不显示数字。不要加 `total` 字段,检查会失败。没有价格就不要估价器,把这个键删掉。

### 其他板块
| 键 | 字段和上限 | 路由 | 信息不足时 |
|---|---|---|---|
| `about` | `headline` 60 / 26,`lede` 220 / 110,`note` 70 / 34,`body` 内容块,`principles`(最多 6 张便利贴,90 / 45),`principlesTitle` 48 / 20,`facts` 是 `{label 20 / 10, value 90 / 45}` 列表 | `#/about` | 只写他的事实。不要替他编信条。 |
| `experience` | `{period 24 / 20, role 60 / 30, org 48 / 24, note 240 / 120}` 列表,每条至少有角色、机构、时间中的两项 | `#/experience` | 只写真实经历,没有就不写。 |
| `journal` | `{slug, title 70 / 30, date "2026-03-14", summary 180 / 90, body}` 列表 | `#/journal`、`#/journal/slug` | 不写。除非用户要求代写,否则不要凑文章。 |
| `faq` | `{tab 20 / 10, items: [{q 110 / 50, a 500 / 250, note 70 / 34}]}` 列表。只有一组时不显示标签条。 | `#/faq` | 只按他说过的回答。 |
| `contact` | `title` 60 / 26,`lede` 220 / 110,`note` 70 / 34,`form`(写 `false` 去掉表单) | `#/contact` | 有任何联系方式,或者是虚构页面时才写。 |
| `newsletter` | `title` 60 / 26,`intro` 220 / 110,`cadence` 70 / 34,`note` 70 / 34,`url`(真实订阅页) | `#/newsletter` | 他没有也不想要就不写。 |
| `privacy` | `lede` 220 / 110,`body` 内容块,或 `auto: true` | `#/privacy` | 不写,或用 `auto`。只说符合实际托管情况的话。 |
| `testimonials` | `{quote 320 / 160, name 48 / 24, role 60 / 30, source}` 列表。`source` 写明用户从哪里得到这句话,不会显示。 | 首页 | 只放用户提供的真实评价。没有来源就没有评价。 |
| `workIntro`、`servicesIntro`、`journalIntro` | `title`、`lede`、`note`,上限同 `contact` | 列表页 | 不写。 |
| `labels` | 改导航和标题的叫法:`work`、`services`、`journal`、`selected`、`about`、`contact`、`estimate`、`experience`、`faq`、`newsletter`、`privacy`、`latest`、`quotes`。 | | 其他职业可用,如 `{"work":"婚礼"}`。 |
| `footerLine` | 页脚的大字。60 / 26 | | 不写,用中性默认句。 |

**证明:** 百分比、倍数、“获奖”“信赖”“十年经验”这类数字和说法,会被当成可能的虚假证明而失败。如果确实是用户给的,把原文短语抄进 `meta.verified`。用户没给的,绝不要写进去。

## 路由和自动行为

路由:`#/`、`#/work`、`#/work/slug`、`#/services`、`#/services/slug`、`#/estimate`、`#/about`、`#/experience`、`#/journal`、`#/journal/slug`、`#/contact`、`#/faq`、`#/newsletter`、`#/privacy`。其他地址,包括没有内容的板块,都显示设计过的 404。

下面这些页面会自己做,不用你操心:
- 作品版式跟数量走:1 个是宽卡片,2 个和 4 个成对,其余铺满整行不留空。
- 3 个以上项目且有 2 个以上标签时出现筛选;4 个以上项目时出现搜索和排序。只有 1 个或 2 个项目时没有这些控件,这是设计如此,不是缺陷。筛选状态记在网址里。
- 只有一项的标签组不显示标签条。评价轮播有 2 条以上才有控制按钮,不会自动翻页。
- 超长单词会让标题自动缩小到放得下。所有文字里的中文都只在词与词之间换行,结尾的词也不会落单。页边批注每行大约放 9 到 12 个汉字,折行不好看就缩短。
- 正文里的竖长图片最高占屏幕的 72%,点开在灯箱里看全图。
- 涂鸦每个路由第一次看到时画一次,减弱动效时直接显示。文字从不做动画,也从不隐藏。
- 表单先校验,再明确告诉访客什么都没有发送。有 `person.email` 时,会有按钮打开访客自己的邮件应用。真要收消息,需要托管和表单服务,这不在本技能范围内,要告诉用户。
- 估价器的按钮能把选择带进联系表单。
- 图片在灯箱里完整显示,方向键、Esc 和滑动都能用。裁切时遵循 `focal`。
- 字体随技能嵌入:Fraunces、Newsreader、Caveat,以及中文用的思源宋体(Noto Serif SC)、霞鹜文楷和龙藏体。全部是开源许可,许可证写在文件的注释里。GB2312 以外的字会退回系统字体,构建时会列出来。

## check.mjs 会拦下什么

引擎被改动;外部请求;占位文字;示例残留;可能的虚假证明;虚构标注重复或缺失;演示表单声称已发送;正文价格不在价目里;字段超长;混入另一种语言;页面溢出;文字出屏或被裁切;对比度不足;文字被效果隐藏;单字或单词落单;中文词被拆开;大块空白;涂鸦压字;批注互相重叠;占位标注被遮挡;手机上点击区小于 44 像素;标签、筛选、估价器、表单或灯箱不工作。

断行问题一直过不去,就改文字,不要申请例外。大块空白的报错绝不靠加字解决:内容短永远可以。内容少的页面报了这个错,就删掉空的板块,或者把它当作技能缺陷报告,绝不凑字。

## 交付物

一个离线的 `index.html`,标明是草稿还是发布版,加一段简短说明:哪些没写、哪些是推断、哪些是假设,以及发布前清单(如果有)。

## 交付前检查

- [ ] `check.mjs` 以 0 退出且跑了视觉检查(或者你已说明没跑)。
- [ ] 手机和桌面的每个路由都看过,`drive.mjs` 的各状态也看过。
- [ ] 每个客户、评价、数字和日期都来自用户,或者 `meta.fictional` 为 `true`。
- [ ] 示例内容一点不剩。
- [ ] 发布前报告已写进你的消息,或者 `check.mjs --publish` 以 0 退出。
- [ ] 已告诉用户表单是演示,不会发送。

## 不适合的情况

严肃的企业官网、需要真正内容管理系统的大型目录、网店,或者不另外托管就必须真能收消息的场景。如果摄影师需要每屏都由图片主导,以图库为主的版式更合适。一个文件只有一种语言,两种语言就做两个文件。

## 环境要求

Node 18 或以上。视觉检查需要 Playwright(`npm install playwright`,必要时设 `NODE_PATH`)。构建和浏览都不需要联网。

用在这些流程里

相似技能