一、ASCII Art:从电传打字机到现代终端
ASCII Art(ASCII 艺术)是用可打印 ASCII 字符拼合成图案的视觉艺术形式。它的历史比大多数人想象的更久远:
- 1966 年:Ken Knowton 在贝尔实验室用字符打孔卡片生成图案,被视为 ASCII Art 的先驱
- 1970 年代:电传打字机(TTY)时代,开发者用字符绘制流程图、电路图、Logo
- 1991 年:Glenn Chappell 与 Ian Chai 发布 FIGlet,让 ASCII Art 文本横幅生成进入自动化时代
- 现代:GitHub README 标题、CLI 启动横幅、源码注释装饰、终端签名、Slack/IRC 表情
即使在图形化界面普及的今天,ASCII Art 仍有不可替代的价值:
- 纯文本兼容:任何环境(终端、邮件、Markdown、代码注释)都能正确显示,无需图片
- 等宽即对齐:在等宽字体下,字符天然对齐,无需额外排版
- 零依赖传播:复制粘贴即用,无需下载字体文件或图片资源
- 版本控制友好:作为文本存储在 Git 中,diff 清晰可读
二、FIGlet 与 FIGfont 字体格式
2.1 FIGlet 程序
FIGlet 是最经典的 ASCII Art 字体渲染程序。它接收文本输入,按指定字体渲染为多行 ASCII Art 输出。核心特性:
- 字体可插拔:字体独立存储为
.flf文件,程序与字体解耦 - 多渲染模式:支持全宽(full width)、紧排(kerning)、压缩(smushed)三种字符拼接模式
- 社区生态:FIGfont 仓库收录了数百种字体,如 Standard、Big、Slant、Shadow、Banner 等
2.2 FIGfont 文件格式
每个 .flf 文件由头部与字符数据两部分组成:
flf2a$ 7 5 16 15 11 0 24321
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
│ │ │ │ │ │ │ └─ 注释行数
│ │ │ │ │ │ └─── 旧布局(已废弃)
│ │ │ │ │ └───── 打印方向(0=左到右,1=右到左)
│ │ │ │ └──────── 硬空白列数
│ │ │ └─────────── 字符最大宽度(列数)
│ │ └────────────── 基线行号(从 1 开始)
│ └───────────────── 字符高度(行数)
└────────────────────── 签名行 + 硬空白字符(此处为 $)
字符数据按 ASCII 码顺序排列,每个字符占 height 行,行间用 @ 等结束符分隔。硬空白字符(如 $)表示字符内的空格,避免被行尾 trim 去除。
2.3 拼接模式
FIGlet 支持三种字符拼接模式:
| 模式 | 说明 | 效果 |
|---|---|---|
| 全宽 | 每字符占满最大宽度,字符间无重叠 | 视觉最宽,对齐最整齐 |
| 紧排 | 相邻字符的空白列重叠 | 视觉紧凑,部分字符可粘连 |
| 压缩 | 相邻字符的边界字符按规则合并 | 视觉最紧凑,字形可能变形 |
本工具采用「全宽 + 可调间距」策略:字符间用 0-2 个空格分隔,既保证可读性,又提供灵活性。相比 FIGlet 的复杂紧排算法,这种方案实现简单且效果可控。
三、三种字体的设计差异
本工具内置 Block、Banner、Small 三种字体,分别对应不同使用场景:
3.1 Block(5 行高,方块风格)
█████
██ ██
███████
██ ██
██ ██
- 字符宽度:统一 7 列,视觉最整齐
- 填充字符:
█(全角块),对比度最高 - 适用场景:终端标题、README 主标题、文档醒目位置
- 设计取舍:7 列宽度让 M、W 等宽字符也能紧凑显示,但 I 等窄字符需居中填充
3.2 Banner(7 行高,宽幅风格)
██
████
██ ██
████████
██ ██
██ ██
██ ██
- 字符宽度:8 列,视觉最宽
- 填充字符:
█,但字形更圆润(如 A 的斜边) - 适用场景:启动横幅、CLI 欢迎 Banner、大标题
- 设计取舍:7 行高占用纵向空间多,但视觉冲击力最强
3.3 Small(3 行高,紧凑风格)
██
██ █
███
- 字符宽度:变宽(2-8 列),最节省横向空间
- 填充字符:
█,但字形高度简化 - 适用场景:多行输出、注释块标题、CLI 签名、邮件签名
- 设计取舍:3 行高让多行内容不会过长,但字形辨识度略低
四、渲染算法核心
4.1 数据结构
每个字体定义为字符映射表:
type Font = {
name: string; // 字体名称
height: number; // 字体高度(行数)
chars: Record<string, string>; // 字符 -> 多行 ASCII Art(用 \n 分隔)
};
每个字符的 ASCII Art 用 \n 分隔的多行字符串表示:
'A': ' █████ \n██ ██\n███████\n██ ██\n██ ██'
4.2 横向拼接算法
渲染流程:
- 预处理:可选转大写(字体仅含大写字母)
- 逐字符查找:在字体表中查找字符数据,未找到用占位符
?渲染 - 行对齐:将每个字符的数据按
\n切分为行数组,确保行数与字体高度一致 - 横向拼接:逐行将所有字符的对应行用空格分隔拼接
for (let row = 0; row < height; row++) {
const rowParts = charBlocks.map(block => block[row] ?? '');
const line = rowParts.join(separator);
resultLines.push(line.trimEnd());
}
4.3 占位符处理
未覆盖字符(如中文、Emoji、Unicode 符号)统一用 ? 占位符渲染。占位符的尺寸与字体高度一致,保证输出不变形。实际使用中,建议将非 ASCII 字符替换为等价表达(如「工具」→「GONGJU」)。
五、应用场景实战
5.1 GitHub README 标题
███████ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ███ ███████ ██ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ███████
# MyProject
一个简洁高效的项目描述...
用代码块包裹保持等宽对齐,GitHub 渲染器会保留 ASCII Art 的原始格式。
5.2 终端启动横幅
Node.js CLI 工具常在启动时输出 ASCII Art:
console.log(`
███████ ██ ██ ███████ ██
██ ██ ██ ██ ██
██ ███ ███████ ██
██ ██ ██ ██ ██
███████ ██ ██ ██ ███████
v1.0.0
`);
注意终端需使用等宽字体(Consolas、Monaco、Source Code Pro)才能正确对齐。
5.3 源码注释装饰
/*
* ███████ ██ ██ ███████ ██
* ██ ██ ██ ██ ██
* ██ ███ ███████ ██
* ██ ██ ██ ██ ██
* ███████ ██ ██ ██ ███████
*
* 模块入口:用户认证
*/
5.4 邮件签名
邮件签名中插入小型 ASCII Art Logo,既个性化又不会过于突兀:
██
██ █
███
GitHub: @yourname
六、纯原生 TypeScript 实现要点
6.1 零依赖设计
本工具不依赖 figlet npm 包或任何字体文件,而是:
- 字体数据硬编码:3 种字体的字符数据直接写在
asciiArt.ts中,约 200 行 - 渲染算法纯 TS 实现:横向拼接 + 行对齐,无外部依赖
- Bundle 体积可控:AsciiArtTool 组件 19KB(gzip 3.9KB),远低于 200KB 红线
6.2 字符集覆盖策略
字体覆盖 A-Z、0-9、空格与常用标点(共约 60 个字符)。选择依据:
- 使用频率:A-Z 与 0-9 覆盖 90% 以上的标题场景
- 标点选择:
! ? . , - _ : ; ' " ( ) / \ @ # $ % & * + = ~ ^ < > [ ]覆盖常见标点 - 未覆盖字符:中文、Emoji、Unicode 符号用
?占位,避免渲染异常
6.3 等宽对齐保证
为保证输出对齐,每个字符的行数据需满足:
- 行数一致:每字符的行数等于字体高度(Block 为 5 行)
- 行宽一致(可选):Block 字体统一 7 列,Banner 统一 8 列;Small 字体允许变宽
- 尾部 trim:渲染时去除每行尾部空白,避免行尾多余空格影响复制
6.4 复制与下载
- 复制:复用共享
utils/clipboard.ts,优先 Clipboard API,降级 execCommand - 下载:用
Blob+URL.createObjectURL生成临时下载链接,零依赖实现文件下载
七、字体设计注意事项
7.1 字符宽度统一 vs 变宽
- 统一宽度:每字符占固定列数(如 Block 的 7 列),渲染最整齐,但 I 等窄字符需居中填充
- 变宽:每字符按实际宽度,I 仅占 3 列,M 占 8 列,视觉更自然但需处理对齐
本工具 Block 与 Banner 采用统一宽度,Small 采用变宽,兼顾整齐与紧凑。
7.2 填充字符选择
常见填充字符:█▓▒░#*@|/\+=:-.。选择依据:
- 对比度:
█(全角块)对比度最高,适合标题 - 可读性:
#字符辨识度高,适合注释 - 终端友好:
*+等字符在所有终端都能正确显示
本工具统一用 █ 填充,对比度最高。
7.3 字符间距作用
字符间距指相邻字符之间的空格列数:
- 间距 0:字符紧挨,视觉最紧凑,但 H、I 等字符可能粘连
- 间距 1(默认):字符间 1 列空格,可读性最佳
- 间距 2:字符间距更宽,适合大字体或强调分隔
八、与现有工具的联动
ASCII Art 工具与工具盒子中的文本处理工具形成联动:
- MarkdownTool:生成的 ASCII Art 可粘贴到 Markdown 代码块中作为标题
- LoremTool:占位文本可与 ASCII Art 横幅组合,生成完整的文档骨架
- DiffTool:对比不同字体的渲染结果,观察差异
- HashTool:将 ASCII Art 作为输入计算哈希,验证复制完整性
九、局限性与改进方向
当前实现仍有改进空间:
- 字符集有限:仅覆盖大写字母与常用标点,小写字母、中文无对应字形
- 字体种类少:仅 3 种字体,FIGlet 社区有数百种字体可选
- 无紧排模式:仅支持全宽 + 间距,未实现 FIGlet 的 kerning/smushed 模式
- 无 ANSI 颜色:终端场景常需 ANSI 颜色码,当前仅输出纯文本
未来可考虑:动态加载 FIGlet .flf 字体文件、支持小写字体、添加 ANSI 颜色输出、支持多行文本逐行渲染。
十、总结
ASCII Art 是计算机文化中独特的视觉表达形式,从电传打字机时代延续至今。FIGlet 让字体渲染进入自动化时代,但完整 FIGlet 实现复杂度高。本工具采用「精简字体 + 纯原生 TS 渲染」策略,内置 3 种字体覆盖常见场景,Bundle 仅 19KB,在零依赖前提下提供了实用的 ASCII Art 生成能力。
无论是 GitHub README 标题、终端启动横幅,还是源码注释装饰,ASCII Art 都能在纯文本环境中提供视觉冲击力,是开发者工具箱中值得保留的小工具。