“不要自己生成墙壁资产,用我给你的。”

这句话是我在开发过程中,对AI编程助手说过的最直白的一句指令。在此之前,它交出的代码在语法上挑不出毛病,运行起来也确实有墙——只不过那些墙是它自己用程序生成的几何体,而不是我精心准备好的GLB模型。

打开网易新闻 查看精彩图片

这件事让我意识到一个尴尬的事实:一个模型可以完美满足你请求的语义含义,却完全错过你的视觉意图。而这一切,都源于一个原本只想做“梦境日记”的业余项目。

从梦境日记到一座图书馆

项目最初的样子和现在毫无关系。我搭了一个由Sanity驱动的梦境记录工具,梦会关联到反复出现的符号、情绪和其他结构化信息。这些关系被渲染成一张可视化地图,然后地图变成了3D,再然后我想在里面走动。

梦变成了环境,我加入了第一人称移动,又加了连接相关记忆的传送门。做到某个节点时我不得不问自己:我是不是不小心开始做一款电子游戏了?

但实验底下浮出了一个更有用的东西。这个想法不再专属于梦境,我开始好奇结构化信息能不能拥有某种“地理形态”。我短暂尝试过用同样的结构去探索文件和代码库,然后我看向了DEV——文章天然就带着关系:作者、标签、主题、搜索。

隐喻突然变得显而易见。

于是有了Oniria:一座活着的DEV图书馆。你不再是在信息流、网格或搜索页里浏览DEV,而是走进一个个房间。文章变成书,主题占据书架,部分档案会根据活跃度随时间演化,而Sanity会记住那个物理空间里此前放着什么。

整个项目背后的问题最终变成了:如果信息拥有地理形态,会怎样?

六扇门,而不是一张图

第一版DEV集成要抽象得多。文章和用户资料作为对象存在于一个可探索的空间网络里。技术上它跑通了,体验上却不行——所有东西都在争夺注意力,缺乏足够的层级。

于是我把它简化成六个明确的目的地:

  • 精选
  • 新到
  • 主题
  • 创作者
  • 搜索
  • 档案库

这是第一次重大路线修正。与其解释一张图,不如在用户面前放一扇门;与其解释一个文章节点,不如把一本书放上书架。复杂性留在底层,访客看到的是一座图书馆。

数据流向也很清晰:DEV提供实时内容,Sanity提供这个世界的记忆和结构,Three.js把两者变成一个可以走进去的地方。我不想把DEV文章复制进CMS然后管这叫集成。DEV告诉Oniria当前存在什么,Sanity告诉Oniria这个世界意味着什么、东西该放在哪里、那里以前发生过什么。

建筑本身是通过代码、配置、可复用资产和结构化世界数据组装出来的,而不是靠传统的3D关卡编辑器。这最后一点,成了整个项目最重要的部分之一。

当AI交出一堵“语义正确”的墙

开发过程中我大量使用了Codex,ChatGPT则帮我梳理架构、用户体验、调试和项目方向。这些智能体极其有用,同时也非常擅长产出技术上合法、视觉上错误的东西。

墙壁事件是最清楚的例子。我提供了真实的墙壁资产,要求智能体用它们构建环境。结果看起来不对——它生成了程序化的墙壁几何体。技术上确实有墙,只是不是我给它的那些墙。

直到我把提示词改成“不要自己生成墙壁资产,用我给你的”,下一次实现才移除了生成的可见墙壁,让手工制作的GLB资产成为唯一事实来源。原始几何体则保留下来做不可见碰撞和结构辅助。

灯光问题是另一个例子。有一段时间,图书馆几乎被洗得发白。第一个解释聚焦在重叠的灯光和过亮的材质上,其中一部分甚至是对的,但没能完全解释我看到的现象。继续测试后,更大的问题浮出水面:泛光阈值让场景中太多部分参与进来,导致整个环境发光。

这次调试很有价值,因为第一个答案听起来很合理。重要的是继续测试实际体验,而不是因为一个解释听起来够技术就接受它。

最大的限制出现在我开始精确放置书架和建筑结构的时候。我没有使用传统的3D关卡编辑器,这意味着每一次空间调整都得靠代码和配置来完成。这个项目不是来自一个完美的提示词,它反复改变方向,因为真正走进智能体产出的东西里,会暴露出光看代码根本无法理解的问题。

一座图书馆的诞生,最终靠的不是一个完美的提示词,而是一次次走进现场、发现问题、再动手修正的过程。