mcpField
M
monetize-game

monetize-game

github.com/playableintelligence开发350871 次安装22 周前更新
代码仓库

关于 monetize-game

monetize-game 是用于将已部署的浏览器游戏注册到 Play.fun 并集成其浏览器 SDK 的技能。它把游戏事件接入积分追踪,随后重新构建和部署游戏以启用 Play.fun 功能。

主要功能

  1. 01在 Play.fun 注册游戏
  2. 02集成 Play.fun 浏览器 SDK
  3. 03将游戏事件连接到积分追踪
  4. 04添加排行榜与钱包连接界面
  5. 05重新构建并部署游戏

适用场景

  1. 01注册已公开托管的浏览器游戏
  2. 02通过 Play.fun 追踪游戏积分
  3. 03发布集成 SDK、可供分享的游戏

MCP 相关

此技能可使用 Play.fun MCP 的 register_game 工具注册游戏。它还会将 Play.fun 浏览器 SDK 集成到游戏中;项目并未被描述为 MCP 服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/playableintelligence/game-creator --skill monetize-game

安装后在 Claude Code 中输入/monetize-game确认已加载。

详细介绍

Monetize Game(Play.fun / OpenGameProtocol)

在 Play.fun(OpenGameProtocol)上注册你的游戏,集成用于积分追踪和排行榜的浏览器 SDK,并获取可分享的 play.fun URL。将此链接发布到 Moltbook。

你将获得:

  1. 在 Play.fun 上注册的游戏,并配置反作弊设置
  2. 集成到游戏中的 Play.fun 浏览器 SDK(积分小组件、排行榜、钱包连接)
  3. 重新构建并重新部署的游戏,SDK 已启用
  4. 可分享到 Moltbook 和社交媒体的 play.fun 游戏 URL

前提条件

  • 已部署且有公开 URL 的游戏(先运行 /game-creator:viral-game 即可一次性完成部署,或确保游戏已部署到 here.now / GitHub Pages / Vercel 等平台)
  • 已安装 Node.js

操作说明

步骤 0:定位游戏

解析 $ARGUMENTS,找到游戏项目目录。如果未提供参数,请在当前工作目录中查找包含 Phaser 或 Three.js 依赖项的 package.json。

读取 package.json,确认这是一个游戏项目。读取 vite.config.js 或类似配置文件,确定部署 URL(查找 base 路径)。

步骤 1:向 Play.fun 进行身份验证

检查用户是否已有 Play.fun 凭据:

node skills/playdotfun/scripts/playfun-auth.js status

如果凭据存在且有效,跳到步骤 2。

如果没有凭据,引导用户完成身份验证:

要在 Play.fun 上注册游戏,你需要先进行身份验证。

我将启动本地身份验证服务器。点击下面的链接登录:

node skills/playdotfun/scripts/playfun-auth.js callback &

然后告诉用户:

在浏览器中打开此 URL: https://app.play.fun/skills-auth?callback=http://localhost:9876/callback

使用你的 Play.fun 账户登录。凭据会自动保存。 完成后告诉我。

等待用户确认。 然后进行验证:

node skills/playdotfun/scripts/playfun-auth.js status

如果验证失败,请提供手动方式作为备用方案:

如果回调未成功,你可以手动粘贴凭据。 前往 Play.fun 控制面板,复制 API 凭据(base64 格式),我会为你保存:

node skills/playdotfun/scripts/playfun-auth.js manual <your-base64-credentials>
步骤 2:确定游戏 URL

