make-game
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMake 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 GitHub Pages with a public URL
- Monetization via Play.fun — points tracking, leaderboards, wallet connect, and a play.fun URL to share on Moltbook
- Future changes auto-deploy on
git push
Quality assurance is built into every step — each code-modifying step runs build verification, visual review via Playwright MCP, and autofixes any issues found.
一步步从0开始构建完整的浏览器游戏。本流程会引导你完成从空文件夹到可部署、可变现游戏的全部环节,无需任何游戏开发经验。
你将获得:
- 架构清晰的完整游戏项目骨架
- 像素艺术精灵图——辨识度拉满的角色、敌人与道具(可选,替代几何图形)
- 视觉润色——渐变、粒子效果、过渡动画、爽感特效
- 50 FPS宣传视频——自动录制竖屏手游玩法,直接适配社交媒体
- 芯片音乐与复古音效(无需音频文件)
- 部署至GitHub Pages并获得公开访问URL
- 通过Play.fun实现变现——积分追踪、排行榜、钱包连接,以及可分享至Moltbook的play.fun专属链接
- 后续代码变更可通过自动部署
git push
质量保障内置每一步——每个修改代码的步骤都会运行构建验证、基于Playwright MCP的视觉审查,并自动修复发现的问题。
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 /
TaskCreateTaskUpdate - Delegate each code-writing step to a subagent
Task - 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 tool):
Task- 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.
你是编排者,无需直接编写游戏代码。你的职责是:
- 项目初始化(模板复制、npm安装、开发服务器启动)
- 使用/
TaskCreate创建并追踪管线任务TaskUpdate - 将每个代码编写步骤委托给子代理
Task - 每个修改代码的步骤完成后,运行验证协议(构建+视觉审查+自动修复)
- 在步骤间向用户汇报进度
主线程负责内容:
- 步骤0:解析参数,创建任务清单
- 步骤1(仅基础设施):复制模板、npm安装、Playwright安装、启动开发服务器
- 验证协议编排(启动QA子代理、读取结果、需要时启动自动修复子代理)
- 步骤4(部署):交互式认证需要与用户来回协作
子代理负责内容(通过工具):
Task- 步骤1(游戏实现):将模板转换为实际游戏概念
- 步骤1.5:像素艺术精灵图与背景
- 步骤2:视觉润色
- 步骤2.5:录制宣传视频
- 步骤3:音频集成
每个子代理会收到:步骤说明、相关技能名称、项目路径、引擎类型、开发服务器端口、游戏概念描述。
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.
每个修改代码的步骤(步骤1、1.5、2、3)完成后都要运行本协议。步骤2.5(宣传视频)不修改游戏代码,可跳过QA。所有QA工作都委托给子代理,以减少主线程的上下文占用。
Playwright MCP Check (once, before first QA run)
Playwright MCP检查(首次QA前执行一次)
Before the first QA run (after Step 1 infrastructure setup), check if Playwright MCP tools like are available. If not:
browser_navigate- 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运行前(步骤1基础设施搭建完成后),检查等Playwright MCP工具是否可用。如果不可用:
browser_navigate- 运行:
claude mcp add playwright npx @playwright/mcp@latest - 告知用户:"已添加Playwright MCP,请重启Claude Code使其生效,之后告知我继续。"
- 等待用户重启并确认,MCP工具可用前不要继续。
QA Subagent
QA子代理
Launch a subagent with these instructions:
TaskYou are the QA subagent for the game creation pipeline.Project path:Dev server port:<project-dir>Step being verified:<port><step name>Run these phases in order. Stop early if a phase fails critically (build or runtime).Phase 1 — Build Checkbashcd <project-dir> && npm run buildIf the build fails, report FAIL immediately with the error output.Phase 2 — Runtime Checkbashcd <project-dir> && node scripts/verify-runtime.mjsIf the runtime check fails, report FAIL immediately with the error details.Phase 3 — Gameplay Verificationbashcd <project-dir> && node scripts/iterate-client.js \ --url http://localhost:<port> \ --actions-file scripts/example-actions.json \ --iterations 3 --screenshot-dir output/iterateAfter running, read the state JSON files () and error files (output/iterate/state-*.json):output/iterate/errors-*.json
- Scoring: At least one state file should show
score > 0- Death: At least one state file should show
. 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.mode: "game_over"- Errors: No critical errors in error files
Skip this phase ifis not present.scripts/iterate-client.jsPhase 4 — Architecture Validationbashcd <project-dir> && node scripts/validate-architecture.mjsReport 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:
tobrowser_navigatehttp://localhost:<port> — wait 2 seconds for the game to loadbrowser_wait_for — save asbrowser_take_screenshotoutput/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),
— save asbrowser_take_screenshotoutput/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: Ifhangs 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.browser_take_screenshotNote on iterate screenshots: The iterate-client useswhich returns blank/black images when Phaser uses WebGL withcanvas.toDataURL(). Always prefer Playwright MCP viewport screenshots (preserveDrawingBuffer: false) over iterate screenshots for visual review.browser_take_screenshotWithout MCP (fallback):
- Read the iterate screenshots from
(may be black if WebGL — this is expected)output/iterate/shot-*.png- 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 if any> ISSUES: - <issue descriptions, or "None"> SCREENSHOTS: output/qa-gameplay.png, output/qa-gameover.png
启动子代理并附上以下说明:
Task你是游戏创建管线的QA子代理。项目路径:开发服务器端口:<project-dir>待验证步骤:<port><step name>按顺序运行以下阶段,若某阶段严重失败(构建或运行时错误)则提前终止。阶段1 — 构建检查bashcd <project-dir> && npm run build若构建失败,立即返回FAIL并附上错误输出。阶段2 — 运行时检查bashcd <project-dir> && node scripts/verify-runtime.mjs若运行时检查失败,立即返回FAIL并附上错误详情。阶段3 — 玩法验证bashcd <project-dir> && node scripts/iterate-client.js \ --url http://localhost:<port> \ --actions-file scripts/example-actions.json \ --iterations 3 --screenshot-dir output/iterate运行后,读取状态JSON文件()和错误文件(output/iterate/state-*.json):output/iterate/errors-*.json
- 得分:至少有一个状态文件显示
score > 0- 死亡:至少有一个状态文件显示
。若未触发game_over则标记为SKIPPED(而非FAIL)——部分游戏有多条生命系统或随机生成危险,短时间运行可能无法可靠触发死亡。SKIPPED状态可接受,不会阻塞管线。mode: "game_over"- 错误:错误文件中无严重错误
若不存在则跳过此阶段。scripts/iterate-client.js阶段4 — 架构验证bashcd <project-dir> && node scripts/validate-architecture.mjs报告所有警告,但不会仅因架构问题标记为失败。阶段5 — 基于Playwright MCP的视觉审查 使用Playwright MCP对游戏进行视觉审查。若MCP工具不可用,退而读取中的截图。output/iterate/有MCP时:
访问browser_navigatehttp://localhost:<port> ——等待2秒让游戏加载完成browser_wait_for ——保存为browser_take_screenshotoutput/qa-gameplay.png- 评估:实体是否可见?游戏渲染是否正常?
- 检查安全区域:是否有UI被顶部约8%的区域遮挡(Play.fun组件区域)?
- 检查实体尺寸:主角是否足够大(角色类游戏需占屏幕宽度的12–15%)?
- 等待游戏结束(或手动导航至游戏结束界面),
——保存为browser_take_screenshotoutput/qa-gameover.png- 检查按钮:按钮标签是否可见?空白矩形代表按钮样式损坏。
- 检查静音按钮:是否有可见的静音切换按钮?若无则标记为问题。
截图超时处理:若卡顿超过10秒(持续WebGL动画可能导致此问题),取消操作并转而进行代码审查。不要让截图卡顿阻塞整个QA阶段。browser_take_screenshot关于迭代截图的说明:当Phaser使用WebGL且时,iterate-client使用的preserveDrawingBuffer: false会返回空白/黑色图片。视觉审查时始终优先使用Playwright MCP的视口截图(canvas.toDataURL())而非迭代截图。browser_take_screenshot无MCP时( fallback ):
- 读取
中的迭代截图(若使用WebGL可能为黑色,此为预期情况)output/iterate/shot-*.png- 退而进行代码审查:读取场景文件并从代码评估视觉正确性
请严格按照以下格式返回结果(仅文本,无图片):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 if any> ISSUES: - <issue descriptions, or "None"> 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启动QA子代理 → 读取文本结果
如果PASS → 进入下一步
如果FAIL → 携带问题列表启动自动修复子代理 → 重新运行QA子代理
每个步骤最多尝试3次Autofix Logic
自动修复逻辑
When the QA subagent reports FAIL:
- Read to see what fixes were already attempted. If a previous entry matches the same
output/autofix-history.jsonandissuewithfix_attempted, instruct the subagent to try a different approach.result: "failure" - Launch a fix subagent via tool with:
Task- The ISSUES list from the QA result
- The phase that failed (build errors, runtime errors, gameplay issues, visual problems)
- Any relevant failed attempts from so the subagent knows what NOT to repeat
output/autofix-history.json
- After each autofix attempt, append an entry to :
output/autofix-history.jsonjson{ "step": "<step name>", "issue": "<what failed>", "fix_attempted": "<what was tried>", "result": "success|failure", "timestamp": "<ISO date>" } - 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.
当QA子代理报告FAIL时:
- **读取**查看已尝试的修复。若之前有相同
output/autofix-history.json和issue且fix_attempted,指示子代理尝试不同方法。result: "failure" - 通过工具启动修复子代理,并提供:
Task- QA结果中的问题列表
- 失败的阶段(构建错误、运行时错误、玩法问题、视觉问题)
- 中相关的失败尝试记录,以便子代理避免重复无效操作
output/autofix-history.json
- 每次自动修复尝试后,向追加一条记录:
output/autofix-history.jsonjson{ "step": "<step name>", "issue": "<what failed>", "fix_attempted": "<what was tried>", "result": "success|failure", "timestamp": "<ISO date>" } - 重新运行QA子代理(所有阶段)
- 每个步骤最多尝试3次(1次原始尝试+2次重试)
- 若3次尝试均失败,向用户报告失败并询问是否跳过或终止
重要提示:进入下一步前必须修复所有问题。自动修复循环确保每个步骤都能产出可正常运行、视觉正确的结果。
Instructions
操作步骤
Step 0: Initialize pipeline
步骤0:初始化管线
Parse to determine the game concept. Arguments can take two forms:
$ARGUMENTS解析确定游戏概念。参数有两种形式:
$ARGUMENTSForm A: Direct specification
形式A:直接指定
- Engine: (Phaser — side-scrollers, platformers, arcade) or
2d(Three.js — first-person, third-person, open world). If not specified, ask the user.3d - Name: The game name in kebab-case. If not specified, ask the user what kind of game they want and suggest a name.
- 引擎:(Phaser——横版卷轴、平台跳跃、街机类)或
2d(Three.js——第一人称、第三人称、开放世界)。若未指定,询问用户。3d - 名称:短横线分隔的游戏名称(kebab-case)。若未指定,询问用户想要的游戏类型并建议名称。
Form B: Tweet URL as game concept
形式B:以推文URL作为游戏概念
If contains a tweet URL (matching , , , or ):
$ARGUMENTSx.com/*/status/*twitter.com/*/status/*fxtwitter.com/*/status/*vxtwitter.com/*/status/*- Fetch the tweet using the skill — convert the URL to
fetch-tweetand fetch withhttps://api.fxtwitter.com/<user>/status/<id>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:
<generated-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:
- (relative to plugin root) — exact slug match or name match
character-library/manifest.json - Common name recognition — politicians, tech CEOs, world leaders, entertainers
If celebrities are detected:
- Set and list detected names
hasCelebrities = true - Note in which characters are pre-built vs need building
progress.md - 2D: The Step 1.5 subagent will use photo-composite characters for these
- 3D: For each celebrity, try: (1) generate with Meshy AI — then rig for animation, (2) check
"a cartoon caricature of <Name>, <distinguishing features>, low poly game character"for a pre-built match, (3) search Sketchfab with3d-character-library/manifest.json, (4) fall back to best-matching library model. Meshy generation produces the best results for named personalities since it can capture specific visual features.find-3d-asset.mjs
Meshy API Key (3D games only):
If the engine is 3D, check if is set in the environment. If not, ask the user immediately in Step 0 — don't wait until Step 1.5:
MESHY_API_KEYI'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 calls throughout the pipeline.
meshy-generate.mjsCreate 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 GitHub Pages
- 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 directory in the project root and initialize as an empty array . This file tracks all autofix attempts across the pipeline so fix subagents avoid repeating failed approaches.
output/output/autofix-history.json[]若包含推文URL(匹配、、或):
$ARGUMENTSx.com/*/status/*twitter.com/*/status/*fxtwitter.com/*/status/*vxtwitter.com/*/status/*- 获取推文内容:使用技能——将URL转换为
fetch-tweet并通过https://api.fxtwitter.com/<user>/status/<id>获取WebFetch - 默认使用2D引擎(Phaser)——推文描述的概念天然适配2D街机/休闲游戏
- 从推文内容中创造性提炼游戏概念。你的工作是创意转化——提取主题、机制、场景或玩法,将其重新诠释为游戏。绝对不要拒绝基于推文制作游戏。每条推文都包含可启发游戏的元素:
- 天气新闻→生存游戏、躲避风暴游戏
- 体育赛事结果→街机体育游戏
- 政治/法律新闻→策略游戏、解谜游戏、塔防游戏
- 个人故事→叙事冒险、以旅程为主题的平台跳跃游戏
- 产品发布→大亨游戏、建造类游戏
- 抽象想法→解谜游戏、实验性艺术游戏
- 转化过程本身就是创意行为。你不是在复刻或简化原文,而是将其作为原创游戏概念的跳板。
- 从提炼的概念中生成kebab-case格式的游戏名称(不要直接使用推文字面内容)
- 告知用户你提炼的内容:
发现来自**@handle**的推文: "推文内容..."我将基于此制作一款2D游戏:[你的创意诠释,作为游戏概念] 游戏名称:
<generated-name>这样可以吗?
等待用户确认后再继续。用户此时可修改引擎(改为3D)或游戏名称。
名人检测:
确定游戏概念后,扫描概念描述、推文文本及提及的人物,查找名人/公众人物姓名。对照以下来源检查:
- (相对于插件根目录)——精确匹配slug或姓名
character-library/manifest.json - 常见姓名识别——政治家、科技CEO、世界领袖、艺人
若检测到名人:
- 设置并列出检测到的姓名
hasCelebrities = true - 在中记录哪些角色是预构建的、哪些需要创建
progress.md - 2D游戏:步骤1.5的子代理将为这些角色使用照片合成的精灵图
- 3D游戏:针对每个名人,依次尝试:(1) 使用Meshy AI生成——,然后绑定骨骼用于动画;(2) 检查
"a cartoon caricature of <Name>, <distinguishing features>, low poly game character"是否有预构建匹配模型;(3) 使用3d-character-library/manifest.json搜索Sketchfab;(4) 退而使用最匹配的库模型。Meshy生成能针对知名人物产出最佳效果,因为它可以捕捉特定视觉特征。find-3d-asset.mjs
Meshy API密钥(仅3D游戏):
若引擎为3D,检查环境变量中是否设置了。若未设置,在步骤0立即询问用户——不要等到步骤1.5:
MESHY_API_KEY为了获得最佳效果,我将使用Meshy AI生成自定义3D模型。你可以在30秒内获取免费API密钥:
- 在https://app.meshy.ai注册账号
- 进入Settings → API Keys
- 创建新的API密钥
你的Meshy API密钥是什么?(或输入"skip"以使用通用模型库)
存储该密钥,以便在整个管线中用于所有调用。
meshy-generate.mjs使用提前创建所有管线任务:
TaskCreate- 从模板搭建游戏骨架
- 添加资源:像素艺术精灵图(2D)或Meshy AI生成的GLB模型+动画角色(3D)
- 添加视觉润色(粒子、过渡、爽感特效)
- 录制宣传视频(自动50 FPS捕获)
- 添加音频(背景音乐+音效)
- 部署至GitHub Pages
- 通过Play.fun实现变现(在OpenGameProtocol注册、添加SDK、重新部署)
这能让用户随时全面了解管线进度。质量保障(构建、运行时、视觉审查、自动修复)内置每个步骤,而非独立任务。
创建任务后,在项目根目录创建目录并初始化为空数组。该文件追踪管线中所有自动修复尝试,以便修复子代理避免重复失败的方法。
output/output/autofix-history.json[]Step 1: Scaffold the game
步骤1:搭建游戏骨架
Mark task 1 as .
in_progressMain 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 directory relative to this plugin's install location
templates/
- The agent's plugin cache (e.g.
- Determine the target directory. If the current working directory is the plugin repository (check for
game-creatormentioning "game-creator" orCLAUDE.md), create the game inside.claude-plugin/plugin.json(e.g.,examples/). Otherwise, create it in the current working directory (examples/<game-name>/).<game-name>/ - Copy the entire template directory to the target:
- 2D: copy →
templates/phaser-2d/<target-dir>/ - 3D: copy →
templates/threejs-3d/<target-dir>/
- 2D: copy
- Update — set
package.jsonto the game name"name" - Update in
<title>to a human-readable version of the game nameindex.html - Verify Node.js/npm availability: Run to confirm Node.js and npm are installed and accessible. If they fail (e.g., nvm lazy-loading), try sourcing nvm:
node --version && npm --versionthen retry. If Node.js is not installed at all, tell the user they need to install it before continuing.export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" - Run in the new project directory
npm install - 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 explicitly
npm install -D @playwright/test - 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)
- Check if Playwright is available:
- Verify template scripts exist — The template ships with ,
scripts/verify-runtime.mjs, andscripts/iterate-client.js. Confirm they are present. Thescripts/example-actions.jsonandverifynpm scripts are already initeratefrom the template.package.json - Start the dev server — Before running , check if the configured port (in
npm run dev) is already in use:vite.config.js. If occupied, updatelsof -i :<port> -tto 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 tovite.config.jsvia thescripts/verify-runtime.mjsenv variable in subsequent runs.PORT
Subagent — game implementation:
Launch a subagent with these instructions:
TaskYou are implementing Step 1 (Scaffold) of the game creation pipeline.Project path:Engine:<project-dir>Game concept:<2d|3d>Skill to load:<user's game description>(2D) orphaser(3D)threejs-gameCore 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
in Constants.js. This locks portrait layout on desktop (pillarboxed with black bars viaFORCE_PORTRAIT = true). Use fixed design dimensions (540×960), not conditionalScale.FIT + CENTER_BOTH._isPortrait ? 540 : 960- Visible touch indicators required: Always render semi-transparent arrow buttons (or direction indicators) on touch-capable devices. Use capability detection (
), NOT OS detection (('ontouchstart' in window) || (navigator.maxTouchPoints > 0)). Enable pointer events (pointerdown/pointermove/pointerup) on ALL devices — never gate behinddevice.os.android || device.os.iOS. UseisMobileconstants from Constants.js for sizing.TOUCH- Minimum 7–8% canvas width for collectibles/hazards: Items smaller than 7% of
become unrecognizable blobs on phone screens. Size attacks at ~9%, power-ups at ~7%, player character at 12–15%.GAME.WIDTH- Wire spectacle events: emit
inSPECTACLE_ENTRANCE,create()on every player input,SPECTACLE_ACTIONon score/destroy,SPECTACLE_HITon consecutive hits (passSPECTACLE_COMBO),{ combo }at milestones (5, 10, 25 — passSPECTACLE_STREAK),{ streak }on close callsSPECTACLE_NEAR_MISSVisual 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
: player starts off-screen, tweens into position withcreate(), landing shake + particle burstBounce.easeOut- Add combo tracking to GameState:
(current streak, resets on miss),combo(session high), both reset inbestComboreset()- Ensure restart is clean — test mentally that 3 restarts in a row would work identically
- Add
to GameState for mute supportisMutedCRITICAL — Preserve the button pattern:
- The template's
contains a workingGameOverScene.jshelper (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.createButton()Character & entity sizing:
- Character WIDTH from
, HEIGHT fromGAME.WIDTH * ratio(whereWIDTH * SPRITE_ASPECTfor 200×300 spritesheets). Never define character HEIGHT asconst SPRITE_ASPECT = 1.5— on mobile portrait,GAME.HEIGHT * ratiois much larger thanGAME.HEIGHT, squishing characters.GAME.WIDTH- For character-driven games (named personalities, mascots, famous figures): make the main character prominent —
toGAME.WIDTH * 0.12(12–15% of screen width). Use caricature proportions (large head = 40–50% of sprite height, exaggerate distinguishing features) for personality games.GAME.WIDTH * 0.15- Non-character entities (projectiles, collectibles, squares) can use
for both dimensions since they have no intrinsic aspect ratio to preserve.GAME.WIDTH * ratioPlay.fun safe zone:
- Import
fromSAFE_ZONE. All UI text, buttons, and interactive elements (title text, score panels, restart buttons) must be positioned belowConstants.js. The Play.fun SDK renders a 75px widget bar at the top of the viewport (z-index 9999). UseSAFE_ZONE.TOPfor proportional positioning within the usable area (wheresafeTop + usableH * ratio).usableH = GAME.HEIGHT - SAFE_ZONE.TOPGenerate game-specific test actions: After implementing the core loop, overwritewith actions tailored to this game. Requirements:scripts/example-actions.json
- 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):json[ {"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):json[ {"buttons":["space"],"frames":4}, {"buttons":[],"frames":25}, {"buttons":["space"],"frames":4}, {"buttons":[],"frames":25}, {"buttons":["space"],"frames":4}, {"buttons":[],"frames":80} ]Before returning, write:<project-dir>/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 at the game's project root. Read the game's actual source files to populate it accurately:
progress.md- Read for the event list
src/core/EventBus.js - Read for the key sections (GAME, PLAYER, ENEMY, etc.)
src/core/Constants.js - List files in for entity names
src/entities/ - Read for state fields
src/core/GameState.js
Write with this structure:
progress.mdmarkdown
undefined标记任务1为。
in_progress主线程——基础设施搭建:
- 定位插件的模板目录。按以下顺序检查路径直至找到:
- 代理的插件缓存(例如)
~/.claude/plugins/cache/local-plugins/game-creator/1.0.0/templates/ - 相对于本插件安装位置的目录
templates/
- 代理的插件缓存(例如
- 确定目标目录。若当前工作目录是插件仓库(检查
game-creator是否提及"game-creator"或是否存在CLAUDE.md),则在.claude-plugin/plugin.json中创建游戏(例如examples/)。否则,在当前工作目录创建(examples/<game-name>/)。<game-name>/ - 将整个模板目录复制到目标目录:
- 2D:复制→
templates/phaser-2d/<target-dir>/ - 3D:复制→
templates/threejs-3d/<target-dir>/
- 2D:复制
- 更新——将
package.json设置为游戏名称"name" - 更新中的
index.html为游戏名称的易读版本<title> - 验证Node.js/npm可用性:运行确认Node.js和npm已安装且可访问。若失败(例如nvm延迟加载),尝试加载nvm:
node --version && npm --version后重试。若未安装Node.js,告知用户需先安装才能继续。export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" - 在新项目目录中运行
npm install - 安装Playwright和Chromium——Playwright是运行时验证和迭代循环所必需的:
- 检查Playwright是否可用:
npx playwright --version - 若失败,检查
node_modules/.bin/playwright --version - 若均不可用,显式运行
npm install -D @playwright/test - 然后安装浏览器二进制文件:
npx playwright install chromium - 验证安装成功;若失败,发出警告并继续(构建验证仍可工作,但运行时/迭代检查将被跳过)
- 检查Playwright是否可用:
- 验证模板脚本存在——模板附带、
scripts/verify-runtime.mjs和scripts/iterate-client.js。确认这些文件存在。模板的scripts/example-actions.json中已包含package.json和verifynpm脚本。iterate - 启动开发服务器——运行前,检查配置的端口(在
npm run dev中)是否已被占用:vite.config.js。若已占用,更新lsof -i :<port> -t使用下一个可用端口(尝试3001、3002等)。然后在后台启动开发服务器并确认其可响应。在整个管线运行期间保持服务器运行。记录实际端口号——后续运行vite.config.js时通过scripts/verify-runtime.mjs环境变量传递。PORT
子代理——游戏实现:
启动子代理并附上以下说明:
Task你正在实现游戏创建管线的步骤1(搭建骨架)。项目路径:引擎:<project-dir>游戏概念:<2d|3d>需加载的技能:<user's game description>(2D)或phaser(3D)threejs-game优先实现核心循环——按以下顺序实现:
- 输入(从一开始就支持触摸+键盘——绝不要仅支持键盘)
- 玩家移动/核心机制
- 失败条件(死亡、碰撞、计时器)
- 得分系统
- 重启流程(GameState.reset() → 完全重置状态)
控制范围:1个场景、1种核心机制、1个失败条件。在核心循环旁接入Spectacle EventBus钩子——这些是骨架,而非润色内容。将模板转换为游戏概念:
- 重命名实体、场景/系统和事件以匹配概念
- 实现核心玩法机制
- 接入EventBus事件、GameState字段和Constants值
- 确保所有模块仅通过EventBus通信
- 所有魔法数值放入Constants.js
- 不要添加标题界面——模板直接启动进入玩法。不要创建MenuScene或标题界面。仅在用户明确要求时添加。
- 不要添加游戏内得分HUD——Play.fun组件会在游戏顶部的安全区域显示得分。不要创建UIScene或HUD叠加层用于显示得分。
- 移动端优先输入:为游戏概念选择最佳移动端输入方案(点击区域、虚拟摇杆、陀螺仪倾斜、滑动)。从一开始就实现触摸+键盘支持——绝不要仅支持键盘。使用统一的模拟InputSystem模式(moveX/moveZ),使游戏逻辑与输入源无关。
- 垂直游戏强制竖屏:对于躲避类、跑酷类、收集类和无尽下落类游戏,在Constants.js中设置
。这会在桌面端锁定竖屏布局(通过FORCE_PORTRAIT = true添加黑边)。使用固定设计尺寸(540×960),不要使用条件判断Scale.FIT + CENTER_BOTH。_isPortrait ? 540 : 960- 必须显示触摸指示器:在支持触摸的设备上始终渲染半透明箭头按钮(或方向指示器)。使用能力检测(
),而非系统检测(('ontouchstart' in window) || (navigator.maxTouchPoints > 0))。在所有设备上启用指针事件(pointerdown/pointermove/pointerup)——绝不要仅在device.os.android || device.os.iOS时启用。使用Constants.js中的isMobile常量设置尺寸。TOUCH- 道具/危险物最小尺寸为画布宽度的7–8%:小于
7%的道具在手机屏幕上会变成难以辨认的斑点。攻击类实体尺寸约9%,增益道具约7%,玩家角色约12–15%。GAME.WIDTH- 接入Spectacle事件:在
中触发create(),每次玩家输入时触发SPECTACLE_ENTRANCE,得分/销毁时触发SPECTACLE_ACTION,连续命中时触发SPECTACLE_HIT(传递SPECTACLE_COMBO),达到里程碑时触发{ combo }(5、10、25次——传递SPECTACLE_STREAK),险象环生时触发{ streak }SPECTACLE_NEAR_MISS视觉辨识度——突出特征:
- 若玩家角色代表真实人物或品牌,从一开始就将视觉辨识度融入实体。不要使用通用圆形/矩形作为占位符——使用描述性颜色、比例和特征,即使在添加像素艺术前也能传达身份。
- 命名的对手/NPC必须在屏幕上有视觉存在感——绝不要仅用文本。至少使用不同颜色的形状暗示品牌。更好的方式:具有可识别特征的简单角色形态。
- 道具和危险物必须视觉上不言自明。避免抽象概念(如"想象力块"、"创意火花")。使用玩家能立即识别的具体物品(拍立得照片、奖杯、闪电、钱袋等)。
- 思考:"有人截图后能立即知道这是什么游戏吗?"
- 绝对不要使用单个字母(C、G、O)作为角色的视觉标识
- 绝对不要仅通过填充颜色区分两个角色——它们必须有独特的轮廓和特征
- 当涉及公司(OpenAI、Anthropic、xAI等)时,使用CEO作为角色:OpenAI用Altman,Anthropic用Amodei,xAI用Musk,Meta用Zuckerberg,Microsoft用Nadella,Google用Pichai,NVIDIA用Huang
- 在
中添加入场序列:玩家从屏幕外开始,通过create()缓动进入位置,伴随落地震动+粒子爆发Bounce.easeOut- 在GameState中添加连击追踪:
(当前连击数,未命中时重置)、combo(会话最高连击数),两者都在bestCombo中重置reset()- 确保重启流程干净——在脑海中测试连续重启3次是否能正常工作
- 在GameState中添加
用于静音支持isMuted关键要求——保留按钮样式:
- 模板的
包含可用的GameOverScene.js辅助函数(Container + Graphics + Text)。不要重写此方法。保持原样或复制到任何需要按钮的新场景中。正确的层级顺序是:Graphics在最底层(背景),Text在中间(标签),Container设置为可交互。若将Graphics放在Text上方,文本会不可见。若仅将Graphics设置为可交互而非Container,悬停/按下状态会失效。createButton()角色与实体尺寸:
- 角色宽度从
计算,高度从GAME.WIDTH * ratio计算(对于200×300精灵图,WIDTH * SPRITE_ASPECT)。绝对不要将角色高度定义为const SPRITE_ASPECT = 1.5——在移动端竖屏模式下,GAME.HEIGHT * ratio远大于GAME.HEIGHT,会导致角色被压扁。GAME.WIDTH- 对于以角色为核心的游戏(知名人物、吉祥物、名人):主角要突出——占
到GAME.WIDTH * 0.12(屏幕宽度的12–15%)。使用漫画比例(大头=精灵高度的40–50%,夸张突出特征)制作人格化游戏。GAME.WIDTH * 0.15- 非角色实体(投射物、道具、方块)可使用
同时定义宽高,因为它们没有需要保留的内在宽高比。GAME.WIDTH * ratioPlay.fun安全区域:
- 从Constants.js导入
。所有UI文本、按钮和交互元素(标题文本、得分面板、重启按钮)必须位于SAFE_ZONE下方。Play.fun SDK会在视口顶部渲染75px的组件栏(z-index 9999)。使用SAFE_ZONE.TOP在可用区域内按比例定位(其中safeTop + usableH * ratio)。usableH = GAME.HEIGHT - SAFE_ZONE.TOP生成游戏专属测试动作: 实现核心循环后,覆盖为适配本游戏的动作序列。要求:scripts/example-actions.json
- 使用游戏实际的输入按键(例如躲避类游戏用ArrowLeft/ArrowRight,Flappy Bird类用space,平台跳跃类用space)
- 包含足够的玩法以获得至少1分
- 包含长空闲期(60+帧无输入)以触发失败条件
- 总帧数至少150帧
躲避类游戏示例(方向键):json[ {"buttons":["ArrowRight"],"frames":20}, {"buttons":["ArrowLeft"],"frames":20}, {"buttons":["ArrowRight"],"frames":15}, {"buttons":[],"frames":10}, {"buttons":["ArrowLeft"],"frames":20}, {"buttons":[],"frames":80} ]平台跳跃类游戏示例(space跳跃):json[ {"buttons":["space"],"frames":4}, {"buttons":[],"frames":25}, {"buttons":["space"],"frames":4}, {"buttons":[],"frames":25}, {"buttons":["space"],"frames":4}, {"buttons":[],"frames":80} ]返回前,编写:<project-dir>/design-brief.md# 设计 brief ## 概念 一句话游戏概念。 ## 核心机制 每个机制: - **名称**:功能描述 - **状态字段**:影响的GameState字段 - **预期幅度**:变化程度/速度(例如"无玩家输入时,在回合持续时间内达到最大值的50-70%") ## 胜负条件 - 玩家获胜方式 - 玩家失败方式 - 确认两种结果使用当前Constants.js值均可实际达成 ## 实体交互 每个可见实体(敌人、投射物、道具、环境物体): - **名称**:实体类型 - **视觉标识**:外观及原因(参考真实logo、人物、物体——不要抽象概念) - **突出特征**:缩略图尺寸下可见的唯一夸张特征(例如"Amodei的深色卷发+眼镜"、"Jensen Huang的皮夹克") - **真实图像资源**:要下载的logo URL,或无真实图像时填写"pixel art" - **行为**:实体动作(移动、下落、生成等) - **玩家交互**:玩家与实体的交互方式(躲避、收集、点击、阻挡,或"无——背景/装饰") - **AI/对手交互**:对手与实体的交互方式(若适用) 对于知名人物:描述发型、眼镜、面部毛发、服装。对于公司:指定要下载的logo。绝对不要使用字母或文本标签作为视觉标识。 ## 表情映射 每个人格化角色,将游戏事件映射到表情: ### 玩家:[Name] | 游戏事件 | 表情 | 原因 | |---|---|---| | 空闲/默认 | 正常 | 休息状态 | | 得分/收集道具 | 开心 | 正向反馈 | | 受伤/失去生命 | 愤怒 | 直观反应 | | 增益道具/特殊事件 | 惊讶 | 兴奋感 | | 胜利/高分游戏结束 | 开心 | 庆祝 | | 失败/低分游戏结束 | 愤怒 | 挫败感 | ### 对手:[Name] | 游戏事件 | 表情 | 原因 | |---|---|---| | 空闲/默认 | 正常 | 休息状态 | | 玩家得分 | 愤怒 | 因失分而沮丧 | | 对手得分 | 开心 | 炫耀 | | 险象环生 | 惊讶 | 紧张感 |不要启动开发服务器或运行构建——编排者会处理这些。
子代理返回后,运行验证协议。
在游戏项目根目录创建。读取游戏实际源代码以准确填充:
progress.md- 读取获取事件列表
src/core/EventBus.js - 读取获取关键配置段(GAME、PLAYER、ENEMY等)
src/core/Constants.js - 列出中的文件以获取实体名称
src/entities/ - 读取获取状态字段
src/core/GameState.js
按以下结构编写:
progress.mdmarkdown
undefinedProgress
进度
Game Concept
游戏概念
- Name: [game name from project]
- Engine: Phaser 3 / Three.js
- Description: [from user's original prompt]
- 名称:[项目中的游戏名称]
- 引擎:Phaser 3 / Three.js
- 描述:[来自用户原始提示的内容]
Step 1: Scaffold
步骤1:搭建骨架
- 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]
- 实体:[来自src/entities/的实体名称列表]
- 事件:[来自EventBus.js的事件名称列表]
- Constants键:[来自Constants.js的顶级配置段,例如GAME、PLAYER、ENEMY、COLORS]
- 得分系统:[得分获取方式,来自GameState+场景逻辑]
- 失败条件:[游戏结束的触发条件]
- 输入方案:[已实现的键盘/鼠标/触摸控制]
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.**- [搭建过程中的重要决策或问题]
**告知用户:**
> 你的游戏已搭建完成并正在运行!项目结构如下:
> - `src/core/Constants.js` — 所有游戏设置(速度、颜色、尺寸)
> - `src/core/EventBus.js` — 游戏各模块间的通信方式
> - `src/core/GameState.js` — 追踪得分、生命值等状态
> - **已内置移动端控制** — 支持手机(触摸/倾斜)和桌面(键盘)
>
> **下一步:像素艺术**。我将为每个角色、敌人、道具和背景 tile 创建自定义像素艺术精灵图——全部通过代码生成,无需图像文件。之后会添加视觉润色。
标记任务1为`completed`。
**等待用户确认后再继续。**Step 1.5: Add game assets
步骤1.5:添加游戏资源
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_progressPre-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 to identify personality characters and their slugs.
design-brief.md2. Resolve the character library path — find relative to the plugin root:
character-library/manifest.json- Check relative to the plugin install directory
character-library/manifest.json - 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 . If yes, copy sprites:
manifest.jsonbash
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: or
"<Name> portrait photo"— neutral expression"<Name> face" - happy: or
"<Name> smiling""<Name> laughing" - angry: or
"<Name> angry""<Name> serious stern" - surprised: or
"<Name> surprised""<Name> shocked"
Prefer real photographs (not illustrations/cartoons). Head shots and half-body shots both work — uses face detection to isolate the face automatically. Download as , , etc. (any image extension).
crop-head.mjsnormal.jpghappy.jpgIf all 4 found, download to and run:
<project-dir>/public/assets/characters/<slug>/raw/bash
node <plugin-root>/scripts/build-character.mjs "<Name>" \
<project-dir>/public/assets/characters/<slug>/ --skip-findResult: 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 (e.g., only
raw/andnormal.png)happy.png - Duplicate the best image (prefer normal) into the missing expression slots:
bash
cp raw/normal.png raw/angry.png # fill missing with normal cp raw/normal.png raw/surprised.png - Run as above — all 4 raw slots are filled, pipeline produces a 4-frame spritesheet
build-character.mjs - 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 — produces a spritesheet where all 4 frames are identical
build-character.mjs - 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 skill — 32x48 pixel art grid at scale 4
game-assets - Note in :
progress.md"<Name>: 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.mdundefined2D和3D游戏均需运行此步骤。2D游戏获取像素艺术精灵图;3D游戏获取GLB模型和动画角色。
标记任务2为。
in_progress前置步骤:角色库检查
启动资源子代理前,检查游戏是否使用人格化角色。对于每个人格化角色,通过以下分层 fallback解析其精灵图(按顺序尝试每个层级,成功则停止):
**1. 读取**识别人格化角色及其slug。
design-brief.md2. 解析角色库路径——找到相对于插件根目录的:
character-library/manifest.json- 检查相对于插件安装目录的
character-library/manifest.json - 检查常见插件缓存路径(例如)
~/.claude/plugins/cache/local-plugins/game-creator/*/character-library/
3. 对于每个人格化角色,按以下层级顺序尝试:
层级1 — 预构建(最佳):检查slug是否存在于。若存在,复制精灵图:
manifest.jsonbash
mkdir -p <project-dir>/public/assets/characters/<slug>/
cp <plugin-root>/character-library/characters/<slug>/sprites/* \
<project-dir>/public/assets/characters/<slug>/结果:4表情精灵图已准备就绪。完成。
层级2 — 从4张图片构建(良好):WebSearch搜索4张不同表情的照片。任何照片格式均可(jpg、png、webp)——管线内置ML背景移除功能,无需透明PNG。广泛搜索:
- normal:或
"<Name> portrait photo"——中性表情"<Name> face" - happy:或
"<Name> smiling""<Name> laughing" - angry:或
"<Name> angry""<Name> serious stern" - surprised:或
"<Name> surprised""<Name> shocked"
优先选择真实照片(而非插画/卡通)。头像和半身照均可——使用人脸识别自动隔离面部。下载为、等(任何图片扩展名)。
crop-head.mjsnormal.jpghappy.jpg若找到全部4张,下载到并运行:
<project-dir>/public/assets/characters/<slug>/raw/bash
node <plugin-root>/scripts/build-character.mjs "<Name>" \
<project-dir>/public/assets/characters/<slug>/ --skip-find结果:4表情精灵图。完成。
层级3 — 从1-3张图片构建(可接受):若WebSearch仅找到1-3张可用图片:
- 将找到的图片下载到(例如仅
raw/和normal.png)happy.png - 复制最佳图片(优先选择normal)填充缺失的表情槽:
bash
cp raw/normal.png raw/angry.png # 用normal填充缺失的表情 cp raw/normal.png raw/surprised.png - 运行——所有4个原始槽均已填充,管线会生成4帧精灵图
build-character.mjs - 结果:4帧精灵图,部分表情使用相同面部。功能正常——表情系统仍可工作,只是视觉多样性不足。
层级4 — 单张图片 fallback(最低要求):若WebSearch仅找到1张图片或管线处理部分图片失败:
- 将单张成功获取的图片用于所有4个表情槽
- 运行——生成的精灵图4帧均相同
build-character.mjs - 结果:角色可识别但无表情变化。仍为照片合成,可与表情系统对接(只是无可见变化)。
层级5 — 生成式像素艺术(最坏情况):若无法找到任何图片或整个管线失败(背景移除崩溃、所有图片人脸识别失败、网络错误):
- 退而使用技能中的**人格化角色(漫画)**原型——32x48像素网格,缩放4倍
game-assets - 在中记录:
progress.md"<Name>: pixel art fallback — no photo-composite available" - 子代理将根据game-assets精灵图设计规则创建具有可识别特征(发型、眼镜、服装)的像素艺术
- 结果:无照片合成,但角色仍可通过像素艺术漫画实现视觉区分。
4. 在中记录每个角色的处理结果:
progress.mdundefinedCharacters
角色
- 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**: `<project-dir>`
> **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/<slug>/`. 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:
> 1. Read all entity files (`src/entities/`) to find `generateTexture()` / `fillCircle()` calls
> 2. Choose the palette that matches the game's theme (DARK, BRIGHT, or RETRO)
> 3. Create `src/core/PixelRenderer.js` — the `renderPixelArt()` + `renderSpriteSheet()` utilities
> 4. Create `src/sprites/palette.js` with the chosen palette
> 5. Create sprite data files (`player.js`, `enemies.js`, `items.js`, `projectiles.js`) with pixel matrices
> 6. Create `src/sprites/tiles.js` with background tiles (ground variants, decorative elements)
> 7. Create or update the background system to use tiled pixel art instead of flat colors/grids
> 8. Update entity constructors to use pixel art instead of geometric shapes
> 9. Add Phaser animations for entities with multiple frames
> 10. 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.
---- trump:层级1(预构建,4种表情)
- karpathy:层级3(找到1张图片,复制填充4个槽)
- some-ceo:层级5(像素艺术 fallback)
**5. 传递给子代理**:角色slug列表、每个角色的解析层级、每个角色的独特表情数量。子代理需要此信息以确定是否接入完整表情变化逻辑,或为层级5角色跳过表情逻辑。
启动`Task`子代理并附上以下说明:
> 你正在实现游戏创建管线的步骤1.5(像素艺术精灵图)。
>
> **项目路径**:`<project-dir>`
> **引擎**:2D(Phaser 3)
> **需加载的技能**:`game-assets`
>
> **先读取项目根目录的`progress.md`**。其中描述了游戏的实体、事件、常量和步骤1的完成情况。
>
> **角色库精灵图已复制**到`public/assets/characters/<slug>/`。对于人格化角色,加载精灵图并根据game-assets技能的"表情接入模式"接入表情变化。在Constants.js中添加`EXPRESSION`和`EXPRESSION_HOLD_MS`。根据`design-brief.md`中的表情映射,将表情变化与EventBus事件对接。
>
> 对于非人格化实体,完全遵循game-assets技能:
> 1. 读取所有实体文件(`src/entities/`)查找`generateTexture()`/`fillCircle()`调用
> 2. 选择与游戏主题匹配的调色板(DARK、BRIGHT或RETRO)
> 3. 创建`src/core/PixelRenderer.js`——包含`renderPixelArt()` + `renderSpriteSheet()`工具函数
> 4. 创建`src/sprites/palette.js`包含所选调色板
> 5. 创建精灵数据文件(`player.js`、`enemies.js`、`items.js`、`projectiles.js`)包含像素矩阵
> 6. 创建`src/sprites/tiles.js`包含背景tile(地面变体、装饰元素)
> 7. 创建或更新背景系统以使用瓦片像素艺术替代纯色/网格
> 8. 更新实体构造函数以使用像素艺术替代几何图形
> 9. 为多帧实体添加Phaser动画
> 10. 调整物理体以适配新精灵尺寸
>
> **角色突出性**:若游戏包含真实人物或知名人格,使用人格化角色(漫画)原型——32x48网格,缩放4倍(渲染为128x192px,约占画布高度的35%)。角色必须是屏幕上视觉主导元素。辅助实体使用中等(16x16)或小型(12x12)尺寸,以创建清晰的视觉层级。
>
> **突出特征——主题表现力:**
> - 精灵图必须直观体现所代表的人物/物体。"Grok AI"的精灵图应看起来像Grok(包含logo特征、品牌颜色、xAI美学)——不要使用通用机器人或彩色圆形。
> - 对于真实人物:夸张其最具辨识度的特征(标志性发型、眼镜、面部毛发、服装)。辨识度就是 meme 吸引力。
> - 对于品牌/产品:将logo形状、品牌颜色和独特视觉元素融入精灵图设计。
> - 对于游戏物体:使其可立即识别。"增益道具"应看起来像主题中代表的具体物品,不要使用通用星星或钻石。
> - 对手之间必须视觉区分明显——不同颜色、形状、尺寸和人格。玩家应能一眼区分。
>
> **返回前自我审核**——检查每个人格化精灵图是否符合以下要求:
> - 每个精灵图是否有独特发型(而非纯色圆顶)?
> - 每个精灵图是否有眼睛之外的面部特征(眼镜、面部毛发或服装细节,若适用)?
> - 若使用相同颜色渲染,两个角色精灵图是否仍有区别?
> - 是否使用`scene.add.text()`作为主要标识?若是,移除并添加物理特征替代。
> - 头部区域(行0-28)是否使用至少4种不同调色板索引?
> - 对于品牌实体:是否下载并加载了真实logo?若未加载,原因是什么?
>
> **完成工作后**,在`progress.md`中追加`## 步骤1.5:资源`部分,包含:使用的调色板、创建的精灵图、实体尺寸变更(若有)。
>
> 不要运行构建——编排者会处理验证。
**2D子代理返回后**,运行验证协议。
---3D Asset Flow (Three.js games)
3D资源流程(Three.js游戏)
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).
-
Readto identify all characters (player + opponents/NPCs) and their names/descriptions.
design-brief.md -
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.
bash
undefined对于3D游戏,使用Meshy AI生成自定义模型并集成为动画角色和世界道具。这是2D像素艺术步骤的3D对应流程。
前置步骤:角色与资源生成
步骤0中应已获取Meshy API密钥。若未设置,现在询问用户(参见步骤0说明)。
-
**读取**识别所有角色(玩家+对手/NPC)及其名称/描述。
design-brief.md -
每个类人角色,完整运行生成→绑定骨骼流程作为一个原子步骤:
层级1 — 使用Meshy AI生成+绑定骨骼(首选):这是两步命令链——类人角色必须同时运行两步。绑定骨骼步骤会自动下载行走/跑步动画GLB。
bash
undefinedStep A: Generate the character model
步骤A:生成角色模型
MESHY_API_KEY=<key> node <plugin-root>/scripts/meshy-generate.mjs
--mode text-to-3d
--prompt "a stylized <character description>, low poly game character, full body"
--polycount 15000 --pbr
--output <project-dir>/public/assets/models/ --slug <character-slug>
--mode text-to-3d
--prompt "a stylized <character description>, low poly game character, full body"
--polycount 15000 --pbr
--output <project-dir>/public/assets/models/ --slug <character-slug>
MESHY_API_KEY=<key> node <plugin-root>/scripts/meshy-generate.mjs
--mode text-to-3d
--prompt "a stylized <character description>, low poly game character, full body"
--polycount 15000 --pbr
--output <project-dir>/public/assets/models/ --slug <character-slug>
--mode text-to-3d
--prompt "a stylized <character description>, 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
步骤B:从meta中读取refineTaskId,立即绑定骨骼
The rig command auto-downloads walk/run GLBs as <slug>-walk.glb and <slug>-run.glb
绑定骨骼命令会自动下载行走/跑步GLB,保存为<slug>-walk.glb和<slug>-run.glb
REFINE_ID=$(python3 -c "import json; print(json.load(open('<project-dir>/public/assets/models/<character-slug>.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>
--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:
- `<slug>.glb` — rigged model with skeleton (use `loadAnimatedModel()` + `SkeletonUtils.clone()`)
- `<slug>-walk.glb` — walking animation (auto-downloaded)
- `<slug>-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:
```bash
cp <plugin-root>/3d-character-library/models/<model>.glb \
<project-dir>/public/assets/models/<slug>.glbTier 3 — Search Sketchfab: Use to search for a matching animated model:
find-3d-asset.mjsbash
node <plugin-root>/scripts/find-3d-asset.mjs \
--query "<character name> animated character" \
--max-faces 10000 --list-onlyTier 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 entity list:
design-brief.mdbash
undefinedREFINE_ID=$(python3 -c "import json; print(json.load(open('<project-dir>/public/assets/models/<character-slug>.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>
--mode rig --task-id $REFINE_ID --height 1.7
--output <project-dir>/public/assets/models/ --slug <character-slug>
完成后,每个角色会有3个文件:
- `<slug>.glb`——绑定骨骼的模型(使用`loadAnimatedModel()` + `SkeletonUtils.clone()`加载)
- `<slug>-walk.glb`——行走动画(自动下载)
- `<slug>-run.glb`——跑步动画(自动下载)
**绝对不要生成未绑定骨骼的类人角色**。静态模型需要程序化动画,看起来很生硬。
对于知名人物,提示要具体:`"a cartoon caricature of Trump, blonde hair, suit, red tie, low poly game character, full body"`。
对于多个角色,使用不同描述生成以保证视觉多样性。并行运行不同角色的生成→绑定骨骼流程以节省时间。
**层级2 — 使用`3d-character-library/`中的预构建模型**(Meshy不可用时):检查`manifest.json`是否有名称/主题匹配的模型。复制GLB:
```bash
cp <plugin-root>/3d-character-library/models/<model>.glb \
<project-dir>/public/assets/models/<slug>.glb层级3 — 搜索Sketchfab:使用搜索匹配的动画模型:
find-3d-asset.mjsbash
node <plugin-root>/scripts/find-3d-asset.mjs \
--query "<character name> animated character" \
--max-faces 10000 --list-only层级4 — 通用库 fallback:使用中最匹配的模型:
3d-character-library/- Soldier——动作/军事/默认人类
- Xbot——科幻/科技/未来风格
- RobotExpressive——卡通/休闲/趣味(动画最多)
- Fox——自然/动物
若2+角色退而使用库模型,使用不同模型以区分。
3. 生成/搜索世界物体——读取中的实体列表:
design-brief.mdbash
undefinedWith Meshy (preferred) — generate each prop
使用Meshy(首选)——生成每个道具
MESHY_API_KEY=<key> node <plugin-root>/scripts/meshy-generate.mjs
--mode text-to-3d
--prompt "a <entity description>, low poly game asset"
--polycount 5000
--output <project-dir>/public/assets/models/ --slug <entity-slug>
--mode text-to-3d
--prompt "a <entity description>, low poly game asset"
--polycount 5000
--output <project-dir>/public/assets/models/ --slug <entity-slug>
MESHY_API_KEY=<key> node <plugin-root>/scripts/meshy-generate.mjs
--mode text-to-3d
--prompt "a <entity description>, low poly game asset"
--polycount 5000
--output <project-dir>/public/assets/models/ --slug <entity-slug>
--mode text-to-3d
--prompt "a <entity description>, low poly game asset"
--polycount 5000
--output <project-dir>/public/assets/models/ --slug <entity-slug>
Without Meshy — search free libraries
无Meshy时——搜索免费库
node <plugin-root>/scripts/find-3d-asset.mjs --query "<entity description>"
--source polyhaven --output <project-dir>/public/assets/models/
--source polyhaven --output <project-dir>/public/assets/models/
**4. Record results** in `progress.md`:node <plugin-root>/scripts/find-3d-asset.mjs --query "<entity description>"
--source polyhaven --output <project-dir>/public/assets/models/
--source polyhaven --output <project-dir>/public/assets/models/
**4. 在`progress.md`中记录结果**:3D Characters
3D角色
- knight (player): Tier 1 — Meshy AI generated + rigged (idle/walk/run)
- goblin (enemy): Tier 1 — Meshy AI generated + rigged (idle/walk/run)
- knight(玩家):层级1——Meshy AI生成+绑定骨骼(空闲/行走/跑步动画)
- goblin(敌人):层级1——Meshy AI生成+绑定骨骼(空闲/行走/跑步动画)
3D Assets
3D资源
- 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**: `<project-dir>`
> **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:
>
> 1. 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`.
> 2. 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.
> 3. 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
> 4. For static models (ring, props): use `loadModel()` (regular clone)
> 5. **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)
> 6. 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.**- tree:Meshy AI生成(静态道具)
- barrel:Meshy AI生成(静态道具)
- house:Poly Haven fallback(CC0授权)
**启动`Task`子代理并附上以下说明:**
> 你正在实现游戏创建管线的步骤1.5(3D资源)。
>
> **项目路径**:`<project-dir>`
> **引擎**:3D(Three.js)
> **需加载的技能**:`game-3d-assets`和`meshyai`
>
> **先读取项目根目录的`progress.md`**。其中列出了生成/下载的模型和角色详情。
>
> **绑定骨骼的角色GLB+动画GLB已放入**`public/assets/models/`。设置角色控制器:
>
> 1. 创建`src/level/AssetLoader.js`——**关键要求:对绑定骨骼的模型使用`SkeletonUtils.clone()`**(常规`.clone()`会破坏骨骼绑定→导致T字姿势)。从`three/addons/utils/SkeletonUtils.js`导入。
> 2. 在Constants.js中添加`MODELS`配置,包含:每个模型的`path`(绑定骨骼的GLB)、`walkPath`、`runPath`、`scale`、`rotationY`。**初始设置`rotationY: Math.PI`**——大多数Meshy模型朝向+Z方向,需要翻转。
> 3. 每个绑定骨骼的模型:
> - 使用`loadAnimatedModel()`加载,创建`AnimationMixer`
> - 单独加载行走/跑步动画GLB,将其剪辑注册为mixer动作
> - 记录所有剪辑名称:`console.log('Clips:', clips.map(c => c.name))`
> - 将mixer和动作存储在实体的`userData`中
> - 每帧调用`mixer.update(delta)`
> - 使用`fadeToAction()`模式实现平滑过渡
> 4. 静态模型(环、道具):使用`loadModel()`(常规克隆)
> 5. **方向与缩放验证(强制要求):**
> - 加载每个模型后,记录其边界框尺寸
> - 计算自动缩放以适配目标高度和容器边界
> - 对齐脚到地面:`position.y = -box.min.y`
> - **角色必须朝向彼此/正确方向**——调整Constants中的`rotationY`
> - **角色必须适配其环境**(环、竞技场、平台)
> - 角色位置必须足够近以交互(攻击范围内,而非横跨竞技场)
> 6. 每个模型加载的`.catch()`中添加原型fallback
>
> **完成工作后**,在`progress.md`中追加`## 步骤1.5:3D资源`部分,包含:使用的模型(Meshy生成vs库模型)、缩放/方向调整、已验证的朝向。
>
> 不要运行构建——编排者会处理验证。
**3D子代理返回后**,运行验证协议。
---
**告知用户(2D游戏):**
> 你的游戏现在有像素艺术精灵图和背景了!每个角色、敌人、道具和背景tile都有独特的视觉标识。创建的内容包括:
> - `src/core/PixelRenderer.js` — 渲染引擎
> - `src/sprites/` — 所有精灵数据、调色板和背景tile
**告知用户(3D游戏):**
> 你的游戏现在有自定义3D模型了!角色通过Meshy AI生成(或从模型库获取)、绑定骨骼并添加了行走/跑步/空闲动画。道具和场景从GLB文件加载。创建的内容包括:
> - `src/level/AssetLoader.js` — 带SkeletonUtils的模型加载器
> - `public/assets/models/` — Meshy生成和/或库GLB模型
> - 带WASD移动的OrbitControls相机
> **下一步:视觉润色**。我将添加粒子效果、屏幕过渡和爽感特效。可以开始了吗?
标记任务2为`completed`。
**等待用户确认后再继续。**Step 2: Design the visuals
步骤2:视觉设计
Mark task 3 as .
in_progressLaunch a subagent with these instructions:
TaskYou are implementing Step 2 (Visual Design — Spectacle-First) of the game creation pipeline.Project path:Engine:<project-dir>Skill to load:<2d|3d>game-designerReadat the project root before starting. It describes the game's entities, events, constants, and what previous steps have done.progress.mdApply 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:
on scene startcameras.main.flash(300)- Player slam-in: player starts off-screen, tweens in with
, landing shake (0.012) + particle burst (20 particles)Bounce.easeOut- 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
andSPECTACLE_ACTIONSPECTACLE_HIT- Floating score text (28px, scale 1.8,
) onElastic.easeOutSCORE_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 asection to## Step 2: Designwith: improvements applied, new effects added, any color or layout changes.progress.mdDo 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 .
completedProceed directly to Step 2.5 — no user confirmation needed (promo video is non-destructive and fast).
标记任务3为。
in_progress启动子代理并附上以下说明:
Task你正在实现游戏创建管线的步骤2(视觉设计——优先视觉冲击力)。项目路径:引擎:<project-dir>需加载的技能:<2d|3d>game-designer先读取项目根目录的。其中描述了游戏的实体、事件、常量和之前步骤的完成情况。progress.md应用game-designer技能,将视觉冲击力作为最高优先级。按以下顺序工作:1. 开场时刻(关键——决定宣传视频成败):
- 入场闪光:场景启动时
cameras.main.flash(300)- 玩家 slam-in:玩家从屏幕外开始,通过
缓动进入位置,伴随落地震动(0.012)+粒子爆发(20个粒子)Bounce.easeOut- 从第1帧开始启用环境粒子(漂浮尘埃、闪光)
- 可选风味文本(例如"GO!"、"DODGE!")——仅当自然适配游戏氛围时添加
- 验证:前3秒无静态帧
2. 动作触发效果(与步骤1的SPECTACLE_*事件对接):
和SPECTACLE_ACTION触发时粒子爆发(12-20个粒子)SPECTACLE_HIT 触发时显示浮动得分文本(28px,初始缩放1.8,SCORE_CHANGED缓动)Elastic.easeOut 触发时背景脉冲(叠加混合,透明度0.15)SCORE_CHANGED- 跟随玩家的持续轨迹粒子发射器(
)blendMode: ADD- 命中时屏幕震动(0.008-0.015)
3. 连击与 streak 系统(与SPECTACLE_COMBO / SPECTACLE_STREAK对接):
- 连击计数器文本随连击数缩放(基础32px,每增加1连击+4px)
- 达到5x、10x、25x streak里程碑时全屏文本 slam +40粒子爆发
- 销毁事件时命中冻结帧(60ms物理暂停)
- 屏幕震动强度随连击数缩放(0.008 + combo * 0.002,上限0.025)
4. 标准设计审核:
- 完整10项审核(背景、调色板、动画、粒子、过渡、排版、游戏手感、游戏结束界面、角色突出性、第一印象/传播吸引力)
- 每项得分必须≥4——改进得分低于4的项
- 第一印象/传播吸引力是最关键的类别
5. 强度校准:
- 粒子爆发:每个事件12-30个粒子(不少于10个)
- 屏幕震动:0.008(轻)到0.025(重)
- 浮动文本:最小28px,初始缩放1.8
- 闪光叠加层:透明度0.3-0.5
- 所有新值放入Constants.js,使用EventBus触发效果
- 不要修改玩法机制
完成工作后,在中追加progress.md部分,包含:应用的改进、添加的新效果、颜色或布局变更(若有)。## 步骤2:设计不要运行构建——编排者会处理验证。
子代理返回后,运行验证协议。
告知用户:
你的游戏现在看起来好多了!变更内容包括:[总结变更]下一步:宣传视频。我将自动录制50 FPS的竖屏手游玩法片段——直接适配社交媒体。之后会添加音乐和音效。
标记任务3为。
completed直接进入步骤2.5——无需用户确认(宣传视频无破坏性且速度快)。
Step 2.5: Record promo video
步骤2.5:录制宣传视频
Mark task 4 as .
in_progressThis 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
bash
ffmpeg -version | head -1If FFmpeg is not found, warn the user and skip this step:
FFmpeg is not installed. Skipping promo video. Install it with(macOS) orbrew install ffmpeg(Linux), then runapt install ffmpeglater./game-creator:promo-video
Mark task 4 as and proceed to Step 3.
completedCopy the conversion script from the plugin:
bash
cp <plugin-root>/skills/promo-video/scripts/convert-highfps.sh <project-dir>/scripts/
chmod +x <project-dir>/scripts/convert-highfps.shLaunch a subagent to generate the game-specific capture script:
TaskYou are implementing Step 2.5 (Promo Video) of the game creation pipeline.Project path:Dev server port:<project-dir>Skill to load:<port>promo-videoReadand the following source files to understand the game:progress.md
— find the death/failure method(s) to patch outsrc/scenes/GameScene.js — understand event flowsrc/core/EventBus.js — check input keys, game dimensionssrc/core/Constants.js — verifysrc/main.jsand__GAME__are exposed__GAME_STATE__Createfollowing thescripts/capture-promo.mjsskill template. You MUST adapt these game-specific parts:promo-video
Death patching — identify ALL code paths that lead to game over and monkey-patch them. Search for,triggerGameOver,gameOver,takeDamage,playerDied, or any method that setsonPlayerHit. Patch every one.gameState.gameOver = true Input sequence — determine the actual input keys from the game's input handling (look for,createCursorKeys(),addKeys(), etc.). Generate ainput.on('pointerdown')function that produces natural-looking gameplay for this specific game type:generateInputSequence(totalMs)
- 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(9:16 mobile portrait) unless the game is desktop-only landscape.{ width: 1080, height: 1920 } Duration — 13s of game-time by default. For slower-paced games (puzzle, strategy), use 8-10s.Config: The script must accept,--port, and--durationCLI args with sensible defaults.--output-dirDo NOT run the capture — just create the script. The orchestrator runs it.
After subagent returns, run the capture and conversion from the main thread:
bash
undefined标记任务4为。
in_progress此步骤在主线程执行。不修改游戏代码——使用Playwright自动录制玩法片段并通过FFmpeg转换。无需QA验证。
前置检查:FFmpeg可用性
bash
ffmpeg -version | head -1若未找到FFmpeg,告知用户并跳过此步骤:
未安装FFmpeg。跳过宣传视频录制。可通过(macOS)或brew install ffmpeg(Linux)安装,之后运行apt install ffmpeg重试。/game-creator:promo-video
标记任务4为并进入步骤3。
completed从插件复制转换脚本:
bash
cp <plugin-root>/skills/promo-video/scripts/convert-highfps.sh <project-dir>/scripts/
chmod +x <project-dir>/scripts/convert-highfps.sh启动子代理生成游戏专属捕获脚本:
Task你正在实现游戏创建管线的步骤2.5(宣传视频)。项目路径:开发服务器端口:<project-dir>需加载的技能:<port>promo-video读取和以下源文件以了解游戏:progress.md
— 查找导致游戏结束的所有代码路径并进行猴子补丁src/scenes/GameScene.js — 了解事件流src/core/EventBus.js — 检查输入按键、游戏尺寸src/core/Constants.js — 验证src/main.js和__GAME__已暴露__GAME_STATE__**创建**遵循scripts/capture-promo.mjs技能模板。必须适配以下游戏专属部分:promo-video
死亡补丁——识别所有导致游戏结束的代码路径并进行猴子补丁。搜索、triggerGameOver、gameOver、takeDamage、playerDied或任何设置onPlayerHit的方法。对所有找到的方法打补丁。gameState.gameOver = true 输入序列——从游戏输入处理中确定实际输入按键(查找、createCursorKeys()、addKeys()等)。生成input.on('pointerdown')函数,为特定游戏类型生成自然的玩法序列:generateInputSequence(totalMs)
- 躲避类(左右移动):交替按住按键,时间随机,偶尔双击
- 平台跳跃类(跳跃):有节奏的点击,间隔变化
- 射击类(移动+射击):移动和射击输入交替
- 俯视角(WASD):8字形或扫动模式
入场暂停——开头包含1-2秒暂停,让入场动画完整播放(这是视觉钩子)。 视口——始终使用(9:16移动端竖屏),除非游戏是桌面端专属横屏游戏。{ width: 1080, height: 1920 } 时长——默认13秒游戏时间。对于慢节奏游戏(解谜、策略),使用8-10秒。配置:脚本必须接受、--port和--durationCLI参数,并提供合理默认值。--output-dir不要运行捕获——仅创建脚本。编排者会运行脚本。
子代理返回后,在主线程运行捕获和转换:
bash
undefinedEnsure output directory exists
确保输出目录存在
mkdir -p <project-dir>/output
mkdir -p <project-dir>/output
Run capture (takes ~26s for 13s game-time at 0.5x)
运行捕获(13秒游戏时间,0.5倍速度,约需26秒)
node scripts/capture-promo.mjs --port <port>
node scripts/capture-promo.mjs --port <port>
Convert to 50 FPS MP4
转换为50 FPS MP4
bash scripts/convert-highfps.sh output/promo-raw.webm output/promo.mp4 0.5
**Verify the output:**
1. Check `output/promo.mp4` exists and is non-empty
2. Verify duration is approximately `DESIRED_GAME_DURATION / 1000` seconds
3. 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:
```bash
ffmpeg -y -ss 5 -i output/promo.mp4 -frames:v 1 -update 1 output/promo-thumbnail.jpgRead the thumbnail image and show it to the user.
Tell the user:
Promo video recorded! 50 FPS, mobile portrait (1080x1920).File:([duration]s, [size])output/promo.mp4This 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 .
completedWait for user confirmation before proceeding.
bash scripts/convert-highfps.sh output/promo-raw.webm output/promo.mp4 0.5
**验证输出:**
1. 检查`output/promo.mp4`存在且非空
2. 验证时长约为`DESIRED_GAME_DURATION / 1000`秒
3. 验证帧率为50 FPS
若捕获失败(Playwright错误、超时等),告知用户并跳过——宣传视频是锦上添花的功能,非必须。
**提取缩略图供用户预览:**
```bash
ffmpeg -y -ss 5 -i output/promo.mp4 -frames:v 1 -update 1 output/promo-thumbnail.jpg读取缩略图并展示给用户。
告知用户:
宣传视频已录制完成!50 FPS,移动端竖屏(1080x1920)。文件:([时长]秒,[大小])output/promo.mp4视频为自动录制——游戏以0.5倍速度运行,录制帧率25 FPS,之后通过FFmpeg加速至50 FPS。已禁用死亡机制,展示连续玩法。下一步:音乐和音效。可以开始了吗?
标记任务4为。
completed等待用户确认后再继续。
Step 3: Add audio
步骤3:添加音频
Mark task 5 as .
in_progressLaunch a subagent with these instructions:
TaskYou are implementing Step 3 (Audio) of the game creation pipeline.Project path:Engine:<project-dir>Skill to load:<2d|3d>game-audioReadat the project root before starting. It describes the game's entities, events, constants, and what previous steps have done.progress.mdApply the game-audio skill:
- Audit the game: check for
, read EventBus events, read all scenes@strudel/web- Install
if needed@strudel/web- Create
,src/audio/AudioManager.js,music.js,sfx.jsAudioBridge.js- Add audio events to EventBus.js (including
)AUDIO_TOGGLE_MUTE- Wire audio into main.js and all scenes
- Important: Use explicit imports from
(@strudel/web) — do NOT rely on global registrationimport { stack, note, s } from '@strudel/web'- Mute toggle: Wire
toAUDIO_TOGGLE_MUTE. Add M key shortcut and a speaker icon UI button. See thegameState.game.isMutedrule and the game-audio skill "Mute Button" section for requirements and drawing code.mute-buttonAfter completing your work, append asection to## Step 3: Audiowith: BGM patterns added, SFX event mappings, mute wiring confirmation.progress.mdDo 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. Note: Strudel is AGPL-3.0, so your project needs a compatible open source license.Next up: deploy to the web. I'll help you set up GitHub Pages so your game gets a public URL. Future changes auto-deploy when you push. Ready?
Mark task 5 as .
completedWait for user confirmation before proceeding.
标记任务5为。
in_progress启动子代理并附上以下说明:
Task你正在实现游戏创建管线的步骤3(音频)。项目路径:引擎:<project-dir>需加载的技能:<2d|3d>game-audio先读取项目根目录的。其中描述了游戏的实体、事件、常量和之前步骤的完成情况。progress.md应用game-audio技能:
- 审核游戏:检查
使用情况,读取EventBus事件,读取所有场景@strudel/web- 若需要安装
@strudel/web- 创建
、src/audio/AudioManager.js、music.js、sfx.jsAudioBridge.js- 在EventBus.js中添加音频事件(包括
)AUDIO_TOGGLE_MUTE- 在main.js和所有场景中接入音频
- 重要:使用
的显式导入(@strudel/web)——不要依赖全局注册import { stack, note, s } from '@strudel/web'- 静音切换:将
与AUDIO_TOGGLE_MUTE对接。添加M键快捷键和扬声器图标UI按钮。参见gameState.game.isMuted规则和game-audio技能的"静音按钮"部分了解要求和绘制代码。mute-button完成工作后,在中追加progress.md部分,包含:添加的BGM模式、SFX事件映射、静音对接确认。## 步骤3:音频不要运行构建——编排者会处理验证。
子代理返回后,运行验证协议。
告知用户:
你的游戏现在有音乐和音效了!点击/触摸一次激活音频,之后就能听到音乐。 注意:Strudel采用AGPL-3.0协议,因此你的项目需要使用兼容的开源许可证。下一步:部署到网页。我将帮你设置GitHub Pages,让游戏获得公开URL。后续变更可自动部署。可以开始了吗?
标记任务5为。
completed等待用户确认后再继续。
Step 4: Deploy to GitHub Pages
步骤4:部署到GitHub Pages
Mark task 6 as .
in_progressLoad the game-deploy skill. This step stays in the main thread because it requires interactive authentication and user back-and-forth.
标记任务6为。
in_progress加载game-deploy技能。此步骤在主线程执行,因为需要交互式认证和用户协作。
6a. Check prerequisites
6a. 检查前置条件
Run to check if the GitHub CLI is installed and authenticated.
gh auth statusIf is not found, tell the user:
ghYou need the GitHub CLI to deploy. Install it with:
- macOS:
brew install gh- Linux:
or see https://cli.github.comsudo apt install ghOnce installed, runand follow the prompts, then tell me when you're ready.gh auth login
Wait for the user to confirm.
If is not authenticated, tell the user:
ghYou need to log in to GitHub. Run this command and follow the prompts:gh auth loginChoose "GitHub.com", "HTTPS", and authenticate via browser. Tell me when you're done.
Wait for the user to confirm. Then re-run to verify.
gh auth status运行检查GitHub CLI是否已安装并认证。
gh auth status若未找到,告知用户:
gh部署需要GitHub CLI。安装方式:
- macOS:
brew install gh- Linux:
或访问https://cli.github.comsudo apt install gh安装完成后,运行并按照提示操作,完成后告知我。gh auth login
等待用户确认。
若未认证,告知用户:
gh需要登录GitHub。运行以下命令并按照提示操作:gh auth login选择"GitHub.com"、"HTTPS",并通过浏览器认证。完成后告知我。
**等待用户确认。**然后重新运行验证。
gh auth status6b. Build the game
6b. 构建游戏
bash
npm run buildVerify exists and contains and assets. If the build fails, fix the errors before proceeding.
dist/index.htmlbash
npm run build验证存在且包含和资源。若构建失败,修复错误后再继续。
dist/index.html6c. Set up the Vite base path
6c. 设置Vite基础路径
Read . The option must match the GitHub Pages URL pattern . If it's not set or wrong, update it:
vite.config.jsbase/<repo-name>/js
export default defineConfig({
base: '/<game-name>/',
// ... rest of config
});Rebuild after changing the base path.
读取。选项必须匹配GitHub Pages URL模式。若未设置或错误,更新:
vite.config.jsbase/<repo-name>/js
export default defineConfig({
base: '/<game-name>/',
// ... 其余配置
});修改基础路径后重新构建。
6d. Create the GitHub repo and push
6d. 创建GitHub仓库并推送
Check if the project already has a git remote. If not:
bash
git init
git add .
git commit -m "Initial commit"
gh repo create <game-name> --public --source=. --pushIf it already has a remote, just make sure all changes are committed and pushed.
检查项目是否已有git远程仓库。若无:
bash
git init
git add .
git commit -m "Initial commit"
gh repo create <game-name> --public --source=. --push若已有远程仓库,确保所有变更已提交并推送。
6e. Deploy with gh-pages
6e. 使用gh-pages部署
bash
npm install -D gh-pages
npx gh-pages -d distThis pushes the folder to a branch on GitHub.
dist/gh-pagesbash
npm install -D gh-pages
npx gh-pages -d dist此命令将文件夹推送到GitHub的分支。
dist/gh-pages6f. Enable GitHub Pages
6f. 启用GitHub Pages
bash
GITHUB_USER=$(gh api user --jq '.login')
gh api repos/$GITHUB_USER/<game-name>/pages -X POST --input - <<< '{"build_type":"legacy","source":{"branch":"gh-pages","path":"/"}}'If Pages is already enabled, this may return an error — that's fine, skip it.
bash
GITHUB_USER=$(gh api user --jq '.login')
gh api repos/$GITHUB_USER/<game-name>/pages -X POST --input - <<< '{"build_type":"legacy","source":{"branch":"gh-pages","path":"/"}}'若Pages已启用,此命令可能返回错误——无需处理,跳过即可。
6g. Get the live URL and verify
6g. 获取在线URL并验证
bash
GITHUB_USER=$(gh api user --jq '.login')
GAME_URL="https://$GITHUB_USER.github.io/<game-name>/"
echo $GAME_URLWait ~30 seconds for the first deploy to propagate, then verify:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"If it returns 404, wait another minute and retry — GitHub Pages can take 1-2 minutes on first deploy.
bash
GITHUB_USER=$(gh api user --jq '.login')
GAME_URL="https://$GITHUB_USER.github.io/<game-name>/"
echo $GAME_URL等待约30秒让首次部署生效,然后验证:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"若返回404,再等待1分钟并重试——首次部署GitHub Pages可能需要1-2分钟。
6h. Add deploy script
6h. 添加部署脚本
Add a script to so future deploys are one command:
deploypackage.jsonjson
{
"scripts": {
"deploy": "npm run build && npx gh-pages -d dist"
}
}Tell the user:
Your game is live!URL:https://<username>.github.io/<game-name>/How auto-deploy works: Whenever you make changes, just run:npm run deployOr if you're working with me, I'll commit your changes and run deploy 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?
Mark task 6 as .
completedWait for user confirmation before proceeding.
在中添加脚本,以便后续一键部署:
package.jsondeployjson
{
"scripts": {
"deploy": "npm run build && npx gh-pages -d dist"
}
}告知用户:
你的游戏已上线!URL:https://<username>.github.io/<game-name>/自动部署方式:每次修改代码后,只需运行:npm run deploy若与我协作,我会提交你的变更并运行部署。下一步:变现。我将帮你在Play.fun(OpenGameProtocol)注册游戏、添加SDK并重新部署。玩家可获得奖励,你可获得可分享至Moltbook的play.fun URL。可以开始了吗?
标记任务6为。
completed等待用户确认后再继续。
Step 5: Monetize with Play.fun
步骤5:通过Play.fun变现
Mark task 7 as .
in_progressThis step stays in the main thread because it requires interactive authentication.
标记任务7为。
in_progress此步骤在主线程执行,因为需要交互式认证。
7a. Authenticate with Play.fun
7a. Play.fun认证
Check if the user already has Play.fun credentials. The auth script is bundled with the plugin:
bash
node skills/playdotfun/scripts/playfun-auth.js statusIf credentials exist, skip to 7b.
If no credentials, start the auth callback server:
bash
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/callbackLog 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 statusIf callback fails, offer manual method as fallback.
检查用户是否已有Play.fun凭证。认证脚本已随插件捆绑:
bash
node skills/playdotfun/scripts/playfun-auth.js status若凭证存在,跳至7b。
若无凭证,启动认证回调服务器:
bash
node skills/playdotfun/scripts/playfun-auth.js callback &告知用户:
要在Play.fun注册游戏,需要登录一次。 在浏览器中打开此URL: https://app.play.fun/skills-auth?callback=http://localhost:9876/callback使用你的Play.fun账号登录。凭证将本地保存。 完成后告知我。
**等待用户确认。**然后通过验证。
playfun-auth.js status若回调失败,提供手动方法作为fallback。
7b. Register the game on Play.fun
7b. 在Play.fun注册游戏
Determine the deployed game URL from Step 6 ().
https://<username>.github.io/<game-name>/Read for the game name and description. Read to determine reasonable anti-cheat limits based on the scoring system.
package.jsonsrc/core/Constants.jsUse the Play.fun API to register the game. Load the skill for API reference. Register via :
playdotfunPOST https://api.play.fun/gamesjson
{
"name": "<game-name>",
"description": "<game-description>",
"gameUrl": "<deployed-url>",
"platform": "web",
"isHTMLGame": true,
"iframable": true,
"maxScorePerSession": <based on game scoring>,
"maxSessionsPerDay": 50,
"maxCumulativePointsPerDay": <reasonable daily cap>
}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.
从步骤6确定已部署的游戏URL()。
https://<username>.github.io/<game-name>/读取获取游戏名称和描述。读取根据得分系统确定合理的反作弊限制。
package.jsonsrc/core/Constants.js使用Play.fun API注册游戏。加载技能获取API参考。通过注册:
playdotfunPOST https://api.play.fun/gamesjson
{
"name": "<game-name>",
"description": "<game-description>",
"gameUrl": "<deployed-url>",
"platform": "web",
"isHTMLGame": true,
"iframable": true,
"maxScorePerSession": <基于游戏得分系统>,
"maxSessionsPerDay": 50,
"maxCumulativePointsPerDay": <合理每日上限>
}反作弊指南:
- 休闲点击/放置类:
maxScorePerSession: 100-500 - 技能型街机类(Flappy Bird、跑酷):
maxScorePerSession: 500-2000 - 竞技/复杂类:
maxScorePerSession: 1000-5000
保存返回的游戏UUID。
7c. Add the Play.fun Browser SDK
7c. 添加Play.fun浏览器SDK
First, extract the user's API key from stored credentials:
bash
undefined首先,从存储的凭证中提取用户的API密钥:
bash
undefinedRead API key from agent config (stored by playfun-auth.js)
从代理配置中读取API密钥(由playfun-auth.js存储)
Example path for Claude Code — adapt for your agent
Claude Code示例路径——根据你的代理调整
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:
```html
<meta name="x-ogp-key" content="<USER_API_KEY>" />
<script src="https://sdk.play.fun/latest"></script>Important: The 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.
x-ogp-keyCreate that wires the game's EventBus to Play.fun points tracking:
src/playfun.jsjs
// src/playfun.js — Play.fun (OpenGameProtocol) integration
import { eventBus, Events } from './core/EventBus.js';
const GAME_ID = '<game-uuid>';
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 |
|---|---|---|
| During gameplay | Buffers points locally, non-blocking |
| Game over / level end | Opens blocking modal, syncs buffered points to server |
⚠️ Do NOT call 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).
savePoints()Read the actual EventBus.js to find the correct event names and payload shapes. Adapt accordingly.
Add to :
initPlayFun()src/main.jsjs
import { initPlayFun } from './playfun.js';
// After game init
initPlayFun().catch(err => console.warn('Play.fun init failed:', err));API_KEY=$(cat ~/.claude.json | jq -r '.mcpServers["play-fun"].headers["x-api-key"]')
echo "用户API密钥:$API_KEY"
若未找到API密钥,提示用户先认证。
然后在`index.html`的`</head>`前添加SDK脚本和meta标签,替换为实际API密钥:
```html
<meta name="x-ogp-key" content="<USER_API_KEY>" />
<script src="https://sdk.play.fun/latest"></script>重要提示: meta标签必须包含用户的Play.fun API密钥(而非游戏ID)。不要保留占位符——务必替换为上述提取的实际密钥。
x-ogp-key创建将游戏的EventBus与Play.fun积分追踪对接:
src/playfun.jsjs
// src/playfun.js — Play.fun(OpenGameProtocol)集成
import { eventBus, Events } from './core/EventBus.js';
const GAME_ID = '<game-uuid>';
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未加载');
return;
}
sdk = new SDKClass({ gameId: GAME_ID, ui: { usePointsWidget: true } });
await sdk.init();
initialized = true;
// addPoints() — 玩法期间频繁调用以本地缓冲积分(非阻塞)
eventBus.on(Events.SCORE_CHANGED, ({ score, delta }) => {
if (initialized && delta > 0) sdk.addPoints(delta);
});
// savePoints() — 仅在自然断点调用(游戏结束、关卡完成)
// 警告:savePoints()会打开阻塞式弹窗——绝不要在活跃玩法期间调用!
eventBus.on(Events.GAME_OVER, () => { if (initialized) sdk.savePoints(); });
// 页面卸载时保存(浏览器会优雅处理)
window.addEventListener('beforeunload', () => { if (initialized) sdk.savePoints(); });
}SDK关键行为:
| 方法 | 使用时机 | 行为 |
|---|---|---|
| 玩法期间 | 本地缓冲积分,非阻塞 |
| 游戏结束 / 关卡结束 | 打开阻塞式弹窗,将缓冲积分同步到服务器 |
⚠️ 绝不要定时调用或在活跃玩法期间调用——会通过弹窗打断玩家。仅在自然暂停点调用(游戏结束、关卡过渡、菜单界面)。
savePoints()读取实际的EventBus.js找到正确的事件名称和负载结构。据此调整。
在中添加:
src/main.jsinitPlayFun()js
import { initPlayFun } from './playfun.js';
// 游戏初始化后
initPlayFun().catch(err => console.warn('Play.fun初始化失败:', err));7d. Rebuild and redeploy
7d. 重新构建并部署
bash
cd <project-dir> && npm run build && npx gh-pages -d distWait ~30 seconds, then verify the deployment is live.
bash
cd <project-dir> && npm run build && npx gh-pages -d dist等待约30秒,然后验证部署已生效。
7e. Tell the user
7e. 告知用户
Your game is monetized on Play.fun!Play:Play.fun:<game-url>https://play.fun/games/<game-uuid>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你的游戏已在Play.fun实现变现!游玩地址:Play.fun地址:<game-url>https://play.fun/games/<game-uuid>Play.fun组件已上线——玩家可查看积分、排行榜和钱包连接。 积分在玩法期间缓冲,游戏结束时保存。分享至Moltbook:将游戏URL发布到moltbook.com——77万+代理已准备好游玩和点赞。
标记任务7为。
completedPipeline 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 GitHub Pages with a 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
告知用户:
你的游戏已完成全流程管线!你现在拥有:
- 清晰的项目架构——模块化代码结构
- 像素艺术精灵图——可识别的角色(若选择)或简洁几何图形
- 视觉润色——渐变、粒子、过渡、爽感特效
- 宣传视频——50 FPS竖屏手游玩法片段(
)output/promo.mp4- 音乐与音效——芯片背景音乐和复古音效
- 质量保障——每个步骤均通过构建、运行时和视觉审查验证
- 网页上线——部署至GitHub Pages并获得公开URL
- Play.fun变现——积分追踪、排行榜和钱包连接
在Moltbook分享你的play.fun URL,触达代理互联网上的77万+代理。 在TikTok、Reels或X发布宣传视频以引流。下一步可以做什么?
- 添加新玩法功能:
/game-creator:add-feature [描述需求]- 升级为像素艺术(若使用图形):
/game-creator:add-assets- 重新录制宣传视频:
/game-creator:record-promo- 为游戏发行playcoin(玩家可获得代币奖励)
- 持续迭代!重新运行任意步骤:
、/game-creator:design-game/game-creator:add-audio- 变更后重新部署:
npm run deploy