From game-creator
Scaffolds monetization-agnostic hooks for gateable features in browser games: skin picker, continue-after-death, bonus mode, save slots, daily challenge. For Phaser 3/Three.js games with EventBus/GameState.
npx claudepluginhub opusgamelabs/game-creator --plugin game-creatorThis skill uses the workspace's default tool permissions.
- Take your time to understand the game before proposing features
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Add gateable features to an existing game. This skill produces hooks — skin pickers, continue-after-death flows, bonus modes, save slots, daily challenges — each wired through EventBus with a single capability-check seam (isEntitled(key)). It does NOT add any specific monetization SDK (Play.fun, sub.games, Stripe, etc.); it produces the scaffolding that any paywall, subscription, or entitlement layer can later switch on.
The default state is everything locked — isEntitled(key) returns false for all keys. The game must feel completely normal in that state. When a downstream monetization layer flips an entitlement on, the gateable feature lights up.
Use these to reason about what to propose and what to reject. They are rules, not guidelines.
isEntitled returning false, the game must feel normal — not broken, not missing.Use game-standard progression labels: bronze / silver / gold. This keeps the skill monetization-agnostic and reads naturally to players.
Bronze is the default tier — every player is bronze by default. The bronze experience IS the core game loop that everyone always gets. No feature is scaffolded at bronze; scaffold-gateables only produces features at silver and gold.
The downstream integration layer maps silver/gold to its own paid tier system:
| scaffold-gateables | sub.games | Play.fun (points-based) |
|---|---|---|
| silver | supporter ($3–8/mo) | mid-threshold points |
| gold | founder ($150/yr) | high-threshold points |
State this mapping in the Step 2 output so the handoff to /subgames or /monetize-game is explicit.
The user wants to add gateables to the game at $ARGUMENTS (or the current directory if no path given). Optional hint tokens after the path (e.g., skins continue) bias the proposal.
package.json — detect engine (phaser → Phaser, three → Three.js).src/core/Constants.js, src/core/EventBus.js, src/core/GameState.js.src/main.js to find window.render_game_to_text() and the orchestrator entry point.progress.md at the project root if it exists (written by the /make-game pipeline).Then tell the creator one sentence:
The core loop is
<verb>— I will not gate it. Gateables will be additive features that layer on top.
Generate 2–3 candidate gateables at silver and gold tiers anchored in the five principles. Present as a Markdown table:
| Feature | Tier | Entitlement key | What it adds | Locked path | EventBus events | GameState additions |
|---|---|---|---|---|---|---|
| Skin picker | silver | premium_skins | 5 cosmetic variants via a picker on GameOverScene | Default skin only; button greyed out | skin:selected, skin:unlocked | selectedSkin: 'default', unlockedSkins: ['default'] (persist through reset) |
| Continue after death | silver | continue | One continue per session offered on death | No continue prompt; immediate restart | continue:offered, continue:accepted | continueOffered: false, usedContinue: false (clear on reset) |
| Daily challenge mode | gold | daily_challenge | Unique seeded run each day with its own leaderboard | No daily challenge menu visible | daily:opened, daily:completed | dailyChallengeSeed: null, dailyBestScore: 0 (persist through reset) |
Anchor picks in the principles. Reject any suggestion that gates the core loop. Never propose bronze-tier features — bronze is the default everyone gets. Prefer cosmetic > convenience > bonus > persistence for short-session games; flip the order for long-form.
In interactive mode (user-invoked skill): wait for creator confirmation before implementing. Let them drop, swap, or tweak suggestions.
In pipeline mode (called from /make-game Step 1.25): auto-pick the top 2–3 and continue without prompting.
Follow this order strictly:
3a. Create src/systems/Entitlements.js — the single capability-check seam:
// 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. Add events to src/core/EventBus.js (append-only, domain:action form).
3c. Add state fields to src/core/GameState.js. Update reset() to preserve persistent fields (e.g., unlockedSkins, bonusModeUnlocked) and clear transient ones (e.g., usedContinue, continueOffered).
3d. Add constants to src/core/Constants.js under a new GATEABLES section (skin list, continue cooldown, bonus mode config, etc.).
3e. Create gateable modules in the existing src/ subdirectories matching the game's layout:
src/ui/SkinPicker.js (Phaser scene or Three.js panel)src/systems/ContinueFlow.jssrc/systems/BonusMode.jsEach gateable's entry point calls isEntitled(key) and branches:
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');
}
Never create a pre-gameplay title screen or skin-picker-first flow. The template boots directly into gameplay. Gateable UI opens from pause menu, settings, or GameOverScene only.
3f. Update window.render_game_to_text() in src/main.js additively — add new observable fields (selectedSkin, continueAvailable, bonusModeActive) without removing existing ones. This is load-bearing for AI test harnesses.
npm run build clean.npm run dev and play with isEntitled returning false (default). Core loop must feel identical to pre-skill state. If anything feels broken or missing, you gated the core loop — revert and revise.Entitlements.js to return true; for all keys. Confirm each feature activates correctly. Revert.tests/ exists and snapshots render_game_to_text() via exact equality (toEqual), update baselines — field additions are intentional. If tests use toMatchObject, no update needed.## Gateables section to progress.md at the project root with:
Cause: You gated part of the core loop, or the locked path is incomplete.
Fix: Revert. The locked path must produce normal-feeling gameplay. Test by running with isEntitled returning false — if anything is missing or broken, revise.
render_game_to_text updateCause: Tests use exact toEqual on output; you added new fields.
Fix: Regenerate baselines — the additions are intentional and backward-compatible for any consumer that tolerates extra keys.
Cause: Picker launches pre-gameplay. Fix: Move entry point to a pause menu, settings screen, or GameOverScene. The template boots directly into gameplay and must continue to do so.
Entitlements.js already existsCause: The skill has been run before, or a monetization layer is already wired.
Fix: Read the file. If it's a stub (return false), add new keys and continue. If it's wired to a real monetization layer, leave it alone and only add the new entitlement keys as new function branches.
Cause: You picked features that restrict the free experience. Fix: Principle 2 (additive over subtractive). Free players should never feel punished by the absence of a gateable. If removing a gateable makes the game feel worse for a free player, it's gating the wrong thing.
Tell the user:
src/systems/Entitlements.js and explain: "Flip isEntitled(key) to return true for a key to activate that feature. Wire it to /monetize-game (Play.fun) or /subgames (subscription) next."npm run dev and play. Everything should feel normal (all gateables locked by default). Edit Entitlements.js to return true; temporarily to see features light up."/monetize-game or /subgames as appropriate./scaffold-gateables
Result: reads the game, proposes 2–3 gateables, implements them after confirmation. Creates Entitlements.js, new UI modules, new events and state. Game feels unchanged until the entitlement seam is flipped.
/scaffold-gateables skins continue
Result: proposal biased toward a skin picker and a continue-after-death flow. Other suggestions still possible if they fit the game better.
/scaffold-gateables ./examples/flappy-bird
Result: operates on the given directory rather than the cwd.
Run this once per game. If you later want to add more gateables, use
/add-featurefor specific additions or run this skill again — it detects existingEntitlements.jsand only appends new keys.Integration comes next:
/monetize-gamewires Play.fun points to gateables viaEntitlements.js;/subgames(from thesubdotgames/skillsrepo, separate install) wires subscription tiers. Either way,Entitlements.jsis the only file that needs to change to turn gateables on.