关于 scaffold-gateables
面向现有游戏的技能,用于搭建可由权益检查控制的附加功能,例如皮肤、续玩和每日挑战。它以默认锁定且不影响核心玩法为原则,并通过单一的 isEntitled(key) 接口连接后续权益系统。
主要功能
- 01生成统一权益检查接口
- 02搭建银级与金级功能钩子
- 03通过 EventBus 添加事件
- 04扩展游戏状态与配置
- 05为锁定状态设计正常游戏路径
适用场景
- 01为游戏添加可选皮肤入口
- 02搭建死亡后续玩流程
- 03加入每日挑战或奖励模式
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ playableintelligence/ game-creator --skill scaffold-gateables安装后在 Claude Code 中输入/scaffold-gateables确认已加载。
详细介绍
性能说明
- 提议功能前,先花时间了解游戏
- 质量比速度更重要——错误的门控功能会永久损害游戏
- 不要跳过步骤 4 中的锁定路径验证
搭建门控功能
为现有游戏添加门控功能。此技能会生成 挂钩——皮肤选择器、死亡后继续流程、奖励模式、存档槽位、每日挑战——每项功能都通过 EventBus 接入,并采用单一的能力检查切入点(isEntitled(key))。它不会添加任何特定的变现 SDK(Play.fun、sub.games、Stripe 等);它生成的脚手架可供之后接入任何付费墙、订阅或权益层。
默认状态下,所有功能均处于锁定状态——isEntitled(key) 对所有键都返回 false。游戏在此状态下必须感觉完全正常。下游变现层启用某项权益后,相应的门控功能才会亮起。
核心原则
用这些原则判断哪些提议该接受、哪些该拒绝。这些是规则,而非建议。
- 绝不对核心循环设限。 如果游戏的核心是跳跃,那所有人都能跳。限制皮肤,不限制重力。
- 优先增加内容,而非削减内容。 添加奖励模式;不要缩减免费模式。免费玩家绝不会觉得自己受到了惩罚。
- 契合游戏节奏。 短时游玩 → 按单次游戏会话生效的特权(继续游戏、每日皮肤、每日挑战种子)。长篇游戏 → 持续性内容(存档槽位、解锁树、奖励章节)。
- 仅在 silver 和 gold 档提议 2–3 项门控功能。 Bronze 是默认档——每位玩家默认都能获得 bronze 体验,因此不会在该档搭建任何功能。目标是提供一两项 silver 便利功能和一项 gold 级盛宴。数量仅供参考——建议真正适合游戏的功能。
- 每项门控功能都必须能平稳降级。 当
isEntitled返回false时,游戏必须感觉正常——不能显得出故障或有所缺失。
档位术语
使用游戏中常见的进阶标签:bronze / silver / gold。这样能让此技能不受具体变现方案影响,也更符合玩家的阅读习惯。
Bronze 是默认档——每位玩家默认都是 bronze。 Bronze 体验就是所有人始终都能游玩的核心游戏循环。不会在 bronze 档搭建任何功能;scaffold-gateables 只会生成 silver 和 gold 档的功能。
下游集成层会将 silver/gold 映射到自己的付费档位系统:
| scaffold-gateables | sub.games | Play.fun(基于积分) |
|---|---|---|
| silver | supporter($3–8/mo) | 中等积分门槛 |
| gold | founder($150/yr) | 高积分门槛 |
在步骤 2 的输出中说明此映射,以明确交接给 /subgames 或 /monetize-game 的流程。
说明
用户希望为 $ARGUMENTS 中指定的游戏(若未提供路径,则为当前目录)添加门控功能。路径后还可提供可选提示词(例如 skins continue),以影响提议方向。
步骤 1:了解游戏
- 阅读
package.json——检测引擎(phaser→ Phaser,three→ Three.js)。 - 阅读
src/core/Constants.js、src/core/EventBus.js、src/core/GameState.js。 - 阅读
src/main.js,找到window.render_game_to_text()和协调器入口。 - 如果项目根目录存在
progress.md,则阅读该文件(由/viral-game流程编写)。 - 阅读主要场景/系统文件,了解核心循环。
然后用一句话告诉创作者:
核心循环是
<verb>——我不会对它设限。门控功能将作为额外内容叠加其上。
第 2 步:提出功能建议
围绕五项原则,提出 2–3 个银级和金级的候选门控功能。以 Markdown 表格呈现:
| 功能 | 等级 | 权益键 | 新增内容 | 锁定状态 | EventBus 事件 | GameState 新增字段 |
|---|---|---|---|---|---|---|
| 皮肤选择器 | 银级 | premium_skins | 在 GameOverScene 中通过选择器提供 5 种外观变体 | 仅有默认皮肤;按钮呈灰色 | skin:selected、skin:unlocked | selectedSkin: 'default'、unlockedSkins: ['default'](重置后保留) |
| 死亡后继续 | 银级 | continue | 死亡时提供每局一次的继续机会 | 不显示继续提示;立即重新开始 | continue:offered、continue:accepted | continueOffered: false、usedContinue: false(重置时清除) |
| 每日挑战模式 | 金级 | daily_challenge | 每天生成独特的种子运行,并配有独立排行榜 | 不显示每日挑战菜单 | daily:opened、daily:completed | dailyChallengeSeed: null、dailyBestScore: 0(重置后保留) |
根据原则确定候选项。拒绝任何会锁定核心循环的建议。绝不提出青铜级功能——青铜级是所有人默认享有的。对于短局游戏,优先级为外观 > 便利性 > 奖励 > 持久化;对于长篇游戏则反过来。
交互模式(用户主动调用的技能): 实施前等待创作者确认。允许他们删除、替换或调整建议。
流水线模式(由 /viral-game 第 1.25 步调用): 自动选择排名最高的 2–3 项并继续,不要提示用户。
第 3 步:实施
严格按照以下顺序操作:
3a. 创建 src/systems/Entitlements.js——作为唯一的能力检查接口:
// src/systems/Entitlements.js
// Single capability check for all gateable features.
// Returns false by default — every gateable must degrade cleanly when locked.
// Wire this to your monetization layer (sub.games, Play.fun, custom paywall)
// by replacing the body with real checks. See `/monetize-game` or `/subgames`.
export function isEntitled(key) {
// TODO: wire to monetization layer.
return false;
}
3b. 在 src/core/EventBus.js 中添加事件(仅追加,使用 domain:action 格式)。
3c. 在 src/core/GameState.js 中添加状态字段。更新 reset(),以保留持久字段(例如 unlockedSkins、bonusModeUnlocked),并清除临时字段(例如 usedContinue、continueOffered)。
3d. 在 src/core/Constants.js 的新增 GATEABLES 部分中添加常量(皮肤列表、继续冷却时间、奖励模式配置等)。
3e. 在现有 src/ 子目录中,根据游戏布局创建可门控模块:
src/ui/SkinPicker.js(Phaser 场景或 Three.js 面板)src/systems/ContinueFlow.jssrc/systems/BonusMode.js- 等等
每个可门控功能的入口点都会调用 isEntitled(key) 并进行分支处理:
import { isEntitled } from '../systems/Entitlements.js';
function openSkinPicker() {
if (!isEntitled('premium_skins')) {
// Locked path: greyed-out button with lock icon, no picker opens.
// Default skin remains selected. Game continues normally.
return;
}
// Entitled path: open the picker scene.
scene.scene.launch('SkinPickerScene');
}
绝不要创建游戏开始前的标题画面,也不要采用先选皮肤再开始游戏的流程。 模板会直接启动游戏。可门控 UI 仅从暂停菜单、设置或 GameOverScene 打开。
3f. 在 src/main.js 中以增量方式更新 window.render_game_to_text()——添加新的可观测字段(selectedSkin、continueAvailable、bonusModeActive),但不要移除现有字段。这对 AI 测试框架至关重要。
第 4 步:验证
npm run build无错误。- 运行
npm run dev,并在isEntitled返回false(默认值)时进行游戏。核心循环必须与技能运行前的状态完全一致。 如果有任何功能感觉损坏或缺失,说明你锁定了核心循环——请撤销并修改。 - 临时将
Entitlements.js编辑为对所有键都return true;。确认每项功能都能正确启用,然后恢复原状。 - 如果存在
tests/,且快照通过精确相等(toEqual)检查render_game_to_text(),则更新基准值——新增字段是有意为之。如果测试使用toMatchObject,则无需更新。 - 在项目根目录的
progress.md中追加## Gateables部分,包含:- 添加的功能(名称 + 等级 + 权益键)
- 添加的 EventBus 事件
- 添加的 GameState 字段(标明是持久字段还是临时字段)
- 添加的常量键
- 锁定状态说明(每项功能一行)
故障排除
功能在已授权时正常,但锁定时游戏会出问题
原因: 你限制了核心循环的一部分,或者锁定路径不完整。
修复: 撤销更改。锁定路径必须带来正常的游戏体验。通过让 isEntitled 返回 false 来运行游戏并进行测试——如果有任何内容缺失或出错,请修改。
更新 render_game_to_text 后快照测试失败
原因: 测试对输出使用了精确的 toEqual;你添加了新字段。
修复: 重新生成基线——这些新增内容是有意添加的,对于能容忍额外键的使用方来说向后兼容。
皮肤选择器阻碍首次游玩
原因: 选择器在开始游戏前弹出。 修复: 将入口移至暂停菜单、设置界面或 GameOverScene。模板会直接启动游戏,必须保持如此。
Entitlements.js 已存在
原因: 此技能之前已运行过,或者已经接入了变现层。
修复: 阅读该文件。如果它是存根(return false),请添加新键并继续。如果它已接入实际的变现层,请不要改动现有内容,只通过新增函数分支来添加新的授权键。
提案限制过多或让人感到受罚
原因: 你选择了会限制免费体验的功能。 修复: 原则 2(增益优先于删减)。免费玩家不应因缺少可设门槛的功能而感到受罚。如果移除某项可设门槛的功能会让免费玩家的体验变差,就说明你限制错了功能。
输出
告知用户:
- 新增内容——列出每项可设门槛的功能(名称、层级、授权键)
- 唯一的接入点——指向
src/systems/Entitlements.js并说明:“将某个键对应的isEntitled(key)改为返回true,即可启用该功能。接下来将其接入/monetize-game(Play.fun)或/subgames(订阅)。” - 如何测试——“运行
npm run dev并开始游玩。所有可设门槛的功能默认锁定,但整体体验应当正常。暂时将Entitlements.js改为return true;,即可查看功能启用效果。” - 下一步——根据情况建议使用
/monetize-game或/subgames。
使用示例
当前游戏目录中的默认提案
/scaffold-gateables
结果:读取游戏内容,提出 2–3 项可设门槛的功能,并在获得确认后实现。创建 Entitlements.js、新的 UI 模块、新事件和状态。在接入点启用前,游戏体验不会改变。
带提示的偏向性提案
/scaffold-gateables skins continue
结果:提案会优先考虑皮肤选择器和死亡后继续流程。如果其他建议更适合该游戏,也仍可提出。
指定项目路径
/scaffold-gateables ./examples/flappy-bird
结果:在给定目录而非当前工作目录中操作。
提示
每个游戏运行一次即可。如果之后想添加更多可设门槛的功能,请使用
/add-feature添加特定功能,或再次运行此技能——它会检测现有的Entitlements.js,并且只追加新键。接下来进行集成:
/monetize-game会通过Entitlements.js将 Play.fun 积分接入可设门槛的功能;/subgames(来自subdotgames/skills仓库,需要单独安装)会接入订阅层级。无论采用哪种方式,只需更改Entitlements.js即可启用可设门槛的功能。