narraeon 0.5.6 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/dist/node/protocol/appPreferences.js +4 -2
  4. package/dist/node/protocol/gameplay.js +69 -0
  5. package/dist/node/protocol/playFailure.js +13 -0
  6. package/dist/node/protocol/protagonistTemplates.js +13 -0
  7. package/dist/node/protocol/resolution.js +274 -0
  8. package/dist/node/protocol/v1.js +40 -19
  9. package/dist/node/protocol/worldArchives.js +7 -0
  10. package/dist/node/runtime/RuntimeErrorLog.js +95 -0
  11. package/dist/node/runtime/V1Runtime.js +103 -8
  12. package/dist/node/runtime/archive/WorldArchiveZip.js +202 -0
  13. package/dist/node/runtime/archive/WorldArchives.js +389 -0
  14. package/dist/node/runtime/config/AppPreferencesStore.js +23 -10
  15. package/dist/node/runtime/config/ProtagonistTemplateStore.js +134 -0
  16. package/dist/node/runtime/content/ContentWorkspace.js +15 -2
  17. package/dist/node/runtime/content/CurrentTreeContentLibrary.js +43 -2
  18. package/dist/node/runtime/content/FileNativeContentTree.js +8 -1
  19. package/dist/node/runtime/history/StoryExport.js +33 -0
  20. package/dist/node/runtime/model/FileNativeModelAdapters.js +34 -2
  21. package/dist/node/runtime/model/ModelHost.js +12 -1
  22. package/dist/node/runtime/model/ModelHostStream.js +11 -3
  23. package/dist/node/runtime/play/FileNativePlayAdvanceStore.js +37 -1
  24. package/dist/node/runtime/play/FileNativePlayPresetStore.js +48 -3
  25. package/dist/node/runtime/play/FileNativePlayTimelineStore.js +87 -4
  26. package/dist/node/runtime/play/LegacyModelBindingFailure.js +10 -0
  27. package/dist/node/runtime/play/OrderedPlayPrompts.js +68 -6
  28. package/dist/node/runtime/play/PlayCallChain.js +177 -57
  29. package/dist/node/runtime/play/PlayCallChainError.js +3 -1
  30. package/dist/node/runtime/play/PlayContinuity.js +3 -20
  31. package/dist/node/runtime/play/PlayFailure.js +20 -0
  32. package/dist/node/runtime/play/PlayTraceRetention.js +3 -11
  33. package/dist/node/runtime/play/TabletopResolution.js +372 -0
  34. package/dist/node/runtime/play/TabletopRules.js +141 -0
  35. package/dist/node/runtime/prompt/FileNativePromptCompiler.js +49 -32
  36. package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -4
  37. package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +4 -1
  38. package/dist/node/runtime/setting/SettingAuthoringTransaction.js +56 -13
  39. package/dist/node/runtime/setting/SettingImprovementSession.js +6 -4
  40. package/dist/node/runtime/world/FileNativeWorldStore.js +207 -40
  41. package/dist/node/runtime/world/WorldActivity.js +143 -0
  42. package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +2 -0
  43. package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +35 -6
  44. package/dist/node/runtime/world-revision/WorldRevisionSession.js +9 -5
  45. package/dist/node/server/ConversationStream.js +2 -0
  46. package/dist/node/server/createServer.js +48 -0
  47. package/dist/node/shared/default-preset-host.js +10 -6
  48. package/dist/node/shared/ordered-author-prompts.js +8 -0
  49. package/dist/node/shared/ordered-play-prompts.js +25 -2
  50. package/dist/node/shared/sample-packages/index.js +10 -0
  51. package/dist/node/shared/sample-packages/rainy-inn-en.js +194 -0
  52. package/dist/node/shared/sample-packages/rainy-inn-zh.js +194 -0
  53. package/dist/node/shared/tabletop-guidance.js +100 -0
  54. package/dist/web/assets/index-BJ-1Mb0e.css +1 -0
  55. package/dist/web/assets/index-BgBL8G-A.js +1323 -0
  56. package/dist/web/index.html +2 -2
  57. package/package.json +6 -2
  58. package/dist/web/assets/index-BH8NyuE4.js +0 -1233
  59. package/dist/web/assets/index-CVN48xrw.css +0 -1
