用 Cloudflare Workers 搭建战术终端风格界面

作者 mcx 日期 2026-06-17
用 Cloudflare Workers 搭建战术终端风格界面

最近给 GeekZip 的下载页做了个「战术终端」风格的界面,跑了 Cloudflare Workers 上。记录一下思路和实现。

为什么选 Workers

简单原则:不要多一个服务器。GeekZip 本身在 GitHub Releases 上托管二进制,但需要一个好看的下载页。如果为了一个静态页面去配 Nginx/Caddy/Vercel,太重了。

Workers 的好处:

  • 免费计划每天 10 万请求,个人项目用不完
  • 全球边缘节点,延迟约等于 0
  • 可以在 fetch handler 里直接代理 GitHub 下载,比静态 CDN 灵活
  • 自定义域名绑定一行命令搞定

整体架构

1
2
3
4
5
6
7
8
用户 → z.xpai.uk

Cloudflare Edge

Worker (geekzip)
├── / → 返回战术终端 HTML
├── /download/* → 代理 GitHub Release 文件
└── /api/releases → 转发 GitHub API

Worker 的代码结构很简单——一个 fetch() 函数根据路径分发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/") {
return new Response(HTML, {
headers: { "content-type": "text/html;charset=UTF-8" }
});
}
if (url.pathname.startsWith("/download/")) {
// 代理下载
}
...
}
};

战术终端设计

风格参考了军用终端 UI 和 CRT 显示器的视觉效果。全部用纯 CSS 实现,没有图片。

字体

正文用 JetBrains Mono(等宽字体,编程感),标题用 Major Mono Display(粗犷的显示字体,军事感)。Google Fonts 加载:

1
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Major+Mono+Display&display=swap" rel="stylesheet">

单色调色盘

只用了绿色 #00ff95,通过透明度变化分出层次:

1
2
3
4
5
6
:root {
--green: #00ff95;
--green-dim: rgba(0,255,149,0.15);
--green-mid: rgba(0,255,149,0.5);
--border: rgba(0,255,149,0.2);
}

CRT 扫描线

repeating-linear-gradientbody::after 上绘制 2px 间隔的黑线,模拟老式 CRT 显示器的扫描线纹理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
body::after {
content: '';
position: fixed;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0,0,0,0.08) 2px,
rgba(0,0,0,0.08) 4px
);
pointer-events: none;
z-index: 999;
}

再加一个径向渐变模拟 CRT 屏幕边缘的暗角:

1
2
3
4
5
6
7
body::before {
background: radial-gradient(
ellipse at center,
transparent 60%,
rgba(0,0,0,0.4) 100%
);
}

四角作战标记

四个 <svg> 定位在页面的四个角,L 形线条,旋转/镜像组合:

1
2
3
4
5
<div class="corner corner-tl">
<svg viewBox="0 0 28 28">
<path d="M26,2 L26,10 M26,2 L18,2 M26,2 L2,26"/>
</svg>
</div>

四个的变换分别是 scaleX(-1)scaleY(-1)scale(-1,-1),形成一个封闭的”框”效果。

LED 脉冲指示灯

用 CSS animation 模拟三个状态指示灯(SYS、NET、DOCK),pulse 关键帧控制发光圆点的呼吸节奏:

1
2
3
4
5
6
7
8
9
10
11
.led-dot {
width: 6px; height: 6px;
border-radius: 50%;
background: var(--green);
box-shadow: 0 0 4px var(--green);
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.3; transform: scale(0.8); }
}

DOCK 指示灯用 .off 类关掉(灰色),表示「当前未对接」。

按钮扫光动画

鼠标移入下载按钮时,一道高光从左侧扫过。用伪元素 ::before 实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.dl-btn::before {
content: '';
position: absolute;
top: 0; left: -100%;
width: 100%; height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(0,255,149,0.08),
transparent
);
transition: left 0.5s;
}
.dl-btn:hover::before {
left: 100%;
}

CLI 命令框 + 闪烁光标

模拟终端输入效果,cursor 用 step-end 动画实现 blink:

1
2
3
4
5
6
7
8
.cli-box .cursor {
display: inline-block;
width: 7px; height: 14px;
background: var(--green);
animation: blink 1s step-end infinite;
vertical-align: text-bottom;
}
@keyframes blink { 50% { opacity: 0; } }

操作日志

日志区域模拟终端输出,每行包含时间戳、等级标签和消息。等级用颜色区分:

  • INFO → 半透明白
  • OK → 亮绿
  • WARN → 橙黄
  • ERR → 红色

偶数列用 nth-child(even) 加微弱斑马纹,类似 TUI 日志查看器。

部署

使用 wrangler CLI,一条命令搞定:

1
2
3
4
5
6
7
8
# 安装 wrangler
npm install -g wrangler

# 登录(或用 API token 环境变量)
export CLOUDFLARE_API_TOKEN="cfat_xxxx"

# 部署并绑定自定义域名
wrangler deploy --domain z.xpai.uk

Worker 的路由配置在 wrangler.toml

1
2
3
name = "geekzip"
main = "index.js"
compatibility_date = "2026-06-17"

下载代理

Worker 同时担任 GitHub Release 的下载代理。/download/GeekZip-macos-arm64.app.zip 会被转发到 https://github.com/mcxen/GeekZip/releases/latest/download/...,这样用户下载时走 Cloudflare 边缘节点,比直连 GitHub 快很多。

1
2
3
4
5
6
7
8
9
10
if (url.pathname.startsWith("/download/")) {
const asset = url.pathname.slice(10);
const gh = await fetch(
"https://github.com/mcxen/GeekZip/releases/latest/download/" + asset,
{ headers: { "User-Agent": "GeekZip-Worker" } }
);
const hdrs = new Headers(gh.headers);
hdrs.set("content-disposition", 'attachment; filename="' + asset + '"');
return new Response(gh.body, { headers: hdrs });
}

踩坑记录

DNS 的问题

一开始把 go.opencode.aiopencode.ai/zen/go/v1 搞混了,在 DNS 上浪费了不少时间。检查域名是否真的是公共 DNS 记录,可以直接 dig +short <domain> 验证。

透明代理 vs 显式代理

在 Ubuntu VM上试验时,iptables REDIRECT 把 443 流量导到代理的 redir-port,但代理看不到原始域名(只有 IP),导致路由失败。显式 HTTP CONNECT 代理更可靠。

Workers 自定义域名

wrangler deploy --domain 会自动处理 DNS 记录和 Workers Route 的绑定,不需要手动去 Cloudflare Dashboard 点。但需要注意 API Token 需要有 Workers 和 DNS 的权限。

最终效果

访问 https://z.xpai.uk 可以看到成品。整个页面不到 12KB(gzip 后 3.6KB),没有依赖任何框架或 UI 库,纯手写 CSS + Workers。代码在 GeekZip 仓库workers/ 目录下。