Files
blog/docs/research/05-极客交互设计案例与实现.md
T
wait4xandGLM-5.3 0fbb023375 docs: 落库博客重设计调研报告 v1.8 与视觉样板 v2
调研收官产物入库:主报告(架构 C''=Astro SSG+gitea 双写作流、
Artalk 评论、分片 webfont、双语预译管线、多端适配规格、
Phase 0-5 实施规划)+ 五份侦察原稿 + 可交互单文件样板
(三路线×明暗×五页型,命令面板/终端/热力图/masonry)。

Co-authored-by: GLM-5.3
2026-10-24 21:48:11 +08:00

18 KiB
Raw Blame History

task-2 · 极客交互设计侦察报告(极客精神设计语言:真实案例 × 可落地实现)

侦察员 @agent-aeff1b · 2026-10-24 方法:所有案例均于本次用 curl 实际抓取验证(HTTP 状态 / 页面源码标记 / 开源仓源码 / npm registry / caniuse 官方数据),命令面板与终端站深挖到 JS bundle 与命令表。抓不到、不命中的一律如实标注为负发现。技术基线:Astro SSG + 自托管 Gitea,视觉路线「灰阶骨架×分轨正文」。


1. 命令面板 Ctrl+K

实测案例

站点 抓取证据 说明
Starlight / Astro 官方文档 starlight.astro.build HTTP 200;页面源码含 aria-keyshortcuts="Control+K" ×1 + pagefind ×3 静态站 + Pagefind + 自定义模态的官方参考实现,MIT 源码:withastro/starlight → packages/starlight/src/components/Search.astro(已实抓源码头 25 行:按钮 aria-keyshortcuts="Control+K" + pagefind 翻译注入 + data-open-modal)
spectre.lou.gg(louisescher/spectre,164★) HTTP 200;服务端 HTML 直接含 <input id="search" placeholder="Search (Ctrl+K)">,且 HTML 内有 pagefind-ignore= 属性、pagefindInitialized = false(首次聚焦才懒加载 Pagefind) Astro 原生终端风主题,与本博客技术栈同源,Ctrl+K 搜索框静态可抓,是「静态站 Ctrl+K + Pagefind」最佳抄写对象
paco.me(Paco Coursey,cmdk 作者本人站) HTTP 200;源码含 ⌘K、command menu、cmdk 字样 cmdk 生态的活样本
blog.maximeheckel.com(Maxime Heckel 博客) 开源仓 MaximeHeckel/blog.maximeheckel.com package.json 实抓:依赖 cmdk ^1.1.1 个人博客用 cmdk 的实证

未验证(如实说明):leerob.com / rauchg.com / kentcdodds.com / brianlovin.com / joshwcomeau.com 首页静态 HTML 均无面板标记(客户端懒渲染),未继续深挖各自 bundle,不作案例引用。kentcdodds/kentcdodds.com 与 sreetamdas/sreetamdas.com 的 package.json 中均无 kbar/cmdk。

库与取舍(npm registry 实抓数据)

  • cmdk:React 无样式 primitive(UI 全自理),周下载 26,647,174。适合已有 React 岛的站。
  • kbar:即插即用 React 面板(自带动画/快捷键注册/持久化),周下载 226,077;README 实抓:「plug-n-play React component…built in animations and fully customizable components」。
  • 静态站推荐:自写 vanilla TS(~150–200 行,零运行时框架)。Pagefind 官方 JS API 文档实抓(pagefind.app/docs/api/,HTTP 200):pagefind.search() ×8、pagefind.debouncedSearch() ×3、pagefind.options() ×3、pagefind.filters() ×1 —— 程序化搜索接口完备,就是为自定义 UI 准备的。

