@jogabox/game-sdk
@jogabox/game-sdk
把静态 HTML5 游戏接入 jogabox 大厅(PWA / Telegram Mini App)。
游戏在大厅的 iframe 里运行,SDK 经 postMessage 与大厅通信:生命周期、激励视频、云存档、遥测。
大厅是权威方,游戏不能自己发积分——奖励由服务端校验后入账,游戏只读回执。
推荐用 npm + 打包器(Vite),不要用
<script>CDN 动态引入。
SDK v2 升级提示:为了进入 Games 关卡漏斗、教程漏斗、进度快照、性能与错误分析,开发者需要升级到最新版
@jogabox/game-sdk,并优先使用levelStart/levelComplete/levelFail、roundStart/roundEnd、tutorialStep、progressUpdate、gameError、performance等 typed API。旧track()仍兼容,但只作为自定义事件。
1. 安装
npm i @jogabox/game-sdk@0.3.2
2. 用法(Vite 工程)
src/main.ts:
import { createClient } from '@jogabox/game-sdk/client'
const jogabox = createClient()
async function boot() {
const ctx = await jogabox.init() // { account_id, tenant_id, game_ref, locale, brand, channel }
jogabox.loadingFinished() // 资源就绪、进入可玩
jogabox.gameplayStart() // 开始游玩(暂停时配对调用 gameplayStop)
// —— 你的游戏逻辑 ——
// 看广告得奖励(服务端发放, 游戏只读 granted/余额):
// const r = await jogabox.rewardedBreak({ placement: 'level_end' })
// confirmed_balance 是入账后的权威余额;points 只用于 "+N" 动效
// if (r.granted) updateBalance(r.confirmed_balance)
// 云存档(跨设备):
// await jogabox.save('progress', { level: 5 })
// const { value } = await jogabox.load('progress')
}
boot()
vite.config.ts(关键:base: './' 让资源用相对路径,因为游戏托管在版本化子路径下):
import { defineConfig } from 'vite'
export default defineConfig({ base: './', build: { outDir: 'dist' } })
不想从零搭?用官方模板
templates/game-vite/(含上面所有配置),复制后改src/main.ts即可。
3. API
| 方法 | 说明 | 返回 |
|---|---|---|
init() |
握手取上下文;无大厅父窗口时自动返回 standalone mock context | { account_id, tenant_id, game_ref, locale, brand, channel, config, autostart } |
getContext() |
同步取已缓存上下文 | 同上 / null |
shouldAutostart() |
大厅是否要"进入即开局"(默认 true) | boolean |
进入即开局(autostart)—— 必做
大厅是奖励大厅,玩家点游戏就是要马上玩。不要展示菜单/空棋盘/需要再点 "New/Start" 的中间态。
init() 后调用 jogabox.shouldAutostart(),为真就立刻开一局;New/Restart 只作手动重开。
const ctx = await jogabox.init()
jogabox.loadingFinished()
if (jogabox.shouldAutostart()) startNewRound() // ← 直接开局,别停在空盘
jogabox.gameplayStart()
旧版 SDK 无
shouldAutostart()时:把ctx.autostart !== false当作 true 处理即可(等价)。 |loadingProgress(0..1)/loadingFinished()| 加载进度 / 进入可玩 | — | |gameplayStart()/gameplayStop()| 游玩生命周期(驱动广告频控+留存) | — | |rewardedBreak({ placement })| 看视频得奖励(大厅放广告→完播校验→入账) |{ granted, points, confirmed_balance }| |commercialBreak()| 插屏(自然停顿;是否真出由大厅频控) |{ shown }| |save(key, value)/load(key)| 云存档(跨设备同步) |{ ok }/{ value }| |setScore(board, score)| 排行榜 | — | |track(event, props)| 自定义遥测 → 分析 | — | |roundStart/roundEnd| 标准局内生命周期事件;自动补runId| — | |levelStart/levelComplete/levelFail| 标准关卡漏斗事件;自动继承当前runId| — | |tutorialStep| 新手教程漏斗 | — | |resourceEvent| 游戏内资源来源/消耗(非平台积分) | — | |progressUpdate(snapshot)| 平台可读进度快照 | — | |gameError/performance| 错误与性能遥测 | — | |happyTime(0..1)| 高光时刻信号(提示装 PWA / 交叉导流) | — | |requestExit()/share(payload)| 退出 / 分享 | — |
标准事件(v2)—— 推荐
track() 仍可用于自定义事件,但运营看板优先识别标准事件:
const round = await jogabox.roundStart({ mode: 'classic', level: 3 })
await jogabox.levelStart({ runId: round.runId, level: 3, difficulty: 'normal' })
await jogabox.levelComplete({ runId: round.runId, level: 3, score: 1200, durationMs: 42000, moves: 18 })
await jogabox.progressUpdate({
runId: round.runId,
current_level: 4,
highest_level: 4,
rounds_played: 12,
wins: 8,
fails: 4,
last_result: 'win',
custom_summary: { booster_count: 2 }
})
约定:
runId用于配对roundStart/roundEnd、levelStart/levelComplete/levelFail与进度快照;roundStart()未传时 SDK 自动生成。progressUpdate是平台可读快照;完整私有存档仍用save/load。progressUpdate的通用字段放顶层:current_level/highest_level/rounds_played/wins/fails/last_result/completion/highest_tile/best_distance/difficulty;游戏私有摘要放custom_summary。- 游戏内金币/道具用
resourceEvent;平台可兑积分不可由游戏写入。 - 关卡事件必须带稳定
level;否则无法做关卡漏斗。
安全与本地开发
SDK 0.3.2 起,client/host 双向 postMessage 都校验具体 origin/source,不再使用 '*'。正常在 jogabox 大厅 iframe 内运行时无需配置;SDK 会从 document.referrer / ancestorOrigins 推断 host origin。特殊本地嵌入可显式传:
const jogabox = createClient({ hostOrigin: 'http://localhost:5173', timeoutMs: 8000 })
无父窗口直接打开游戏时,SDK 自动进入 standalone mock 模式:init() 立即返回假 context,事件输出到 console.debug,广告默认 { granted:false }。也可以显式配置:
const jogabox = createClient({
mock: true,
mockContext: { locale: 'pt-BR', game_ref: 'my-game' },
mockRewarded: { granted: true, points: 10, confirmed_balance: 110 }
})
4. 铁律
- 不要自己发积分:
rewardedBreak的奖励由服务端发放,游戏只读granted/confirmed_balance;confirmed_balance是入账后权威余额,直接展示,不要本地再累加;广告期间暂停 + 静音。 - 资源相对路径(
base:'./'):游戏跑在…/games/<slug>/<version>/下,绝对/path会指错。 - 云存档不写经济字段:积分/余额以服务端为准;
save单条建议 < 100KB。 account_id当不透明 ID 用,不含 PII。
5. 打包与上线
npm run build # → dist/(静态)+ game.zip(模板已配 zip 打包)
- 打包产物
dist/直接在 studio 后台「上传游戏」 上传(CLI 上传后续提供)。 - 版本化:每次新版本上传为新 version;上线即在大厅目录可见;回滚=切回旧 version。
6. 本地联调
把 dist/ 放进大厅 apps/arcade/public/games/<slug>/ 并在 studio 设 entry_url=/games/<slug>/index.html、status=active,起 core(:4000) + arcade(:5173),打开 http://localhost:5173 进入游戏,观察 SDK 调用回流(core 日志 / ClickHouse game_event)。
宿主端(大厅集成):import { createGameHost } from '@jogabox/game-sdk/host'。