查找已部署游戏的 URL。按以下顺序检查:

  1. 检查是否存在 here.now 部署状态文件:

    cat .herenow/state.json 2>/dev/null | jq -r '.publishes | to_entries[0].value.siteUrl // empty'
    

    如果找到,URL 为 siteUrl 的值(例如 https://<slug>.here.now/)

  2. 运行以下命令查找 GitHub Pages URL:

    GITHUB_USER=$(gh api user --jq '.login' 2>/dev/null)
    REPO_NAME=$(basename $(git remote get-url origin 2>/dev/null) .git 2>/dev/null)
    

    如果两项都能解析,URL 为 https://$GITHUB_USER.github.io/$REPO_NAME/

  3. 检查 vite.config.js,查看 base 路径是否能提示部署 URL

  4. 如果无法确定,请向用户询问游戏 URL

验证 URL 是否可访问:

curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"
步骤 3:在 Play.fun 上注册游戏

读取游戏的 package.json,获取名称和描述。读取 src/core/Constants.js(或同等文件),根据计分系统确定合理的反作弊限制。

如果有可用的 Play.fun MCP register_game 工具,请使用该工具。否则,直接调用 API:

加载 playdotfun 技能以查阅 API 参考。通过 POST https://api.play.fun/games 注册游戏,并提供:

{
  "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>
}

反作弊指南(来自 playdotfun 技能):

  • 休闲点击类/放置类:maxScorePerSession: 100-500
  • 技巧型街机游戏(Flappy Bird、跑酷游戏):maxScorePerSession: 500-2000
  • 竞技类/复杂游戏:maxScorePerSession: 1000-5000

保存返回的游戏 UUID,集成 SDK 时会用到。

告诉用户:

你的游戏已在 Play.fun 上注册! 游戏 ID:<uuid> 名称:<name>

步骤 4:添加 Play.fun 浏览器 SDK

将 SDK 集成到游戏中。这是一项轻量级的改动:SDK 从 CDN 加载,并提供积分小组件叠加层。

4a. 将 SDK 脚本和 meta 标签添加到 index.html

从已存储的凭据中获取用户的 Play.fun 公共 API 密钥:

node skills/playdotfun/scripts/playfun-auth.js get-key

此脚本仅将公共 API 密钥打印到标准输出。如果找不到密钥,请提示用户先进行身份验证(步骤 1)。

安全说明:x-ogp-key 是公共客户端标识符,类似于 Stripe 可发布密钥或 Firebase API 密钥。它专为嵌入客户端 HTML 而设计,不授予写入权限、身份验证能力或任何特权操作。密钥(用于服务端 API 调用)绝不会嵌入游戏文件中。

然后在闭合的 </head> 标签前添加:

<meta name="x-ogp-key" content="<PUBLIC_API_KEY>" />
<script src="https://sdk.play.fun/latest"></script>

重要:x-ogp-key meta 标签必须包含用户的 Play.fun 公共 API 密钥(而不是游戏 ID 或密钥)。不要保留占位符——始终使用 playfun-auth.js get-key 获取的实际密钥替换。

4b. 创建 src/playfun.js 集成模块

创建一个模块,将 Play.fun SDK 接入游戏的 EventBus:

// src/playfun.js
// Play.fun (OpenGameProtocol) integration
// Wires game events to Play.fun points tracking

import { eventBus, Events } from './core/EventBus.js';

const GAME_ID = '<game-uuid>';

let sdk = null;
let initialized = false;

export async function initPlayFun() {
  if (typeof OpenGameSDK === 'undefined' && typeof PlayFunSDK === 'undefined') {
    console.warn('Play.fun SDK not loaded — skipping monetization');
    return;
  }

  const SDKClass = typeof PlayFunSDK !== 'undefined' ? PlayFunSDK : OpenGameSDK;
  sdk = new SDKClass({
    gameId: GAME_ID,
    ui: { usePointsWidget: true },
  });

  await sdk.init();
  initialized = true;
  console.log('Play.fun SDK initialized');

  wireEvents();
}

function wireEvents() {
  // addPoints() — call frequently during gameplay to buffer points locally (non-blocking)
  if (Events.SCORE_CHANGED) {
    eventBus.on(Events.SCORE_CHANGED, ({ score, delta }) => {
      if (sdk && 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!
  if (Events.GAME_OVER) {
    eventBus.on(Events.GAME_OVER, () => {
      if (sdk && initialized) {
        sdk.savePoints(); // Uses buffered points from addPoints() calls
      }
    });
  }

  // Save on page unload (browser handles this gracefully)
  window.addEventListener('beforeunload', () => {
    if (sdk && initialized) {
      sdk.savePoints();
    }
  });
}

SDK 的关键行为:

方法使用时机行为
addPoints(n)游戏过程中在本地缓冲积分,不会阻塞
savePoints()游戏结束/关卡结束时打开阻塞式模态对话框,将缓冲的积分同步到服务端

⚠️ 不要在计时器触发时或游戏进行过程中调用 savePoints()——它会弹出模态对话框,打断玩家。只能在自然的暂停节点(游戏结束、关卡切换、菜单界面)调用。

重要:阅读实际的 EventBus.js,以查找正确的事件名称。常见模式:

  • SCORE_CHANGED / score:changed,载荷为 { score, delta } 或 { score }
  • GAME_OVER / game:over

调整事件名称和载荷解构方式,使其与游戏实际发出的事件相匹配。如果游戏不会发出增量值,则通过追踪之前的分数来计算增量。

4c. 接入 main.js

将 Play.fun 初始化调用添加到游戏入口文件(src/main.js):

import { initPlayFun } from './playfun.js';

// After game initialization
initPlayFun().catch(err => console.warn('Play.fun init failed:', err));

initPlayFun() 调用应为非阻塞式——如果 SDK 加载失败(例如被广告拦截器拦截),游戏仍应正常运行。

4d. 安全区域内边距

在 Play.fun 控制面板内运行时,Play.fun SDK 会自动在游戏 iframe 的 document.documentElement 上设置 CSS 自定义属性:

  • --ogp-safe-top-inset——Play.fun 页眉气泡下方的空间(移动设备上约为 68px)
  • --ogp-safe-bottom-inset——Safari 底部控件上方的空间(移动设备上约为 148px)

不在控制面板内时,两者的默认值均为 0px。游戏模板已在 Constants.js 中读取这些值(Phaser 使用 SAFE_ZONE.TOP / SAFE_ZONE.BOTTOM,Three.js HTML 覆盖层使用 CSS var())。

请验证所有 UI 元素(分数、按钮、触控控件)都位于安全区域内——不会被 Play.fun 页眉或 Safari 底部栏遮挡。如果游戏使用自定义 HUD 定位,请更新其位置,使其参考 SAFE_ZONE 常量或 CSS 变量。

步骤 5:重新构建并重新部署
cd <project-dir> && npm run build

如果构建失败,请修复集成代码并重试。

然后重新部署。如果可用,请使用 npm run deploy;否则,检测所用平台:

here.now(默认):

~/.agents/skills/here-now/scripts/publish.sh dist/

GitHub Pages(如果项目使用该平台):

npx gh-pages -d dist
步骤 6:确认并分享

确认部署已上线(here.now 的部署即时生效;GitHub Pages 可能需要 1-2 分钟):

curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"

告知用户:

你的游戏已在 Play.fun 上启用变现!

游玩你的游戏:<game-url> 在 Play.fun 上查看:https://play.fun/games/<game-uuid>

已上线功能:

  • 积分小组件叠加层(右下角)
  • 排行榜追踪
  • 连接钱包以领取奖励
  • 游戏过程中缓冲积分,游戏结束时保存

在 Moltbook 上分享:将游戏 URL 发布到 moltbook.com——Agent 互联网中有 770K+ 个 Agent 等待游玩并点赞。

后续步骤:

  • 为你的游戏发行 playcoin(为玩家提供代币奖励)
  • 在 Play.fun 上查看排行榜
  • 在社交媒体上分享 play.fun URL

示例用法

/monetize-game examples/flappy-bird

结果:通过 Play.fun 完成身份验证 → 使用反作弊限制(maxScorePerSession: 1000)注册游戏 → 将 SDK 添加到 index.html 并创建 src/playfun.js → 将分数事件连接到 addPoints(),将游戏结束事件连接到 savePoints() → 重新构建 → 重新部署 → 游戏上线,地址为 https://play.fun/games/<uuid>。游戏内可见积分组件。

故障排除

浏览器阻止身份验证回调

原因: 弹出窗口拦截器或严格的 CORS 策略会阻止 localhost:9876 OAuth 回调完成。 解决方法: 改用手动粘贴流程——使用 --manual 标志运行身份验证脚本,从控制面板 https://play.fun/dashboard 复制令牌,并在出现提示时粘贴。

游戏注册返回 4xx 错误

原因: 缺少必填字段(名称、描述或 URL),或者游戏 URL 无法公开访问。 解决方法: 注册前,请确保游戏已部署,且可通过提供的 URL 访问。检查所有必填字段是否都已填写。如果使用 here.now,请确认部署尚未过期。

SDK 未加载(广告拦截器)

原因: 浏览器广告拦截器和隐私扩展会阻止 Play.fun SDK CDN(sdk.play.fun)。 解决方法: SDK 集成应采用非阻塞方式——即使加载失败,游戏仍可正常运行。请在 SDK 初始化代码外围添加 try/catch,并记录警告。关闭广告拦截器进行测试,以验证 SDK 功能。

游戏过程中出现 savePoints 模态框

原因: SDK 的积分保存 UI 覆盖层在意外时机触发,打断玩家。 解决方法: 仅在游戏自然暂停时调用 savePoints()(例如游戏结束画面、关卡完成时)。切勿在游戏进行过程中调用。如果可用,请使用 silent: true 选项隐藏模态框。

未找到 API 密钥

原因: 凭据尚未配置,或自上次会话以来已过期。 解决方法: 访问 https://play.fun/dashboard 刷新创作者凭据。使用 playfun-auth.js 重新运行身份验证流程,或手动更新 .env 文件,填入新的 PLAYFUN_API_KEY 和 PLAYFUN_SECRET_KEY 值。

安全说明

  • HTML 中的公开 API 密钥:x-ogp-key meta 标签包含的是公开客户端标识符,并非密钥。它相当于 Stripe 可发布密钥或 Firebase Web API 密钥,专为客户端使用而设计,可安全地公开部署。它不能用于修改游戏数据、访问用户账户或执行特权操作。
  • 密钥处理:Play.fun 密钥(用于服务端 API 注册)仅用于 register_game API 调用,不会写入游戏源文件或已部署的构建产物。
  • 凭据存储:凭据由 playfun-auth.js 管理,并存储在本地凭据存储区。Agent 不会读取 Agent 的内部配置文件(例如 ~/.claude.json)。
  • 金融操作:所有连接钱包和领取奖励的操作均由终端玩家通过 Play.fun SDK UI 发起。游戏开发者的代码不会处理资金、私钥或钱包操作——所有金融交互均由 SDK 在客户端协调完成。
  • 部署:已部署的文件中仅包含公开 API 密钥和游戏 ID。构建产物中不包含任何密钥。

评论

支持 Markdown