docs(logo): 新增 logo v5.1 正式资产、使用规范与构建脚本

- 白文印「标」(AI 生成原图经脚本抠图、统一为 #D9291C、矢量化)
- 字标:思源宋体 SemiBold + Libre Caslon;比例 H2,英文视觉内缩 C2
- svg/、png/、favicon:横版、竖版、反白、单色、印章、各尺寸图标
- scripts/:logo_lib.py 统一排版参数,build_assets.sh 一键生成
- logo-spec.md、logo-sheet.html、字体许可证(OFL)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-02 20:28:18 +08:00
parent f4ef7af542
commit 5753b51131
51 changed files with 1160 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
"""生成字标字体对比与印章高度对比(docs/design/logo/compare/)。
用法:.work/venv/bin/python scripts/wordmark_compare.py
字体文件在 .work/fonts/(不进 git),许可证见 compare/index.html 与 logo-spec.md。
"""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from logo_lib import CN_H, GAP, LOGO, NAVY, PY_CAP, WHITE, lockup, wordmark # noqa: E402
OUT = LOGO / "compare"
OUT.mkdir(exist_ok=True)
# (编号, 中文字体, 中文字重, 中文字距(em), 拼音字体, 拼音字重, 名称, 许可证, 说明)
PAIRS = [
("F1", "NotoSerifSC[wght].ttf", 900, 0.00, "Cinzel[wght].ttf", 600, "思源宋体 Black + Cinzel", "OFL", "现用。最粗的宋体,庄重、有分量"),
("F2", "NotoSerifSC[wght].ttf", 600, 0.04, "CormorantGaramond[wght].ttf", 600, "思源宋体 SemiBold + Cormorant Garamond", "OFL", "同一家族的细一档,更清秀,和印章的轻重对比更明显"),
("F3", "ZhuqueFangsong.ttf", None, 0.06, "CormorantSC-SemiBold.ttf", None, "朱雀仿宋 + Cormorant SC", "OFL", "仿宋,招标文件和公文的正文字体,文书感最强"),
("F4", "HuiwenMincho.ttf", None, 0.04, "LibreCaslonText[wght].ttf", 700, "汇文明朝体 + Libre Caslon", "授权需复核", "老铅字印刷的宋体,带油墨感,和印章最搭;授权说明不规范"),
("F5", "LXGWWenKai-Medium.ttf", None, 0.06, "EBGaramond[wght].ttf", 600, "霞鹜文楷 + EB Garamond", "OFL", "楷书,书卷气,亲切但不够硬朗"),
("F6", "ZCOOLXiaoWei-Regular.ttf", None, 0.04, "MarcellusSC-Regular.ttf", None, "站酷小薇 LOGO 体 + Marcellus SC", "OFL", "为标志设计的宋体,笔画更有个性;但「标」的木字旁写成带钩的连笔,容易被看成「扌」,不建议"),
("F7", "NotoSansSC[wght].ttf", 900, 0.02, "Montserrat[wght].ttf", 600, "思源黑体 Black + Montserrat", "OFL", "黑体,现代、稳重,和传统印章形成反差"),
("F8", "SmileySans-Oblique.ttf", None, 0.02, "SmileySans-Oblique.ttf", None, "得意黑(中英同一字体)", "OFL", "带倾斜的现代黑体,年轻、有速度感"),
]
# 1. 印章高度对比(字体 F1)
body, w, h = wordmark(PAIRS[0], NAVY)
cn_h = CN_H
variants = [
("H0", "现状:96%,上下没对齐", lockup(body, w, h, h * 0.961, (h - h * 0.961) / 2 + 0.6)),
("H1", "等高对齐:印章上下边对齐中文顶端和拼音底部", lockup(body, w, h, h, 0)),
("H2", "等高 + 光学补偿 2%:抵消印章颗粒边缘显虚", lockup(body, w, h, h * 1.02, -h * 0.01)),
("H3", "放大到 115%:图形主导", lockup(body, w, h, h * 1.15, -h * 0.075)),
("H4", "书法落款式:印章只与中文同高", lockup(body, w, h, cn_h, 0)),
]
for vid, _, svg in variants:
(OUT / f"height-{vid}.svg").write_text(svg)
# 2. 字体对比(统一用 H2)
for p in PAIRS:
for color, dark, suffix in ((NAVY, False, ""), (WHITE, True, "-reverse")):
body, w, h = wordmark(p, color)
(OUT / f"font-{p[0]}{suffix}.svg").write_text(lockup(body, w, h, h * 1.02, -h * 0.01, on_dark=dark))
# 3. 对比页
rows_h = "".join(f'<figure class="tile"><img src="height-{vid}.svg" alt="{t}"><figcaption><b>{vid}</b> {t}</figcaption></figure>'
for vid, t, _ in variants)
rows_f = "".join(
f'<section class="font"><h3>{p[0]} · {p[6]}</h3><p>{p[8]}<span class="lic{" warn" if p[7] != "OFL" else ""}">{p[7]}</span></p>'
f'<div class="pair"><div class="tile"><img src="font-{p[0]}.svg" alt="{p[6]} 浅色底"></div>'
f'<div class="tile dark"><img src="font-{p[0]}-reverse.svg" alt="{p[6]} 深色底"></div></div>'
f'<div class="small"><img src="font-{p[0]}.svg" width="200" alt=""><img src="font-{p[0]}.svg" width="120" alt=""></div></section>'
for p in PAIRS)
html = f"""<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>字标与比例对比</title><style>
:root{{--ink:#1D2733;--sub:#5C6670;--line:#D9DDD8}}
*{{box-sizing:border-box}}body{{margin:0;background:#F5F6F3;color:var(--ink);font:15px/1.7 "PingFang SC","Microsoft YaHei",system-ui,sans-serif}}
main{{max-width:1120px;margin:0 auto;padding:40px 24px 80px}}h1{{font-size:26px;margin:0 0 4px}}h2{{font-size:19px;margin:44px 0 6px}}h3{{font-size:16px;margin:0}}
p.note{{color:var(--sub);margin:0 0 18px;max-width:48em}}
.grid{{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:14px}}
.tile{{background:#fff;border:1px solid var(--line);padding:28px;margin:0}}.tile.dark{{background:#1D2733;border-color:#1D2733}}
.tile img{{display:block;width:100%;height:auto}}figcaption{{font-size:13px;color:var(--sub);margin-top:12px}}
.font{{background:#fff;border:1px solid var(--line);padding:20px;margin:0 0 16px}}.font p{{margin:2px 0 12px;color:var(--sub);font-size:14px}}
.pair{{display:grid;grid-template-columns:1fr 1fr;gap:12px}}.pair .tile{{padding:20px}}
.small{{display:flex;gap:24px;align-items:center;margin-top:12px}}
.lic{{display:inline-block;margin-left:8px;font-size:12px;padding:0 6px;border:1px solid #2E6B4F;color:#2E6B4F;border-radius:2px}}.lic.warn{{border-color:#A66300;color:#A66300}}
@media (max-width:700px){{.pair{{grid-template-columns:1fr}}}}
</style></head><body><main>
<h1>字标与比例对比</h1><p class="note">两个问题:一、印章和右边文字的高度关系;二、字标字体。所有版本都用同一枚印章,文字已转成路径。</p>
<h2>一、印章高度</h2><p class="note">字体统一用 F1。H0 是现在的版本,H2 是建议的版本。</p>
<div class="grid">{rows_h}</div>
<h2>二、字标字体</h2><p class="note">比例统一用 H2。每组下面一行是 200px 和 120px 宽度的实际效果。</p>
{rows_f}
</main></body></html>"""
(OUT / "index.html").write_text(html)
print("ok", len(PAIRS), "fonts,", len(variants), "height variants")
# 4. 英文字体对比:中文固定为 F2(思源宋体 SemiBold),比例 H2
# (编号, 英文字体, 字重, 名称, 对应的经典字体 / 类型, 说明)
EN_OPTIONS = [
("E0", "CormorantGaramond[wght].ttf", 600, "Cormorant Garamond", "Garamond 类 · 古典衬线", "现选(F2)。纤细优雅,笔画对比高"),
("E1", "Cinzel[wght].ttf", 500, "Cinzel", "Trajan 类 · 罗马碑刻大写", "庄重、权威,金融和教育机构常用的气质"),
("E2", "MarcellusSC-Regular.ttf", None, "Marcellus SC", "Optima / Albertus 类 · 半衬线", "笔画末端微微张开,介于衬线和无衬线之间,和宋体很合拍"),
("E3", "TenorSans-Regular.ttf", None, "Tenor Sans", "Optima 类 · 人文无衬线", "无衬线但有书法韵味,现代而不冷"),
("E4", "EBGaramond[wght].ttf", 600, "EB Garamond", "Garamond · 古典衬线", "比 E0 更结实、更正统的 Garamond"),
("E5", "LibreCaslonText[wght].ttf", 600, "Libre Caslon", "Caslon · 老派衬线", "英国老字号和出版社的经典选择,沉稳"),
("E6", "SourceSerif4[opsz,wght].ttf", 600, "Source Serif 4", "与思源宋体同属 Adobe Source 家族", "和中文出自同一设计体系,最协调、最「工整」"),
("E7", "BodoniModa[opsz,wght].ttf", 600, "Bodoni Moda", "Didot / Bodoni 类 · 现代高对比", "时尚、精致,奢侈品和杂志常用"),
("E8", "Jost[wght].ttf", 500, "Jost", "Futura 类 · 几何无衬线", "现代、干净,和传统印章形成反差"),
]
cn = PAIRS[1] # F2
for eid, ef, ew, *_ in EN_OPTIONS:
pair = (eid, cn[1], cn[2], cn[3], ef, ew)
for color, dark, suffix in ((NAVY, False, ""), (WHITE, True, "-reverse")):
body, w, h = wordmark(pair, color)
(OUT / f"en-{eid}{suffix}.svg").write_text(lockup(body, w, h, h * 1.02, -h * 0.01, on_dark=dark))
rows_e = "".join(
f'<section class="font"><h3>{e[0]} · {e[3]}</h3><p>{e[4]}。{e[5]}<span class="lic">OFL</span></p>'
f'<div class="pair"><div class="tile"><img src="en-{e[0]}.svg" alt="{e[3]} 浅色底"></div>'
f'<div class="tile dark"><img src="en-{e[0]}-reverse.svg" alt="{e[3]} 深色底"></div></div>'
f'<div class="small"><img src="en-{e[0]}.svg" width="200" alt=""><img src="en-{e[0]}.svg" width="120" alt=""></div></section>'
for e in EN_OPTIONS)
(OUT / "english.html").write_text(html.split("<h1>")[0] + f"""<h1>英文字体对比(H2 + F2)</h1>
<p class="note">中文固定为思源宋体 SemiBold,比例固定为 H2,只换下方英文。全部是 Google Fonts 上的 SIL OFL 1.1 字体,可以免费商用、可以用在 logo 里。</p>
{rows_e}
</main></body></html>""")
print("ok", len(EN_OPTIONS), "english options")
# 5. 英文特写:只显示拼音这一行,放大比较字形
py_top, py_h = CN_H * (1 + GAP), CN_H * PY_CAP
for eid, ef, ew, *_ in EN_OPTIONS:
body, w, h = wordmark((eid, cn[1], cn[2], cn[3], ef, ew), NAVY)
(OUT / f"en-{eid}-detail.svg").write_text(
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 {py_top - 3:.1f} {w + 4:.1f} {py_h + 6:.1f}">{body}</svg>')
detail = "".join(f'<figure class="tile"><img src="en-{e[0]}-detail.svg" alt="{e[3]} 特写"><figcaption><b>{e[0]}</b> {e[3]}</figcaption></figure>'
for e in EN_OPTIONS)
page = (OUT / "english.html").read_text()
page = page.replace("</main>", f'<h2>英文特写</h2><p class="note">只看拼音这一行,放大比较字形细节。</p><div class="grid">{detail}</div></main>')
(OUT / "english.html").write_text(page)
print("ok detail")
# 6. 英文视觉对齐补偿(H2 + F2 + E5)
# 实测:中文两端只有细横画尖,英文两端是 B、I 的粗竖画;按墨迹浓度算英文左超 6.5、右超 7.7(中文字高 = 100)
E5 = next(e for e in EN_OPTIONS if e[0] == "E5")
ALIGN = [
("C0", (0.0, 0.0), "不补偿:几何两端对齐(现状)"),
("C1", (3.5, 4.0), "补偿一半:左 3.5、右 4.0"),
("C2", (5.0, 5.8), "补偿约 3/4:左 5.0、右 5.8"),
("C3", (6.5, 7.7), "完全补偿:按墨迹浓度边缘对齐,左 6.5、右 7.7"),
]
CN_VISUAL = (8.6, 315.4) # 中文「浓度 ≥ 15%」的视觉边缘(实测)
pair_e5 = ("E5", cn[1], cn[2], cn[3], E5[1], E5[2])
for cid, ins, _ in ALIGN:
for color, dark, suffix in ((NAVY, False, ""), (WHITE, True, "-reverse")):
body, w, h = wordmark(pair_e5, color, inset=ins)
(OUT / f"align-{cid}{suffix}.svg").write_text(lockup(body, w, h, h * 1.02, -h * 0.01, on_dark=dark))
# 带辅助线的字标特写:红线 = 中文视觉边缘,灰线 = 中文几何边界
body, w, h = wordmark(pair_e5, NAVY, inset=ins)
guides = (f'<line x1="0" y1="-4" x2="0" y2="{h + 4:.1f}" stroke="#999" stroke-width="0.6" stroke-dasharray="2 2"/>'
f'<line x1="{w:.1f}" y1="-4" x2="{w:.1f}" y2="{h + 4:.1f}" stroke="#999" stroke-width="0.6" stroke-dasharray="2 2"/>'
f'<line x1="{CN_VISUAL[0]}" y1="-4" x2="{CN_VISUAL[0]}" y2="{h + 4:.1f}" stroke="#D9291C" stroke-width="0.6"/>'
f'<line x1="{CN_VISUAL[1]}" y1="-4" x2="{CN_VISUAL[1]}" y2="{h + 4:.1f}" stroke="#D9291C" stroke-width="0.6"/>')
(OUT / f"align-{cid}-guides.svg").write_text(
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-8 -8 {w + 16:.1f} {h + 16:.1f}"><rect x="-8" y="-8" width="{w + 16:.1f}" height="{h + 16:.1f}" fill="#fff"/>{body}{guides}</svg>')
rows_a = "".join(
f'<section class="font"><h3>{c[0]} · {c[2]}</h3>'
f'<div class="pair"><div class="tile"><img src="align-{c[0]}.svg" alt="{c[0]} 浅色底"></div>'
f'<div class="tile"><img src="align-{c[0]}-guides.svg" alt="{c[0]} 辅助线"></div></div>'
f'<div class="small"><img src="align-{c[0]}.svg" width="240" alt=""><img src="align-{c[0]}.svg" width="160" alt=""></div></section>'
for c in ALIGN)
(OUT / "alignment.html").write_text(html.split("<h1>")[0] + f"""<h1>英文视觉对齐补偿(H2 + F2 + E5)</h1>
<p class="note">右侧特写的辅助线:灰色虚线是中文的几何边界(最外的墨迹),红线是中文的视觉边缘(墨迹浓度达到行高 15% 的位置)。
补偿越多,英文越往红线靠。建议不看辅助线、只看左侧的整体效果做判断。</p>
{rows_a}
</main></body></html>""")
print("ok alignment")