关于 tui-designer
用于设计复古与赛博朋克风格文本界面的技能,覆盖 React、SwiftUI、CSS 和 WebGL。内容包括 CRT 效果、霓虹样式、字体与配色、组件指导及常见实现问题。
主要功能
- 01CRT 与扫描线效果
- 02霓虹发光样式
- 03复古配色与字体
- 04React Tuimorphic 组件指导
- 05SwiftUI Metal 与 Web 技法
- 06跨平台问题与性能建议
适用场景
- 01设计终端风格界面
- 02为 SwiftUI 视图添加 CRT 效果
- 03构建霓虹风格 React 或 Web UI
- 04选择配色与等宽字体
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ckorhonen/ claude-skills --skill tui-designer安装后在 Claude Code 中输入/tui-designer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/color-palettes.mdcopywriting-guide.mdcrt-effects-web.mddesign-patterns.mdmetal-shaders-ios.mdtuimorphic-reference.mdtypography-guide.mdscripts/generate_palette.pytemplates/crt-shader.metalneon-glow.cssreact-tuimorphic-starter.tsxswiftui-crt-view.swift详细介绍
TUI 设计器 - 复古/赛博朋克终端 UI 专家
为设计和实现具有真实复古计算美学的文本界面提供专业指导:CRT 显示器、荧光粉辉光、扫描线和赛博朋克霓虹。
适用场景
适用于以下情况:
- 创建终端风格或黑客美学的 UI
- 实现 CRT 显示器效果(扫描线、辉光、桶形畸变)
- 构建赛博朋克/合成波/复古波界面
- 在 React 中使用 Tuimorphic 组件
- 在 SwiftUI 中实现 Metal 着色器以呈现复古效果
- 设计霓虹辉光文字和 UI 元素
- 为复古计算美学选择配色方案
- 使用等宽字体和制表符绘图字符
设计原则
复古/赛博朋克美学
这种美学源自:
- CRT 显示器:荧光粉辉光、扫描线、屏幕曲率、闪烁
- 终端界面:等宽字体、制表符绘图字符、绿色/琥珀色文字
- 赛博朋克小说:霓虹色、深色背景、高对比度
- 1980 年代计算机:ASCII 艺术、有限的配色方案、块状图形
视觉元素清单
- 深色背景(近黑色,带微妙的色调)
- 全程使用等宽字体
- 使用制表符绘图字符绘制边框和框架
- 文字和/或边框带有霓虹辉光
- 扫描线效果(细微的水平线)
- 有限的配色方案(1-3 种强调色)
- 文字与背景之间具有高对比度
- 可选:CRT 曲率、色差、闪烁
快速参考:配色方案
荧光绿(经典终端)
| 角色 | Hex | 用途 |
|---|---|---|
| 明亮 | #00ff00 | 主要文字、高亮 |
| 中等 | #00cc00 | 次要文字 |
| 深色 | #009900 | 暗化元素 |
| 背景 | #001100 | 主背景 |
| 深色背景 | #000800 | 面板背景 |
赛博朋克霓虹
| 角色 | Hex | 用途 |
|---|---|---|
| 青色 | #00ffff | 主要强调色 |
| 洋红色 | #ff00ff | 次要强调色 |
| 电光蓝 | #0066ff | 第三强调色 |
| 亮粉色 | #ff1493 | 警告 |
| 背景 | #0a0a1a | 主背景 |
琥珀色 CRT
| 角色 | Hex | 用途 |
|---|---|---|
| 明亮 | #ffb000 | 主要文字 |
| 中等 | #cc8800 | 次要文字 |
| 深色 | #996600 | 暗化元素 |
| 背景 | #1a1000 | 主背景 |
完整规范请参见 color-palettes.md。
排版
推荐字体
Web:
font-family: 'GNU Unifont', 'IBM Plex Mono', 'JetBrains Mono',
'SF Mono', 'Consolas', monospace;
SwiftUI:
.font(.system(size: 14, weight: .regular, design: .monospaced))
制表符绘图字符
Light: ─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼
Heavy: ━ ┃ ┏ ┓ ┗ ┛ ┣ ┫ ┳ ┻ ╋
Double: ═ ║ ╔ ╗ ╚ ╝ ╠ ╣ ╦ ╩ ╬
Rounded: ╭ ╮ ╰ ╯
完整参考请参见 typography-guide.md。
文案撰写
终端界面有独特的语气:简洁、技术化、权威。除非项目另有要求,否则采用以下默认原则。
核心原则
- 简洁直接 - 每个词都应发挥作用
- 技术权威感 - 系统清楚自己在做什么
- 机械般精准 - 不要模棱两可、道歉或使用填充词
文本格式
| 元素 | 大小写 | 示例 |
|---|---|---|
| 标题/名称 | 全部大写 | SYSTEM STATUS |
| 标签 | 全部大写 | CPU USAGE: |
| 状态指示器 | 全部大写 | ONLINE、OFFLINE |
| 命令/输入 | 小写 | > run diagnostic |
| 正文 | 句首大写 | Connection established |
消息前缀
[SYS] System message [ERR] Error
[USR] User action [WRN] Warning
[INF] Information [NET] Network
词汇速查
| 操作 | 终端动词 |
|---|---|
| 启动 | INITIALIZE、BOOT、LAUNCH、ACTIVATE |
| 停止 | TERMINATE、HALT、ABORT、KILL |
| 保存 | WRITE、COMMIT、STORE、PERSIST |
| 加载 | READ、FETCH、RETRIEVE、LOAD |
| 删除 | PURGE、REMOVE、CLEAR、WIPE |
| 状态 | 终端用语 |
|---|---|
| 处理中 | PROCESSING、EXECUTING、RUNNING |
| 已完成 | COMPLETE、SUCCESS、FINISHED |
| 失败 | ERROR、FAULT、ABORTED |
| 就绪 | ONLINE、AVAILABLE、ARMED |
常见模式
> INITIALIZING SYSTEM...
> LOADING MODULES [████████░░] 80%
> AUTHENTICATION COMPLETE
> SYSTEM READY
ERROR: ACCESS DENIED
ERR_CONNECTION_REFUSED: Timeout after 30s
WARNING: Low disk space (< 10%)
CONFIRM DELETE? [Y/N]
SELECT OPTION [1-5]:
避免
- “Please”“Sorry”“Oops”
- “Just”“Maybe”“Might”
- 过多使用感叹号
- 表情符号(除非特别要求)
完整的语气与风格指南请参阅 copywriting-guide.md。
平台:React 与 Tuimorphic
Tuimorphic 是一个 React 组件库,提供 37 个终端风格且易于访问的 UI 组件。
快速入门
npm install tuimorphic
import { Button, Card, Input } from 'tuimorphic';
import 'tuimorphic/styles.css';
function App() {
return (
<div className="theme-dark tint-green">
<Card>
<h1>SYSTEM ACCESS</h1>
<Input placeholder="Enter command..." />
<Button variant="primary">EXECUTE</Button>
</Card>
</div>
);
}
主题配置
在父元素上通过 CSS 类应用主题:
// Dark mode with green tint
<div className="theme-dark tint-green">
// Light mode with cyan tint
<div className="theme-light tint-blue">
可用色调: tint-green、tint-blue、tint-red、tint-yellow、tint-purple、tint-orange、tint-pink
主要组件
| 组件 | 用途 |
|---|---|
Button | 使用 variant="primary|secondary|ghost" 的操作 |
Input | 采用终端样式的文本输入 |
Card | 带有框线字符边框的容器 |
Dialog | 模态对话框 |
Menu | 下拉菜单 |
CodeBlock | 带语法高亮的代码 |
Table | 数据表格 |
Tabs | 标签页导航 |
TreeView | 文件树显示 |
完整 API 请参阅 tuimorphic-reference.md。
添加霓虹光晕
使用 CSS 光晕效果增强 Tuimorphic:
/* Neon text glow */
.neon-text {
color: #0ff;
text-shadow:
0 0 5px #fff,
0 0 10px #fff,
0 0 20px #0ff,
0 0 40px #0ff,
0 0 80px #0ff;
}
/* Neon border glow */
.neon-border {
border-color: #0ff;
box-shadow:
0 0 5px #0ff,
0 0 10px #0ff,
inset 0 0 5px #0ff;
}
/* Flickering animation */
@keyframes flicker {
0%, 100% { opacity: 1; }
50% { opacity: 0.95; }
52% { opacity: 1; }
54% { opacity: 0.9; }
}
.flicker {
animation: flicker 3s infinite;
}
平台:使用 Metal 着色器的 SwiftUI
iOS 17+ 支持通过 .colorEffect()、.distortionEffect() 和 .layerEffect() 在 SwiftUI 中直接使用 Metal 着色器。
CRT 效果实现
CRT.metal:
#include <metal_stdlib>
#include <SwiftUI/SwiftUI.h>
using namespace metal;
[[stitchable]] half4 crtEffect(
float2 position,
SwiftUI::Layer layer,
float time,
float2 size,
float scanlineIntensity,
float distortionStrength
) {
float2 uv = position / size;
// Barrel distortion
float2 center = uv - 0.5;
float dist = length(center);
float2 distorted = center * (1.0 + distortionStrength * dist * dist);
float2 samplePos = (distorted + 0.5) * size;
// Bounds check
if (samplePos.x < 0 || samplePos.x > size.x ||
samplePos.y < 0 || samplePos.y > size.y) {
return half4(0, 0, 0, 1);
}
// Sample color
half4 color = layer.sample(samplePos);
// Scanlines
float scanline = sin(position.y * 3.14159 * 2.0) * scanlineIntensity;
color.rgb *= 1.0 - scanline;
// Subtle color shift (chromatic aberration)
color.r *= 1.0 + 0.02 * sin(time * 2.0);
color.b *= 1.0 - 0.02 * sin(time * 2.0);
// Slight flicker
color.rgb *= 1.0 + 0.01 * sin(time * 60.0);
return color;
}
SwiftUI 视图修饰符:
struct CRTEffectModifier: ViewModifier {
@State private var startTime = Date()
var scanlineIntensity: Float = 0.1
var distortionStrength: Float = 0.1
func body(content: Content) -> some View {
TimelineView(.animation) { timeline in
let time = Float(timeline.date.timeIntervalSince(startTime))
GeometryReader { geo in
content
.layerEffect(
ShaderLibrary.crtEffect(
.float(time),
.float2(geo.size),
.float(scanlineIntensity),
.float(distortionStrength)
),
maxSampleOffset: .init(width: 10, height: 10)
)
}
}
}
}
extension View {
func crtEffect(
scanlines: Float = 0.1,
distortion: Float = 0.1
) -> some View {
modifier(CRTEffectModifier(
scanlineIntensity: scanlines,
distortionStrength: distortion
))
}
}
用法:
Text("SYSTEM ONLINE")
.font(.system(size: 24, weight: .bold, design: .monospaced))
.foregroundColor(.green)
.crtEffect(scanlines: 0.15, distortion: 0.08)
SwiftUI 中的霓虹光晕
extension View {
func neonGlow(color: Color, radius: CGFloat = 10) -> some View {
self
.shadow(color: color.opacity(0.8), radius: radius / 4)
.shadow(color: color.opacity(0.6), radius: radius / 2)
.shadow(color: color.opacity(0.4), radius: radius)
.shadow(color: color.opacity(0.2), radius: radius * 2)
}
}
// Usage
Text("NEON")
.font(.system(size: 48, design: .monospaced))
.foregroundColor(.cyan)
.neonGlow(color: .cyan, radius: 15)
完整着色器代码请参阅 metal-shaders-ios.md。
平台:CSS/原生 Web
扫描线叠加层
.crt-container {
position: relative;
background: #000800;
}
.crt-container::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
pointer-events: none;
}
霓虹文字效果
.neon-text {
color: #0ff;
text-shadow:
/* White core */
0 0 5px #fff,
0 0 10px #fff,
/* Colored glow layers */
0 0 20px #0ff,
0 0 30px #0ff,
0 0 40px #0ff,
0 0 55px #0ff,
0 0 75px #0ff;
}
CRT 曲率(CSS 变换)
.crt-screen {
border-radius: 20px;
transform: perspective(1000px) rotateX(2deg);
box-shadow:
inset 0 0 50px rgba(0, 255, 0, 0.1),
0 0 20px rgba(0, 255, 0, 0.2);
}
使用 CRTFilter.js 的 WebGL CRT
<script type="module">
import { CRTFilterWebGL } from 'crtfilter';
const canvas = document.getElementById('crt-canvas');
const crt = new CRTFilterWebGL(canvas, {
scanlineIntensity: 0.15,
glowBloom: 0.3,
chromaticAberration: 0.002,
barrelDistortion: 0.1,
staticNoise: 0.03,
flicker: true,
retraceLines: true
});
crt.start();
</script>
完整实现技巧请参阅 crt-effects-web.md。
效果模式
扫描线
| 平台 | 实现方式 |
|---|---|
| CSS | repeating-linear-gradient 伪元素 |
| SwiftUI | 使用 sin(position.y * frequency) 的 Metal 着色器 |
| WebGL | 片段着色器亮度调制 |
泛光/光晕
| 平台 | 实现方式 |
|---|---|
| CSS | 使用多个模糊度递增的 text-shadow |
| SwiftUI | 使用多个 .shadow() 修饰符 |
| WebGL | 高斯模糊通道 + 加法混合 |
| Three.js | 使用 luminanceThreshold 的 UnrealBloomPass |
色差
| 平台 | 实现方式 |
|---|---|
| CSS | 三个重叠元素,颜色通道各有偏移 |
| SwiftUI | 对每个 RGB 通道在偏移位置采样纹理 |
| WebGL | 对每个通道在略微偏移的 UV 位置采样 |
闪烁
| 平台 | 实现方式 |
|---|---|
| CSS | 使用 @keyframes 动画改变不透明度(0.9-1.0) |
| SwiftUI | 由计时器驱动的不透明度变化,或基于着色器时间的效果 |
| WebGL | 基于时间的噪声乘数 |
性能注意事项
CSS 效果
box-shadow和text-shadow由 GPU 加速,但图层过多时开销较大- 光晕效果的阴影图层限制在 4-5 层
- 对动画元素使用
will-change: transform - 考虑使用
prefers-reduced-motion媒体查询
SwiftUI/Metal
- 支持 iOS 17+ 的所有设备上,Metal 着色器的运行帧率为 60-120fps
.layerEffect()会处理每个像素,因此着色器应保持简单- 使用
.compile()预编译着色器(iOS 18+) - 在较旧设备上测试(iOS 17 最低要求为 A12)
WebGL
- CRTFilter.js 使用硬件加速,对性能影响极小
- Three.js 中的泛光效果需要渲染到纹理的通道
- 移动设备可考虑使用较低分辨率的渲染目标
通用建议
- 降低移动设备上的效果强度
- 提供关闭效果的选项以满足无障碍需求
- 使用实际内容进行性能分析,而不只是空白屏幕
模板
可直接使用的入门文件:
- react-tuimorphic-starter.tsx - 使用 Tuimorphic 的 React 应用
- swiftui-crt-view.swift - 带有 CRT 效果的 SwiftUI 视图
- crt-shader.metal - 完整的 Metal 着色器
- neon-glow.css - CSS 霓虹效果
常见问题
本节记录了会导致 TUI 实现出错的真实故障模式和边缘情况。这些问题不易察觉,是在跨平台的实际使用中发现的。
终端兼容性问题
问题: 不同终端模拟器对转义序列的支持各异。在 iTerm2 中有效的内容,可能在旧版 xterm、SSH 终端或 Windows Terminal 中失效。
常见故障:
- 256 色与 ANSI: 各终端支持的色彩深度不同。使用
#rgb十六进制颜色的代码在现代终端中有效,但在旧系统中会退回到 16 色 ANSI。 - 重置序列: 忘记重置文本属性(
\x1b[0m或\x1b[m)可能会污染终端状态,影响后续输出。 - Windows 上的 Unicode 制表符: Windows PowerShell/Terminal 可能无法正确渲染
─ │ ┌ ┐。发布前请在 Windows 上测试。 - VT100 支持不完整: SSH 连接到较旧的 Linux 系统时,通常只能使用 VT100 支持。制表符会显示为乱码。
预防措施:
- 在目标终端上测试:iTerm2、Terminal.app、Windows Terminal、SSH Linux、Alacritty
- 制表符无法正常显示时退回到 ASCII:使用
+、-、|作为替代 - 设置样式的文本后始终重置属性:
\x1b[0m可以解决问题 - 检测终端功能:检查
TERM环境变量(TERM=xterm-256color与TERM=xterm)
安全封装示例:
const supportsUnicode = process.env.TERM && process.env.TERM.includes('256');
const border = supportsUnicode ? '─' : '-';
调整大小时布局错乱
问题: 终端调整大小时,固定宽度布局会崩溃。在宽高比意外变化的基于 Web 的 TUI 中尤为常见。
常见故障:
- 硬编码行宽: 假设宽度为 80 列的居中标题,在 60 列终端中会错乱。
- 隐藏溢出但未截断: 内容宽度为 100% 再加上内边距,超出容器后会导致文本溢出或意外换行。
- 宽高比假设: 扫描线叠加效果和 CRT 曲线假设宽高比为 16:9。在超宽屏或移动设备上,瑕疵会很明显。
- 网格布局使用固定尺寸项: 使用
display: grid和grid-template-columns: 100px 200px 100px无法适应小屏幕。
预防措施:
- 使用相对于视口的单位:
vw、vh或calc(100% - Xpx) - 使用省略号截断文本:
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - 在以下宽度下测试:120 列、80 列、40 列(移动设备)、超宽屏
- 对于扫描线效果,使用随视口缩放的百分比频率
- 使用 CSS
@media或 JSResizeObserver动态调整布局
有问题的扫描线示例:
/* ❌ Breaks on narrow screens */
background: repeating-linear-gradient(0deg, transparent, transparent 20px, black 20px, black 21px);
更好的做法:
/* ✅ Scales with viewport height */
background: repeating-linear-gradient(0deg, transparent, transparent calc(2% of height), black calc(2% of height), black calc(2% of height + 1px));
输入处理边缘情况
问题: 用户输入不只有字母和数字。现实中的输入还包括多字节 UTF-8、特殊按键、粘贴缓冲区和自动补全。
常见故障:
- UTF-8 字符计数: JavaScript 的
string.length计算的是 UTF-16 代码单元,而不是字符。一个 4 字节表情符号🎮的值为length: 2,会导致光标定位和验证出错。 - 粘贴缓冲区处理: 用户会粘贴大段文本。未采用流式处理的输入处理器会导致 UI 卡顿。
- 方向键与 WASD: 基于终端的游戏通常只支持 WASD,但用户期望能用方向键。缺少支持会导致糟糕的用户体验。
- 特殊按键无法正常传递: Ctrl+C、Ctrl+Z、Tab 在不同平台上的行为各不相同。SSH 终端会丢失某些组合键。
- IME 组合输入: 输入法引擎(用于中文、日文和韩文)会在最终组合完成前发送部分字符。每次按键都进行验证会导致 IME 输入出错。
预防措施:
- 使用能识别字素的库:
Intl.Segmenter(现代方案),或 npm 包graphemesplitter - 将粘贴内容作为多字符流处理,而不是单个事件
- 导航时同时支持方向键和 WASD
- 处理 IME:仅在最终的
compositionend时验证,不要在compositionupdate时验证 - 在 macOS(Command 键)、Windows(Alt)和 Linux(各种 WM 行为)上测试
正确的 UTF-8 光标定位方式:
// ❌ Wrong: counts UTF-16 code units
const cursorPos = input.value.length; // "🎮🎮" = length: 4
// ✅ Correct: counts grapheme clusters
const segmenter = new Intl.Segmenter();
const cursorPos = [...segmenter.segment(input.value)].length; // "🎮🎮" = 2
性能问题
问题: TUI 效果(扫描线、发光、闪烁)开销很大。简单实现会导致卡顿以及 CPU 和电池耗电。
常见故障:
- 持续重绘: 每帧都通过 JS 更新 DOM(而不是 GPU),每秒会触发 60 次以上重排,导致动画卡顿,CPU 占用率超过 100%。
- 文本阴影层过多: 每个
text-shadow: 0 0 5px, 0 0 10px, 0 0 20px, ...都需要单独的 GPU 渲染通道。10 层以上的阴影会造成明显延迟。 - 高频闪烁: 用于闪烁效果的
setInterval(..., 16ms)与动画帧时间绑定,主线程繁忙时会导致卡顿。 - 扫描线叠层重新计算: 每次调整大小时都重新计算
repeating-linear-gradient(且未进行防抖)会导致卡顿。 - 未进行限流的 WebGL: 在低端移动设备上以 120fps 运行全屏 CRT 着色器会迅速耗尽电池。
预防措施:
- 使用 CSS
@keyframes实现持续效果(由 GPU 加速) - 将霓虹发光限制在 3-4 层文本阴影;在移动设备上测试
- 对调整大小的处理器进行防抖:使用带限流的
ResizeObserver,或window.requestAnimationFrame - 对需要动画的元素谨慎使用
will-change: transform, filter - 提供减少动态效果选项:
prefers-reduced-motion: reduce - 在移动设备上检测 CPU 性能:对低功耗设备降低效果更新频率
性能良好的闪烁效果:
/* ✅ GPU-accelerated, smooth */
@keyframes flicker {
0%, 100% { opacity: 1; }
50% { opacity: 0.95; }
}
.flicker { animation: flicker 3s infinite; }
会导致卡顿的闪烁效果:
// ❌ Main thread blocked, stutter
setInterval(() => {
element.style.opacity = Math.random() > 0.5 ? 1 : 0.9;
}, 50);
无障碍支持缺失
问题: 终端 UI 往往忽视无障碍需求。屏幕阅读器、键盘导航和颜色对比度都可能存在问题。
常见问题:
- 不支持键盘导航: 可点击元素只能通过鼠标操作。屏幕阅读器用户和仅使用键盘的用户都会受阻。
- 仅用颜色表示状态: 错误显示红色文本,成功显示绿色文本。色盲用户(男性占 8%,女性占 0.5%)无法区分。
- 缺少 ARIA 标签: 屏幕阅读器只会播报“按钮”,而不是“执行命令”。这会让盲人用户感到困惑。
- 文本大小固定: 48px 的霓虹光效看起来很酷,但对视力受损的用户而言,缩小到 14px 就会出问题。不支持缩放就意味着无障碍性不足。
- 没有焦点指示器: 按 Tab 键导航到按钮后,没有可见的焦点环。用户会找不到当前位置。
- 动画元素无法暂停: 闪烁和扫描线可能引发光敏性癫痫。缺少
prefers-reduced-motion支持会带来法律和安全风险。
预防措施:
- 实现完整的键盘导航:Tab/Shift+Tab、按 Enter 激活、使用方向键操作列表
- 使用屏幕阅读器进行测试:VoiceOver(macOS)、NVDA(Windows)、JAWS
- 添加 ARIA 标签:
aria-label="Start system"、aria-describedby="help-text" - 确保文本对比度达到 4.5:1(WCAG AA 标准)
- 提供
prefers-reduced-motion替代方案:禁用闪烁、扫描线和动画 - 焦点指示器:
:focus { outline: 2px solid #0ff; }是必需的
无障碍霓虹按钮:
<button
aria-label="Execute diagnostic"
className="neon-button"
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
>
EXECUTE
</button>
<style>
.neon-button:focus {
outline: 2px solid #0ff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.neon-button {
text-shadow: none; /* Remove glow */
animation: none; /* Remove flicker */
}
}
</style>
终端模拟器差异
平台特定行为速查:
| 模拟器 | 显著特性 | 修复方法 |
|---|---|---|
| iTerm2(macOS) | 可正确渲染所有 Unicode;支持真彩色 | 无需处理 |
| Terminal.app(macOS) | 调色板有限;行为类似旧版 xterm | 使用 256 色模式进行测试 |
| Alacritty | 速度极快;支持真彩色;可能无法渲染部分 Unicode | 如果 iTerm2 可正常工作,则运行可靠 |
| Windows Terminal | 支持真彩色;WSL 集成良好 | 现代代码无需处理 |
| PowerShell | 旧版本会将框线字符渲染为 ?;请使用备用方案 | 检查 $PSVersionTable |
| SSH/xterm | 仅支持 VT100;不支持真彩色和鼠标事件 | 回退到 ASCII 和 ANSI 颜色 |
| Tmux | 真彩色需要直通模式:set -g default-terminal "tmux-256color" | 配置 tmux.conf |
| Screen | 支持的终端更旧;避免使用复杂效果 | 使用纯 ASCII 模式 |
平台检测示例:
if [[ "$TERM" == "xterm" ]]; then
# Old terminal: use ASCII
BORDER="+"
COLORS="ANSI"
elif [[ "$TERM" == *"256color"* ]]; then
# Modern terminal: use box-drawing + 256 colors
BORDER="─"
COLORS="256"
else
# Unknown: default to safe
BORDER="+"
COLORS="ANSI"
fi
CRT 效果适得其反的情况
问题: 扫描线、辉光和失真在样图中看起来很酷,但实际使用时会造成问题。
常见问题:
- 扫描线降低可读性: 覆盖在文本上的细水平线会增加阅读难度,尤其是在移动设备上或远距离观看时。视力较弱的人可能无法阅读。
- 辉光遮挡文本: 强烈的霓虹辉光(包含 10 层以上的
text-shadow)会模糊文本边缘,降低可读性。 - 桶形失真破坏对齐: CRT 曲面效果看起来很逼真,但会让内容显得错位。用户会以为 UI 出了问题。
- 闪烁引发晕动症: 轻微闪烁也会让部分用户感到恶心。光敏性癫痫是真实存在的安全隐患。
预防措施:
- 使用轻微的扫描线:透明度设为 10-15%,效果清晰可见,但不影响文本
- 控制辉光强度:如果辉光半径超过 20px,文本就会变得难以辨认
- 失真仅用于装饰:切勿将其用于关键布局
- 始终提供
prefers-reduced-motion退出选项 - 与实际用户进行测试:“这样读起来舒服吗?”
资源
库
- Tuimorphic - React 终端 UI 组件
- Inferno - SwiftUI 的 Metal 着色器
- CRTFilter.js - WebGL CRT 效果
- @react-three/postprocessing - React Three.js 效果
文档
灵感来源
- SRCL / Sacred Computer - Tuimorphic 的设计灵感
- Cool Retro Term - 带 CRT 效果的终端模拟器