Pagefind 聚合进面板的实现路径

  1. astro build 后跑 pagefind --site dist 出索引(或用 astro-pagefind 集成,567★,README 实抓:构建时自动建索引 + 官方声明支持 Astro View Transitions)。
  2. 自写模态:全局 keydown 监听 Ctrl/Cmd+K 与 / → 打开 <div role="dialog">(或 <dialog>)。
  3. 面板数据三层:动作项(静态数组:切主题、跳 gitea、复制 RSS)+ 页面/文章(Pagefind search(query) 返回 pages + 文内摘要)+ 分组渲染。
  4. spectre 的懒加载模式值得抄:pagefindInitialized=false,首次打开面板才 import('/pagefind/pagefind.js'),不拖首屏。

对本博客的适配建议

Astro 零框架站不要为面板引 React(cmdk/kbar 都会把 React runtime 拖进来)。抄 Starlight Search.astro 的结构 + spectre 的懒加载,自写 ~200 行 vanilla 模态。灰阶骨架下,面板天然「一整层黑底等宽字浮层」,视觉零违和。


2. 键盘快捷键惯例

实测案例(GitHub 官方文档页逐字取证)

docs.github.com/en/get-started/accessibility/keyboard-shortcuts(HTTP 200)HTML 表格实抓:

  • <kbd>S</kbd> or <kbd>/</kbd> → "Focus the search bar"(/ 聚焦搜索实锤)
  • <kbd>G</kbd> <kbd>N</kbd> → notifications;<kbd>G</kbd> <kbd>C</kbd> → Code tab;G P → PRs;G A → Actions;G W → Wiki(g-chords 和弦导航实锤)
  • <kbd>?</kbd> → "brings up a dialog box that lists the keyboard shortcuts available"(? 帮助浮层实锤)
  • <kbd>Esc</kbd> → 关闭悬浮卡

未验证(如实说明):Gmail(support.google.com/mail/answer/6594)与 Linear(linear.app/keyboard-shortcuts 与 /docs/shortcuts 404)键位页均为客户端渲染,静态抓取零命中,不能引用为抓取实证;GitHub 证据已足够作键位锚点。 负发现:「t 切主题」「g h 回首页」未找到可验证的个人博客公开实例——这反而是原创空间:惯例来自 GitHub/Gmail,移植到博客即成特色。

实现路径

  • 自写(推荐,~120–150 行):一个 keydown 监听 + 200ms 和弦缓冲(识别 g h)+ 输入框聚焦时旁路 + ? 帮助浮层。无依赖。
  • 或配 tinykeys(jamiebuilds,周下载 193,770,约 400B)管绑定,自写部分只剩 chord 逻辑与浮层。
  • 主题切换若想配 View Transitions 圆形扩散动画:ocavue/astro-theme-toggle(62★,"ripple-style theme toggle animation to your Astro project",GitHub API 实抓)。

对本博客的适配建议

P0 键位集:/ 聚焦搜索、? 帮助浮层(可发现性的关键,务必做)、t 切主题、g h 回首页、Esc 关一切浮层。键位表数据与 ? 浮层同源生成,永不失同步。灰阶骨架 + 等宽字提示角标(如导航项旁的 g h 小字)本身就是极客视觉语言的一部分。


3. 构建透明化(页脚 commit hash · 构建时间)

实测案例

站点 抓取证据
sreetamdas.com(sreetamdas/sreetamdas.com,Next.js,MIT) 仓内 scripts/generate-build-info.mjs 全文实抓:WORKERS_CI_COMMIT_SHA / CF_PAGES_COMMIT_SHA / GITHUB_SHA / git rev-parse HEAD 四重回退 → 写 src/build-info.json,字段 {branch, commit(前7位), commitUrl, time: ISO时间}。注:其站静态 HTML 页脚未见 hash(该信息主要供 CI 冒烟/接口用),展示环节未验证
mldangelo.com(mldangelo/personal-site,1695★ 个人站模板,Next 静态导出) sourcegraph 实抓源码:src/components/Stats/Site.tsx 含 built_commit: builtCommit();配套测试断言页面上存在 'Built from commit' 行 —— 个人站模板直接内置「构建透明化」区块,live 站 HTTP 200

负发现:gwern.net、survivejs.com、search.nixos.org、notes.eatonphil.com、drewdevault.com、mxb.dev、darekkay.com、fasterthanli.me、joshfinnie.com、stefanjudis.com 十个极客向站首页/页脚抓取均无 commit hash —— 说明这在主流个人站里罕见,做了反而差异化。

