CJK Typography · 中文排版四件套(回退栈 / 字号总表 / 系统栈 / 免费细体)
cjk-typographyv1.0.0
排版
MIT(本包 JSON / 文档 / 断言为自产;所列字体各自沿用自己的许可,见 tokens/free-thin-cjk.json)
新中文项目定字族与字号时:先对三场景字号总表,再定回退栈,还要选一款免费细体中文(含许可与下载来源)时
不适用场景
档位 / 行高 / 字距 / 文字影的收敛(走 cjk-thin-type-system)、配色(走 themes 包)、需要 700 粗体力量感的品牌页
载入预览…
卡片与舞台里跑的是包内真实的预览页;WebGL 类需点“运行预览”才会建立渲染上下文。
取用方式
固定版本(CDN)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nakamotosai/sai-assets@pack/cjk-typography@1.0.0/packs/cjk-typography/css/default.css">raw 直取(跟随 main)
curl -O https://raw.githubusercontent.com/nakamotosai/sai-assets/main/packs/cjk-typography/SKILL.md仓库内落地
python scripts/apply.py cjk-typography --to <项目目录>整包下载
https://assets.ouuut.com/downloads/cjk-typography.zip源码与规则
pack.json{
"schema": 1,
"id": "cjk-typography",
"title": "CJK Typography · 中文排版四件套(回退栈 / 字号总表 / 系统栈 / 免费细体)",
"kind": "fonts",
"category": "fonts",
"version": "1.0.0",
"license": "MIT(本包 JSON / 文档 / 断言为自产;所列字体各自沿用自己的许可,见 tokens/free-thin-cjk.json)",
"attribution": [
{
"name": "本地素材库 · 中文正文字体栈原子卡",
"license": "自产观测(2026-09-30 全网扫描)",
"what": "回退栈、字号地板、300 陷阱与子集化口径"
},
{
"name": "本地素材库 · 字号偏好总表原子卡",
"license": "自产观测",
"what": "工具台 / 纸媒电视 1920 / 营销落地 三场景字号数字"
},
{
"name": "本地素材库 · 系统控制台栈原子卡",
"license": "自产观测",
"what": "system-ui 系统栈与 tabular-nums 口径"
},
{
"name": "本地素材库 · 免费细体中文三选原子卡",
"license": "自产观测(2026-10-06 npm / CDN 实查)",
"what": "三份候选的许可、可变轴与 unicode-range 分片实测"
},
{ "name": "Noto Sans SC / Noto Serif SC", "url": "https://cdn.jsdelivr.net/npm/@fontsource-variable/noto-sans-sc@5.3.0/index.css", "license": "OFL-1.1", "what": "字族名与 CDN 分发入口(npm 包路径)" },
{ "name": "MiSans VF", "url": "https://cdn.jsdelivr.net/npm/misans@5.0.0/lib/Normal/MiSansVF.min.css", "license": "Apache-2.0", "what": "字族名与 CDN 分发入口(npm 包路径)" },
{ "name": "HarmonyOS Sans SC", "url": "https://cdn.jsdelivr.net/npm/harmonyos-sans-sc-webfont-splitted@1.1.0/dist/Light.css", "license": "Unlicense", "what": "字族名与 CDN 分发入口(npm 包路径)" },
{ "name": "JetBrains Mono / Inter / Space Mono / Maple Mono NF CN / Cascadia Code(字族名引用)", "license": "各上游许可(OFL-1.1 等待核)", "what": "等宽与拉丁字族名,包内不含字体文件" }
],
"origin": {
"project": "asset-source",
"path": "fonts/",
"derived_from": null
},
"entry": "SKILL.md",
"files": {
"tokens": [
"tokens/index.json",
"tokens/body-sans.json",
"tokens/size-scale.json",
"tokens/console.json",
"tokens/free-thin-cjk.json"
],
"usage": "docs/usage.md",
"assert": "scripts/assert_tokens.py",
"preview": "preview/index.html"
},
"tags": ["cjk", "font-stack", "type-scale", "monospace", "free-fonts", "license", "subsetting"],
"when": "新中文项目定字族与字号时:先对三场景字号总表,再定回退栈,还要选一款免费细体中文(含许可与下载来源)时",
"not_for": "档位 / 行高 / 字距 / 文字影的收敛(走 cjk-thin-type-system)、配色(走 themes 包)、需要 700 粗体力量感的品牌页",
"default_variant": null,
"verified": {
"date": "2026-11-03",
"how": "python packs/cjk-typography/scripts/assert_tokens.py",
"evidence": "PASS assert_tokens cjk-typography / 三场景 console · print-1920 · landing 数字与源卡冻结值一致 / 免费清单 3 条逐条带「字体名 | 许可 | 来源」(OFL-1.1 · Apache-2.0 · Unlicense,上游主页标待核)/ preview 23 条字号声明最小 12px;负例 7/7 判失败(许可待核 / 清单行缺来源 / 场景数字漂移 / 11px / body 混 serif / 上游未标待核 / 候选数不足)"
},
"canonical_home": null
}tokens/index.json{
"id": "cjk-typography",
"kind": "fonts",
"title": "CJK Typography · 中文排版四件套",
"version": "1.0.0",
"summary": "四张卡合成一包:正文无衬线回退栈 · 三场景字号总表 · 系统等宽栈 · 免费细体中文三选(纯许可清单)。",
"cards": [
{ "id": "body-sans", "file": "tokens/body-sans.json", "what": "正文无衬线回退栈:UI / 正文 / 长文衬线 / 等宽四个角色" },
{ "id": "size-scale", "file": "tokens/size-scale.json", "what": "三场景字号总表:工具台 / 纸媒电视 1920 / 营销落地" },
{ "id": "console", "file": "tokens/console.json", "what": "系统栈:零 Web 字体的工具台默认" },
{ "id": "free-thin", "file": "tokens/free-thin-cjk.json", "what": "免费细体中文三选 + 许可 + 下载来源" }
],
"related_pack": "cjk-thin-type-system",
"split": "本包管「用哪些字、多大」;cjk-thin-type-system 管「用几档、多细、多宽、多高、几层影」。两包不重叠:字族只在本包定义,档位只在那边定义。",
"hard_rules": [
"SimSun / 宋体 / serif 禁入 body 回退栈(静默回退 = 硬错误,不是风格问题)",
"免费字体清单只列许可明确的条目,逐条给「字体名 | 许可 | 来源」;缺许可或来源未核的写「待核」,不许写成已验证",
"禁推荐需要盗版 / 破解的商业字体文件;商业字族最多只写字族名,不给文件、不给破解源",
"中文正文禁 letter-spacing、禁两端对齐",
"中文字库大:必须子集化 + font-display:swap 防 FOIT;零 Web 字体场景直接用系统栈"
]
}tokens/body-sans.json{
"id": "body-sans",
"title": "CJK Body Sans · 正文无衬线回退栈",
"roles": {
"body": "\"Noto Sans SC\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif",
"display": "\"Noto Sans SC\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif",
"article": "\"Noto Serif SC\", \"Source Han Serif SC\", \"Songti SC\", serif",
"mono": "\"JetBrains Mono\", \"Maple Mono NF CN\", ui-monospace, monospace"
},
"css": "body{font-family:'Noto Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;font-display:swap;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}\narticle{font-family:'Noto Serif SC','Source Han Serif SC','Songti SC',serif}\np{line-height:1.75;letter-spacing:.02em;font-size:16px}\n@media(min-width:1024px){p{font-size:17px}}",
"weights": "正文 400–500 · 强调 700 · 禁 11–15px 中文用 300(笔画溶解「300 陷阱」)· 禁加粗宋体冒充黑体",
"sizes": "正文 16px(移动 15px)· 次级 / 卡片 14px · 角标 12px · 整页可读最小 14px · 卡片禁 9 / 10 / 11 / 13px · 标题 20px 起、层级差 ≥4px",
"line_height": "中文正文 1.7–1.8 · 长文衬线 ≥1.6",
"features": [
"SimSun / 宋体 / serif 禁入 body 回退栈(静默回退 = 硬错误)",
"中文字库大:必须子集化 + font-display:swap 防 FOIT",
"零 Web 字体场景直接用系统栈(苹方 / 微软雅黑),不拉外部字体",
"大容器字号 ≥ 同屏小容器"
],
"when": "一切中文正文与 UI;长文阅读切 article 衬线栈;纸媒标题衬线走主题包的 display 档",
"note": "`css` 里的 p{letter-spacing:.02em} 是源卡的拉丁 / 标题用法;中文正文按 cjk-thin-type-system 的口径加字距为 0,正文落地时以那边为准。",
"sample": "正文十六字 · 卡片十四字 · 标题二十起"
}tokens/size-scale.json{
"id": "size-scale",
"title": "字号偏好总表 · 三场景",
"unit_note": "新项目先对这张表:场景先定,数字后取;同屏只有一套场景。",
"scenes": [
{
"id": "console",
"scene": "工具台",
"h1": "15–22px",
"body": "14px(HUD 12)",
"meta": "11–12px",
"code": "11–13px",
"note": "零 Web 字体优先;数字 tabular"
},
{
"id": "print-1920",
"scene": "纸媒 / 电视 1920",
"h1": "64–110px(封面可 100+)",
"body": "≥40px",
"meta": "UI / 脚注 ≥26px",
"code": "—",
"note": "Serif 标题 + Sans 正文;真字重"
},
{
"id": "landing",
"scene": "营销落地",
"h1": "clamp(2rem–7rem) 负字距",
"body": "16–17px · lh 1.55–1.65",
"meta": "mono eyebrow ~0.72rem · ls .14–.2em",
"code": "mono 元信息",
"note": "手写体 / 衬线只上拉丁标题;正文用中文安全栈"
}
],
"mono_default": "一律 JetBrains Mono(印刷 / 波普风可换 Space Mono)",
"cjk_rule": "有 @font-face 必须挂 SC 安全回落;禁把日文字重当中文品牌",
"cjk_floor_note": "工具台场景的 meta 11–12px / code 11–13px 是拉丁与数字标签的档;中文标签取上限 12px,与 cjk-thin-type-system 的 12px 地板一致(两包同一口径,不是两套标准)。"
}tokens/console.json{
"id": "console",
"title": "System Console · 系统栈(零 Web 字体)",
"roles": {
"display": "system-ui, -apple-system, \"Segoe UI\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif",
"body": "system-ui, -apple-system, \"Segoe UI\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif",
"mono": "\"JetBrains Mono\", \"Cascadia Code\", Consolas, monospace"
},
"weights": "400 / 600 / 700",
"features": ["tabular-nums 数字", "不引外部字体请求"],
"when": "控制台、地图 HUD、内网工具",
"note": "系统栈的取值随操作系统,视觉不可完全控制;要「一套语言」的暗色单页站走 cjk-thin-type-system,不要拿系统栈硬凑。",
"sample": "系统控制台 · 震度 5 強 · 14px 正文"
}tokens/free-thin-cjk.json{
"id": "free-thin",
"title": "免费细体中文无衬线(三选)",
"claim": "「无衬线 + 很细 + 高级 + 免费商用」的中文正文配方。三份候选都免费可商用、都有真细体、都按 unicode-range 分片(浏览器只拉页面实际用到的字形)。中文想细,必须用可变字体 —— 静态档位只有 100 的整数倍,取不到 150 这种中间值。",
"candidates": [
{
"id": "noto-sans-sc",
"name": "Noto Sans SC(可变)",
"license": "OFL-1.1",
"license_full": "SIL Open Font License 1.1",
"weight_axis": "可变 100–900",
"family_css": "\"Noto Sans SC Variable\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif",
"source": {
"kind": "npm 包 · CDN 文件",
"package": "@fontsource-variable/noto-sans-sc@5.3.0",
"css": "https://cdn.jsdelivr.net/npm/@fontsource-variable/noto-sans-sc@5.3.0/index.css",
"checked": "2026-10-06 实查 npm 与 CDN:unicode-range 101 片",
"upstream_home": "待核(未联网核对上游项目主页)"
},
"pick": "中性稳妥;首屏 150 / 其余 300",
"license_note": "Google/Noto 官方即 OFL-1.1;已见的 npm 分发同许可。"
},
{
"id": "misans",
"name": "MiSans VF",
"license": "Apache-2.0",
"license_full": "Apache License 2.0,三份里最宽松",
"weight_axis": "可变 150–700",
"family_css": "\"MiSans VF\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif",
"source": {
"kind": "npm 包 · CDN 文件",
"package": "misans@5.0.0",
"css": "https://cdn.jsdelivr.net/npm/misans@5.0.0/lib/Normal/MiSansVF.min.css",
"checked": "2026-10-06 实查 npm 与 CDN:80KB CSS,unicode-range 分片",
"upstream_home": "待核(未联网核对上游项目主页)"
},
"pick": "许可最宽松时选它",
"license_note": "许可 id 取自 npm 包 misans@5.0.0 的声明;小米上游字体许可页未联网核对(不确定是否等同 Apache-2.0),正式对外分发前须核。"
},
{
"id": "harmonyos-sans-sc",
"name": "HarmonyOS Sans SC",
"license": "Unlicense",
"license_full": "Unlicense,等同公有领域",
"weight_axis": "Thin / Light(分片包按档给:Light 300)",
"family_css": "\"HarmonyOS Sans SC\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif",
"source": {
"kind": "npm 包 · CDN 文件",
"package": "harmonyos-sans-sc-webfont-splitted@1.1.0",
"css": "https://cdn.jsdelivr.net/npm/harmonyos-sans-sc-webfont-splitted@1.1.0/dist/Light.css",
"checked": "2026-10-06 实查 npm 与 CDN:82 片,unicode-range 分片",
"upstream_home": "待核(未联网核对上游项目主页)"
},
"pick": "要几何方正时选它",
"license_note": "上游许可页未核,须核。"
}
],
"latin": "\"Inter\", var(--f-sans) —— 拉丁走 Inter,中文自然落到中文栈",
"weights": "分档而不是全局统一:首屏那两行(15px / 25px)才压得住 150;其余一律 300。中文 11–15px 用 300 以下会「笔画溶解」(300 陷阱),所以小字别再往下拉。",
"size": "CDN 直连实测 1.5–2.4MB(整页滚完);页面唯一字符往往只有两三百个 → 本地子集化可压到 20–40KB,差 50 倍。子集化是纯收益,条件允许就做。",
"features": [
"unicode-range 分片:浏览器只拉用到的字形,不是整包",
"可变字体是「取中间字重」的唯一途径(静态档位只有 100 的整数倍)",
"拉丁与中文分家:UI 字族用 Inter 打头,中文自然落到中文栈",
"标题可以另用衬线(标题走衬线 + 合成倾斜时,倾斜只给拉丁,中文不倾斜)"
],
"when": "任何「中文要细、要高级、要免费商用」的正文场景;三选按许可与气质:许可最宽松选 MiSans,要几何方正选 HarmonyOS Sans SC,要中性稳妥选 Noto Sans SC",
"refused": [
"需盗版 / 破解的商业字体文件(本清单一条都不收)",
"许可缺失(MISSING)或来源不明的字体",
"不子集化、整包下载中文字库当 Web 字体",
"把日文字重当成中文品牌字重(有 @font-face 必须挂 SC 安全回落)"
]
}
docs/usage.md# usage · cjk-typography 中文排版四件套
> 先定**场景与字族**,再谈档位。档位(几档字号、多细、多宽、多高、几层影)在 `cjk-thin-type-system`;本包只管「用哪些字、多大」。
## 1 三场景字号表(数字即口径)
| 场景 | h1 | body | meta / 脚注 | code | 备注 |
|---|---|---|---|---|---|
| **工具台** | 15–22px | 14px(HUD 12) | 11–12px | 11–13px | 零 Web 字体优先;数字 `tabular-nums` |
| **纸媒 / 电视 1920** | 64–110px(封面可 100+) | ≥40px | ≥26px | — | Serif 标题 + Sans 正文;真字重 |
| **营销落地** | `clamp(2rem–7rem)` 负字距 | 16–17px · lh 1.55–1.65 | mono eyebrow ~0.72rem · ls .14–.2em | mono 元信息 | 手写体 / 衬线只上拉丁标题;正文用中文安全栈 |
- 一个屏幕只有一套场景,不跨场景混用数字。
- 工具台的 `meta 11–12px` / `code 11–13px` 是**拉丁与数字标签**的档;中文标签取上限 **12px** —— 与 `cjk-thin-type-system` 的 12px 中文地板同口径(不是两套标准)。
- 等宽一律 JetBrains Mono;印刷 / 波普风可换 Space Mono。
## 2 字族与回退栈(四个角色)
| 角色 | 字族栈 | 什么时候用 |
|---|---|---|
| 正文 / UI | `"Noto Sans SC", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif` | 一切正文与界面 |
| 显示 / 标题 | 同正文栈 | 标题不用衬线时;要衬线标题走主题包的 display 档 |
| 长文阅读 | `"Noto Serif SC", "Source Han Serif SC", "Songti SC", serif` | `article` 长文正文 |
| 等宽 | `"JetBrains Mono", "Maple Mono NF CN", ui-monospace, monospace` | 代码、数字、eyebrow |
- **`SimSun` / 宋体 / `serif` 禁入 `body` 回退栈**:静默回退到宋体是硬错误(字形与字面全变),不是风格选择。
- 字号地板:正文 16px(移动 15px)· 次级 / 卡片 14px · 角标 12px · 整页可读最小 14px;卡片禁 9 / 10 / 11 / 13px;标题 20px 起、层级差 ≥4px。
- 行高:中文正文 1.7–1.8 · 长文衬线 ≥1.6。中文正文**禁** `letter-spacing`、**禁**两端对齐。
- 字重:正文 400–500 · 强调 700;**中文 11–15px 不许挂 300 以下**(「300 陷阱」:笔画溶解);禁加粗宋体冒充黑体。
- 大容器字号 ≥ 同屏小容器。
## 3 免费细体中文三选(许可 + 来源)
「中文要细、要高级、**免费商用**」的三个候选。三份都免费可商用、都有真细体、都按 `unicode-range` 分片(浏览器只拉页面实际用到的字形)。
| 字体名 | 许可 | 下载来源(npm 包 · CDN 文件) |
|---|---|---|
| Noto Sans SC(可变) | OFL-1.1(SIL Open Font License 1.1) | `@fontsource-variable/noto-sans-sc@5.3.0` · `https://cdn.jsdelivr.net/npm/@fontsource-variable/noto-sans-sc@5.3.0/index.css` |
| MiSans VF | Apache-2.0(三份里最宽松) | `misans@5.0.0` · `https://cdn.jsdelivr.net/npm/misans@5.0.0/lib/Normal/MiSansVF.min.css` |
| HarmonyOS Sans SC | Unlicense(等同公有领域) | `harmonyos-sans-sc-webfont-splitted@1.1.0` · `https://cdn.jsdelivr.net/npm/harmonyos-sans-sc-webfont-splitted@1.1.0/dist/Light.css` |
- 三份**只引用字族名 / 走 CDN,不随包分发字体文件**;许可与版本随上游走,落地时把版本号钉死。
- 每条来源都在 **2026-10-06 实查过 npm 与 CDN**(unicode-range 分片:Noto 101 片 / HarmonyOS 82 片 / MiSans 80KB CSS)。**上游项目主页未联网核对 → 标「待核」**;要写进对外文档前请自行核一次。
- 选型:许可最宽松 → **MiSans**;要几何方正 → **HarmonyOS Sans SC**;要中性稳妥 → **Noto Sans SC**。
- 可变轴:Noto `100–900` · MiSans `150–700`;HarmonyOS 分片包按档给(如 Light 300)。
- 字重分档而不是全局统一:**首屏那两行(15px / 25px)才压得住 150**,其余一律 300;中文 11–15px 别再往下拉。
- 拉丁与中文分家:UI 字族用 `"Inter", var(--f-sans)` 打头,拉丁走 Inter,中文自然落到中文栈。
### 子集化(必做)
CDN 直连实测 **1.5–2.4MB**(整页滚完);而页面唯一字符往往只有两三百个 → 本地子集化可压到 **20–40KB**,差 **50 倍**。上 Web 字体必须 `font-display:swap` 防 FOIT,并做子集化。
## 4 系统栈(零 Web 字体)
| 角色 | 栈 |
|---|---|
| UI / 正文 | `system-ui, -apple-system, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif` |
| 等宽 | `"JetBrains Mono", "Cascadia Code", Consolas, monospace` |
字重 400 / 600 / 700,数字开 `tabular-nums`,不引外部字体请求。适用于控制台、地图 HUD、内网工具。系统栈的取值随操作系统,视觉不可完全控制;**要「一套语言」的暗色单页站走 `cjk-thin-type-system`,不要拿系统栈硬凑**。
## 5 反模式
- **推荐需盗版 / 破解的商业字体文件**;或把商业字族连同字体文件一起塞进项目(本包一条都不收)。
- 列了字体名却不写**许可与来源**;把「来源未核」写成「已验证」。
- `serif` / 宋体 / `SimSun` 混进 `body` 回退栈(换台机器静默变宋体)。
- 中文 15px 挂 300 字重;或给加粗宋体冒充黑体。
- 中文正文加 `letter-spacing`、`text-align: justify`。
- 不子集化直接整包拉中文字库(整页 1.5–2.4MB)。
- 拿日文字重当中文品牌字重(有 `@font-face` 必须挂 SC 安全回落)。
- 跨场景抄数字:把纸媒 1920 的 `≥40px` 正文塞进工具台。
## 6 取用
```bash
python <sai-assets>/scripts/apply.py cjk-typography --to src/tokens
```
消费后在项目 `design-lock.json` 记 `assets[]`:`pack=cjk-typography`、`version`、`sha`,并把选中的字体名 + 许可 + 来源一并记下(见 `docs/USAGE-INTEGRATION.md`)。
SKILL.md---
name: cjk-typography
description: CJK typography recipe pack — body sans fallback stacks, a three-scene type-size table (console / 1920 print-and-TV / marketing landing), the zero-web-font system stack, and three free-for-commercial-use thin CJK faces with explicit licenses and download sources. Use when starting a Chinese/Japanese project and deciding font stacks, size floors, or a free thin CJK webfont; skip when the task is about size tiers, line-height, tracking or text-shadow convergence.
---
# cjk-typography
中文排版四件套合成一包:**用哪些字 + 多大**。四张来源卡:正文无衬线回退栈、三场景字号总表、系统等宽栈、免费细体中文三选(纯许可清单)。
## When to use
- 新中文项目**定字族**:正文 / UI / 长文衬线 / 等宽四个角色各用什么
- **对字号**:先判断是工具台、纸媒电视 1920 还是营销落地,再照表取数
- 需要「中文要细、要高级、**免费商用**」的正文:三选候选 + 许可 + 下载来源都在这
- 零 Web 字体场景(控制台 / HUD / 内网工具):直接用系统栈
## When not to use
- 档位收敛(几档字号 / 字距 / 行高 / 文字影、地板 12px、越大越细):走 `cjk-thin-type-system`
- 配色与主题:走 themes 类包
- 需要商业字体文件:**本包不提供**;也不接受"从哪下破解版"这类用法
## Default
正文 / UI = `"Noto Sans SC", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif`;长文阅读切 `article` 衬线栈;工具台走 `system-ui` 系统栈。
## Files
| path | use |
|------|-----|
| `tokens/index.json` | 四张卡的目录 + 与 `cjk-thin-type-system` 的分工 + 硬规则 |
| `tokens/body-sans.json` | 正文无衬线回退栈(4 个角色)+ 字号地板 + 300 陷阱 |
| `tokens/size-scale.json` | 三场景字号总表:工具台 / 纸媒电视 1920 / 营销落地 |
| `tokens/console.json` | 系统栈(零 Web 字体的工具台默认) |
| `tokens/free-thin-cjk.json` | 免费细体中文三选:许可 / 可变轴 / 下载来源 / 子集化 |
| `docs/usage.md` | **三场景表 + 免费字体清单(字体名 / 许可 / 来源三列)+ 反模式** |
| `preview/index.html` | 活预览(三场景字号对照 + 三选字族展示) |
| `scripts/assert_tokens.py` | 断言:产物齐备 · 三场景数字 · 清单三列齐 · preview 引用 · 字号地板 |
## Agent apply steps
1. 读 `tokens/size-scale.json`,按项目场景取一行数字(工具台 / 纸媒电视 1920 / 营销落地),不要跨场景混用。
2. 读 `tokens/body-sans.json` 取回退栈;**禁止**自己编字族顺序,`serif` / 宋体不许进 `body`。
3. 要细体中文:读 `tokens/free-thin-cjk.json`,按「许可最宽松 / 要几何 / 要中性」三选一,连许可与下载来源一起抄进项目 `design-lock.json`。
4. 上 Web 字体必须挂 `font-display:swap` 并子集化;零 Web 字体场景改读 `tokens/console.json`。
5. 档位(几档、多细、多宽)去 `cjk-thin-type-system` 取,本包不给档位。
## Hard rules
- 清单只列**许可明确**的字体,逐条给「字体名 | 许可 | 来源」;许可或来源没核到就写「待核」,不许当已验证。
- **禁推荐需盗版 / 破解的商业字体文件**;商业字族最多只写字族名。
- `SimSun` / 宋体 / `serif` 禁入 `body` 回退栈(静默回退 = 硬错误)。
- 中文 11–15px 不许挂 300 以下字重(笔画溶解);小字抬字重,不要往下拉字重。
- 中文正文禁 `letter-spacing`、禁两端对齐。
- 工具台场景 meta `11–12px` / code `11–13px` 是拉丁与数字标签的档;**中文标签取 12px 上限**,与 `cjk-thin-type-system` 同口径。
- 有 `@font-face` 必须挂 SC 安全回落;不把日文字重当中文品牌字重。