最近我做了一个有点“前端脑洞化”的小游戏,叫 排版防线(Editorial Defender)。
在线预览:steve245270533.github.io/editorial-d…
它表面上是一款生存射击游戏,但真正有意思的地方不是坦克、敌人或者子弹,而是整张地图本身其实是一层会动态变化的文字排版。玩家在文字之间穿梭,文字会像遇到浮动元素一样向四周避让;子弹打出去,不光能打敌人,也会把一部分文字障碍打碎。
这个项目的灵感,来自最近很火的库🔥 @chenglou/pretext。我第一次看到它仓库里的那些示例时,最直接的感受就是:这东西不只适合做排版工具,拿来做游戏地形应该也很酷。既然它擅长处理多语言文本、逐行布局、绕开障碍物,那是不是可以反过来,把“排版规则”本身变成玩法?
一开始,它其实是个 Canvas 版本
最开始我并不是从现在这版架构起步的,而是先用 Gemini 的 Canvas 帮我快速生成了一版底层由 Canvas 驱动的原型。那一版的价值很直接:先把“这个点子到底成不成立”跑通。
因为在这种偏实验性的项目里,最重要的不是一上来就把工程做得多优雅,而是尽快验证一件事:
文字避让、射击、生存压力,这三件事放在一起,到底好不好玩。
当原型能跑起来之后,我再把代码导入到本地,开始用 Codex 接着往下做。这个阶段我做的事,不是单纯“修修补补”,而是借助 Context7 这个MCP工具去查 pretext 的相关api用法,然后把原本更偏 Canvas 思路的实现,逐步迁移成现在这套:
- 纯 DOM 分层渲染
@chenglou/pretext负责文本预处理和逐行布局- TypeScript 管理游戏状态、实体和循环
对我来说,这个过程很像一种接力式的 vibe coding:先让 AI 帮我把想法长出来,再把它拉回本地工程里,结合真实代码结构和库文档,慢慢打磨成一个更完整、也更有“前端味”的作品。
这个游戏到底在玩什么
玩法其实很简单,上手门槛非常低。
玩具用鼠标控制一辆坦克,在屏幕中央附近移动和射击。敌人会从四周不断靠近,而地图并不是传统的墙体或贴图,而是一整层由文字构成的动态障碍。你靠近时,周围文字会被“挤开”;你离开后,它们又会慢慢回弹。于是地图并不是固定不变的,而是会随着你的移动不断重组。
同时,游戏里还有几种增益道具,比如:
- 冻结敌人
- 提高射速
- 短暂无敌
- 一次开火打出一整圈子弹
所以它玩起来不是那种纯躲弹幕式的射击,更像是在一个不断流动的排版系统里找生路、开路、清场。
技术思路其实可以用大白话理解
我没有把这件事做得特别学术,整体思路其实很朴素。
第一步,是先准备一大段文本语料。
第二步,用 pretext 先把文本“准备好”,然后一行一行往屏幕里排。
第三步,在屏幕中间预留一个安全区,让每一行文字在排版时自动绕开它。这样一来,整个画面天然就会长得很像网页里“正文绕开主体内容”的感觉。
第四步,再给每个文字块一点简单的运动规则,让它们在玩家靠近时散开、远离后回弹。
第五步,把敌人、子弹、粒子、道具这些东西都放在文字层上面跑,游戏就成立了。
这里 pretext 对我最大的帮助,不是“帮我把字画出来”,而是它把文本如何按行组织、如何在不同宽度下继续往下排这件事处理得很顺。像我这种需求,本质上就是每一行可用宽度都可能不同,因为中间要给玩家留出生存空间,这时候它那种按行推进的布局方式就非常合适。
为什么最后选择了 DOM + Pretext
从常规游戏开发的角度看,Canvas 当然是更自然的路线,性能上通常也更容易做高。但我这次真正想尝试的,不是“怎么把一款射击游戏做到最极致”,而是:
能不能结合 pretext 这个库,在原生 DOM 上玩一点不一样的花活。
所以现在这个项目采用了纯 DOM 分层渲染。文字层、敌人层、子弹层、粒子层、UI 层各自分开,逻辑更新和渲染也做了拆分。这样做的好处是,排版感会特别直接,很多前端开发者一眼就能看懂这个项目在“借用什么语义”。它不是把网页技术伪装成游戏,而是反过来,把网页排版真的变成了游戏机制的一部分。
当然也要诚实地说一句:如果目标只是追求更高性能,Canvas 方案可能依然更合适。 这个开源项目更像一次有趣的技术实验,一次把排版引擎思路、DOM 渲染和小游戏玩法揉在一起的尝试。
如果你也对这种前端奇技淫巧感兴趣
欢迎大家来试玩这个项目,也欢迎看看代码。如果你觉得这个点子有意思,或者也喜欢这种把“网页能力”拧成玩法的实验项目,特别欢迎给仓库点个 Star 收藏支持一下。