Astro 实现路径

  1. 零依赖自写(推荐,~20 行):astro.config.mjs 里
    vite: { define: {
      'import.meta.env.GIT_COMMIT_SHA': JSON.stringify(execSync('git rev-parse HEAD').toString().trim()),
      'import.meta.env.GIT_COMMIT_DATE': JSON.stringify(execSync('git log -1 --format=%cI').toString().trim()),
    }}
    
    页脚组件读 import.meta.env.GIT_COMMIT_SHA.slice(0,7)。sreetamdas 的四重回退模式(CI 环境变量优先)值得照抄。
  2. 现成包(npm registry 实证存在,但体积/维护一般):vite-plugin-git-revision-info@1.1.0、git-revision-vite-plugin、@jinixx/vite-plugin-git-revision。
  3. CI 注意:Gitea Actions 的 checkout 步骤默认浅克隆也能拿到 HEAD sha(或直接用 gitea.event.head_commit.id 注入环境变量)。

对本博客的适配建议

页脚一行灰字:built from a1b2c3d · 2026-10-24 18:51 UTC,hash 链接到自托管 gitea 的 commit 页。半小时代价,极客气质浓度极高。


4. 贡献活动图(自托管 Gitea 数据从哪来)

核心实测结论:Gitea/Forgejo 原生就有热力图 API

  • gitea.com/swagger.v1.json 实抓:存在唯一热力图路由 GET /api/v1/users/{username}/heatmap,schema UserHeatmapData = {contributions, timestamp}。
  • 真实数据双验证:gitea.com/api/v1/users/lunny/heatmap 与 codeberg.org/api/v1/users/6543/heatmap 均 HTTP 200,返回 [{"timestamp":1760616000,"contributions":6},…](事件级 Unix 秒粒度,前端自行聚合到日/周格子)。
  • CORS 实测:gitea.com 与 codeberg.org 对 API 请求均返回 access-control-allow-origin: * → 静态站构建时拉没问题,甚至浏览器运行时直拉也通。

GitHub 工具能否指过来?

不能直接换标。github-readme-stats / contribution-graph 类方案依赖 GitHub GraphQL 的 contributionsCollection(REST 根本没有贡献端点),无法指向 Gitea。生态佐证(GitHub 搜索实抓):oliver-drewing/forgeheat(Forgejo 热力图挂件)、BenevolentFutures/forgejo-github-sync(反向把自托管提交同步养 GitHub 图)——「自托管后贡献图怎么办」是真实普遍痛点,各自造轮子。

自建数据源方案(git log 统计 → JSON)

git -C /path/repo log --all --pretty=format:'%ad' --date=unix \
  | awk -v d=$(date +%s) '{day=strftime("%Y-%m-%d",$1); c[day]++} END {for(k in c) print k, c[k]}' > contrib.json
  • 多仓循环合并即可;优点:算本地全历史(含从 GitHub 迁移来的仓、heatmap 端点统计不到的活动)、无网络依赖、CI 里必成。
  • 也可和 heatmap API 并用:API 为主、git log 兜底。

对本博客的适配建议

构建时 fetch https://<自家gitea>/api/v1/users/<user>/heatmap → 聚合成 53×7 格 SVG/CSS grid,灰阶色阶恰好是热力图的完美配色(从 #ececec 到 #111 的七档)。失败时回退 git log 本地统计。~120 行 + 一个聚合函数。


5. 终端彩蛋页

实测案例(GitHub search "terminal portfolio" + 首页/JS bundle 抓取)

