用 TypeScript 从零重写《仙剑奇侠传》:能通关的浏览器版,和一个给它做内容的可视化编辑器

在线试玩:pal.illegalscreed.cn/ (推荐电脑浏览器) 源码:github.com/IllegalCree...

为什么要干这件事

《仙剑奇侠传》是很多人的第一款 RPG。我一直有个念头:能不能不靠模拟器、不把现成的 C 引擎编译成 WASM,而是用 TypeScript 把这个游戏从头"重新想一遍"------它的资源怎么打包、脚本怎么驱动剧情、战斗公式怎么算。

网页版仙剑其实不新鲜,之前 V2EX 上也有朋友分享过把 sdlpal 编译到 WASM 的版本,那条路很实用。type-pal 走的是另一条路:运行时用 TS 从头写,开源重实现 sdlpal 只作为参考规格,最终以原版数据和原版实际行为为准。做着做着,又多了一个目标:既然数据和脚本都已经结构化了,能不能给它做一个可视化编辑器,让人用这套引擎做自己的"仙剑味" RPG。

先交代一个背景:这个项目从 2026 年 5 月 22 日建仓到现在 4 个多月,全部代码都由 AI 编程 Agent 生成,我没有手写过代码。我负责的是产品判断、定优先级、裁决分歧和最终验收。后面有一节专门讲这套协作方式和测试门禁。

项目分成了两个阶段:

  • 第一阶段 · 忠实复刻(v1.0.0,2026-06-24 发布):浏览器里从开场玩到结局。
  • 第二阶段 · Reforge(活跃开发中):基于现代内容格式的新运行时 + React 可视化编辑器 + 把原版数据转成新格式的离线迁移器。

我觉得最值得看的两块,一是第二阶段的编辑器,二是第一阶段里那一堆配套工具。下面按顺序讲。

第一阶段:怎么在浏览器里把仙剑跑起来

整体数据流很简单:

text 复制代码
原版数据 ─ pal-extract(离线提取)─> 结构化数据 + 网页可用资源 ─> 第一阶段运行时
                                      └─ migrate(离线迁移)─> 新格式工程 ─> 编辑器 / Reforge

1. 解包。 原版资源大多装在 MKF 归档里。MKF 的格式很朴素:文件头是 N+1 个 u32 小端偏移,子文件数 = (head[0] - 4) / 4。项目用的是 Win95 版数据,子文件用 YJ_2 压缩(自适应 Huffman + LZSS 回引),解压器是对照 sdlpal 的实现逐行移植的。提取器 pnpm extract 一站式处理调色板、精灵 RLE→PNG、地图、战斗素材、字体、文本,以及事件脚本的反汇编 → 注解 → 重编译 → roundtrip 校验。

2. 脚本虚拟机。 仙剑的剧情、过场、场景切换、战斗触发全是事件字节码驱动的,每条指令是一个 opcode 加 3 个操作数。第一阶段实现了 0x00..0xA7 范围内除不存在指令外的全部 164 个事件/战斗 opcode,逐条状态记录在 docs/phase1/status/opcode-status.md。

3. 320×200 索引色渲染。 为了尽量还原 DOS/Win9x 的画面,渲染层是一块 320×200 的软件帧缓冲,里面只存调色板下标,到真正上屏时才用调色板上色。这样调色板渐变、淡入淡出这类效果都很自然:

ts 复制代码
export function createFramebuffer(width = SCREEN_W, height = SCREEN_H): Framebuffer {
  const indices = new Uint8Array(width * height)
  return {
    width, height, indices,
    writePixel(x, y, index) {
      if (x < 0 || x >= width || y < 0 || y >= height) return
      indices[y * width + x] = index
    },
    clear() { indices.fill(0) },
    toImageData(palette) {
      const data = new Uint8ClampedArray(width * height * 4)
      for (let i = 0; i < indices.length; i++) {
        const c = palette.colors[indices[i]!] ?? [0, 0, 0]
        data[i * 4] = c[0]; data[i * 4 + 1] = c[1]; data[i * 4 + 2] = c[2]; data[i * 4 + 3] = 255
      }
      return new ImageData(data, width, height)
    },
  }
}

(摘自 packages/game/src/present/framebuffer.ts,略有压缩排版。)

4. 战斗系统。 回合制战斗按原版重建:行动队列、伤害公式、法术、状态、敌方 AI、动画时间线。音乐方面,原版 MIDI 用 SpessaSynth 在浏览器里实时合成。

5. 网页侧的小工程。 线上冷启动大约 3,200 个请求,所以加载用了 Service Worker 两段预缓存:先拉到"可玩线"就能进游戏,其余资源后台续传、支持断点续传。

第一阶段的配套工具:「仙剑 · 工具」面板