@@ -0,0 +1,194 @@
1
+ export const rainyInnChinese = {
2
+ title: "雨灯旅店的一封信",
3
+ files: [
4
+ {
5
+ path: "opening.md",
6
+ contents: `雨水沿着旅店的檐角落下,门上的小铜铃还在轻轻晃动。你面前的柜台亮着一盏暖黄的灯,湿伞架旁飘来姜茶的香气。
7
+
8
+ 柜台后,一位系着墨绿围裙的女人把空的蓝瓷碟翻过来,又放回原处。「刚才还在这里的。」她低声说。
9
+
10
+ 窗边穿灰色针织衫的客人抬起头:「是一个浅蓝信封,明早要寄给我妹妹。还没有封口。」她看向柜台边抱着登记簿的年轻邮差。邮差停下擦拭书角的手,神情有些茫然。
11
+
12
+ 女人转向你,递来一条干毛巾:「先擦擦雨吧。我们正找一封信——你愿意帮忙看看吗?」柜台、伞架和窗边的小桌都在灯光里,她等着你的回答。
13
+ `,
14
+ },
15
+ {
16
+ path: "world/current-situation.yaml",
17
+ contents: `$document:
18
+ id: situation.rainy-inn
19
+ ref: current-situation
20
+ title: 灯下的空瓷碟
21
+ summary: 雨灯旅店大厅里的一次小小寻物。
22
+ aliases: []
23
+ 背景:
24
+ 时间: 秋日,雨夜,晚上九点
25
+ 地点: 溪桥镇,雨灯旅店大厅
26
+ 在场人物:
27
+ - $ref: character.shen-he
28
+ - $ref: character.lin-lan
29
+ - $ref: character.zhou-cheng
30
+ 进行中事件:
31
+ 寻信: 林岚发现寄给妹妹的浅蓝信封不在柜台蓝瓷碟上;大厅里尚未有人开始系统寻找。
32
+ 待回应:
33
+ 说话者: { $ref: character.shen-he }
34
+ 邀请: 先擦擦雨吧。我们正找一封信——你愿意帮忙看看吗?
35
+ 短期局面:
36
+ - 你刚抵达门口,沈禾递来的干毛巾尚未被接过。
37
+ - 周澄抱着登记簿,刚停下擦拭湿书角的动作。
38
+ `,
39
+ },
40
+ {
41
+ path: "world/characters/shen-he.yaml",
42
+ contents: `$document:
43
+ id: character.shen-he
44
+ ref: shen-he
45
+ title: 沈禾
46
+ summary: 雨灯旅店的店主,做事细致,待客温和。
47
+ aliases: [沈老板]
48
+ 外貌: 短发,眉眼柔和,袖口上有一点面粉。
49
+ 衣着: 米色衬衣,墨绿围裙,布鞋。
50
+ 性格: 耐心,遇到疏漏先寻找补救办法,不轻易责怪人。
51
+ 关系:
52
+ 林岚:
53
+ 对象: { $ref: character.lin-lan }
54
+ 看法: 常住的熟客,珍惜她带来的植物故事;希望她今晚能安心休息。
55
+ 周澄:
56
+ 对象: { $ref: character.zhou-cheng }
57
+ 看法: 邻居家的年轻邮差,热心但偶尔忙中出错;愿意让他说明情况。
58
+ 认知:
59
+ 信件: 记得把林岚的浅蓝信封放在蓝瓷碟上,此后忙着烧姜茶,没有留意柜台。
60
+ 依据: { $ref: event.letter-entrusted }
61
+ `,
62
+ },
63
+ {
64
+ path: "world/characters/lin-lan.yaml",
65
+ contents: `$document:
66
+ id: character.lin-lan
67
+ ref: lin-lan
68
+ title: 林岚
69
+ summary: 途经溪桥镇的植物绘图员,喜欢用信分享见闻。
70
+ aliases: []
71
+ 外貌: 戴圆框眼镜,指尖有淡淡的铅笔灰。
72
+ 衣着: 灰色针织衫,深蓝长裤,晾在伞架旁的棕色雨披。
73
+ 性格: 观察细致,说话慢,担心时会反复核对细节。
74
+ 关系:
75
+ 沈禾:
76
+ 对象: { $ref: character.shen-he }
77
+ 看法: 熟悉而可靠的店主,信不见了也不认为她会故意隐瞒。
78
+ 周澄:
79
+ 对象: { $ref: character.zhou-cheng }
80
+ 看法: 今晚才认识的邮差,相信他熟悉寄信流程,尚不了解他的习惯。
81
+ 重要物品:
82
+ 给妹妹的信: 浅蓝信封,未封口,内有一页见闻和一张手绘叶片图;原计划明早寄出。
83
+ 认知:
84
+ 信件: 知道自己把信交给了沈禾;只看到现在瓷碟空了,不知道它后来去了哪里。
85
+ 依据: { $ref: event.letter-entrusted }
86
+ `,
87
+ },
88
+ {
89
+ path: "world/characters/zhou-cheng.yaml",
90
+ contents: `$document:
91
+ id: character.zhou-cheng
92
+ ref: zhou-cheng
93
+ title: 周澄
94
+ summary: 镇上的年轻邮差,雨天也会顺路帮邻居跑腿。
95
+ aliases: [小周]
96
+ 外貌: 头发被雨压得贴在额前,笑起来有浅酒窝。
97
+ 衣着: 蓝色雨衣敞着扣子,条纹衬衣,湿了鞋尖的帆布鞋。
98
+ 性格: 热心,做事容易分心;一旦发现自己弄错,愿意承认并帮忙补救。
99
+ 关系:
100
+ 沈禾:
101
+ 对象: { $ref: character.shen-he }
102
+ 看法: 从小认识的邻居,信任她,也在意自己能否帮上忙。
103
+ 林岚:
104
+ 对象: { $ref: character.lin-lan }
105
+ 看法: 刚认识的客人,她的植物画很有趣,想请她解释画里的树叶。
106
+ 认知:
107
+ 自己记得的动作: 刚才挪开柜台上的浅蓝信封给湿登记簿腾地方,顺手把它夹进登记簿封底;以为那只是空信封。
108
+ 当前理解: 尚未听清林岚在找什么,没有把她的信与自己挪过的信封联系起来。
109
+ 随身物品:
110
+ 登记簿: 抱在手里,封底书角被雨打湿。
111
+ `,
112
+ },
113
+ {
114
+ path: "world/locations/rain-lantern-inn.yaml",
115
+ contents: `$document:
116
+ id: location.rain-lantern-inn
117
+ ref: rain-lantern-inn
118
+ title: 雨灯旅店
119
+ summary: 溪桥镇桥头的小旅店,邻里常来避雨喝茶。
120
+ aliases: []
121
+ 大厅: 木柜台正对入口,柜台上有蓝瓷碟和铜灯;窗边放着小桌,门旁是伞架。
122
+ 日常: 客人可在大厅休息、喝姜茶,店主替熟客暂存待寄信件。
123
+ `,
124
+ },
125
+ {
126
+ path: "world/events/letter-entrusted.yaml",
127
+ contents: `$document:
128
+ id: event.letter-entrusted
129
+ ref: letter-entrusted
130
+ title: 柜台上的托付
131
+ summary: 林岚把待寄信件交给沈禾暂存的一次托付。
132
+ aliases: []
133
+ 时间: 今晚约半小时前
134
+ 经过: 林岚将未封口的浅蓝信封交给沈禾,说明里面有给妹妹的信和叶片图;沈禾当着她的面放在柜台蓝瓷碟上。
135
+ 原话: 林岚说「明早我再来封口,麻烦先放这里」。沈禾答应替她暂存。
136
+ 来源: 林岚与沈禾当时都在柜台旁。
137
+ `,
138
+ },
139
+ {
140
+ path: "control/frame.yaml",
141
+ contents: `format: narraeon.world-frame/v1
142
+ bindings:
143
+ currentSituation: "@current-situation"
144
+ instructions:
145
+ - markdown: blocks/world.md
146
+ context:
147
+ - slot: { kind: catalog, directory: characters, maxEntries: 3 }
148
+ - slot: { kind: catalog, directory: locations, maxEntries: 4 }
149
+ - slot: { kind: catalog, directory: events, maxEntries: 12 }
150
+ - slot: { kind: document, document: "@rain-lantern-inn" }
151
+ - slot:
152
+ kind: reference_targets
153
+ from:
154
+ document: "@current-situation"
155
+ locator: { yaml: [在场人物] }
156
+ maxEntries: 3
157
+ - slot: { kind: current_situation }
158
+ - slot: { kind: additional_materials }
159
+ `,
160
+ },
161
+ {
162
+ path: "control/blocks/world.md",
163
+ contents: `<!-- opening.md 是玩家看到的开场;world/current-situation.yaml 记录背景与待回应局面;characters/ 各自保存人物状态、关系与认知;locations/ 保存地点;events/ 保存共同往事;frame.yaml 选择游玩材料;player-views.yaml 选择状态栏原值。可从这些文件改写自己的故事。 -->
164
+
165
+ # 本世界的题材与边界
166
+
167
+ 以小镇旅店的日常交谈和轻微悬疑为主,线索来自物件、记忆和误会。保持温暖、适合所有年龄;不引入暴力、成人内容或威胁生命的阴谋。信件的私人内容由收信人与写信人决定是否分享。
168
+
169
+ ## 本世界的文档与保存位置
170
+
171
+ 人物之间的关系、各自看法与认知写在各自的 world/characters/ 人物文档中,不设统一真相或秘密字段。需要共同引用的事件经过写在 world/events/,人物通过引用关联,不重复抄写经过。地点的持续变化写回 world/locations/。信件先作为所属人物的重要物品维护,需要独立转移追踪时再建文档。
172
+ `,
173
+ },
174
+ {
175
+ path: "control/player-views.yaml",
176
+ contents: `format: narraeon.player-views/v1
177
+ views:
178
+ - id: scene-status
179
+ title: 此刻
180
+ items:
181
+ - id: time
182
+ label: 时间
183
+ select:
184
+ document: "@current-situation"
185
+ locator: { yaml: [背景, 时间] }
186
+ - id: place
187
+ label: 地点
188
+ select:
189
+ document: "@current-situation"
190
+ locator: { yaml: [背景, 地点] }
191
+ `,
192
+ },
193
+ ],
194
+ };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Application-owned tabletop guidance. These builtins are tabletop-scoped: the
3
+ * compiler expands them only for tabletop worlds or packages. Scheme-specific
4
+ * rules are never written here; Runtime derives them from control/gameplay.json.
5
+ */
6
+ export function tabletopAuthorGuidance(locale) {
7
+ return locale === "zh-CN"
8
+ ? `## 为实际游玩准备局面
9
+ - 从玩家眼前值得行动的局面开始:想得到什么、什么阻碍着他们、为什么现在需要决定。先写可互动的人物、地点和线索,再按需补背景;不预写玩家必经的剧情或结局。
10
+ - 为重要人物写出欲望、顾虑、掌握的信息和能采取的手段;说明冲突各方在无人干预时会怎样行动及玩家能察觉的迹象。推进应有原因,不因玩家偏离预想路线而惩罚他们。
11
+ - 提供多种可以探索的办法与可利用的环境细节;不要求唯一解,也不把列出的办法当成穷尽选项。调查、准备、装备和盟友应能实际改变处境或判定数值。
12
+ - 写明所选方案的数值尺度、常见难度参照与准备带来的影响,保持前后一致;角色、战斗和资源体系按世界需要设计。隐藏事实可以保密,明显风险与行动所需信息应让玩家能够获知。
13
+ - 按实际玩家视图的绑定范围分开放置公开信息和主持秘密。整份文档若会展示给玩家,其中的标题、摘要和任何子字段都不能藏秘密;只绑定公开节点时,主持资料才可放在未展示的节点。当前情境也不天然私密。记录角色各自知道什么,避免主持知道的真相成为玩家或 NPC 的知识。字段结构按世界需要设计。
14
+ - 开场呈现冲突并停在玩家能决定的位置,不替玩家接受任务或选择路线。让后续主持人能依据人物动机和当前状态继续,而不是依赖一份秘密剧本。
15
+
16
+ ### 开场正反例
17
+ 弱例:“你来到一座繁华港口,这里有悠久的历史。”只有背景,没有眼前可行动的关系。
18
+ 较好:“明早处刑的走私犯知道你妹妹的下落。他愿意交换情报,条件是今晚带他离开牢房。守卫队长欠你一个人情。”玩家可以求人、调查、交易、潜入或另寻办法;不要预定他们劫狱。
19
+ 示例仅说明设计方法,不向当前世界添加港口、妹妹或走私犯。`
20
+ : `## Prepare situations for actual play
21
+ - Start with something worth acting on: what the player wants, what stands in the way, and why a decision matters now. Prepare people, places and clues before background lore. Do not script a mandatory route or ending.
22
+ - Give important NPCs desires, concerns, information and available means. Describe what opposing parties do without intervention and signs the player can notice. Develop events causally; do not punish departures from your expected route.
23
+ - Offer several discoverable approaches and useful environmental details, without requiring a single solution or treating listed approaches as exhaustive. Investigation, preparation, equipment and allies must be able to change circumstances or check inputs.
24
+ - Document the selected scheme's numeric scale, ordinary difficulty benchmarks and effects of preparation consistently. Design character, combat and resource systems for this world. Secrets may remain hidden; make obvious risks and information needed for decisions discoverable.
25
+ - Separate public information from GM secrets according to actual player-view bindings. If a whole document is displayed, none of its titles, summaries or nested fields may contain secrets. GM material may occupy an unexposed node when only the public node is bound. The current situation is not inherently private. Track what each character knows; GM knowledge is not player or NPC knowledge. Choose field structures for this world.
26
+ - End the opening at a player decision, without accepting a mission or choosing a route for them. Prepare motivations and current state that another GM can use, rather than a secret script.
27
+
28
+ ### Opening examples
29
+ Weak: “You arrive at a bustling port with a long history.” This supplies background but no immediate actionable relationship.
30
+ Better: “A smuggler facing execution tomorrow knows where your missing sister is. He offers the information if you get him out tonight. The guard captain owes you a favour.” The player may negotiate, investigate, trade, infiltrate or find another approach; do not prescribe a jailbreak.
31
+ These examples illustrate technique; they do not add a port, sister or smuggler to the current world.`;
32
+ }
33
+ export function tabletopPlayGuidance(locale) {
34
+ return locale === "zh-CN"
35
+ ? `## 主持流程
36
+ 1. 呈现玩家现在能察觉的局面、可互动细节与明显风险,区分已知事实和人物猜测。保留有依据的秘密,但不要在判定后临时补造机关、敌人或限制来否定结果。
37
+ 2. 理解玩家想实现的目标和采取的办法。意图清楚就直接推进;只有歧义会显著改变目标、范围或风险时才简短澄清,不逐步索取确认,不替玩家补行动和台词。
38
+ 3. 对有成败不确定性、风险或对抗且后果值得展开的行动进行判定。纯描述、已完成事实和没有成败问题的衔接可直接叙述;不能因行动显得简单或离谱就绕开需要的判定、预定成败。明确一次判定覆盖的目标和范围,根据已建立的能力、环境、准备及世界难度参照确定数值,再调用当前方案工具。不要先决定剧情结果再倒推难度。
39
+ 4. 完整兑现工具结果。成功取得约定成果,失败未取得约定成果;大成功和大失败也按回执兑现。已取得的成果成为后续可依靠的事实。新障碍必须有独立原因,不能紧接着取消刚刚的成功;失败也不能用偶然获得等价好处来偷偷改成成功。
40
+ 5. 让后果带来新的处境和可决定的事情,而不是只有“失败了,再试一次”。根据已建立的风险、人物动机和现场情况决定后果,避免每次失败都升级为灾难。新判定应对应新的目标或实际变化的障碍,不把一个目标拆成连续掷骰直到失败。
41
+ 6. 用世界工具保存人物数值、资源、关系、位置和重要局势的实际变化。让 NPC 依据动机和已知信息反应,允许玩家说服敌人、绕过冲突或提前解决危机;不把所有路线导回预定场景。无人处理的事情按既有原因发展并留下迹象。
42
+ 7. 重要选择与后果展开写,重复过程和没有新变化的路程简略带过,也给交谈和喘息留空间。叙述到需要玩家决定的位置就停。可以提示眼前可行的办法,但不能限制玩家只能选它们。
43
+
44
+ ### 落笔与保存前的核对
45
+ - 知识边界:查明哪些文档或节点会进入玩家视图,再决定写在哪里。叙事、公开面板、标题和摘要只呈现玩家已知或当前可察觉的内容;尚未发现的故障原因、敌方计划等保存在不会展示的主持资料中。幕后变化仍须按保存约定落盘,不能为了保密丢掉状态,也不能把主持真相写进公开的当前情境。NPC 只能依据自己获得的信息行动。
46
+ - 当前状态:一个事实改变后,检查它影响的已有记录及玩家视图绑定,例如人物、借贷、位置、场景现状、可见细节与当前情境。按工具约定读取相关内容,更新受影响字段,删除失效的当前断言或明确改为过去记录,不只在末尾追加相反的新句子。历史不必抹除,无关文档不必重写,也不必把同一事实复制到每处;实际公开值和本轮叙事必须一致。其他持久变化按运行时保存约定处理。
47
+ - 玩家意图:保留条件、否定的作用范围、尚未决定的事项和执行状态。提议不是已成交,愿意不是已执行,“不要替我接受”不是“我拒绝任何替代方案”。不要把一次有条件的表达写成长期立场。条件未满足时停在玩家保留的决定处。
48
+ 例如,玩家还只听见异响时,公开情境不能写“必须同时修好阀门与定位销”;查明后才可公开诊断。修好后,既更新“灯已稳定”,也检查“可见细节”中是否还断言异响正在发生。借用完成后,“尚未借用”应移除或标为过去。
49
+ 玩家说“如果对方不同意这个价,先告诉我,不替我接受别的条件”,可记为“提出该价格;其他条件待玩家决定”,不能记为“不接受替代条件”。这些核对通过读写与叙事完成,不把内部检查清单交给玩家确认。
50
+
51
+ ### 连续主持示例:目标、判定、后果、新选择
52
+ 玩家:“趁换岗,我从排水渠潜入厨房,别惊动守卫。”
53
+ 主持:依据已知的换岗时间和湿滑通道,说明此次目标是“不惊动守卫进入城堡内部”,确定修正与难度,调用当前判定工具。
54
+ 若成功:玩家已经进入厨房且未惊动守卫。描述可观察的走廊、厨房人员或线索,停下来让玩家决定。反例:“你成功进入,但守卫立刻发现你。”这抵消了约定成果。
55
+ 后续玩家:“我偷走守卫腰间的钥匙。”主持确定目标与风险并判定。若失败:钥匙仍在守卫身上;例如守卫察觉并抓住玩家手腕,要求解释。玩家现在可解释、贿赂、逃跑或采取其他行动。不要代选,也不要说“虽然失败,旁边却恰好有一把同样的钥匙”。
56
+ 若玩家准备了可信的身份文件来解释,应让这份准备影响新的处境或判定;不能为了保住劫狱剧情强制开战。后续若成功说服守卫,就兑现说服的目标。
57
+ 以上是假设分支,必须由实际回执选择成败,不能照抄成功或失败;示例中的地点、人物和物品不属于当前世界。`
58
+ : `## GM procedure
59
+ 1. Describe what the player can perceive, useful details and obvious risks. Distinguish facts from character guesses. Keep grounded secrets, but never invent traps, enemies or restrictions after a check to negate its result.
60
+ 2. Understand the intended goal and approach. Proceed when clear; ask briefly only when ambiguity materially changes the goal, scope or risk. Do not request confirmation at every step or invent the player's actions and dialogue.
61
+ 3. Check actions with uncertain success, risk or opposition whose consequences matter. Pure description, established accomplishments and transitions without a success question need no check. Do not bypass a needed check or predetermine success or failure because an action seems easy or absurd. Specify the goal and scope, derive inputs from established abilities, circumstances, preparation and world difficulty benchmarks, then call the selected tool. Never reverse-engineer difficulty from a desired plot result.
62
+ 4. Honour the complete receipt: success achieves the agreed goal; failure does not. Honour critical outcomes too. Accomplishments remain usable facts. New obstacles need independent causes and must not immediately cancel success; do not secretly turn failure into success through an equivalent lucky reward.
63
+ 5. Create a changed situation with a new decision, not just “failed, try again.” Derive consequences from established risks, motivations and circumstances; not every failure is a catastrophe. Each new check needs a new goal or a materially changed obstacle. Never split one goal into repeated rolls until it fails.
64
+ 6. Persist actual changes to values, resources, relationships, location and important situations with world tools. NPCs react according to their motives and information. Allow persuasion, bypassed conflicts and early solutions; do not funnel every route into a planned scene. Unattended events develop for established reasons and leave observable signs.
65
+ 7. Give consequential choices and outcomes space; compress repetition and uneventful travel, and allow conversation and breathing room. Stop at the player's next decision. Suggested approaches are possibilities, never an exhaustive menu.
66
+
67
+ ### Before narrating and saving
68
+ - Knowledge boundaries: inspect which documents or nodes feed player views before choosing where to write. Narration, public panels, titles and summaries contain only player-known or currently perceptible information. Undiscovered causes and opposing plans belong in unexposed GM material. Still persist offscreen changes under the runtime saving contract; secrecy must neither discard state nor put GM truth into a public current situation. NPCs act only on information they have acquired.
69
+ - Current state: when a fact changes, inspect affected existing records and player-view bindings, such as characters, loans, locations, scene status, observable details and the current situation. Read relevant content under tool rules, update affected fields, and remove expired current assertions or explicitly mark them as past records instead of merely appending contradictory updates. Preserve history where useful; do not rewrite unrelated documents or duplicate every fact everywhere. Actual public values must agree with this turn's narration. Handle other persistent changes under the runtime saving contract.
70
+ - Player intent: preserve conditions, the scope of negation, pending decisions and execution status. An offer is not a completed deal; willingness is not execution; “do not accept for me” is not “I reject every alternative.” Do not turn a conditional statement into an enduring stance. If its condition is unmet, stop at the decision reserved for the player.
71
+ For example, while the player has only heard a rattle, a public situation must not reveal “both valve and pin need repair”; disclose the diagnosis after discovery. After repairs, update “the light is stable” and inspect observable details for a stale assertion that rattling continues. Once a loan occurs, remove “not borrowed yet” or mark it as past.
72
+ “If they decline my price, tell me first; do not accept other terms for me” can become “offered that price; other terms await the player's decision,” never “rejects alternative terms.” Perform these checks through tools and narration; do not ask the player to approve an internal checklist.
73
+
74
+ ### Connected example: goal, check, consequence, next choice
75
+ Player: “During the shift change, I enter the kitchen through the drain without alerting the guards.”
76
+ GM: Use the known shift timing and slippery passage, establish the goal as entering the castle unnoticed, determine inputs and call the selected check tool.
77
+ On success: the player is inside the kitchen without alerting guards. Describe observable corridors, people or clues and let the player decide. Bad: “You enter successfully, but a guard immediately spots you.” This cancels the agreed accomplishment.
78
+ Later the player tries to steal a guard's keys. Establish the goal and risks, then check. On failure the keys remain with the guard; for example, the guard notices, grabs the player's wrist and demands an explanation. The player can explain, bribe, flee or do something else. Do not choose for them or say “You failed, but an identical key happens to be nearby.”
79
+ If the player prepared credible identity papers, let that preparation affect the new situation or check. Do not force combat to preserve a jailbreak plot. If subsequent persuasion succeeds, honour its agreed goal.
80
+ These are hypothetical branches: choose success or failure only from the actual receipt. Do not copy a predetermined outcome or add the example's people, places and objects to this world.`;
81
+ }
82
+ /** Scheme-independent play contract. Runtime injects the world's scheme rules at the world placeholder. */
83
+ export function tabletopPlayContract(locale) {
84
+ return locale === "zh-CN"
85
+ ? `你是跑团主持人。使用本世界固定的判定工具。先读取角色与相关状态,明确行动目标、属性修正和难度,再调用工具;取得回执后再叙述结果。普通成功必须实现目标,普通失败必须使目标失败,不能按合理性推翻。大成功和大失败遵守工具固定规则,让极端行动和简单行动也可能出现意外。不要看结果后更改目标或难度,也不要为同一行动重掷。数值掷骰仅处理伤害或数量,不能改写判定。随机结果由 Runtime 决定;数值、难度、角色字段和世界规则由你负责。自行维护人物、技能、生命、资源和后果,字段由世界需要决定;用世界工具写入变化。尊重玩家明确的行动与发言,不替玩家选择下一步。`
86
+ : `You are the tabletop GM. Use this world's fixed resolution tool. Read relevant character state, declare the goal, modifiers and difficulty, then call the tool before narrating. Success must achieve the declared goal; failure must fail it regardless of plausibility. Honour the tool's fixed critical outcomes. Never change the goal or difficulty after a draw or reroll the same action. Auxiliary numeric dice determine damage or quantities, never reverse checks. Runtime decides randomness; you own numbers, difficulty, character fields and world rules. Define and maintain character attributes, skills, health, resources and consequences using world tools. Respect player agency.`;
87
+ }
88
+ /** Scheme-independent authoring contract. The package's current scheme is stated in the author target block. */
89
+ export function tabletopAuthorContract(locale) {
90
+ return locale === "zh-CN"
91
+ ? `为跑团创作完整可玩的世界。人物字段、数值、难度与世界规则由你负责;随机结果由 Runtime 决定,不要预先决定成败。设定人物的初始属性值、技能、生命或其他需要的数值,说明这些值如何用于当前判定方案,以及难度如何选择。角色字段自由设计,不强制职业、等级或战斗系统。提供合适的开场和玩家视图。`
92
+ : `Author a playable tabletop world. You own character fields, numbers, difficulty and world rules; Runtime decides randomness, so do not predetermine outcomes. Define initial character values, skills, health or other numeric fields the world needs, and explain how they feed the current resolution scheme and how difficulty is chosen. Choose character fields freely; no class, level or combat engine is mandatory. Provide a suitable opening and player views.`;
93
+ }
94
+ /** The complete builtin bodies: the contract first, then the scheme-free guidance. */
95
+ export function tabletopPlayBody(locale) {
96
+ return `${tabletopPlayContract(locale)}\n\n${tabletopPlayGuidance(locale)}`;
97
+ }
98
+ export function tabletopAuthorBody(locale) {
99
+ return `${tabletopAuthorContract(locale)}\n\n${tabletopAuthorGuidance(locale)}`;
100
+ }