站点 抓取证据
terminal.satnaing.dev(satnaing/terminal-portfolio,824★,React+TS) bundle(277KB)实抓,命令表坐实:help ×3、whoami、pwd、history、echo、about、projects、clear、welcome —— 真·可交互终端站
codenerve.github.io(CodeNerve,188★,纯 vanilla) index.js 全文仅 2,999 字节:keydown 监听 + ls ×10 等命令 —— 自写 switch 方案极轻的活实证
term.fathi.me(m4tt72/terminal,1564★,"Terminal style website") SPA 壳站,31KB bundle 未能静态取证命令表(如实注明);star 数佐证品类成熟度
spectre.lou.gg(louisescher/spectre,164★) Astro 原生终端风主题(见 §1,还带 Ctrl+K),与技术栈同源,可整主题借鉴或只借 its CSS

实现路径

  1. 自写 switch(推荐,~150–300 行,零依赖):隐藏 input 捕获 + 命令注册表({help, whoami, ls, cat, clear, exit…})+ 上下历史。codenerve 的 3KB 证明下限极低。
  2. 库:jQuery Terminal(jcubic,老牌全功能,自带多级命令/表单支持,风格偏 jQuery 时代)、react-terminal(需 React)、xterm.js(真终端模拟器,VS Code 同款——能跑、但过重,用于彩蛋页杀鸡用牛刀)。

对本博客的适配建议

/terminal 路由作彩蛋:不进主导航,藏在 ? 帮助浮层提示一句 hint: try /terminal(极客自己会发现的秘密)。命令组:help / whoami(输出个人签名档)/ ls blog / cat about.txt / gpg --recv-key <指纹>(真指纹,链接到 key 文件)/ exit(动画后跳回首页)。CRT 扫描线 + 琥珀色单色可选(灰阶骨架里允许一处 CRT 绿或琥珀做点睛)。


6. 页面转场(Astro View Transitions)

实测案例

站点 抓取证据
mazipan.space(mazipan/mazipan.space,102★ 个人站+博客) 线上 HTML 实抓(HTTP 200):含 ClientRouter ×1 + view-transition 标记 ×3 —— 个人博客真实用例
astro-theme-reimu(D-Sketon,79★,demo: d-sketon.github.io/astro-theme-reimu) sourcegraph 全网代码检索命中该仓 .astro 文件含 ClientRouter —— 中文圈在用的博客主题实证
官方文档 docs.astro.build/en/guides/view-transitions/ 实抓:ClientRouter ×45、prefers-reduced-motion 独立章节 ×12、transition:animate ×13、不支持的浏览器的 fallback 行为章节

浏览器兼容(caniuse 官方数据实抓,view-transitions.json)

  • Chrome 111+ ✅、Safari 18.0+ ✅、Firefox 144+ ✅(143 仍在 flag 后)。
  • 2026 年现状:三大引擎全绿。Astro 的 ClientRouter 用的是同文档转场(MPA 导航模拟),落在上述支持范围内;更老浏览器走 fallback(默认 animate 模拟 / 可设 none 直切)+ reduced-motion 降级,无破坏性。

对本博客的适配建议

<ClientRouter /> 一行接入 + 一段保险 CSS:

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

转场动画克制:正文区轻微 fade/slide(呼应「分轨」——轨道间的内容流动),骨架(顶栏/页脚)用 transition:persist 常驻不闪。主题切换想加圆形扩散可参考 ocavue/astro-theme-toggle 的 ripple 方案与 VT 打配。


7. 开源项目墙(自托管 Gitea 动态拉卡片)

数据面实测(codeberg.org / gitea.com 同源 API)

GET /api/v1/repos/search?limit=2 实抓返回字段(Forgejo/Gitea 通用):

{ "full_name": "...", "description": "...", "website": "...", "language": "C",
  "stars_count": 1, "forks_count": 0, "html_url": "...", "avatar_url": "", "updated_at": "..." }

主语言、star、描述、网站全有,卡片所需字段一次到位。GET /api/v1/users/{user}/repos 同理。CORS *(§4 实测)→ 构建时拉、运行时拉皆可。

