一句自然语言实时改写天气、地形物理、敌人行为、战斗规则与任务的可玩 Canvas 世界。
GIF 占位:录制
让这里进入暴风雪,河面结冰,敌人改成怕火的冰狼的完整 8 秒演示。
需要 Node.js 20.19+ 或 22.12+。下载 GitHub Release 源码包并解压,或克隆仓库后运行:
npm install
cp .env.example .env
# 在 .env 填 ANTHROPIC_API_KEY;留空也能使用完整的本地兜底演示
npm startnpm start 会先完成 TypeScript 检查与前端生产构建,再启动服务。默认打开 http://localhost:4173;若该端口已被占用,会自动使用后续空闲端口并在终端打印真实地址。开发时使用 npm run dev 启用热更新。
打开终端显示的地址,输入:
让这里进入暴风雪,河面结冰,敌人改成怕火的冰狼
使用 WASD 移动,J 近战挥击,K 发射自动瞄准最近敌人的投射物。数字键 1–6 或 Tab 切换伤害元素(火/冰/雷/毒/圣/物理),近战与远程都继承当前元素,所以任何"怕雷的敌人"这类规则都能被真正玩出来。火把是有限燃料:连续挥击会耗尽并熄灭,熄灭后惧光敌人不再逃跑。生命归零不会卡死世界——玩家会短暂倒下并在安全地块重生,击杀数与任务进度保留。按反引号键打开技术面板。
规则不是文案,全部由本地确定性代码结算,并且玩家和敌人同样受影响:
| 规则 | 实际效果 |
|---|---|
damage_multiplier |
六种元素各自独立结算,先乘倍率再扣抗性 |
stat_override |
持续覆盖敌人的 hp / speed / damage,按比例保留当前血量 |
material_effect |
damage / heal / slow 同时作用于玩家与敌人 |
global_flag darkness |
压暗画面并缩小敌人索敌范围,点火把会重新暴露自己 |
global_flag low_gravity |
提高目标速度、降低加速度与摩擦,产生漂浮滑行 |
global_flag water_frozen |
无需改写地形即让 water 可通行,敌人也能跟着过河 |
behavior_override |
覆盖 AI 状态机分支 |
collect 目标 |
走过对应材质地块即消耗该格并推进任务 |
敌人会被不可通行地形逐轴阻挡、受材质伤害与减速影响,并在被完全困住时朝出生点回退,所以地形改写本身就是一种战术设计。生成点会自动推到最近的可通行地块,敌人不会被丢进岩浆里。
输入框会在提交前实时显示本地语义解析结果。增强理解器可以在一句话里同时提取天气、时间、地形、实体、数量、行为、元素弱点与任务,也能理解“再来五只”“再强一点”“让冰融化”这类基于当前世界的续写,以及“末日但没有敌人”“暴风雪但河流不要结冰”这类转折和否定。顶部工具提供完整世界快照的撤销、重做、重置与随机复合灵感;Ctrl/Cmd+Z 撤销,Ctrl/Cmd+Shift+Z 重做。
开演前 5 分钟运行 npm run dev,等待终端出现 World cache warm: true。打开 /api/health,确认 ok 与 cacheWarm 均为 true。回到主页,按反引号关闭技术面板。优先使用底部四个安全预设:暴风雪展示地形物理与元素弱点;火山展示危险材质与抗性;深夜展示视野与惧光 AI;和平用于干净收尾。
断网时把地址改为 http://localhost:4173/?offline=1。此模式从 recordings/ 模糊匹配回放,全程不会请求 Claude,故意保留约 400ms 的自然“施法”节奏。评委即兴提问时可以引导:“请同时说一种天气、一种地形变化和敌人的弱点,这样能看到整条规则链。”
没有 API 密钥时 /api/health 的 mode 为 local-fallback,缓存预热表示本地录制和预制补丁已装载。真实 Claude 提示缓存命中需要有效密钥;技术面板中的 CACHE READ 应大于 0。
utterance
│
▼
Claude structured output ──校验失败──► repair retry
│ │
│ 再失败/超时
│ ▼
├──────────────────────────────► 8 preset patches ──无匹配──► visible weather fallback
│
▼
WorldPatch JSON stream
│ env → terrain → rules → entities → quests
▼
apply.ts (normalize + validate + idempotent apply + actual diff)
├──► palette / weather / tiles
├──► AI state machine
├──► combat calculator
├──► quest evaluator
└──► verified rule log
Claude 只产生结构化 WorldPatch。渲染、物理、AI 和伤害结算完全由本地确定性代码从 WorldState 推导。规则面板使用 apply.ts 返回的实际 diff,再为成功变更匹配模型提供的 reason。
顶层属性固定为:
| 属性 | 作用 |
|---|---|
env |
天气、风、可见度、时间、温度、环境色;无变化为 null |
terrain |
replace_material、fill、scatter 操作;无变化为 null |
rules |
添加、移除或清空可结算规则;无变化为 null |
entities |
重定型、生成、移除、修改实体;无变化为 null |
quests |
添加或完成带可判定 objectives 的任务;无变化为 null |
changes |
字段、前值、后值和原因;只给实际 diff 提供解释 |
summary |
UI 最后一行总述 |
规则类型包括元素伤害倍率、数值覆盖、行为覆盖、材质效果与全局标志。目标选择器只能按原型、阵营或全部实体。区域只能是全图、矩形或圆形。完整示例:
{
"env": {
"weather": "blizzard",
"intensity": 0.92,
"wind": { "dir": 5.85, "speed": 0.94 },
"visibility": 0.46,
"time": null,
"temperature": -18,
"ambient": { "hue": 197, "sat": 58, "light": 72 }
},
"terrain": [
{ "op": "replace_material", "from": "water", "to": "ice", "region": { "type": "all" } }
],
"rules": [
{
"op": "add",
"rule": {
"id": "ice-wolf-fire-weakness",
"kind": "damage_multiplier",
"target": { "by": "archetype", "value": "ice_wolf" },
"element": "fire",
"value": 2.5
}
}
],
"entities": [
{
"op": "retype",
"target": { "by": "archetype", "value": "wolf" },
"to": "ice_wolf",
"overrides": null
}
],
"quests": [
{
"op": "add",
"quest": {
"id": "survive-whiteout",
"title": "白幕中的火种",
"description": "穿过冻结的河面,用火焰击退冰狼。",
"objectives": [
{ "type": "kill_count", "target": "ice_wolf", "goal": 3, "progress": 0 }
]
}
}
],
"changes": [
{ "field": "env.weather", "before": "clear", "after": "blizzard", "reason": "暴风雪会立刻压低能见度并改变风场。" },
{ "field": "terrain.replace_material", "before": "water", "after": "ice", "reason": "低温冻结河面,使其可通行且具有滑行惯性。" },
{ "field": "rules.ice-wolf-fire-weakness", "before": "无", "after": "fire ×2.5 vs ice_wolf", "reason": "冰狼的寒冰躯体会被火元素快速瓦解。" }
],
"summary": "暴风雪封锁了荒原;河流已经冻结,火焰成了活下去的唯一答案。"
}Zod 是唯一 schema 来源,服务端通过 zod-to-json-schema 生成 Claude 的 JSON Schema。结构化输出中的可选段以必需但可空的字段表达,所有对象均为 strict。
默认模型为 claude-opus-4-8,使用低 effort、关闭 thinking、8192 max tokens 和流式结构化输出。WORLDSMITH_MODEL 可切换为 claude-sonnet-5 或 claude-haiku-4-5;代码始终显式关闭 thinking。WORLDSMITH_FAST=1 对 Opus 4.8 启用 Fast Mode,429 时自动回到标准通道。SDK 超时为 20 秒,最多一次 SDK 重试。
静态 system prompt 保持逐字节固定并超过 4096-token 缓存门槛,动态世界摘要只放在 user 消息。服务启动发送完整预热请求,随后每 4 分钟保活。调试面板显示首字节、端到端延迟、输入输出 token、cache read、来源、兜底状态、警告、活动规则和原始补丁。
使用 WORLDSMITH_FAULT=invalid-once 注入一次非法输出并观察修复重试;使用 WORLDSMITH_FAULT=always-invalid 验证连续失败后的预制补丁。
增加材质时在 shared/vocab.ts 的 MATERIAL 与 MATERIAL_PROPS 加枚举和完整物理属性,再在 client/render/tiles.ts 加程序化纹理;schema 会自动继承枚举。增加原型时在 ARCHETYPE 与 ARCHETYPE_TEMPLATES 加模板,再按需在 render/entities.ts 调整符号表现。增加规则时在 shared/schema.ts 扩展 RuleSchema,在 client/sim/rules.ts 实现求值(该模块是规则求值的唯一入口,ai.ts、player.ts、combat.ts 都从这里读取),并为 client/apply.ts 保留真实 diff。新机制务必同步 client/interpreter.ts,否则无 API key 时离线演示看不到它。
npm test 不调用真实 API,覆盖预制补丁、所有 apply 操作、幂等性、未知枚举、分片 JSON、三层兜底、伤害公式、材质物理、世界压缩,以及规则求值(stat_override、三个全局标志、slow/heal 聚合)、六元素伤害与抗性、收集任务、地形感知敌人、火把燃料与黑暗、死亡重生。npm run build 同时执行 TypeScript 检查和生产构建。
当前模型偶尔会误解复杂空间关系;世界内容只能来自闭合词汇表;没有存档系统;玩法为单人本地;录制文件在单机文件系统持久化,面向本地路演。玩家的元素选择与火把燃料属于会话状态,不写入 WorldState,因此不会被撤销/重做回滚。敌人使用逐轴阻挡而非寻路,遇到复杂凹形地形时会贴边而不会绕远路。