这是线上版里花了不少心思的地方。打开试玩页,点左下角 ⚙ 或按反引号 `````,就能打开「仙剑 · 工具」面板,一共 6 个 tab:

  • 战斗 :战斗中只读查看双方属性、HP/MP、五行抗性、状态、中毒、可偷物品、灵葫值,以及战场元素效果、是否 Boss 战。
  • 场景:场景小地图,标出主角、NPC、宝物位置,可以常驻在右下角;同时实时显示地图名、场景号、主角坐标、朝向、镜头坐标。
  • 系统 :显示缩放 10%--1000%、全屏、FPS 显示;音乐/音效/视频三路独立音量;5 个存档位各自导出/导入 JSON。
  • 对话:最近 100 条对话历史,按地图分组,支持全文搜索。剧情跳太快没看清,回来翻一下就行。
  • 计时器 :一个速通计时器 ,21 个节点(见石碑 → 学功夫 → ... → 祈雨 → 通关),节点坐标来自社区工具 PalTimer(98柔情),项目里做了 PARTYOFFSET(160,112) 的坐标换算;支持 PB、每节点最佳时间、"跳到节点"测试。F8 暂停/恢复,F4 重置,F2 显示/隐藏覆盖层。
  • 快捷键:全部按键速查。另外大世界里 F5 快存、F9 快读(存档位 1)。

开发版里还有一个更"重"的调试面板(33 场剧情 Boss 一键开战、295 个场景缩略图跳转、物品作弊、opcode 特效触发、MIDI 试听等),它通过 import.meta.env.DEV 门控,生产构建里会被完整 tree-shake 掉,线上 bundle 里搜不到。另外还有逐帧状态 dump,当时用来和 sdlpal 对拍。

第二阶段 Reforge:可视化编辑器(这次的重点)

第一阶段的目标是"像",第二阶段的目标是"能创作"。Reforge 不再直接吃原版二进制,而是读一套现代的、带版本的内容格式;迁移器把原版数据离线转换成这种格式(294 个场景、223 张地图、1,934 条资源,每条带 sha256;事务发布、三方合并,并验证"重迁零计划")。编辑器就建立在这套格式之上。

编辑器是 React 19 + Vite 8 的单页应用,9 个一级模块、31 个子页 :场景、地图、剧情、角色、物品、战斗、战斗模拟器、资源、项目设置。导航、URL 深链(?module=&page=&object=)和覆盖测试都由同一张注册表派生。

地图编辑。 等距地图画布,支持多图层、多瓦片集、相对高度、碰撞、选择/复制/粘贴/变换。下图是 223 张地图里的苏州城:

剧情脚本。 可视化脚本树 + 指令表单。作者指令一共 87 种,分 9 组(演出/对话、流程/存档、队伍/场景、实体、世界状态、音频/战斗配置、走位/相机、战斗/商店、控制流),其中 66 种在指令手册里标注了对应的原版 opcode,其余是新格式里新增的指令。比如"对话"对照 0xFFFF 文本系,"清对话框"对照 0x05 的语义核。这样熟悉原版脚本的人能找到对应关系,新作者又不用直接面对字节码。

角色、物品、战斗数据。 角色、物品、技能、敌人、敌队、毒、战场都有独立表单:

战斗模拟器。 我觉得这是最实用的功能之一。调数值时不用再从存档一路打过去:在"试打方案"里配好我方(1--3 人)、敌方(5 个槽)、背包、战场和音乐,点"开始试打",编辑器里直接跑真实的 Reforge 战斗。预设随工程保存;停止或重新试打不保留消耗和奖励,也不读写正常存档。

商店也有类似的"独立试买"。

资源管理。 精灵、图像、音乐、音效、过场素材统一管理,可以导入、替换。精灵库里能看到每一帧源帧和"用途定义"(比如李逍遥大世界精灵是四向 × 3 帧);过场素材里有帧动画工作台,可以逐帧插入、替换、贴合标准色彩。

引用与诊断。 内容一多,最怕的是删掉一个东西,别处悄悄坏掉。编辑器维护了一份引用索引:选中苏州城地图,"引用"面板会告诉你有 2 处场景引用,"会阻断删除";项目设置里的"问题"页汇总全工程诊断,比如当前 PAL 工程有 181 项"未引用资源"警告、0 个错误,每条都能一键跳转。

试玩预览。 改完可以直接在同源的 play.html 里用 Reforge 运行时试玩,场景编排页有"从默认落点试玩"。另外还有撤销/重做(领域命令 + 历史协调器)、本地工程保存(File System Access API,所以保存工程目前需要 Chrome/Edge 等 Chromium 内核浏览器)、zip 导出。

下面这段动图是一次完整的流程:地图编辑 → 场景编排 → 打开 NPC 脚本 → 切到新运行时试玩。

实话实说它现在的状态: 第二阶段拆成了 8 个领域、63 个能力格,编辑器侧 51 格已完成,还有 1 格(服务器端预制素材库)没做,其余不适用。但"能力格完成"不等于没有缺陷:完整剧情 E2E、编辑器综合工作流、不需要源码仓库的独立可玩包都还没收口,已知问题在仓库的审计文档里。它是一个功能比较全的开发中工具,不是正式版。

编辑器目前没有在线部署 ,需要 clone 仓库后在本地运行。加载完整 PAL 工程前,需要按 README 的「快速开始」自行准备合法取得的原版游戏数据,并完成提取和迁移(pnpm extract、migrate:content --write),然后:

sh 复制代码
pnpm --filter @type-pal/editor dev   # http://localhost:6010

保存工程需要 Chrome/Edge 等 Chromium 内核浏览器。

工程质量

代码全部由 AI 生成,我不可能逐行审完二十多万行,所以只能靠门禁兜底:

  • 7 个 workspace 包,非测试 TS/TSX 代码二十多万行,其中编辑器约 11 万行。
  • 覆盖率基线(2026-10-07)登记了 19,597 个 Vitest 用例,全仓行覆盖 91.3%、分支 83.3%。GitHub Actions 对每次 PR/push 执行"覆盖率只升不降"。不过覆盖率不是目标,仓库里明确要求"测试少而精",重复、恒真的用例要精简。
  • Biome lint、格式、typecheck 要求零诊断,warning 和 info 也不留。
  • 双引擎 E2E:同一条剧情路线(开场 → 客栈 → ... → 跑腿)分别在第一阶段引擎和 Reforge 上跑,产出检查点对比。目前覆盖到前几段,不是完整通关。

一个人 + AI 编程 Agent

再说一遍:这个项目的全部代码都是 AI 生成的,我没有手写代码。我做的是产品判断、定优先级、裁决分歧和最终验收。仓库里的 AGENTS.md 记录了协作协议:现在的模式是 Codex 负责拆任务、分派和独立验收,Cursor、GLM、Grok、Gemini、Kimi 等按任务执行;之前还有过 Codex、Kimi、GLM 三方签字的阶段。几条我觉得真正有用的规则:

  • 非小改都开任务卡,写清前提、范围和验收方式;
  • 同一个实现文件同一时间只有一位 Coding Owner,在隔离分支交付,验收后才合 main;
  • 涉及原版机制的改动,先用原版/sdlpal/一阶段代码做"前提真值"核对,再谈方案;
  • 测试要有判别力,不为覆盖率堆弱断言。

AI 让一个人能推进这种体量的项目,但它也会自信地写错原版细节,所以才有上面那一堆门禁。如果大家感兴趣,我可以单独写一篇讲这套流程的踩坑。

声明

这是一个非官方的同人/学习项目,与《仙剑奇侠传》的版权方(大宇资讯、软星科技等)没有任何关联。《仙剑奇侠传》相关名称、美术、音乐和剧情的权利均归其权利人所有。在线试玩站使用的是从原版游戏中提取的资源,仅供学习交流;如有侵权,接到通知后会立即下架。喜欢这个游戏的话,请支持正版。

最后

欢迎试玩、提 issue、拍砖。我特别想听听大家对内容格式和编辑器架构的意见,也欢迎在评论里报告你发现的"和原版不一样"的地方。觉得有意思的话,点个 Star 就是很大的鼓励。

相关推荐
_zxd3 小时前
TypeScript 类型树
前端·typescript
Flynt10 小时前
SvelteKit 3 升级实录:sv migrate 改完 6 个源文件,还给我留了张任务清单
typescript·前端框架·svelte
光影少年2 天前
Taro 是如何解析入口配置 app.config.ts 和页面配置的?
微信小程序·小程序·typescript·reactjs·百度小程序·taro
AI情绪识别开源3 天前
HFpEF 心房-心室耦联效率无创监测方向(AVCEI)
typescript·laravel·perl
凤城老人3 天前
从 PyQt6 到 Electron:给 Edge TTS 做一个“多角色配音机“的踩坑手记
javascript·typescript·electron
zhousenshan4 天前
TypeScript 入门到精通
typescript
花旗蜕变4 天前
前端转 NestJS 全栈实践:从表单页面到微信业务系统
前端·typescript·nestjs
艺杯羹4 天前
Anthropic突袭发布Claude Code Mods!用TypeScript编写智能体中间件:告别AI误删与失控
人工智能·typescript·系统架构
FYKJ_20107 天前
SSM校园失物招领系统41452-计算机课程设计、毕业设计
java·vue.js·spring boot·python·mysql·typescript·spark