Manifest Reference
bodylink.game.json is your game's contract with the BodyLink host: its
identity, its entry point, the security policy for its iframe, the capabilities
it needs, and how it appears in the catalog. It ships inside the bundle and is
immutable per <slug>@<version> — a new release is a new version.
This page annotates every field. It does not restate the normative Runtime v1 contract — for coordinate/calibration semantics it links the feature guides.
The full manifest, annotated
{
// ---- Identity ----
"id": "tv.bodylink.games.myslug", // permanent, globally-unique id
"name": "My Slug", // human display name
"version": "1.0.0", // semver; bump for every release
"runtimeRange": "^1.0.0", // host runtimes this bundle accepts
"runtime": "bodylink-runtime-v1", // the runtime family
// ---- Entry point ----
"entry": {
"kind": "iframe", // Runtime v1 = iframe entry (NOT "module")
"html": "index.html" // bundle-relative entry HTML
},
// ---- Iframe session security ----
"iframeSession": {
"channel": "postmessage",
"allowedParentOrigins": [ // explicit hosts allowed to embed you
"http://127.0.0.1:7500", // your dev server
"http://127.0.0.1:7320", // the self-hosted runner (dev:hosted)
"https://bodylink.tv" // production
],
"sandbox": ["allow-scripts"] // allow-scripts only; never allow-same-origin
},
// ---- Catalog art ----
"assets": {
"catalog": {
"thumbnail": { "path": "assets/catalog/thumbnail.svg", "type": "image/svg+xml" },
"preview": { "path": "assets/catalog/preview.svg", "type": "image/svg+xml" }
}
},
// ---- Capabilities ----
"capabilities": [
"iframe.bundle.v1", // required for iframe entries
"sdk.proxy.v1", // required for iframe entries
"tracking.frame", // receive pose frames
"input.remote", // receive remote/controller input
"diagnostics.runtime"
],
// ---- Calibration defaults ----
"calibration": {
"mode": "upperBodyAction",
"profile": "upperBody",
"params": { "source": "external-myslug" }
},
// ---- Permissions ----
"permissions": { "network": false },
// ---- Optional tracking/coordinate declarations (additive) ----
"coordinate": {
"mode": "full", // "full" (default) | "roi"
"framing": "full-body", // "full-body" (default) | "upper-body"
"calibration": "none", // optional: skip the get-ready ceremony
"debugOverlay": "off" // overlay's initial mode at entry
},
// ---- Launcher: how you appear + tracking budget ----
"launcher": {
"id": "myslug",
"name": "My Slug",
"description": "Touch the rings with one hand to score.",
"color": "#38BDF8",
"gridSize": "2x2",
"tags": ["arcade", "hand-tracking"],
"howToPlay": [
"Reach one hand to touch the glowing rings.",
"Clear all rings to start the next round."
],
"showScore": false,
"requiresCamera": true,
"showWebcam": true,
"showSkeleton": false,
"launchLifecycle": {
"cameraStart": "deferred-to-game",
"countdown": "deferred-to-game",
"getReady": "deferred-to-game"
},
"trackingFocus": "hand",
"trackingPreset": "handAction",
"trackingTier": "standard",
"trackingPolicy": {
"profile": "latency",
"targetFps": 60,
"cameraMaxWidth": 960,
"cameraMaxHeight": 540,
"minHandConfidence": 0.32,
"holdMs": 220,
"stableJitterPx": 0.05
},
"calibration": "hands"
}
}
Identity
| Field | Required | Notes |
|---|---|---|
id |
yes | Globally-unique, permanent. Derived from your slug as tv.bodylink.games.<slug>. Don't change it after publishing. |
name |
yes | Display name. |
version |
yes | Semver. Bundles are immutable per <slug>@<version> — every release is a new version. |
runtimeRange |
yes | A semver range of host runtimes that may run this bundle, e.g. ^1.0.0. A host outside the range won't load it. |
runtime |
yes | The runtime family (bodylink-runtime-v1). |
Entry
| Field | Required | Notes |
|---|---|---|
entry.kind |
yes | Must be "iframe" for Runtime v1. A missing kind defaults to "module" (legacy) and is rejected. |
entry.html |
yes | Bundle-relative path to your entry page. No absolute, URL-like, or .. paths. |
Iframe session
| Field | Required | Notes |
|---|---|---|
iframeSession.channel |
yes | "postmessage". |
iframeSession.allowedParentOrigins |
yes | Explicit list of origins allowed to embed you. "*" is forbidden. Include your local dev origins and your production host. Full guidance: Allowed Parent Origins. |
iframeSession.sandbox |
yes | Token array. Must include allow-scripts; must never include allow-same-origin (that would defeat the opaque-origin sandbox). |
Capabilities
Declare exactly what your game uses. Iframe entries must include both
iframe.bundle.v1 and sdk.proxy.v1. Add tracking.frame, input.remote,
diagnostics.runtime, and — if used — camera.preview / camera.photo. A
capability your game uses but didn't declare is refused at runtime; the
Validation Reference lists the codes.
Calibration (top-level)
Your game's default calibration request: mode, profile (e.g. upperBody),
and free-form params. To skip the get-ready ceremony entirely, use the
coordinate.calibration: "none" opt-in — see
No-Calibration Opt-In.
Permissions
| Field | Notes |
|---|---|
permissions.network |
Whether the game may make network requests. Default false — keep it false unless you truly need it (and expect extra review scrutiny). |
The coordinate block (optional, additive)
All optional; an undeclared bundle keeps the defaults.
| Field | Values | Meaning |
|---|---|---|
coordinate.mode |
"full" (default) | "roi" |
Which coordinate space your landmarks arrive in. See Camera Preview & Coordinates. |
coordinate.framing |
"full-body" (default) | "upper-body" |
Which landmarks are required (upper-body makes seated play first-class). |
coordinate.calibration |
"none" |
Stream frames at entry with no get-ready ceremony. See No-Calibration Opt-In. |
coordinate.debugOverlay |
"off" (default) | "preview" | "preview-skeleton" | "full" |
Where the host debug overlay starts. See Debug Overlay. |
The launcher block
Display + tracking metadata for the catalog. A missing block is
bundle.launcher_missing; a missing required field is
bundle.launcher_field_missing.
| Field | Meaning |
|---|---|
name, description, color, gridSize, tags, howToPlay |
Catalog card content and layout. |
showScore, requiresCamera, showWebcam, showSkeleton |
Launcher UI hints. |
launchLifecycle.cameraStart / countdown / getReady |
Who owns each entry step. deferred-to-game means your game drives it (call ensureRuntimeReady at entry). |
trackingFocus |
The primary tracked region, e.g. "hand". |
trackingPreset |
A named tracking preset, e.g. "handAction". |
trackingTier |
The pose-inference budget — see below. |
trackingPolicy |
Fine-grained tracking knobs — see below. |
calibration |
The launcher's calibration style, e.g. "hands". |
launcher.trackingTier
The tier sets the pose-inference budget (pose max dimension, pose model) and
nothing else.
| Tier | Budget | Use it for |
|---|---|---|
"standard" (default) |
640 + the lite pose model | Every catalog game today. The right choice for almost all new games — leave it here unless you have rig evidence to move. |
"high" |
960 + the full pose model | Only a precision game that genuinely needs a better depth/world-z stream. Treat switching as a re-tune, not a flag flip — it changes the world-z stream your filters are tuned against, and costs more on-device (a weak device may fall back to standard). |
"custom" |
An explicit budget you supply | A deliberate off-tier budget (e.g. a floor-budget hand game). Requires the budget keys in trackingPolicy. |
The tier owns the budget. Do not also put
poseMaxDim/poseModelintrackingPolicyunless the tier is"custom"—validaterejects that conflict fail-closed. The template'sstandardtier already supplies 640, so itstrackingPolicycarries noposeMaxDim.
launcher.trackingPolicy
Per-game tracking knobs. Common fields (from the scaffold):
| Field | Example | Meaning |
|---|---|---|
profile |
"latency" |
Overall tuning bias (latency vs. quality). |
targetFps |
60 |
Target tracking frame rate. |
cameraMaxWidth / cameraMaxHeight |
960 / 540 |
Camera capture caps. |
minHandConfidence |
0.32 |
Minimum confidence to accept a hand. |
holdMs |
220 |
Hold time before a "touch"/action commits. |
stableJitterPx |
0.05 |
Jitter tolerance for stability. |
Tune these to your game's feel. Keep them explicit; only add poseMaxDim /
poseModel here when trackingTier is "custom".
Related pages
- Your First Game with Vite — a minimal manifest in context.
- Validation Reference — every named check and its fix, including the manifest checks above.
- Allowed Parent Origins — the
allowedParentOriginslist in depth.