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 / poseModel in trackingPolicy unless the tier is "custom"validate rejects that conflict fail-closed. The template's standard tier already supplies 640, so its trackingPolicy carries no poseMaxDim.

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