make-game

安装量: 60
排名: #12397

安装

npx skills add https://github.com/opusgamelabs/game-creator --skill make-game
Make Game (Full Pipeline)
Build a complete browser game from scratch, step by step. This command walks you through the entire pipeline — from an empty folder to a deployed, monetized game. No game development experience needed.
What you'll get:
A fully scaffolded game project with clean architecture
Pixel art sprites — recognizable characters, enemies, and items (optional, replaces geometric shapes)
Visual polish — gradients, particles, transitions, juice
A 50 FPS promo video — autonomous gameplay capture, mobile portrait, ready for social media
Chiptune music and retro sound effects (no audio files needed)
Live deployment to here.now with an instant public URL
Monetization via Play.fun — points tracking, leaderboards, wallet connect, and a play.fun URL to share on Moltbook
Redeploy with a single command (
npm run deploy
)
Quality assurance is built into every step
— each code-modifying step runs build verification, visual review via Playwright MCP, and autofixes any issues found.
Orchestration Model
You are an orchestrator. You do NOT write game code directly.
Your job is to:
Set up the project (template copy, npm install, dev server)
Create and track pipeline tasks using
TaskCreate
/
TaskUpdate
Delegate each code-writing step to a
Task
subagent
Run the Verification Protocol (build + visual review + autofix) after each code-modifying step
Report results to the user between steps
What stays in the main thread:
Step 0: Parse arguments, create todo list
Step 1 (infrastructure only): Copy template, npm install, playwright install, start dev server
Verification protocol orchestration (launch QA subagent, read text result, launch autofix if needed)
Step 4 (deploy): Interactive auth requires user back-and-forth
What goes to subagents
(via
Task
tool):
Step 1 (game implementation): Transform template into the actual game concept
Step 1.5: Pixel art sprites and backgrounds
Step 2: Visual polish
Step 2.5: Promo video capture
Step 3: Audio integration
Each subagent receives: step instructions, relevant skill name, project path, engine type, dev server port, and game concept description.
Verification Protocol
Run this protocol after
every code-modifying step
(Steps 1, 1.5, 2, 3). Step 2.5 (Promo Video) does not modify game code, so it skips QA. It delegates all QA work to a subagent to minimize main-thread context usage.
Playwright MCP Check (once, before first QA run)
Before the first QA run (after Step 1 infrastructure setup), check if Playwright MCP tools like
browser_navigate
are available. If not:
Run:
claude mcp add playwright npx @playwright/mcp@latest
Tell the user: "Playwright MCP has been added. Please restart Claude Code for it to take effect, then tell me to continue."
Wait for user to restart and confirm.
Do not proceed until MCP tools are available.
QA Subagent
Launch a
Task
subagent with these instructions:
You are the QA subagent for the game creation pipeline.
Project path
:
Dev server port
:
Step being verified
:
Run these phases in order. Stop early if a phase fails critically (build or runtime).
Phase 1 — Build Check
cd
<
project-dir
>
&&
npm
run build
If the build fails, report FAIL immediately with the error output.
Phase 2 — Runtime Check
cd
<
project-dir
>
&&
node
scripts/verify-runtime.mjs
If the runtime check fails, report FAIL immediately with the error details.
Phase 3 — Gameplay Verification
cd
<
project-dir
>
&&
node
scripts/iterate-client.js
\
--url
http://localhost:
<
port
>
\
--actions-file scripts/example-actions.json
\
--iterations
3
--screenshot-dir output/iterate
After running, read the state JSON files (
output/iterate/state-*.json
) and error files (
output/iterate/errors-*.json
):
Scoring
At least one state file should show
score > 0
Death
At least one state file should show
mode: "game_over"
. Mark as SKIPPED (not FAIL) if game_over is not reached — some games have multi-life systems or random hazard spawns that make death unreliable in short iterate runs. Death SKIPPED is acceptable and does not block the pipeline.
Errors
No critical errors in error files
Skip this phase if
scripts/iterate-client.js
is not present.
Phase 4 — Architecture Validation
cd
<
project-dir
>
&&
node
scripts/validate-architecture.mjs
Report any warnings but don't fail on architecture issues alone.
Phase 5 — Visual Review via Playwright MCP
Use Playwright MCP to visually review the game. If MCP tools are not available, fall back to reading iterate screenshots from
output/iterate/
.
With MCP:
browser_navigate
to
http://localhost:
browser_wait_for
— wait 2 seconds for the game to load
browser_take_screenshot
— save as
output/qa-gameplay.png
Assess: Are entities visible? Is the game rendering correctly?
Check safe zone: Is any UI hidden behind the top ~8% (Play.fun widget area)?
Check entity sizing: Is the main character large enough (12–15% screen width for character games)?
Wait for game over (or navigate to it),
browser_take_screenshot
— save as
output/qa-gameover.png
Check buttons: Are button labels visible? Blank rectangles = broken button pattern.
Check mute button: Is there a mute toggle visible? If not, flag as ISSUE.
Screenshot timeout
If
browser_take_screenshot
hangs for more than 10 seconds (can happen with continuous WebGL animations), cancel and proceed with code review instead. Do not let a screenshot hang block the entire QA phase.
Note on iterate screenshots
The iterate-client uses
canvas.toDataURL()
which returns blank/black images when Phaser uses WebGL with
preserveDrawingBuffer: false
. Always prefer Playwright MCP viewport screenshots (
browser_take_screenshot
) over iterate screenshots for visual review.
Without MCP (fallback):
Read the iterate screenshots from
output/iterate/shot-*.png
(may be black if WebGL — this is expected)
Fall back to code review: read scene files and assess visual correctness from the code
Return your results in this exact format (text only, no images):
QA RESULT: PASS|FAIL
Phase 1 (Build): PASS|FAIL
Phase 2 (Runtime): PASS|FAIL
Phase 3 (Gameplay): Iterate PASS|FAIL, Scoring PASS|FAIL|SKIPPED, Death PASS|FAIL|SKIPPED, Errors PASS|FAIL
Phase 4 (Architecture): PASS — N/N checks
Phase 5 (Visual): PASS|FAIL —
ISSUES:
-
SCREENSHOTS: output/qa-gameplay.png, output/qa-gameover.png
Orchestrator Flow
Launch QA subagent → read text result
If PASS → proceed to next step
If FAIL → launch autofix subagent with ISSUES list → re-run QA subagent
Max 3 attempts per step
Autofix Logic
When the QA subagent reports FAIL:
Read
output/autofix-history.json
to see what fixes were already attempted. If a previous entry matches the same
issue
and
fix_attempted
with
result: "failure"
, instruct the subagent to try a different approach.
Launch a
fix subagent
via
Task
tool with:
The ISSUES list from the QA result
The phase that failed (build errors, runtime errors, gameplay issues, visual problems)
Any relevant failed attempts from
output/autofix-history.json
so the subagent knows what NOT to repeat
After each autofix attempt
, append an entry to
output/autofix-history.json
:
{
"step"
:
""
,
"issue"
:
""
,
"fix_attempted"
:
""
,
"result"
:
"success|failure"
,
"timestamp"
:
""
}
Re-run the QA subagent (all phases)
Up to
3 total attempts
per step (1 original + 2 retries)
If all 3 attempts fail, report the failure to the user and ask whether to skip or abort
Important
Always fix issues before proceeding to the next step. The autofix loop ensures each step produces working, visually correct output.
Instructions
Step 0: Initialize pipeline
Parse
$ARGUMENTS
to determine the game concept. Arguments can take two forms:
Form A: Direct specification
Engine
:
2d
(Phaser — side-scrollers, platformers, arcade) or
3d
(Three.js — first-person, third-person, open world). If not specified, ask the user.
Name
The game name in kebab-case. If not specified, ask the user what kind of game they want and suggest a name.
Form B: Tweet URL as game concept
If
$ARGUMENTS
contains a tweet URL (matching
x.com//status/
,
twitter.com//status/
,
fxtwitter.com//status/
, or
vxtwitter.com//status/
):
Fetch the tweet
using the
fetch-tweet
skill — convert the URL to
https://api.fxtwitter.com//status/
and fetch with
WebFetch
Default to 2D
(Phaser) — tweets describe ideas that map naturally to 2D arcade/casual games
Creatively abstract a game concept
from the tweet text. Your job is creative transformation — extract themes, dynamics, settings, or mechanics and reinterpret them as a game.
NEVER refuse to make a game from a tweet.
Every tweet contains something that can inspire a game:
News about weather → survival game, storm-dodging game
Sports result → arcade sports game
Political/legal news → strategy game, puzzle game, tower defense
Personal story → narrative adventure, platformer themed around the journey
Product announcement → tycoon game, builder game
Abstract thought → puzzle game, experimental art game
The transformation is the creative act. You are not recreating or trivializing the source — you are using it as a springboard for an original game concept.
Generate a game name
in kebab-case from the abstracted concept (not from literal tweet content)
Tell the user
what you extracted:
Found tweet from
@handle
:
"Tweet text..."
I'll build a 2D game based on this:
[your creative interpretation as a game concept]
Game name:
Sound good?
Wait for user confirmation before proceeding. The user can override the engine (to 3D) or the name at this point.
Celebrity Detection:
After determining the game concept, scan the concept description, tweet text, and any mentioned people for celebrity/public figure names. Check against:
character-library/manifest.json
(relative to plugin root) — exact slug match or name match
Common name recognition — politicians, tech CEOs, world leaders, entertainers
If celebrities are detected:
Set
hasCelebrities = true
and list detected names
Note in
progress.md
which characters are pre-built vs need building
2D
The Step 1.5 subagent will use photo-composite characters for these
3D
For each celebrity, try: (1) generate with Meshy AI —
"a cartoon caricature of , , low poly game character"
then rig for animation, (2) check
3d-character-library/manifest.json
for a pre-built match, (3) search Sketchfab with
find-3d-asset.mjs
, (4) fall back to best-matching library model. Meshy generation produces the best results for named personalities since it can capture specific visual features.
Meshy API Key (3D games only):
If the engine is 3D, check if
MESHY_API_KEY
is set in the environment. If not,
ask the user immediately in Step 0
— don't wait until Step 1.5:
I'll generate custom 3D models with Meshy AI for the best results. You can get a free API key in 30 seconds:
Sign up at
https://app.meshy.ai
Go to Settings → API Keys
Create a new API key
What is your Meshy API key? (Or type "skip" to use generic model libraries instead)
Store the key for all subsequent
meshy-generate.mjs
calls throughout the pipeline.
Create all pipeline tasks upfront using
TaskCreate
:
Scaffold game from template
Add assets: pixel art sprites (2D) or Meshy AI-generated GLB models + animated characters (3D)
Add visual polish (particles, transitions, juice)
Record promo video (autonomous 50 FPS capture)
Add audio (BGM + SFX)
Deploy to here.now
Monetize with Play.fun (register on OpenGameProtocol, add SDK, redeploy)
This gives the user full visibility into pipeline progress at all times. Quality assurance (build, runtime, visual review, autofix) is built into each step, not a separate task.
After creating tasks, create the
output/
directory in the project root and initialize
output/autofix-history.json
as an empty array
[]
. This file tracks all autofix attempts across the pipeline so fix subagents avoid repeating failed approaches.
Step 1: Scaffold the game
Mark task 1 as
in_progress
.
Main thread — infrastructure setup:
Locate the plugin's template directory. Check these paths in order until found:
The agent's plugin cache (e.g.
~/.claude/plugins/cache/local-plugins/game-creator/1.0.0/templates/
)
The
templates/
directory relative to this plugin's install location
Determine the target directory.
If the current working directory is the
game-creator
plugin repository (check for
CLAUDE.md
mentioning "game-creator" or
.claude-plugin/plugin.json
), create the game inside
examples/
(e.g.,
examples//
). Otherwise, create it in the current working directory (
/
).
Copy the entire template directory to the target:
2D: copy
templates/phaser-2d/
/
3D: copy
templates/threejs-3d/
/
Update
package.json
— set
"name"
to the game name
Update
<title>
in
index.html
to a human-readable version of the game name
Verify Node.js/npm availability
Run
node --version && npm --version
to confirm Node.js and npm are installed and accessible. If they fail (e.g., nvm lazy-loading), try sourcing nvm:
export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh"
then retry. If Node.js is not installed at all, tell the user they need to install it before continuing.
Run
npm install
in the new project directory
Install Playwright and Chromium
— Playwright is required for runtime verification and the iterate loop:
Check if Playwright is available:
npx playwright --version
If that fails, check
node_modules/.bin/playwright --version
If neither works, run
npm install -D @playwright/test
explicitly
Then install the browser binary:
npx playwright install chromium
Verify success; if it fails, warn and continue (build verification still works, but runtime/iterate checks will be skipped)
Verify template scripts exist
— The template ships with
scripts/verify-runtime.mjs
,
scripts/iterate-client.js
, and
scripts/example-actions.json
. Confirm they are present. The
verify
and
iterate
npm scripts are already in
package.json
from the template.
Start the dev server
— Before running
npm run dev
, check if the configured port (in
vite.config.js
) is already in use:
lsof -i : -t
. If occupied, update
vite.config.js
to use the next available port (try 3001, 3002, etc.). Then start the dev server in the background and confirm it responds. Keep it running throughout the pipeline. Note the actual port number — pass it to
scripts/verify-runtime.mjs
via the
PORT
env variable in subsequent runs.
Subagent — game implementation:
Launch a
Task
subagent with these instructions:
You are implementing Step 1 (Scaffold) of the game creation pipeline.
Project path
:
Engine
:
<2d|3d>
Game concept
:
Skill to load
:
phaser
(2D) or
threejs-game
(3D)
Core loop first
— implement in this order:
Input (touch + keyboard from the start — never keyboard-only)
Player movement / core mechanic
Fail condition (death, collision, timer)
Scoring
Restart flow (GameState.reset() → clean slate)
Keep scope small:
1 scene, 1 mechanic, 1 fail condition
. Wire spectacle EventBus hooks alongside the core loop — they are scaffolding, not polish.
Transform the template into the game concept:
Rename entities, scenes/systems, and events to match the concept
Implement core gameplay mechanics
Wire up EventBus events, GameState fields, and Constants values
Ensure all modules communicate only through EventBus
All magic numbers go in Constants.js
No title screen
— the template boots directly into gameplay. Do not create a MenuScene or title screen. Only add one if the user explicitly asks.
No in-game score HUD
— the Play.fun widget displays score in a deadzone at the top of the game. Do not create a UIScene or HUD overlay for score display.
Mobile-first input
Choose the best mobile input scheme for the game concept (tap zones, virtual joystick, gyroscope tilt, swipe). Implement touch + keyboard from the start — never keyboard-only. Use the unified analog InputSystem pattern (moveX/moveZ) so game logic is input-source-agnostic.
Force portrait for vertical games
For dodgers, runners, collectors, and endless fallers, set
FORCE_PORTRAIT = true
in Constants.js. This locks portrait layout on desktop (pillarboxed with black bars via
Scale.FIT + CENTER_BOTH
). Use fixed design dimensions (540×960), not conditional
_isPortrait ? 540 : 960
.
Visible touch indicators required
Always render semi-transparent arrow buttons (or direction indicators) on touch-capable devices. Use capability detection (
('ontouchstart' in window) || (navigator.maxTouchPoints > 0)
), NOT OS detection (
device.os.android || device.os.iOS
). Enable pointer events (pointerdown/pointermove/pointerup) on ALL devices — never gate behind
isMobile
. Use
TOUCH
constants from Constants.js for sizing.
Minimum 7–8% canvas width for collectibles/hazards
Items smaller than 7% of
GAME.WIDTH
become unrecognizable blobs on phone screens. Size attacks at ~9%, power-ups at ~7%, player character at 12–15%.
Wire spectacle events: emit
SPECTACLE_ENTRANCE
in
create()
,
SPECTACLE_ACTION
on every player input,
SPECTACLE_HIT
on score/destroy,
SPECTACLE_COMBO
on consecutive hits (pass
{ combo }
),
SPECTACLE_STREAK
at milestones (5, 10, 25 — pass
{ streak }
),
SPECTACLE_NEAR_MISS
on close calls
Visual identity — push the pose:
If the player character represents a real person or brand, build visual recognition into the entity from the start. Don't use generic circles/rectangles as placeholders — use descriptive colors, proportions, and features that communicate identity even before pixel art is added.
Named opponents/NPCs must have visual presence on screen — never text-only. At minimum use distinct colored shapes that suggest the brand. Better: simple character forms with recognizable features.
Collectibles and hazards must be visually self-explanatory. Avoid abstract concepts ("imagination blocks", "creativity sparks"). Use concrete objects players instantly recognize (polaroids, trophies, lightning bolts, money bags, etc.).
Think: "Could someone screenshot this and immediately know what the game is about?"
NEVER
use a single letter (C, G, O) as a character's visual identity
NEVER
differentiate two characters only by fill color — they must have distinct silhouettes and features
When a company is featured (OpenAI, Anthropic, xAI, etc.), use the CEO as the character: Altman for OpenAI, Amodei for Anthropic, Musk for xAI, Zuckerberg for Meta, Nadella for Microsoft, Pichai for Google, Huang for NVIDIA
Add entrance sequence in
create()
player starts off-screen, tweens into position with Bounce.easeOut , landing shake + particle burst Add combo tracking to GameState: combo (current streak, resets on miss), bestCombo (session high), both reset in reset() Ensure restart is clean — test mentally that 3 restarts in a row would work identically Add isMuted to GameState for mute support CRITICAL — Preserve the button pattern: The template's GameOverScene.js contains a working createButton() helper (Container + Graphics + Text). Do NOT rewrite this method. Keep it intact or copy it into any new scenes that need buttons. The correct z-order is: Graphics first (background), Text second (label), Container interactive. If you put Graphics on top of Text, the text becomes invisible. If you make the Graphics interactive instead of the Container, hover/press states break. Character & entity sizing: Character WIDTH from GAME.WIDTH * ratio , HEIGHT from WIDTH * SPRITE_ASPECT (where const SPRITE_ASPECT = 1.5 for 200×300 spritesheets). Never define character HEIGHT as GAME.HEIGHT * ratio — on mobile portrait, GAME.HEIGHT is much larger than GAME.WIDTH , squishing characters. For character-driven games (named personalities, mascots, famous figures): make the main character prominent — GAME.WIDTH * 0.12 to GAME.WIDTH * 0.15 (12–15% of screen width). Use caricature proportions (large head = 40–50% of sprite height, exaggerate distinguishing features) for personality games. Non-character entities (projectiles, collectibles, squares) can use GAME.WIDTH * ratio for both dimensions since they have no intrinsic aspect ratio to preserve. Play.fun safe zone: Import SAFE_ZONE from Constants.js . All UI text, buttons, and interactive elements (title text, score panels, restart buttons) must be positioned below SAFE_ZONE.TOP . The Play.fun SDK renders a 75px widget bar at the top of the viewport (z-index 9999). Use safeTop + usableH * ratio for proportional positioning within the usable area (where usableH = GAME.HEIGHT - SAFE_ZONE.TOP ). Generate game-specific test actions: After implementing the core loop, overwrite scripts/example-actions.json with actions tailored to this game. Requirements: Use the game's actual input keys (e.g., ArrowLeft/ArrowRight for dodger, space for flappy, w/a/s/d for top-down) Include enough gameplay to score at least 1 point Include a long idle period (60+ frames with no input) to let the fail condition trigger Total should be at least 150 frames of gameplay Example for a dodge game (arrow keys): [ { "buttons" : [ "ArrowRight" ] , "frames" : 20 } , { "buttons" : [ "ArrowLeft" ] , "frames" : 20 } , { "buttons" : [ "ArrowRight" ] , "frames" : 15 } , { "buttons" : [ ] , "frames" : 10 } , { "buttons" : [ "ArrowLeft" ] , "frames" : 20 } , { "buttons" : [ ] , "frames" : 80 } ] Example for a platformer (space to jump): [ { "buttons" : [ "space" ] , "frames" : 4 } , { "buttons" : [ ] , "frames" : 25 } , { "buttons" : [ "space" ] , "frames" : 4 } , { "buttons" : [ ] , "frames" : 25 } , { "buttons" : [ "space" ] , "frames" : 4 } , { "buttons" : [ ] , "frames" : 80 } ] Before returning, write /design-brief.md :

