monetize-game

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Monetize Game (Play.fun / OpenGameProtocol)

游戏变现(Play.fun / OpenGameProtocol)

Register your game on Play.fun (OpenGameProtocol), integrate the browser SDK for points tracking and leaderboards, and get a shareable play.fun URL. This is the link you post to Moltbook.
What you'll get:
  1. Your game registered on Play.fun with anti-cheat config
  2. The Play.fun browser SDK integrated into your game (points widget, leaderboard, wallet connect)
  3. A rebuilt + redeployed game with the SDK active
  4. A play.fun game URL to share on Moltbook and social media
Play.fun(OpenGameProtocol)上注册你的游戏,集成用于积分追踪和排行榜的浏览器SDK,获取可分享的play.fun链接。你可以将该链接发布到Moltbook。
你将获得:
  1. 你的游戏已在Play.fun上注册并配置反作弊规则
  2. 游戏中已集成Play.fun浏览器SDK(积分组件、排行榜、钱包连接功能)
  3. 已重新构建并部署激活SDK后的游戏
  4. 可在Moltbook和社交媒体分享的play.fun游戏链接

Prerequisites

前置条件

  • A deployed game with a public URL (run
    /game-creator:make-game
    first, or ensure your game is deployed to GitHub Pages / Vercel / etc.)
  • Node.js installed
  • 已部署且拥有公共URL的游戏(先运行
    /game-creator:make-game
    ,或确保你的游戏已部署到GitHub Pages / Vercel等平台)
  • 已安装Node.js

Instructions

操作步骤

Step 0: Locate the game

步骤0:定位游戏

Parse
$ARGUMENTS
to find the game project directory. If not provided, check the current working directory for a
package.json
with Phaser or Three.js dependencies.
Read
package.json
to confirm this is a game project. Read
vite.config.js
or similar to determine the deployed URL (look for
base
path).
解析
$ARGUMENTS
以找到游戏项目目录。如果未提供该参数,检查当前工作目录中是否存在包含Phaser或Three.js依赖的
package.json
文件。
读取
package.json
确认这是一个游戏项目。读取
vite.config.js
或类似文件以确定部署URL(查找
base
路径)。

Step 1: Authenticate with Play.fun

步骤1:通过Play.fun认证

Check if the user already has Play.fun credentials:
bash
node skills/playdotfun/scripts/playfun-auth.js status
If credentials exist and are valid, skip to Step 2.
If no credentials, walk the user through authentication:
To register your game on Play.fun, you need to authenticate first.
I'll start a local auth server. Click the link below to log in:
bash
node skills/playdotfun/scripts/playfun-auth.js callback &
Then tell the user:
Log in with your Play.fun account. The credentials will be saved automatically. Tell me when you're done.
Wait for user confirmation. Then verify:
bash
node skills/playdotfun/scripts/playfun-auth.js status
If verification fails, offer the manual method as a fallback:
If the callback didn't work, you can paste your credentials manually. Go to your Play.fun dashboard, copy your API credentials (base64 format), and I'll save them:
node skills/playdotfun/scripts/playfun-auth.js manual <your-base64-credentials>
检查用户是否已拥有Play.fun凭证:
bash
node skills/playdotfun/scripts/playfun-auth.js status
如果凭证存在且有效,跳至步骤2。
如果没有凭证,引导用户完成认证:
要在Play.fun上注册你的游戏,你需要先完成认证。
我将启动一个本地认证服务器。点击下方链接登录:
bash
node skills/playdotfun/scripts/playfun-auth.js callback &
然后告知用户:
使用你的Play.fun账号登录。凭证将自动保存。 完成后告知我。
等待用户确认。然后验证:
bash
node skills/playdotfun/scripts/playfun-auth.js status
如果验证失败,提供手动方法作为备选:
如果回调失败,你可以手动粘贴凭证。 进入你的Play.fun控制台,复制你的API凭证(base64格式),我将为你保存:
node skills/playdotfun/scripts/playfun-auth.js manual <your-base64-credentials>

Step 2: Determine the game URL

步骤2:确定游戏URL

Find the deployed game URL. Check in this order:
  1. Look for a GitHub Pages URL by running:
    bash
    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)
    If both resolve, the URL is
    https://$GITHUB_USER.github.io/$REPO_NAME/
  2. Check
    vite.config.js
    for a
    base
    path that hints at the deployment URL
  3. Ask the user for their game URL if it can't be determined
