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:
114
docs/design/logo/scripts/vi_diagrams.py
Normal file
114
docs/design/logo/scripts/vi_diagrams.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""生成 VI 手册里的标志构成与安全区标注图(docs/design/vi/diagrams/)。
|
||||
|
||||
标注数值直接取自 logo_lib 的实际几何,保证和正式资产一致。
|
||||
用法:.work/venv/bin/python scripts/vi_diagrams.py
|
||||
"""
|
||||
from logo_lib import (FINAL, FINAL_INSET, LOGO, NAVY, SB, SEAL_GAP, SEAL_SCALE, SL, SR, ST, CN_H, GAP, PY_CAP,
|
||||
seal_group, wordmark)
|
||||
|
||||
OUT = LOGO.parent / "vi/diagrams"
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
BLUE = "#2F5BD3"
|
||||
FONT = 'font-family="PingFang SC, Noto Sans SC, sans-serif"'
|
||||
|
||||
body, W, H = wordmark(FINAL, NAVY, inset=FINAL_INSET)
|
||||
SEAL_H = H * SEAL_SCALE
|
||||
SEAL_TOP = -(SEAL_H - H) / 2
|
||||
SEAL_W = (SR - SL) * SEAL_H / (SB - ST)
|
||||
GAP_X = SEAL_H * SEAL_GAP
|
||||
TX = SEAL_W + GAP_X
|
||||
|
||||
|
||||
def label(x, y, text, anchor="middle", size=7.5):
|
||||
return f'<text x="{x:.1f}" y="{y:.1f}" fill="{BLUE}" font-size="{size}" text-anchor="{anchor}" {FONT}>{text}</text>'
|
||||
|
||||
|
||||
def hline(x1, x2, y, dash=True):
|
||||
d = ' stroke-dasharray="2 2"' if dash else ""
|
||||
return f'<line x1="{x1:.1f}" y1="{y:.1f}" x2="{x2:.1f}" y2="{y:.1f}" stroke="{BLUE}" stroke-width="0.5"{d}/>'
|
||||
|
||||
|
||||
def vline(x, y1, y2, dash=True):
|
||||
d = ' stroke-dasharray="2 2"' if dash else ""
|
||||
return f'<line x1="{x:.1f}" y1="{y1:.1f}" x2="{x:.1f}" y2="{y2:.1f}" stroke="{BLUE}" stroke-width="0.5"{d}/>'
|
||||
|
||||
|
||||
def dim_v(x, y1, y2, text, side="left"):
|
||||
"""竖向尺寸线,带两端短横。"""
|
||||
t = 2.5
|
||||
lx = x - 4 if side == "left" else x + 4
|
||||
return (vline(x, y1, y2, dash=False) + hline(x - t, x + t, y1, dash=False) + hline(x - t, x + t, y2, dash=False)
|
||||
+ label(lx, (y1 + y2) / 2 + 2.6, text, "end" if side == "left" else "start"))
|
||||
|
||||
|
||||
def dim_h(x1, x2, y, text, below=False):
|
||||
t = 2.5
|
||||
ly = y + 9 if below else y - 3.5
|
||||
return (hline(x1, x2, y, dash=False) + vline(x1, y - t, y + t, dash=False) + vline(x2, y - t, y + t, dash=False)
|
||||
+ label((x1 + x2) / 2, ly, text))
|
||||
|
||||
|
||||
def construction_h():
|
||||
seal, _ = seal_group("clean", 0, SEAL_TOP, SEAL_H)
|
||||
py_top = CN_H * (1 + GAP)
|
||||
x_end = TX + W
|
||||
parts = [seal, f'<g transform="translate({TX:.2f} 0)">{body}</g>']
|
||||
# 文字块上下边界与印章边界
|
||||
parts += [hline(-30, x_end + 12, 0), hline(-30, x_end + 12, H),
|
||||
hline(-30, SEAL_W + 4, SEAL_TOP), hline(-30, SEAL_W + 4, SEAL_TOP + SEAL_H)]
|
||||
parts.append(dim_v(-12, 0, H, "H"))
|
||||
parts.append(dim_v(-26, SEAL_TOP, SEAL_TOP + SEAL_H, "1.02H"))
|
||||
# 印章与文字间距
|
||||
parts.append(dim_h(SEAL_W, TX, H + 18, "0.3 × 印章高", below=True))
|
||||
parts += [vline(SEAL_W, SEAL_TOP + SEAL_H, H + 22), vline(TX, H, H + 22)]
|
||||
# 字标内部:中文字高、间距、拼音高
|
||||
rx = x_end + 10
|
||||
parts.append(dim_v(rx, 0, CN_H, "中文字高 100", side="right"))
|
||||
parts.append(dim_v(rx, CN_H, py_top, "间距 14", side="right"))
|
||||
parts.append(dim_v(rx, py_top, H, "拼音 20", side="right"))
|
||||
# 英文视觉内缩
|
||||
parts += [vline(TX, py_top - 6, H + 4), vline(x_end, py_top - 6, H + 4)]
|
||||
parts.append(vline(TX + FINAL_INSET[0], py_top - 6, H + 4))
|
||||
parts.append(vline(x_end - FINAL_INSET[1], py_top - 6, H + 4))
|
||||
parts.append(label(TX + 2.5, H + 12, f"内缩 {FINAL_INSET[0]:g}", "start", 6.5))
|
||||
parts.append(label(x_end - 2.5, H + 12, f"内缩 {FINAL_INSET[1]:g}", "end", 6.5))
|
||||
vb = (-60, SEAL_TOP - 14, x_end + 150, SEAL_H + 56)
|
||||
return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{" ".join(f"{v:.1f}" for v in vb)}">{"".join(parts)}</svg>'
|
||||
|
||||
|
||||
def construction_v():
|
||||
seal_h = W * 0.5
|
||||
seal, _ = seal_group("clean", (W - seal_h) / 2, 0, seal_h)
|
||||
gap = seal_h * 0.18
|
||||
y_wm = seal_h + gap
|
||||
parts = [seal, f'<g transform="translate(0 {y_wm:.2f})">{body}</g>']
|
||||
parts += [vline(0, -8, y_wm + H + 6), vline(W, -8, y_wm + H + 6)]
|
||||
parts.append(dim_h(0, W, -14, "字标宽 W"))
|
||||
parts.append(dim_h((W - seal_h) / 2, (W + seal_h) / 2, seal_h + 5, "0.5W", below=True))
|
||||
parts.append(dim_v(W + 12, seal_h, y_wm, "0.18 × 印章边长", side="right"))
|
||||
parts += [hline((W + seal_h) / 2, W + 14, seal_h), hline(W, W + 14, y_wm)]
|
||||
vb = (-20, -30, W + 130, y_wm + H + 40)
|
||||
return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{" ".join(f"{v:.1f}" for v in vb)}">{"".join(parts)}</svg>'
|
||||
|
||||
|
||||
def clearspace():
|
||||
seal, _ = seal_group("clean", 0, SEAL_TOP, SEAL_H)
|
||||
m = H / 4
|
||||
x0, y0 = -m, SEAL_TOP - m
|
||||
x1, y1 = TX + W + m, SEAL_TOP + SEAL_H + m
|
||||
parts = [f'<rect x="{x0:.1f}" y="{y0:.1f}" width="{x1 - x0:.1f}" height="{y1 - y0:.1f}" fill="#E7EDFB" stroke="{BLUE}" stroke-width="0.6" stroke-dasharray="3 2"/>',
|
||||
f'<rect x="0" y="{SEAL_TOP:.1f}" width="{TX + W:.1f}" height="{SEAL_H:.1f}" fill="#fff"/>',
|
||||
seal, f'<g transform="translate({TX:.2f} 0)">{body}</g>']
|
||||
# 四边标注 H/4
|
||||
parts.append(dim_h(x0, 0, SEAL_TOP + SEAL_H / 2, "H/4"))
|
||||
parts.append(dim_h(TX + W, x1, SEAL_TOP + SEAL_H / 2, "H/4"))
|
||||
parts.append(dim_v(TX + W / 2, y0, SEAL_TOP, "H/4", side="right"))
|
||||
parts.append(dim_v(TX + W / 2, SEAL_TOP + SEAL_H, y1, "H/4", side="right"))
|
||||
vb = (x0 - 10, y0 - 10, x1 - x0 + 20, y1 - y0 + 20)
|
||||
return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{" ".join(f"{v:.1f}" for v in vb)}">{"".join(parts)}</svg>'
|
||||
|
||||
|
||||
(OUT / "construction-horizontal.svg").write_text(construction_h())
|
||||
(OUT / "construction-vertical.svg").write_text(construction_v())
|
||||
(OUT / "clearspace.svg").write_text(clearspace())
|
||||
print("ok", sorted(p.name for p in OUT.iterdir()))
|
||||
Reference in New Issue
Block a user