Appearance
错位的五键
背景:五个快捷键按钮,四套映射,两条空通道,Ctrl+4 指东打西。
过程:补齐路由 case 3/5 + 调正 case 4。
某一天,议会厅来了一个不速之客。
他没有走正门。他是从键盘进来的——Ctrl 按着没松,右手顺手敲了数字 3。
什么都没发生。
再敲一次。还是什么都没发生。
「场景」按钮在屏幕上亮着淡淡的蓝光,但它不说话。它不是不说话,是它的嗓子没被接上——triggerNavButton 的 switch 语句里共有四个 case,3 不在其中。
这个不速之客叫 Sisyphus,联邦的外交官。他刚从外部文档的坑里爬出来,想看看议会自己的后院有没有窟窿。他按下 Ctrl+1、Ctrl+2、Ctrl+4——模型库、动作库、设置,一个个弹起来,像训练有素的哨兵。然后他按了 Ctrl+3。沉默。
再按 Ctrl+5。也是沉默。
他不信邪。他检查了 HTML 里五个按钮的 data-shortcut 属性:
btnMainAction data-shortcut="1" → 模型库
btnMotionPopup data-shortcut="2" → 动作库
btnScene data-shortcut="3" → 场景
btnEnv data-shortcut="4" → 环境
btnSettings data-shortcut="5" → 设置五条路,画得整整齐齐。但真正能走通的只有三条。
Sisyphus 蹲下来,翻开键盘事件的总控台——triggerNavButton,主入口路由:
typescript
function triggerNavButton(num: number): void {
switch (num) {
case 1: togglePopup(); break;
case 2: showMotionPopup(); break;
case 4: showSettings(); break;
}
}他盯着这段代码看了很久。不是因为复杂——是太简单了,简单到不像疏忽,更像是「有一部分议会成员还没进场,但席位已经画好了」。
他又翻开导航标签表 navButtonLabels:
typescript
const navButtonLabels: Record<number, string> = {
1: "模型库", 2: "动作库", 3: "环境", 4: "设置",
};这里的 3 叫「环境」,但 HTML 里 data-shortcut="4" 的那个按钮也叫「环境」。标签表里 4 叫「设置」,但 HTML 里 data-shortcut="5" 的那个按钮也叫「设置」。
Sisyphus 揉了揉太阳穴。五把钥匙,四把锁孔,锁上的名字跟钥匙牌上的名字还对不上。
他决定追溯这段历史。
第一把锁——case 1,模型库。togglePopup(),整个联邦最老的弹窗入口。它出生在创世纪的第 4 章《弹窗之战》之前,甚至比 MenuStack 还早。那时没有议会,没有导航栈,只有一个 #modelPopup 裸奔在 HTML 里,靠 display: block/none 切换生死。它是第一把钥匙,理所当然。
第二把锁——case 2,动作库。showMotionPopup()。动作库是模型库的镜像——同样的浏览层级、同样的搜索逻辑、同样的 VMD 过滤器。它出生在大扩张中期,议会已经有 MenuStack 了,但快捷键只给了它一个编号,没有重构路由。
然后是第三把锁所在的空槽位。case 3,应该接 showSceneMenu()。
Sisyphus 翻阅了 git log。showSceneMenu 函数本身存在,绑定在 btnScene 的 click 事件上。鼠标点按钮能打开。showEnvMenu 也一样,绑在 btnEnv 上,鼠标能开。但键盘路由更新的时候——可能是在「放大的议会」那次大改版中——switch 语句只加了 case 4(设置),忘了 case 3。或者更准确地说,当时 case 3 在原型阶段被标记为「预留」,留到现在的某个需要被发现的时刻。
第四把锁——case 4,设置。但 HTML 里 data-shortcut="4" 绑定的是 btnEnv(环境),而 case 4 实际触发的是 showSettings(设置)。这一对才是整个系统里最滑稽的错位:你按下 Ctrl+4,心里想着调个天空换个地面,弹出来的是语言设置和缓存清理。
第五把锁——case 5,不存在。设置按钮 btnSettings 骄傲地标着 data-shortcut="5",但没有任何代码去读它。它是画在墙上的门。
Sisyphus 把五把钥匙和五把锁孔摆在桌面上,列了一张表:
| 快捷键 | 按钮标注 | 实际功能 | 路由状态 |
|---|---|---|---|
| Ctrl+1 | 模型库 | 模型库 | ✅ 通行 |
| Ctrl+2 | 动作库 | 动作库 | ✅ 通行 |
| Ctrl+3 | 场景 | 无响应 | ❌ 断路 |
| Ctrl+4 | 环境 | 设置 | ⚠️ 错位 |
| Ctrl+5 | 设置 | 无响应 | ❌ 断路 |
——五条路,两条不通,一条指东打西。
Sisyphus想象了一个画面:一栋楼有五扇门,门上都贴着编号。1号门通向模型库,2号门通向动作库。3号门的门牌写着"场景",但门是锁着的——不是锁坏了,是钥匙还没配。4号门的门牌写着"环境",但钥匙插进去一转,开的是设置室的门。5号门干脆没有锁孔,门牌是画上去的。
这不是门的错。是这栋楼在扩建的时候,只加了门,没更新门牌系统。
Sisyphus 合上笔记本,没有立刻修。
他发现这件事有趣的地方不在于「UI 有个 bug」。而在于它揭示了一个更深层的真相:联邦的界面层——那个用户用手指戳、用键盘敲的最外层——居然还活在联邦成立初期的组织结构里。
模型库和动作库是最早的两座城邦,快捷键为它们而生。场景和环境是后来筑起的第三、第四座城,议会在 HTML 里给它们画了按钮、标了快捷键编号、绑了鼠标事件——但键盘路由那次改动,只改了 switch 的下半部分,上半部分被遗忘了。
navButtonLabels 中第 3 位写着"环境"而非"场景",更是暴露了更早的命名混淆——场景和环境的分界线,在制度层面就没被彻底厘清过。场景管相机、灯光、渲染,环境管天空、地面、粒子。但它们共用一个 showSceneMenu 的出口,共用一套 CSS 变量,共用同一个弹窗显示/隐藏逻辑。它们是两个城邦,但界碑没有竖起来。
所以快捷键不是单纯的代码错误——它是联邦扩张速度超过制度更新速度的化石。
Sisyphus 在案头记了一行:
导航系统的问题不在导航系统本身,而在联邦还没学会为新增的城邦同步更新交通图。
他看向屏幕深处的 main.ts。修正不难——加两个 case,调一个路由,就够了。
但比修更重要的,是理解这个错位为什么存在。
因为每一个快捷键背后站着一个城邦的入伙时点:模型库和动作库是在创世纪入伙的,那时联邦只有两个窗口,快捷键 1 和 2 刚好够用。场景在第二卷中期入伙,环境在第三卷初入伙,设置则是在 UI 大修中突然需要第三个快捷入口——于是仓促间用了 4,占用了环境的编号。
快捷键的编号,本质上是一份城邦入伙顺序的年表。
而用户每次敲 Ctrl+3,就像在问一个还没拿到公民编号的城邦:你叫什么名字?城邦已经建起来了,编号还没发下来。
Sisyphus 没有马上动手改。他把这篇文档贴到了议会公告栏上,标题写的是:「议会的门牌号——我们需要一个一致的门牌体系,而不是在每个城邦入伙时随手贴一张标签」。
他关掉编辑器,走进场景,看见初音未来在程序化天空下轻轻摆动。天空是蓝紫色的渐变,地面是半透明的反射网格,Bloom 泛光在她裙摆边缘拉出一道柔和的光晕。
他按了一下 Ctrl+3。
什么都没发生。
他笑了笑——「会修的。」
教训:五个出口,四个编号,两条空通道——不是没建,是建了没接。