Verify the URL is accessible:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"
查找已部署的游戏URL,按以下顺序检查:
  1. 运行以下命令查找GitHub Pages URL:
    bash
    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/
  2. 检查
    vite.config.js
    中的
    base
    路径,该路径可能暗示部署URL
  3. 如果无法确定,询问用户提供游戏URL
验证URL是否可访问:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"

Step 3: Register the game on Play.fun

步骤3:在Play.fun上注册游戏

Read the game's
package.json
for the name and description. Read
src/core/Constants.js
(or equivalent) to determine reasonable anti-cheat limits based on the scoring system.
Use the Play.fun MCP
register_game
tool if available. Otherwise, use the API directly:
Load the
playdotfun
skill for API reference. Register the game via
POST https://api.play.fun/games
with:
json
{
  "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 (from the playdotfun skill):
  • 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 — you'll need it for the SDK integration.
Tell the user:
Your game is registered on Play.fun! Game ID:
<uuid>
Name:
<name>
读取游戏的
package.json
获取名称和描述。读取
src/core/Constants.js
(或等效文件),根据计分系统确定合理的反作弊限制。
如果Play.fun MCP的
register_game
工具可用,则使用该工具。否则,直接调用API:
加载
playdotfun
技能以获取API参考。通过
POST https://api.play.fun/games
注册游戏,请求体如下:
json
{
  "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>

Step 4: Add the Play.fun Browser SDK

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

Integrate the SDK into the game. This is a lightweight addition — the SDK loads from CDN and provides a points widget overlay.
将SDK集成到游戏中。这是一个轻量级的添加——SDK从CDN加载,并提供积分组件覆盖层。

4a. Add the SDK script and meta tag to
index.html

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

First, extract the user's API key from stored credentials:
bash
undefined
首先,从存储的凭证中提取用户的API密钥:
bash
undefined

Read API key from agent config (stored by playfun-auth.js)

从agent配置中读取API密钥(由playfun-auth.js存储)

Example path for Claude Code — adapt for your agent

Claude Code的示例路径——根据你的agent调整

API_KEY=$(cat ~/.claude.json | jq -r '.mcpServers["play-fun"].headers["x-api-key"]') echo "User API Key: $API_KEY"

If no API key is found, prompt the user to authenticate first (Step 1).

Then add before the closing `</head>` tag, 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
x-ogp-key
meta tag must contain the user's API key (not the game ID). Do NOT leave the placeholder
USER_API_KEY_HERE
— always substitute the actual key extracted above.
API_KEY=$(cat ~/.claude.json | jq -r '.mcpServers["play-fun"].headers["x-api-key"]') echo "User API Key: $API_KEY"

如果未找到API密钥,提示用户先完成认证(步骤1)。

然后在`</head>`闭合标签之前添加以下内容,替换为实际的API密钥:

```html
<meta name="x-ogp-key" content="<USER_API_KEY>" />
<script src="https://sdk.play.fun/latest"></script>
重要提示
x-ogp-key
meta标签必须包含用户的API密钥(而非游戏ID)。请勿保留占位符
USER_API_KEY_HERE
——务必替换为上面提取的实际密钥。

4b. Create
src/playfun.js
integration module

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

Create a module that wires the Play.fun SDK into the game's EventBus:
js
// 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() {
  // Award points on score changes
  // addPoints() buffers points locally — call frequently during gameplay
  if (Events.SCORE_CHANGED) {
    eventBus.on(Events.SCORE_CHANGED, ({ score, delta }) => {
      if (sdk && initialized && delta > 0) {
        sdk.addPoints(delta);
      }
    });
  }

  // Save points on game over
  // savePoints() opens a BLOCKING MODAL — only call at natural break points:
  // - Game over
  // - Level complete
  // - User returns to menu
  // DO NOT call savePoints() during active gameplay or on a timer!
  if (Events.GAME_OVER) {
    eventBus.on(Events.GAME_OVER, () => {
      if (sdk && initialized) {
        sdk.savePoints(); // Uses buffered points from addPoints() calls
      }
    });
  }

  // Save on page unload (non-blocking, browser handles it)
  window.addEventListener('beforeunload', () => {
    if (sdk && initialized) {
      sdk.savePoints();
    }
  });
}
Critical SDK behavior:
MethodWhen to useBehavior
addPoints(n)
During gameplayBuffers points locally, non-blocking
savePoints()
Game over / level endOpens blocking modal, syncs buffered points to server
⚠️ Do NOT call
savePoints()
on a timer or during active gameplay
— it interrupts the player with a modal dialog. Only call at natural pause points (game over, level transitions, menu screens).
Important: Read the actual
EventBus.js
to find the correct event names. Common patterns:
  • SCORE_CHANGED
    /
    score:changed
    with
    { score, delta }
    or
    { score }
  • GAME_OVER
    /
    game:over
Adapt the event names and payload destructuring to match what the game actually emits. If the game doesn't emit a delta, compute it by tracking the previous score.
创建一个模块,将Play.fun SDK连接到游戏的EventBus:
js
// 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() {
  // Award points on score changes
  // addPoints() buffers points locally — call frequently during gameplay
  if (Events.SCORE_CHANGED) {
    eventBus.on(Events.SCORE_CHANGED, ({ score, delta }) => {
      if (sdk && initialized && delta > 0) {
        sdk.addPoints(delta);
      }
    });
  }

  // Save points on game over
  // savePoints() opens a BLOCKING MODAL — only call at natural break points:
  // - Game over
  // - Level complete
  // - User returns to menu
  // DO NOT call savePoints() during active gameplay or on a timer!
  if (Events.GAME_OVER) {
    eventBus.on(Events.GAME_OVER, () => {
      if (sdk && initialized) {
        sdk.savePoints(); // Uses buffered points from addPoints() calls
      }
    });
  }

  // Save on page unload (non-blocking, browser handles it)
  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
根据游戏实际触发的事件,调整事件名称和负载解构。如果游戏不触发delta参数,可通过追踪之前的分数来计算。

4c. Wire into main.js

4c. 连接到main.js

Add the Play.fun init call to the game's entry point (
src/main.js
):
js
import { initPlayFun } from './playfun.js';

// After game initialization
initPlayFun().catch(err => console.warn('Play.fun init failed:', err));
The
initPlayFun()
call should be non-blocking — if the SDK fails to load (e.g., ad blocker), the game still works.
将Play.fun的初始化调用添加到游戏的入口文件(
src/main.js
):
js
import { initPlayFun } from './playfun.js';

// 游戏初始化完成后
initPlayFun().catch(err => console.warn('Play.fun init failed:', err));
initPlayFun()
调用应是非阻塞的——如果SDK加载失败(例如被广告拦截器阻止),游戏仍能正常运行。

Step 5: Rebuild and redeploy

步骤5:重新构建并部署

bash
cd <project-dir> && npm run build
If the build fails, fix the integration code and retry.
Then redeploy:
bash
cd <project-dir> && npx gh-pages -d dist
Or whatever deploy method the project uses (
npm run deploy
if available).
bash
cd <project-dir> && npm run build
如果构建失败,修复集成代码后重试。
然后重新部署:
bash
cd <project-dir> && npx gh-pages -d dist
或使用项目采用的其他部署方法(如果有
npm run deploy
则使用该命令)。

Step 6: Confirm and share

步骤6:确认并分享

Wait ~30 seconds for deployment to propagate, then verify:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"
Tell the user:
Your game is monetized on Play.fun!
Play your game:
<game-url>
View on Play.fun:
https://play.fun/games/<game-uuid>
What's live:
  • Points widget overlay (bottom-right corner)
  • Leaderboard tracking
  • Wallet connect for claiming rewards
  • Points buffered during gameplay, saved on game over
Share on Moltbook: Post your game URL to moltbook.com — 770K+ agents on the agent internet ready to play and upvote.
Next steps:
  • Launch a playcoin for your game (token rewards for players)
  • Check your leaderboard on Play.fun
  • Share the play.fun URL on social media
等待约30秒让部署生效,然后验证:
bash
curl -s -o /dev/null -w "%{http_code}" "$GAME_URL"
告知用户:
你的游戏已在Play.fun上实现变现!
游玩你的游戏
<game-url>
在Play.fun上查看
https://play.fun/games/<game-uuid>
已上线功能:
  • 积分组件覆盖层(右下角)
  • 排行榜追踪
  • 钱包连接以领取奖励
  • 游戏进行中缓冲积分,游戏结束时保存
在Moltbook分享:将你的游戏链接发布到moltbook.com——代理互联网上有77万+代理准备游玩并点赞。
后续步骤:
  • 为你的游戏发行Playcoin(给玩家的代币奖励)
  • 在Play.fun上查看你的排行榜
  • 在社交媒体分享play.fun链接