Design Brief

Concept

One-line game concept.

Core Mechanics

For each mechanic: - Name: what it does - State field: which GameState field it affects - Expected magnitude: how much/fast it should change (e.g., "reaches 50-70% of max within the round duration without player input")

Win/Lose Conditions

  • How the player wins
  • How the player loses
  • Confirm both outcomes are realistically achievable with the current Constants.js values

Entity Interactions

For each visible entity (enemies, projectiles, collectibles, environmental objects): - Name: what it is - Visual identity: what it should LOOK like and why (reference real logos, people, objects — not abstract concepts) - Distinguishing feature: the ONE exaggerated feature visible at thumbnail size (e.g., "curly dark hair + glasses" for Amodei, "leather jacket" for Jensen Huang) - Real image asset: logo URL to download, or "pixel art" if no real image applies - Behavior: what it does (moves, falls, spawns, etc.) - Player interaction: how the player interacts with it (dodge, collect, tap, block, or "none — background/decoration") - AI/opponent interaction: how the opponent interacts with it, if applicable For named people: describe hair, glasses, facial hair, clothing. For companies: specify logo to download. NEVER use a letter or text label as visual identity.

Expression Map

For each personality character, map game events to expressions:

Player: [Name]

Game Event Expression Why
Idle/default normal Resting state
Score point / collect item happy Positive reinforcement
Take damage / lose life angry Visceral reaction
Power-up / special event surprised Excitement
Win / game over (high score) happy Celebration
Lose / game over (low score) angry Defeat
### Opponent: [Name]
Game Event Expression Why
--- --- ---
Idle/default normal Resting state
Player scores angry Frustrated at losing
Opponent scores happy Gloating
Near-miss / close call surprised Tension
Do NOT start a dev server or run builds — the orchestrator handles that.
After subagent returns
, run the Verification Protocol.
Create
progress.md
at the game's project root. Read the game's actual source files to populate it accurately:
Read
src/core/EventBus.js
for the event list
Read
src/core/Constants.js
for the key sections (GAME, PLAYER, ENEMY, etc.)
List files in
src/entities/
for entity names
Read
src/core/GameState.js
for state fields
Write
progress.md
with this structure:
#
Progress
##
Game Concept
-
**
Name
**
: [game name from project]
-
**
Engine
**
: Phaser 3 / Three.js
-
**
Description
**
: [from user's original prompt]
##
Step 1: Scaffold
-
**
Entities
**
: [list entity names from src/entities/]
-
**
Events
**
: [list event names from EventBus.js]
-
**
Constants keys
**
: [top-level sections from Constants.js, e.g. GAME, PLAYER, ENEMY, COLORS]
-
**
Scoring system
**
: [how points are earned, from GameState + scene logic]
-
**
Fail condition
**
: [what ends the game]
-
**
Input scheme
**
: [keyboard/mouse/touch controls implemented]
##
Decisions / Known Issues
-
[any notable decisions or issues from scaffolding]
Tell the user:
Your game is scaffolded and running! Here's how it's organized:
src/core/Constants.js
— all game settings (speed, colors, sizes)
src/core/EventBus.js
— how parts of the game talk to each other
src/core/GameState.js
— tracks score, lives, etc.
Mobile controls are built in
— works on phone (touch/tilt) and desktop (keyboard)
Next up: pixel art.
I'll create custom pixel art sprites for every character, enemy, item, and background tile — all generated as code, no image files needed. Then I'll add visual polish on top.
Mark task 1 as
completed
.
Wait for user confirmation before proceeding.
Step 1.5: Add game assets
Always run this step for both 2D and 3D games.
2D games get pixel art sprites; 3D games get GLB models and animated characters.
Mark task 2 as
in_progress
.
Pre-step: Character Library Check
Before launching the asset subagent, check if the game uses personality characters. For each personality, resolve their sprites using this
tiered fallback
(try each tier in order, stop at the first success):
1. Read
design-brief.md
to identify personality characters and their slugs.
2. Resolve the character library path
— find
character-library/manifest.json
relative to the plugin root:
Check
character-library/manifest.json
relative to the plugin install directory
Check common plugin cache paths (e.g.,
~/.claude/plugins/cache/local-plugins/game-creator/*/character-library/
)
3. For each personality, try these tiers in order:
Tier 1 — Pre-built (best)
: Check if slug exists in
manifest.json
. If yes, copy sprites:
mkdir
-p
<
project-dir
>
/public/assets/characters/
<
slug
>
/
cp
<
plugin-root
>
/character-library/characters/
<
slug
>
/sprites/*
\
<
project-dir
>
/public/assets/characters/
<
slug
>
/
Result: 4-expression spritesheet ready. Done.
Tier 2 — Build from 4 images (good)
: WebSearch for 4 expression photos.
Any photo format works
(jpg, png, webp) — the pipeline has ML background removal built in, so transparent PNGs are NOT required. Search broadly:
normal:
" portrait photo"
or
" face"
— neutral expression
happy:
" smiling"
or
" laughing"
angry:
" angry"
or
" serious stern"
surprised:
" surprised"
or
" shocked"
Prefer real photographs (not illustrations/cartoons). Head shots and half-body shots both work —
crop-head.mjs
uses face detection to isolate the face automatically. Download as
normal.jpg
,
happy.jpg
, etc. (any image extension).
If all 4 found, download to
/public/assets/characters//raw/
and run:
node
<
plugin-root
>
/scripts/build-character.mjs
""
\
<
project-dir
>
/public/assets/characters/
<
slug
>
/ --skip-find
Result: 4-expression spritesheet. Done.
Tier 3 — Build from 1-3 images (acceptable)
: If WebSearch only finds 1-3 usable images:
Download whatever was found to
raw/
(e.g., only
normal.png
and
happy.png
)
Duplicate the best image
(prefer normal) into the missing expression slots:
cp
raw/normal.png raw/angry.png
# fill missing with normal
cp
raw/normal.png raw/surprised.png
Run
build-character.mjs
as above — all 4 raw slots are filled, pipeline produces a 4-frame spritesheet
Result: 4-frame spritesheet where some expressions share the same face. Functional — the expression system still works, just with less visual variety.
Tier 4 — Single image fallback (minimum)
: If WebSearch finds exactly 1 image OR the pipeline fails on some images:
Use the single successful image for all 4 expression slots
Run
build-character.mjs
— produces a spritesheet where all 4 frames are identical
Result: Character is recognizable but has no expression changes. Still photo-composite, still works with the expression wiring (just no visible change).
Tier 5 — Generative pixel art (worst case)
: If NO images can be found or the ENTIRE pipeline fails (bg removal crash, face detection fails on all images, network errors):
Fall back to the
Personality Character (Caricature) archetype
from the
game-assets
skill — 32x48 pixel art grid at scale 4
Note in
progress.md
:
": pixel art fallback — no photo-composite available"
The subagent will create pixel art with recognizable features (hair, glasses, clothing) per the game-assets sprite design rules
Result: No photo-composite, but the character is still visually distinct via pixel art caricature.
4. Record results
for each character in
progress.md
:
## Characters
- trump: Tier 1 (pre-built, 4 expressions)
- karpathy: Tier 3 (1 image found, duplicated to 4 slots)
- some-ceo: Tier 5 (pixel art fallback)
5. Pass to subagent
: the list of character slugs, which tier each resolved to, and how many unique expressions each has. The subagent needs this to know whether to wire full expression changes or skip expression logic for Tier 5 characters.
Launch a
Task
subagent with these instructions:
You are implementing Step 1.5 (Pixel Art Sprites) of the game creation pipeline.
Project path
:
Engine
: 2D (Phaser 3)
Skill to load
:
game-assets
Read
progress.md
at the project root before starting. It describes the game's entities, events, constants, and scoring system from Step 1.
Character library sprites are already copied
to
public/assets/characters//
. For personality characters, load the spritesheet and wire expression changes per the game-assets skill's "Expression Wiring Pattern". Add
EXPRESSION
and
EXPRESSION_HOLD_MS
to Constants.js. Wire expression changes to EventBus events per the Expression Map in
design-brief.md
.
Follow the game-assets skill fully for non-personality entities:
Read all entity files (
src/entities/
) to find
generateTexture()
/
fillCircle()
calls
Choose the palette that matches the game's theme (DARK, BRIGHT, or RETRO)
Create
src/core/PixelRenderer.js
— the
renderPixelArt()
+
renderSpriteSheet()
utilities
Create
src/sprites/palette.js
with the chosen palette
Create sprite data files (
player.js
,
enemies.js
,
items.js
,
projectiles.js
) with pixel matrices
Create
src/sprites/tiles.js
with background tiles (ground variants, decorative elements)
Create or update the background system to use tiled pixel art instead of flat colors/grids
Update entity constructors to use pixel art instead of geometric shapes
Add Phaser animations for entities with multiple frames
Adjust physics bodies for new sprite dimensions
Character prominence
: If the game features a real person or named personality, use the Personality Character (Caricature) archetype — 32x48 grid at scale 4 (renders to 128x192px, ~35% of canvas height). The character must be the visually dominant element on screen. Supporting entities stay at Medium (16x16) or Small (12x12) to create clear visual hierarchy.
Push the pose — thematic expressiveness:
Sprites must visually embody who/what they represent. A sprite for "Grok AI" should look like Grok (logo features, brand colors, xAI aesthetic) — not a generic robot or colored circle.
For real people: exaggerate their most recognizable features (signature hairstyle, glasses, facial hair, clothing). Recognition IS the meme hook.
For brands/products: incorporate logo shapes, brand colors, and distinctive visual elements into the sprite design.
For game objects: make them instantly recognizable. A "power-up" should look like the specific thing it represents in the theme, not a generic star or diamond.
Opponents should be visually distinct from each other — different colors, shapes, sizes, and personality. A player should tell them apart at a glance.
Self-audit before returning
— check every personality sprite against these:
Does each sprite have distinct hair (not a solid-color dome)?
Does each sprite have facial features beyond just eyes (glasses, facial hair, or clothing details if applicable)?
Would two character sprites look different if rendered in the same color?
Is any
scene.add.text()
being used as the primary identifier? If so, remove it and add physical features instead.
Does the head region (rows 0-28) use at least 4 distinct palette indices?
For brand entities: was a real logo downloaded and loaded? If not, why?
After completing your work
, append a
## Step 1.5: Assets
section to
progress.md
with: palette used, sprites created, any dimension changes to entities.
Do NOT run builds — the orchestrator handles verification.
After 2D subagent returns
, run the Verification Protocol.
3D Asset Flow (Three.js games)
For 3D games, generate custom models with Meshy AI and integrate them as animated characters and world props. This is the 3D parallel of the 2D pixel art step above.
Pre-step: Character & Asset Generation
The Meshy API key should already be obtained in Step 0. If not set, ask now (see Step 0 instructions).
Read
design-brief.md
to identify all characters (player + opponents/NPCs) and their names/descriptions.
For EACH humanoid character, run the full generate→rig pipeline as ONE atomic step:
Tier 1 — Generate + Rig with Meshy AI
(preferred): This is a TWO-command chain — always run BOTH for humanoid characters. The rig step auto-downloads walk/run animation GLBs.
# Step A: Generate the character model
MESHY_API_KEY
=
<
key
>
node
<
plugin-root
>
/scripts/meshy-generate.mjs
\
--mode
text-to-3d
\
--prompt
"a stylized , low poly game character, full body"
\
--polycount
15000
--pbr
\
--output
<
project-dir
>
/public/assets/models/
--slug
<
character-slug
>
# Step B: Read the refineTaskId from meta, then rig immediately
# The rig command auto-downloads walk/run GLBs as -walk.glb and -run.glb
REFINE_ID
=
$(
python3
-c
"import json
;
print
(
json.load
(
open
(
'/public/assets/models/.meta.json'
)
)
[
'refineTaskId'
]
)
"
)
MESHY_API_KEY
=
<
key
>
node
<
plugin-root
>
/scripts/meshy-generate.mjs
\
--mode
rig --task-id
$REFINE_ID
--height
1.7
\
--output
<
project-dir
>
/public/assets/models/
--slug
<
character-slug
>
After this completes you have 3 files per character:
.glb
— rigged model with skeleton (use
loadAnimatedModel()
+
SkeletonUtils.clone()
)
-walk.glb
— walking animation (auto-downloaded)
-run.glb
— running animation (auto-downloaded)
NEVER generate humanoid characters without rigging.
Static models require hacky programmatic animation that looks artificial.
For named personalities, be specific:
"a cartoon caricature of Trump, blonde hair, suit, red tie, low poly game character, full body"
.
For multiple characters, generate each with a distinct description for visual variety. Run generate→rig in parallel for different characters to save time.
Tier 2 — Pre-built in
3d-character-library/
(Meshy unavailable): Check
manifest.json
for a name/theme match. Copy the GLB:
cp
<
plugin-root
>
/3d-character-library/models/
<
model
>
.glb
\
<
project-dir
>
/public/assets/models/
<
slug
>
.glb
Tier 3 — Search Sketchfab
: Use
find-3d-asset.mjs
to search for a matching animated model:
node
<
plugin-root
>
/scripts/find-3d-asset.mjs
\
--query
" animated character"
\
--max-faces
10000
--list-only
Tier 4 — Generic library fallback
: Use the best match from
3d-character-library/
:
Soldier
— action/military/default human
Xbot
— sci-fi/tech/futuristic
RobotExpressive
— cartoon/casual/fun (most animations)
Fox
— nature/animal
When 2+ characters fall back to library, use different models to differentiate them.
3. Generate / search for world objects
— Read
design-brief.md
entity list:
# With Meshy (preferred) — generate each prop
MESHY_API_KEY
=
<
key
>
node
<
plugin-root
>
/scripts/meshy-generate.mjs
\
--mode
text-to-3d
\
--prompt
"a , low poly game asset"
\
--polycount
5000
\
--output
<
project-dir
>
/public/assets/models/
--slug
<
entity-slug
>
# Without Meshy — search free libraries
node
<
plugin-root
>
/scripts/find-3d-asset.mjs
--query
""
\
--source
polyhaven
--output
<
project-dir
>
/public/assets/models/
4. Record results
in
progress.md
:
## 3D Characters
- knight (player): Tier 1 — Meshy AI generated + rigged (idle/walk/run)
- goblin (enemy): Tier 1 — Meshy AI generated + rigged (idle/walk/run)
## 3D Assets
- tree: Meshy AI generated (static prop)
- barrel: Meshy AI generated (static prop)
- house: Poly Haven fallback (CC0)
Launch a
Task
subagent with these instructions:
You are implementing Step 1.5 (3D Assets) of the game creation pipeline.
Project path
:
Engine
: 3D (Three.js)
Skill to load
:
game-3d-assets
and
meshyai
Read
progress.md
at the project root before starting. It lists generated/downloaded models and the character details.
Rigged character GLBs + animation GLBs are already in
public/assets/models/
. Set up the character controller:
Create
src/level/AssetLoader.js
CRITICAL: use
SkeletonUtils.clone()
for rigged models
(regular
.clone()
breaks skeleton bindings → T-pose). Import from
three/addons/utils/SkeletonUtils.js
.
Add
MODELS
config to
Constants.js
with:
path
(rigged GLB),
walkPath
,
runPath
,
scale
,
rotationY
per model.
Start with
rotationY: Math.PI
— most Meshy models face +Z and need flipping.
For each rigged model:
Load with
loadAnimatedModel()
, create
AnimationMixer
Load walk/run animation GLBs separately, register their clips as mixer actions
Log all clip names:
console.log('Clips:', clips.map(c => c.name))
Store mixer and actions in entity's
userData
Call
mixer.update(delta)
every frame
Use
fadeToAction()
pattern for smooth transitions
For static models (ring, props): use
loadModel()
(regular clone)
Orientation & scale verification (MANDATORY):
After loading each model, log its bounding box size
Compute auto-scale to fit target height and container bounds
Align feet to floor:
position.y = -box.min.y
Characters must face each other / the correct direction
— adjust
rotationY
in Constants
Characters must fit inside their environment
(ring, arena, platform)
Position characters close enough to interact (punch range, not across the arena)
Add primitive fallback in
.catch()
for every model load
After completing your work
, append a
## Step 1.5: 3D Assets
section to
progress.md
with: models used (Meshy-generated vs library), scale/orientation adjustments, verified facing directions.
Do NOT run builds — the orchestrator handles verification.
After 3D subagent returns
, run the Verification Protocol.
Tell the user (2D):
Your game now has pixel art sprites and backgrounds! Every character, enemy, item, and background tile has a distinct visual identity. Here's what was created:
src/core/PixelRenderer.js
— rendering engine
src/sprites/
— all sprite data, palettes, and background tiles
Tell the user (3D):
Your game now has custom 3D models! Characters were generated with Meshy AI (or sourced from the model library), rigged, and animated with walk/run/idle. Props and scenery are loaded from GLB files. Here's what was created:
src/level/AssetLoader.js
— model loader with SkeletonUtils
public/assets/models/
— Meshy-generated and/or library GLB models
OrbitControls camera with WASD movement
Next up: visual polish.
I'll add particles, screen transitions, and juice effects. Ready?
Mark task 2 as
completed
.
Wait for user confirmation before proceeding.
Step 2: Design the visuals
Mark task 3 as
in_progress
.
Launch a
Task
subagent with these instructions:
You are implementing Step 2 (Visual Design — Spectacle-First) of the game creation pipeline.
Project path
:
Engine
:
<2d 3d>
Skill to load
:
game-designer
Read
progress.md
at the project root before starting. It describes the game's entities, events, constants, and what previous steps have done.
Apply the game-designer skill with spectacle as the top priority. Work in this order:
1. Opening Moment (CRITICAL — this determines promo clip success):
Entrance flash:
cameras.main.flash(300)
on scene start
Player slam-in: player starts off-screen, tweens in with
Bounce.easeOut
, landing shake (0.012) + particle burst (20 particles)
Ambient particles active from frame 1 (drifting motes, dust, sparkles)
Optional flavor text (e.g., "GO!", "DODGE!") — only when it naturally fits the game's vibe
Verify: the first 3 seconds have zero static frames
2. Every-Action Effects (wire to SPECTACLE_
events from Step 1):
*
Particle burst (12-20 particles) on
SPECTACLE_ACTION
and
SPECTACLE_HIT
Floating score text (28px, scale 1.8,
Elastic.easeOut
) on
SCORE_CHANGED
Background pulse (additive blend, alpha 0.15) on
SCORE_CHANGED
Persistent player trail (particle emitter following player,
blendMode: ADD
)
Screen shake (0.008-0.015) on hits
3. Combo & Streak System (wire to SPECTACLE_COMBO / SPECTACLE_STREAK):
Combo counter text that scales with combo count (32px base, +4px per combo)
Streak milestone announcements at 5x, 10x, 25x (full-screen text slam + 40-particle burst)
Hit freeze frame (60ms physics pause) on destruction events
Shake intensity scales with combo (0.008 + combo * 0.002, capped at 0.025)
4. Standard Design Audit:
Full 10-area audit (background, palette, animations, particles, transitions, typography, game feel, game over, character prominence, first impression / viral appeal)
Every area must score 4 or higher
— improve any that fall below
First Impression / Viral Appeal is the most critical category
5. Intensity Calibration:
Particle bursts: 12-30 per event (never fewer than 10)
Screen shake: 0.008 (light) to 0.025 (heavy)
Floating text: 28px minimum, starting scale 1.8
Flash overlays: alpha 0.3-0.5
All new values go in Constants.js, use EventBus for triggering effects
Don't alter gameplay mechanics
After completing your work
, append a
## Step 2: Design
section to
progress.md
with: improvements applied, new effects added, any color or layout changes.
Do NOT run builds — the orchestrator handles verification.
After subagent returns
, run the Verification Protocol.
Tell the user:
Your game looks much better now! Here's what changed: [summarize changes]
Next up: promo video.
I'll autonomously record a 50 FPS gameplay clip in mobile portrait — ready for social media. Then we'll add music and sound effects.
Mark task 3 as
completed
.
Proceed directly to Step 2.5
— no user confirmation needed (promo video is non-destructive and fast).
Step 2.5: Record promo video
Mark task 4 as
in_progress
.
This step stays in the main thread.
It does not modify game code — it records autonomous gameplay footage using Playwright and converts it with FFmpeg. No QA verification needed.
Pre-check: FFmpeg availability
ffmpeg
-version
head
-1
If FFmpeg is not found, warn the user and skip this step:
FFmpeg is not installed. Skipping promo video. Install it with
brew install ffmpeg
(macOS) or
apt install ffmpeg
(Linux), then run
/game-creator:promo-video
later.
Mark task 4 as
completed
and proceed to Step 3.
Copy the conversion script
from the plugin:
cp
<
plugin-root
>
/skills/promo-video/scripts/convert-highfps.sh
<
project-dir
>
/scripts/
chmod
+x
<
project-dir
>
/scripts/convert-highfps.sh
Launch a
Task
subagent
to generate the game-specific capture script:
You are implementing Step 2.5 (Promo Video) of the game creation pipeline.
Project path
:
Dev server port
:
Skill to load
:
promo-video
Read
progress.md
and the following source files to understand the game:
src/scenes/GameScene.js
— find the death/failure method(s) to patch out
src/core/EventBus.js
— understand event flow
src/core/Constants.js
— check input keys, game dimensions
src/main.js
— verify
GAME
and
GAME_STATE
are exposed
Create
scripts/capture-promo.mjs
following the
promo-video
skill template. You MUST adapt these game-specific parts:
Death patching
— identify ALL code paths that lead to game over and monkey-patch them. Search for
triggerGameOver
,
gameOver
,
takeDamage
,
playerDied
,
onPlayerHit
, or any method that sets
gameState.gameOver = true
. Patch every one.
Input sequence
— determine the actual input keys from the game's input handling (look for
createCursorKeys()
,
addKeys()
,
input.on('pointerdown')
, etc.). Generate a
generateInputSequence(totalMs)
function that produces natural-looking gameplay for this specific game type:
Dodger
(left/right): Alternating holds with variable timing, occasional double-taps
Platformer
(jump): Rhythmic taps with varying gaps
Shooter
(move + fire): Interleaved movement and fire inputs
Top-down
(WASD): Figure-eight or sweep patterns
Entrance pause
— include a 1-2s pause at the start so the entrance animation plays (this is the visual hook).
Viewport
— always
{ width: 1080, height: 1920 }
(9:16 mobile portrait) unless the game is desktop-only landscape.
Duration
— 13s of game-time by default. For slower-paced games (puzzle, strategy), use 8-10s.
Config
: The script must accept
--port
,
--duration
, and
--output-dir
CLI args with sensible defaults.
Do NOT run the capture
— just create the script. The orchestrator runs it.
After subagent returns
, run the capture and conversion from the main thread:
# Ensure output directory exists
mkdir
-p
<
project-dir
>
/output
# Run capture (takes ~26s for 13s game-time at 0.5x)
node
scripts/capture-promo.mjs
--port
<
port
>
# Convert to 50 FPS MP4
bash
scripts/convert-highfps.sh output/promo-raw.webm output/promo.mp4
0.5
Verify the output:
Check
output/promo.mp4
exists and is non-empty
Verify duration is approximately
DESIRED_GAME_DURATION / 1000
seconds
Verify frame rate is 50 FPS
If capture fails (Playwright error, timeout, etc.), warn the user and skip — the promo video is a nice-to-have, not a blocker.
Extract a thumbnail
for the user to preview:
ffmpeg
-y
-ss
5
-i
output/promo.mp4
-frames:v
1
-update
1
output/promo-thumbnail.jpg
Read the thumbnail image and show it to the user.
Tell the user:
Promo video recorded! 50 FPS, mobile portrait (1080x1920).
File
:
output/promo.mp4
([duration]s, [size])
This was captured autonomously — the game ran at 0.5x, recorded at 25 FPS, then FFmpeg sped it up to 50 FPS. Death was patched out so it shows continuous gameplay.
Next up: music and sound effects.
Ready?
Mark task 4 as
completed
.
Wait for user confirmation before proceeding.
Step 3: Add audio
Mark task 5 as
in_progress
.
Launch a
Task
subagent with these instructions:
You are implementing Step 3 (Audio) of the game creation pipeline.
Project path
:
Engine
:
<2d 3d>
Skill to load
:
game-audio
Read
progress.md
at the project root before starting. It describes the game's entities, events, constants, and what previous steps have done.
Apply the game-audio skill:
Audit the game: read EventBus events, read all scenes
Create
src/audio/AudioManager.js
— AudioContext init, master gain, BGM sequencer play/stop
Create
src/audio/music.js
— BGM patterns as note arrays using the Web Audio step sequencer
Create
src/audio/sfx.js
— SFX using Web Audio API (OscillatorNode + GainNode + BiquadFilterNode)
Create
src/audio/AudioBridge.js
— wire EventBus events to audio
Add audio events to EventBus.js (including
AUDIO_TOGGLE_MUTE
)
Wire audio into main.js and all scenes
Mute toggle
: Wire
AUDIO_TOGGLE_MUTE
to master gain. Add M key shortcut and a speaker icon UI button. See the game-audio skill "Mute Button" section for requirements and drawing code.
No npm packages needed
— all audio uses the built-in Web Audio API
After completing your work
, append a
## Step 3: Audio
section to
progress.md
with: BGM patterns added, SFX event mappings, mute wiring confirmation.
Do NOT run builds — the orchestrator handles verification.
After subagent returns
, run the Verification Protocol.
Tell the user:
Your game now has music and sound effects! Click/tap once to activate audio, then you'll hear the music.
Next up: deploy to the web.
I'll publish your game to here.now for an instant public URL. Ready?
Mark task 5 as
completed
.
Wait for user confirmation before proceeding.
Step 4: Deploy to here.now
Mark task 6 as
in_progress
.
Load the game-deploy skill.
This step stays in the main thread
because it may require user back-and-forth for API key setup.
6a. Check prerequisites
Verify the here-now skill is installed:
ls
~/.agents/skills/here-now/scripts/publish.sh
If not found
, tell the user:
The here-now skill is needed for deployment. Install it with:
npx skills add heredotnow/skill --skill here-now -g -y
Tell me when you're ready.
Wait for the user to confirm.
6b. Build the game
npm
run build
Verify
dist/
exists and contains
index.html
and assets. If the build fails, fix the errors before proceeding.
6c. Verify the Vite base path
Read
vite.config.js
. For here.now, the
base
should be
'/'
(the default). If it's set to something else (e.g., a GitHub Pages subdirectory path), update it:
export
default
defineConfig
(
{
base
:
'/'
,
// ... rest of config
}
)
;
Rebuild after changing the base path.
6d. Publish to here.now
~/.agents/skills/here-now/scripts/publish.sh dist/
The script outputs the live URL immediately (e.g.,
https://.here.now/
).
Read and follow
publish_result.*
lines from script stderr. Save the slug for future updates.
If anonymous (no API key):
The publish expires in
24 hours and will be permanently deleted
unless the user claims it. The script returns a claim URL.
You MUST immediately tell the user:
ACTION REQUIRED — your game will be deleted in 24 hours!
Visit your claim URL to create a free here.now account and keep your game online permanently.
The claim token is only shown once and cannot be recovered. Do this now before you forget!
Then proceed to 6e to help them set up permanent hosting.
If authenticated:
The publish is permanent. Skip 6e.
6e. Set up permanent hosting
This step is strongly recommended for anonymous publishes.
Help the user create a here.now account so their game stays online:
Ask for their email
Send magic link:
curl
-sS
https://here.now/api/auth/login
-H
"content-type: application/json"
-d
'{"email": "user@example.com"}'
Tell the user: "Check your inbox for a sign-in link from here.now. Click it, then copy your API key from the dashboard."
Save the key:
mkdir
-p
~/.herenow
&&
echo
""
>
~/.herenow/credentials
&&
chmod
600
~/.herenow/credentials
Re-publish to make it permanent:
~/.agents/skills/here-now/scripts/publish.sh dist/
--slug
<
slug
>
6f. Verify the deployment
curl
-s
-o
/dev/null
-w
"%{http_code}"
"https://.here.now/"
Should return 200 immediately (here.now deploys are instant).
6g. Add deploy script
Add a
deploy
script to
package.json
so future deploys are one command:
{
"scripts"
:
{
"deploy"
:
"npm run build && ~/.agents/skills/here-now/scripts/publish.sh dist/"
}
}
Tell the user (if authenticated):
Your game is live!
URL
:
https://.here.now/
Redeploy after changes
: Just run:
npm run deploy
Or if you're working with me, I'll rebuild and redeploy for you.
Next up: monetization.
I'll register your game on Play.fun (OpenGameProtocol), add the points SDK, and redeploy. Players earn rewards, you get a play.fun URL to share on Moltbook. Ready?
Tell the user (if anonymous — no API key):
Your game is live!
URL
:
https://.here.now/
IMPORTANT: Your game will be deleted in 24 hours unless you claim it!
Visit your claim URL to create a free here.now account and keep your game online forever.
The claim token is only shown once — save it now!
Redeploy after changes
: Just run:
npm run deploy
Next up: monetization.
I'll register your game on Play.fun (OpenGameProtocol), add the points SDK, and redeploy. Players earn rewards, you get a play.fun URL to share on Moltbook. Ready?
Mark task 6 as
completed
.
Wait for user confirmation before proceeding.
Step 5: Monetize with Play.fun
Mark task 7 as
in_progress
.
This step stays in the main thread
because it requires interactive authentication.
7a. Authenticate with Play.fun
Check if the user already has Play.fun credentials. The auth script is bundled with the plugin:
node
skills/playdotfun/scripts/playfun-auth.js status
If credentials exist
, skip to 7b.
If no credentials
, start the auth callback server:
node
skills/playdotfun/scripts/playfun-auth.js callback
&
Tell the user:
To register your game on Play.fun, you need to log in once.
Open this URL in your browser:
https://app.play.fun/skills-auth?callback=http://localhost:9876/callback
Log in with your Play.fun account. Credentials are saved locally.
Tell me when you're done.
Wait for user confirmation.
Then verify with
playfun-auth.js status
.
If callback fails, offer manual method as fallback.
7b. Register the game on Play.fun
Determine the deployed game URL from Step 6 (e.g.,
https://.here.now/
or
https://.github.io//
).
Read
package.json
for the game name and description. Read
src/core/Constants.js
to determine reasonable anti-cheat limits based on the scoring system.
Use the Play.fun API to register the game. Load the
playdotfun
skill for API reference. Register via
POST https://api.play.fun/games
:
{
"name"
:
""
,
"description"
:
""
,
"gameUrl"
:
""
,
"platform"
:
"web"
,
"isHTMLGame"
:
true
,
"iframable"
:
true
,
"maxScorePerSession"
:
,
"maxSessionsPerDay"
:
50
,
"maxCumulativePointsPerDay"
:
}
Anti-cheat guidelines:
Casual clicker/idle:
maxScorePerSession: 100-500
Skill-based arcade (flappy bird, runners):
maxScorePerSession: 500-2000
Competitive/complex:
maxScorePerSession: 1000-5000
Save the returned
game UUID
.
7c. Add the Play.fun Browser SDK
First, extract the user's API key from stored credentials:
# Read API key from agent config (stored by playfun-auth.js)
# Example path for Claude Code — adapt for your agent
API_KEY
=
$(
cat
~/.claude.json
jq
-r
'.mcpServers["play-fun"].headers["x-api-key"]'
)
echo
"User API Key:
$API_KEY
"
If no API key is found, prompt the user to authenticate first.
Then add the SDK script and meta tag to
index.html
before
</head>
, substituting the actual API key:
<
meta
name
=
"
x-ogp-key
"
content
=
"
"
/>
<
script
src
=
"
https://sdk.play.fun/latest
"
>
</
script
>
Important
: The
x-ogp-key
meta tag must contain the
user's Play.fun API key
(not the game ID). Do NOT leave the placeholder — always substitute the actual key extracted above.
Create
src/playfun.js
that wires the game's EventBus to Play.fun points tracking:
// src/playfun.js — Play.fun (OpenGameProtocol) integration
import
{
eventBus
,
Events
}
from
'./core/EventBus.js'
;
const
GAME_ID
=
''
;
let
sdk
=
null
;
let
initialized
=
false
;
export
async
function
initPlayFun
(
)
{
const
SDKClass
=
typeof
PlayFunSDK
!==
'undefined'
?
PlayFunSDK
:
typeof
OpenGameSDK
!==
'undefined'
?
OpenGameSDK
:
null
;
if
(
!
SDKClass
)
{
console
.
warn
(
'Play.fun SDK not loaded'
)
;
return
;
}
sdk
=
new
SDKClass
(
{
gameId
:
GAME_ID
,
ui
:
{
usePointsWidget
:
true
}
}
)
;
await
sdk
.
init
(
)
;
initialized
=
true
;
// addPoints() — call frequently during gameplay to buffer points locally (non-blocking)
eventBus
.
on
(
Events
.
SCORE_CHANGED
,
(
{
score
,
delta
}
)
=>
{
if
(
initialized
&&
delta
>
0
)
sdk
.
addPoints
(
delta
)
;
}
)
;
// savePoints() — ONLY call at natural break points (game over, level complete)
// WARNING: savePoints() opens a BLOCKING MODAL — never call during active gameplay!
eventBus
.
on
(
Events
.
GAME_OVER
,
(
)
=>
{
if
(
initialized
)
sdk
.
savePoints
(
)
;
}
)
;
// Save on page unload (browser handles this gracefully)
window
.
addEventListener
(
'beforeunload'
,
(
)
=>
{
if
(
initialized
)
sdk
.
savePoints
(
)
;
}
)
;
}
Critical SDK behavior:
Method
When to use
Behavior
addPoints(n)
During gameplay
Buffers points locally, non-blocking
savePoints()
Game over / level end
Opens blocking modal
, syncs buffered points to server
⚠️
Do NOT call
savePoints()
on a timer or during active gameplay
— it interrupts the player with a modal dialog. Only call at natural pause points (game over, level transitions, menu screens).
Read the actual EventBus.js
to find the correct event names and payload shapes. Adapt accordingly.
Add
initPlayFun()
to
src/main.js
:
import
{
initPlayFun
}
from
'./playfun.js'
;
// After game init
initPlayFun
(
)
.
catch
(
err
=>
console
.
warn
(
'Play.fun init failed:'
,
err
)
)
;
7d. Rebuild and redeploy
cd
<
project-dir
>
&&
npm
run build
&&
~/.agents/skills/here-now/scripts/publish.sh dist/
If the project was deployed to GitHub Pages instead, use
npx gh-pages -d dist
.
Verify the deployment is live (here.now deploys are instant; GitHub Pages may take 1-2 minutes).
7e. Tell the user
Your game is monetized on Play.fun!
Play
:
Play.fun
:
https://play.fun/games/
The Play.fun widget is now live — players see points, leaderboard, and wallet connect.
Points are buffered during gameplay and saved on game over.
Share on Moltbook
: Post your game URL to
moltbook.com
— 770K+ agents ready to play and upvote.
Mark task 7 as
completed
.
Pipeline Complete!
Tell the user:
Your game has been through the full pipeline! Here's what you have:
Scaffolded architecture
— clean, modular code structure
Pixel art sprites
— recognizable characters (if chosen) or clean geometric shapes
Visual polish
— gradients, particles, transitions, juice
Promo video
— 50 FPS gameplay footage in mobile portrait (
output/promo.mp4
)
Music and SFX
— chiptune background music and retro sound effects
Quality assured
— each step verified with build, runtime, and visual review
Live on the web
— deployed to here.now with an instant public URL
Monetized on Play.fun
— points tracking, leaderboards, and wallet connect
Share your play.fun URL on Moltbook
to reach 770K+ agents on the agent internet.
Post your promo video
to TikTok, Reels, or X to drive traffic.
What's next?
Add new gameplay features:
/game-creator:add-feature [describe what you want]
Upgrade to pixel art (if using shapes):
/game-creator:add-assets
Re-record promo video:
/game-creator:record-promo
Launch a playcoin for your game (token rewards for players)
Keep iterating! Run any step again:
/game-creator:design-game
,
/game-creator:add-audio
Redeploy after changes:
npm run deploy
Switch to GitHub Pages if you prefer git-based deploys:
/game-creator:game-deploy
返回排行榜