游戏站一开始只有一款扫雷。后来我给它做了个导航页,多写了几款,剩下的格子就用「即将上线」的占位卡先空着。占位卡挂了很久,久到我自己都快忘了它还欠着债。这次一口气把七款新游戏写出来,13 张卡片全部变成「现在就能玩」。
新写的七款
太空侵略者、打砖块、恐龙跑酷、像素鸟、数独、猜词、国际象棋——前四款是经典的「一条命通关」,后三款要动点脑子。数独带生成器和唯一解校验,猜词做了英文五字母和中文四字成语两种模式,象棋是对着 AI 下。六款旧的(扫雷、百家乐、2048、贪吃蛇、俄罗斯方块、青蛙过河)原样保留。
视觉沿用站里那套黑金像素风:Press Start 2P 配得意黑(Smiley Sans),#0a0a0f 的底、#ffd700 的金、#00ffcc 的青。每款都带键盘和手机触屏两套操作、localStorage 最高分、game over 遮罩。首页是一整块 AVAILABLE NOW · 13 GAMES 的卡片墙,一张占位卡都不剩:

上图:游戏站首页,13 张卡片全部可玩。
能打开,不等于能用
这几款游戏,写出来的过程反而快。真正花时间的是确认它们真的能被玩——而不是「页面能加载」。
我先做了最基本的:14 个 URL 全部 200,线上字节和本地源文件 md5 一致,证明推上去的是新文件而不是缓存。但到这里我还是不放心,因为一个页面完全可能「打开了、看起来完整、其实已经死了」。于是我用无头 Chrome 走 CDP 协议,把每一页真的操作一遍:按键、点击、看分数有没有涨、棋盘有没有响应、遮罩会不会弹,再读 pageErrors 和 consoleErrors,最后在 1280px 和 420px 两档宽度下截图逐张看。
这一下抓出五个真问题,都是「读代码读不出来、只能上手才暴露」的:
- 象棋页整个棋盘空白。 原因是
var history = []撞上了浏览器只读的window.history——严格模式下这行在脚本求值阶段就抛错,后面所有初始化全都没跑。没有报错提示,页面看起来只是「没画出来」。改名成moveHistory后正常。 - 恐龙跑酷一打开就在跑。 分数已经在涨,玩家还没碰键盘就死了。改成进入
ready状态,画面冻住显示「按空格开始」,第一次起跳才启动。 - 太空侵略者 game over 后只能点按钮重开。 加上空格/回车也能重开——藏在触屏区里的隐藏按钮在桌面端是
display:none的,点它等于点空气。 - 恐龙页的太阳压在分数 HUD 上。 亮色圆盘正好叠在
HI 00000文字下面,分数看不清。把装饰元素移出文字带。 - 手机宽度下页脚两行重叠。 那串像素风的
INSERT COIN · PRESS START加字距后超过 420px,补了行高和更小的移动端字号。

上图:改掉 window.history 撞名后,象棋页正常渲染,线上实测 1.e4 后 AI 应 Nf6。
象棋这页还额外做了点验证:用 perft 数局面,perft(1)=20、perft(4)=197281,和标准值一致;再加一个将杀测试。毕竟其他游戏错了顶多是分数不对,象棋引擎错了是「AI 走了一步非法棋」。
一点感想
前端小游戏看起来简单,难的不是写出来,是确认它真的能被玩。一个抛了错的页面不会喊疼,只是安静地白在那里。让浏览器自己去点一遍,比人眼盯代码找 bug 可靠得多。
部署还蹭了个小插曲:容器里没有 docker 也没有 root,站点目录又没挂载进来,最后绕到宿主机一侧才把文件发上去。