消费者案例(诚实负发现 = 差异化机会)

  • sourcegraph 全网代码检索 api/v1/repos/search:消费者仅 linuxserver/Heimdall-Apps(应用目录元数据脚本),无个人博客。
  • gitea lang:astro 全网:仅 RayLabsHQ/gitea-mirror(镜像工具,API 用法可参考)。
  • 结论:个人博客从自托管 git 动态拉项目墙,没有现成公开案例 —— 没得抄,但也意味着做出来就是独一无二的开源自证。
  • 语言颜色:Gitea API 不带色值;用 github-linguist/linguist 的 languages.yml 作映射(实抓样本:Go #00ADD8、TypeScript #3178c6)。

Astro SSG 实现路径(~80 行)

---
// src/pages/projects.astro(frontmatter 在构建时执行)
const GITEA = 'https://git.example.com';
const repos = await fetch(`${GITEA}/api/v1/users/me/repos?limit=30`)
  .then(r => r.json()).catch(() => JSON.parse(cachedFallback)); // 失败读上次缓存 JSON
---

构建时执行 = 零 CORS 问题、零客户端 JS;Gitea Actions 上 push 触发重建保证新鲜度;pinned 置顶仓用手动数组覆盖排序。

对本博客的适配建议

/projects 分轨页:卡片 = 语言色点(灰阶骨架里唯一允许的品牌色点缀,恰与「开源」语义互文)+ star 数 + 一行描述 + updated_at。页脚 built from <hash>(§3)→ 点击即达同源 gitea commit——构建透明化与项目墙共享同一自托管源,叙事闭环。


极客设计语言清单(性价比分级)

级别 项 实现方式 工作量 实证锚点
P0 键盘基础集:/ 搜索、? 帮助浮层、t 主题、g h 回首页 自写 vanilla(keydown+chord buffer+浮层) ~120–150 行,半天 GitHub 键位表逐字实抓
P0 页脚构建信息(hash+时间+commit 链接) vite.define 注入或抄 sreetamdas 脚本 ~20 行,半小时 sreetamdas/mldangelo 源码实抓
P0 View Transitions + reduced-motion 降级 <ClientRouter /> + 5 行 CSS 半小时 mazipan.space 实抓;三引擎全绿
P0 开源项目墙 构建时 fetch gitea API 渲染卡片 ~80 行,半天 API 字段/CORS 实测
P1 Ctrl+K 命令面板(搜索+动作聚合) 自写 vanilla 模态 + Pagefind JS API(懒加载) ~200 行,一天 Starlight Search.astro / spectre 实抓
P1 Gitea 贡献热力图 heatmap API(或 git log 兜底)→ 灰阶 SVG 格 ~120 行,一天 heatmap 端点双站 200 实测
P2 /terminal 终端彩蛋页 自写命令 switch ~200–300 行,一天 codenerve 3KB 实证;satnaing 824★
P2 全 g-chords 体系(g p 项目 / g b 博客) 扩展 §2 chord 表 +30 行 GitHub G+N/C/P 模式移植

协同叙事:所有键位汇聚在 ? 浮层(可发现性)→ 面板是极客动线中枢(搜索+动作+彩蛋入口)→ 页脚 hash 与项目墙共享自托管 gitea 源(开源自证闭环)→ 热力图是这套语言里唯一的「数据可视化」,用灰阶色阶呈现正好。「艺术文学的美观」由灰阶骨架承担,「极客精神」由这层可交互的等宽字神经系统承担——两者不抢戏。

未验证/存疑清单(全部如实声明)

  1. leerob.com / rauchg.com / kentcdodds.com / brianlovin.com / joshwcomeau.com 的面板:静态 HTML 无标记(客户端渲染),未逐一深挖 bundle。
  2. Gmail / Linear 键位官方页:JS 渲染无法静态取证(GitHub 证据已足为键位锚点)。
  3. term.fathi.me 的命令表:bundle 未能静态取证。
  4. 「t 切主题」「g h 导航」在个人博客上:未找到可验证公开实例(属 GitHub/Gmail 惯例移植,无先例包袱)。
  5. 「个人博客动态拉自托管 git 项目墙」:全网无现成公开案例(负发现,同时是机会点)。
  6. sreetamdas.com 的 build-info:生成脚本实抓确凿,但页脚展示环节未在静态 HTML 验证到。