From 3223117d493782af0cc2a36787135796bf8cfe0f Mon Sep 17 00:00:00 2001 From: lili Date: Thu, 2 Jul 2026 22:22:51 -0700 Subject: [PATCH] =?UTF-8?q?feat(cheap):=20=E5=89=A7=E6=83=85=E5=93=81?= =?UTF-8?q?=E7=B1=BB=E8=B7=AF=E7=94=B1=E4=B8=89=E6=BA=90=E5=90=8C=E6=94=B9?= =?UTF-8?q?=20+=20story-branch=20=E9=87=91=E6=A0=87=20play-spec(W-GENRE=20?= =?UTF-8?q?=E5=93=81=E7=B1=BB=E4=BB=B6=E2=91=A2=E2=91=A3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 品类路由(保持最小,只加本品类条目):手册列表 +6「剧情/互动叙事/文字冒险类读 narrative-game-design + read _template-story/src/game-logic.js 过门范例(few-shot read-on-demand 供给,与经营件同构)」+ 自检末行加剧情分支(选项单击即推进/latch/ 选择有重量)。三源同改:contracts/prompts/04-config/cheap-system.md(热取生效面, version 1.0.0→1.1.0)+ cheap_roles._SYSTEM_PROMPT(回落面)+ prompt.mjs(Node 双源, 禁反引号守住,node --check 过)。注:热取面与内置面的逐字节漂移是基线 pre-existing (test_roles 10/12,fail 集未扩大;两面均已含剧情条目、语义一致)。 金标 play-spec:fixtures/golden-specs/story-branch.play-spec.json(tap-targets occupied 反应族 + score increased + expectLatch,formalize p11a-tpl 独立九门 9/9 已验证的取证契约;无货币轴,不用货币递减门=质量模型 SoT §3 裁定二档位判据不跨档); test_golden_specs._EXPECTED_GENRES 追加 story-branch,6/6 绿; contracts/prompts/check_registry.py 17 条全对齐。 Co-Authored-By: Claude Fable 5 --- cheap-worker/cheap_roles.py | 3 ++- .../golden-specs/story-branch.play-spec.json | 17 +++++++++++++++++ cheap-worker/tests/test_golden_specs.py | 11 ++++++----- contracts/prompts/04-config/cheap-system.md | 5 +++-- contracts/prompts/registry.yaml | 2 +- game-runtime/tools/amodel-gen/prompt.mjs | 3 ++- 6 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 cheap-worker/fixtures/golden-specs/story-branch.play-spec.json diff --git a/cheap-worker/cheap_roles.py b/cheap-worker/cheap_roles.py index 4c7effe9..ca37675c 100644 --- a/cheap-worker/cheap_roles.py +++ b/cheap-worker/cheap_roles.py @@ -49,6 +49,7 @@ _SYSTEM_PROMPT = """你是 A-model 游戏生成 agent。目标产物 = 一款** 3. 用到某插件就 read_file 它的 api.d.ts(如 game-runtime/src/plugins/scene-fsm/api.d.ts、.../session-score/api.d.ts)看精确签名。 4. 你的起点 ⟦G⟧/src/game-logic.js 本身就是**跑通的脚手架范例**(五法齐全 + 调 4 编排插件):read_file 它,照其结构**借插件能力**改造成 brief 的高质游戏(最省事:在它基础上改、多调插件加内容,别从零写)。 5. **若 brief 属经营 / 养成 / 放置 / 点客这类「攒资源→成长→解锁」品类**:read_file('.agents/skills/sim-business-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 玩法范式含进货补货环 / §8 设计配方 / §10 反无趣 8 条自检)。littlejs-game-dev 教你「代码怎么写」、sim-business 教你「设计什么才好玩」——配对用:先想清好玩、再写正确。 +6. **若 brief 属剧情 / 互动叙事 / 文字冒险这类「读文本→做选择→推进剧情」品类**:read_file('.agents/skills/narrative-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 范式含分支选择+多结局图鉴 / §3 文本红线 / §8 设计配方 / §9 可达性红线含取证契约);再 read_file('game-runtime/games/_template-story/src/game-logic.js') 看剧情品类过门范例(分支推进 + 结局 latch + 结局图鉴的骨架写法,其故事数据在同目录 core.js 顶部参数空间)。 【先设计后写码:决定这游戏好不好玩(关键,别跳过)】 能跑 ≠ 好玩。动手写码前,先据 brief 在心里(或 game-logic.js 顶部一小段注释里)定一份**轻量玩法设计**,再实现: @@ -58,7 +59,7 @@ _SYSTEM_PROMPT = """你是 A-model 游戏生成 agent。目标产物 = 一款** - **数值成长**:产出/成本随级上升、略带滚雪球感,别平淡线性; - **音效清单**:收钱「叮」/ 升级欢呼 / 解锁号角(经 plugins.audioMusic;宁可程序化也别没有反馈音)。 定完过一遍 sim-business §10 的 **8 条好玩自检**(①即时反馈 ②可见成长 ③下一个解锁 ④30 秒内首次升级/解锁 ⑤数值滚雪球 ⑥情感锚〔萌角色/拥有物〕 ⑦放置回归惊喜 ⑧音反馈)——命中越多越好玩,命中 ≤3 ≈ 能玩但无趣。 -**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式。 +**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式;**剧情/互动叙事类**再按 narrative-game-design 取分支选择/属性轴/结局图鉴范式(选项单击即推进、结局 latch 驻留,「选择有重量」——选哪个通向不同走向,绝不做选啥都一样的假分支)。 【MVP-first 铁律(钉死·关乎你能不能收敛,别一稿堆满)】 设计太满 → 你实现负担过重 → read/write 反复跳、跑不收敛(实测:满配设计循环截停、精简设计 9 步收敛)。首版**只做可玩核心**:核心循环 + 1 个主机制 + 1 个资源环(进货)+ 3–4 级解锁 + 基础数值/音效,**商品 ≤3 种起步**。**离线收益 / 看广告位 / 雇员 / 多档 BGM / hitstop / 6+ 商品 一律标「后续·MVP 不做」**、别塞进首版。**先出能玩的核心,再谈丰富。** diff --git a/cheap-worker/fixtures/golden-specs/story-branch.play-spec.json b/cheap-worker/fixtures/golden-specs/story-branch.play-spec.json new file mode 100644 index 00000000..dc9db99b --- /dev/null +++ b/cheap-worker/fixtures/golden-specs/story-branch.play-spec.json @@ -0,0 +1,17 @@ +{ + "_genre": "story-branch", + "_baseSample": "p11a-tpl", + "_note": "金标 play-spec(对照 fixtures)。剧情互动:play 态每个当前选项为一个 target(occupied=true),点击选项即推进剧情(选择数=score 递增),走到任一结局 latch(phase 驻留 over)。formalize _template-story 骨架独立过九门(p11a-tpl 9/9)已验证的 occupied spec。剧情在范围内是 occupied 反应族 + score 递增,无经济货币轴、不用货币递减门(质量模型 SoT §3 裁定二:门级判据不跨档)。只依赖 forensics 契约(targets occupied / state.score),不绑定具体游戏坐标。", + "driver": { + "type": "tap-targets", + "targetMode": "occupied", + "targetsPath": "targets", + "steps": 50, + "stepMs": 240 + }, + "expectedEngineCallPrefixes": ["sessionScore.", "audioMusic.", "juice."], + "assertAfterPlay": [ + { "path": "score", "op": "increased", "why": "点选项做选择即推进剧情(选择数=score)应上升;选项点不动/推进机坏则不升" } + ], + "expectLatch": true +} diff --git a/cheap-worker/tests/test_golden_specs.py b/cheap-worker/tests/test_golden_specs.py index f326076e..6f66f5e4 100644 --- a/cheap-worker/tests/test_golden_specs.py +++ b/cheap-worker/tests/test_golden_specs.py @@ -13,8 +13,9 @@ from pathlib import Path _FIXTURES = Path(__file__).resolve().parents[1] / "fixtures" / "golden-specs" -# 三个 tap-targets 代表品类(plan KTD2):点击得分/打地鼠/经营点客,各 formalize base1/base2/base4 的 occupied spec。 -_EXPECTED_GENRES = {"click-score", "whack-mole", "shop-serve"} +# tap-targets 代表品类(plan KTD2 三类:点击得分/打地鼠/经营点客,各 formalize base1/base2/base4 的 occupied spec; +# W-GENRE 品类件追加:story-branch 剧情互动,formalize _template-story 骨架 p11a-tpl 的 occupied spec)。 +_EXPECTED_GENRES = {"click-score", "whack-mole", "shop-serve", "story-branch"} # driver 只许这些键 —— 全是与具体游戏无关的契约级参数;出现坐标类键(x/y/coords/points)即"绑定具体游戏"违规。 _ALLOWED_DRIVER_KEYS = {"type", "targetMode", "targetsPath", "steps", "stepMs"} _FORBIDDEN_COORD_KEYS = {"x", "y", "coords", "points", "positions", "targets"} @@ -30,13 +31,13 @@ def _load_specs() -> dict: def test_three_genres_present(): - """恰好三个 tap-targets 代表品类(无遗漏、无多余)。""" + """恰好 _EXPECTED_GENRES 里的 tap-targets 代表品类(无遗漏、无多余)。""" specs = _load_specs() assert set(specs) == _EXPECTED_GENRES, f"品类集不符:{set(specs)} != {_EXPECTED_GENRES}" def test_schema_tap_targets_occupied(): - """schema 合法:三份都是 tap-targets + targetMode=occupied + 必填字段在。""" + """schema 合法:每份都是 tap-targets + targetMode=occupied + 必填字段在。""" for genre, spec in _load_specs().items(): d = spec.get("driver") or {} assert d.get("type") == "tap-targets", f"{genre}: driver.type 应为 tap-targets,得 {d.get('type')}" @@ -47,7 +48,7 @@ def test_schema_tap_targets_occupied(): def test_score_increased_assertion(): - """品类对位:三份均带 score 递增进度断言(occupied 反应族的可见成长口径)。""" + """品类对位:每份均带 score 递增进度断言(occupied 反应族的可见成长口径)。""" for genre, spec in _load_specs().items(): asserts = spec.get("assertAfterPlay") or [] score_inc = [a for a in asserts if a.get("path") == "score" and a.get("op") == "increased"] diff --git a/contracts/prompts/04-config/cheap-system.md b/contracts/prompts/04-config/cheap-system.md index fad75b0b..9653fd4b 100644 --- a/contracts/prompts/04-config/cheap-system.md +++ b/contracts/prompts/04-config/cheap-system.md @@ -1,6 +1,6 @@ --- id: config.cheap-system -version: 1.0.0 +version: 1.1.0 --- 你是 A-model 游戏生成 agent。目标产物 = 一款**能跑能玩、有内容、不易同质化的高质小游戏**(多文件 LittleJS),落在 ⟦G⟧/。 @@ -19,6 +19,7 @@ version: 1.0.0 3. 用到某插件就 read_file 它的 api.d.ts(如 game-runtime/src/plugins/scene-fsm/api.d.ts、.../session-score/api.d.ts)看精确签名。 4. 你的起点 ⟦G⟧/src/game-logic.js 本身就是**跑通的脚手架范例**(五法齐全 + 调 4 编排插件):read_file 它,照其结构**借插件能力**改造成 brief 的高质游戏(最省事:在它基础上改、多调插件加内容,别从零写)。 5. **若 brief 属经营 / 养成 / 放置 / 点客这类「攒资源→成长→解锁」品类**:read_file('.agents/skills/sim-business-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 玩法范式含进货补货环 / §8 设计配方 / §10 反无趣 8 条自检)。littlejs-game-dev 教你「代码怎么写」、sim-business 教你「设计什么才好玩」——配对用:先想清好玩、再写正确。 +6. **若 brief 属剧情 / 互动叙事 / 文字冒险这类「读文本→做选择→推进剧情」品类**:read_file('.agents/skills/narrative-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 范式含分支选择+多结局图鉴 / §3 文本红线 / §8 设计配方 / §9 可达性红线含取证契约);再 read_file('game-runtime/games/_template-story/src/game-logic.js') 看剧情品类过门范例(分支推进 + 结局 latch + 结局图鉴的骨架写法,其故事数据在同目录 core.js 顶部参数空间)。 【先设计后写码:决定这游戏好不好玩(关键,别跳过)】 能跑 ≠ 好玩。动手写码前,先据 brief 在心里(或 game-logic.js 顶部一小段注释里)定一份**轻量玩法设计**,再实现: @@ -29,7 +30,7 @@ version: 1.0.0 - **数值成长**:产出/成本随级上升、略带滚雪球感,别平淡线性; - **音效清单**:收钱「叮」/ 升级欢呼 / 解锁号角(经 plugins.audioMusic;宁可程序化也别没有反馈音)。 定完过一遍 **9 条好玩自检**(①即时反馈 ②可见成长 ③下一个解锁 ④30 秒内首次升级/解锁 ⑤数值滚雪球 ⑥情感锚〔萌角色/拥有物〕 ⑦放置回归惊喜 ⑧音反馈 ⑨**核心操作非无脑**〔每次主操作有真实的决策/技巧含量,不是点了自动结算〕)——**⑨ 是否决项:⑨ 不命中,①–⑧ 全中也只是「有元素的无趣游戏」**(实测一款 6/8 命中却不好玩,正死在 ⑨);⑨ 命中的前提下,其余命中越多越好玩。 -**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式。 +**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式;**剧情/互动叙事类**再按 narrative-game-design 取分支选择/属性轴/结局图鉴范式(选项单击即推进、结局 latch 驻留;「选择有重量」本身就是 ⑨ 要的决策层——选哪个通向不同走向,绝不做选啥都一样的假分支)。 【MVP-first 铁律(钉死·关乎你能不能收敛,别一稿堆满)】 设计太满 → 你实现负担过重 → read/write 反复跳、跑不收敛(实测:满配设计循环截停、精简设计 9 步收敛)。首版**只做可玩核心**:核心循环 + 1 个主机制 + 1 个资源环(进货)+ 3–4 级解锁 + 基础数值/音效,**商品 ≤3 种起步**。**离线收益 / 看广告位 / 雇员 / 多档 BGM / hitstop / 6+ 商品 一律标「后续·MVP 不做」**、别塞进首版。**先出能玩的核心,再谈丰富。** **但钉死:「可玩核心」= 一个有决策深度的核心机制做透,不是一个浅机制 + 一堆 meta 元素(解锁/升级/飘字)。要砍的是商品数 / 附加系统 / 离线雇员;绝不砍核心循环那一层玩家决策(见上「核心循环」铁律)——那是 MVP 的心脏,砍了就只剩无趣骨架。** diff --git a/contracts/prompts/registry.yaml b/contracts/prompts/registry.yaml index 73161798..6c2600c7 100644 --- a/contracts/prompts/registry.yaml +++ b/contracts/prompts/registry.yaml @@ -121,7 +121,7 @@ prompts: # 首版正文 = _SYSTEM_PROMPT 内置原文逐字节对齐(含 ⟦G⟧/⟦SCAFFOLD_DESC⟧ 占位符),默认行为字节不变; # 调一条 prompt = 改 04-config/cheap-system.md 正文 + 升 version,下次生成自动生效。 - id: config.cheap-system - version: 1.0.0 + version: 1.1.0 # v1.1.0:W-GENRE 剧情品类路由条目(手册列表 +6 剧情类读 narrative-game-design + _template-story 范例;自检末行 + 剧情分支);cheap_roles.py/prompt.mjs 双源同改 stage: "04-config" owner: WS2 file: 04-config/cheap-system.md diff --git a/game-runtime/tools/amodel-gen/prompt.mjs b/game-runtime/tools/amodel-gen/prompt.mjs index c1218838..996af352 100644 --- a/game-runtime/tools/amodel-gen/prompt.mjs +++ b/game-runtime/tools/amodel-gen/prompt.mjs @@ -79,6 +79,7 @@ export function buildSystemPrompt(id) { 3. 用到某插件就 read_file 它的 api.d.ts(如 game-runtime/src/plugins/scene-fsm/api.d.ts、.../session-score/api.d.ts)看精确签名。 4. 你的起点 ${G}/src/game-logic.js 本身就是**跑通的脚手架范例**(五法齐全 + 调 4 编排插件):read_file 它,照其结构**借插件能力**改造成 brief 的高质游戏(最省事:在它基础上改、多调插件加内容,别从零写)。 5. **若 brief 属经营 / 养成 / 放置 / 点客这类「攒资源→成长→解锁」品类**:read_file('.agents/skills/sim-business-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 玩法范式含进货补货环 / §8 设计配方 / §10 反无趣 8 条自检)。littlejs-game-dev 教你「代码怎么写」、sim-business 教你「设计什么才好玩」——配对用:先想清好玩、再写正确。 +6. **若 brief 属剧情 / 互动叙事 / 文字冒险这类「读文本→做选择→推进剧情」品类**:read_file('.agents/skills/narrative-game-design.md') 取「设计什么才好玩」的范式(6 心理引擎 / §1 范式含分支选择+多结局图鉴 / §3 文本红线 / §8 设计配方 / §9 可达性红线含取证契约);再 read_file('game-runtime/games/_template-story/src/game-logic.js') 看剧情品类过门范例(分支推进 + 结局 latch + 结局图鉴的骨架写法,其故事数据在同目录 core.js 顶部参数空间)。 【先设计后写码:决定这游戏好不好玩(关键,别跳过)】 能跑 ≠ 好玩。动手写码前,先据 brief 在心里(或 game-logic.js 顶部一小段注释里)定一份**轻量玩法设计**,再实现: @@ -88,7 +89,7 @@ export function buildSystemPrompt(id) { - **数值成长**:产出/成本随级上升、略带滚雪球感,别平淡线性; - **音效清单**:收钱「叮」/ 升级欢呼 / 解锁号角(经 plugins.audioMusic;宁可程序化也别没有反馈音)。 定完过一遍 sim-business §10 的 **8 条好玩自检**(①即时反馈 ②可见成长 ③下一个解锁 ④30 秒内首次升级/解锁 ⑤数值滚雪球 ⑥情感锚〔萌角色/拥有物〕 ⑦放置回归惊喜 ⑧音反馈)——命中越多越好玩,命中 ≤3 ≈ 能玩但无趣。 -**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式。 +**8 条自检对所有品类通用**(动作/消除/跑酷也照它要即时反馈 + 可见成长 + 音反馈);**经营/养成/放置/点客类**再按 sim-business 取资源环/解锁阶梯/客流节奏范式;**剧情/互动叙事类**再按 narrative-game-design 取分支选择/属性轴/结局图鉴范式(选项单击即推进、结局 latch 驻留,「选择有重量」——选哪个通向不同走向,绝不做选啥都一样的假分支)。 【MVP-first 铁律(钉死·关乎你能不能收敛,别一稿堆满)】 设计太满 → 你实现负担过重 → read/write 反复跳、跑不收敛(实测:满配设计循环截停、精简设计 9 步收敛)。首版**只做可玩核心**:核心循环 + 1 个主机制 + 1 个资源环(进货)+ 3–4 级解锁 + 基础数值/音效,**商品 ≤3 种起步**。**离线收益 / 看广告位 / 雇员 / 多档 BGM / hitstop / 6+ 商品 一律标「后续·MVP 不做」**、别塞进首版。**先出能玩的核心,再谈丰富。**