Manifest ReferenceVariants & Partials

Panel Variants

Reference for PanelVariant and PanelPartial — conditional panel content selected at read time by JSON Logic over variables.

Panel variants let one panel show different content depending on state — a reader's earlier choice, their age, an entitlement, or any other variable. Unlike graph branching (different panels), a variant keeps the story flow fixed and swaps the panel's content.

PanelVariant

Defined as $defs/PanelVariant, used in chapters[].panels.<panelId>.variants[].

PropertyTypeRequiredDescription
idIdentifierYesUnique variant ID within the panel.
whenJsonLogicYesCondition evaluated against current variable values. The variant applies when it is truthy.
overridesPanelPartialYesThe panel properties to replace when the variant applies.

Conditions use JSON Logic with { "var": "..." } references to variable IDs, e.g.:

{ "==": [{ "var": "path.choice" }, "left"] }

Selection order

Variants are evaluated in array order; the first variant whose when is truthy applies. When no variant matches, the base panel renders unchanged. A condition that fails to evaluate (unknown operator, malformed logic) counts as false. Players re-evaluate variants whenever a variable changes — hotspot mutations, edge mutations, and host setVariable calls all take effect immediately.

Because the first match wins, order variants from most to least specific when their conditions can overlap. Players may additionally offer readers a manual variant toggle (the reference player's "Alt" toolbar button) as a session-scoped shadow override that cycles automatic → each variant → base → automatic.

PanelPartial

Defined as $defs/PanelPartial — a subset of the Panel object. Every property is optional; a property that is present replaces the base panel's value wholesale (e.g. an overriding layers array replaces the entire base layer list, so repeat any base layers you want to keep).

PropertyTypeDescription
titleLocalizedStringOverride panel title.
descriptionLocalizedStringOverride panel description.
durationMsnumber ≥ 100Override autoplay duration for this panel.
formatViewsmap of PanelFormatViewOverride per-format view settings.
layersLayer[]Replace the panel's layer stack — see Layers.
animationsPanelAnimationsReplace the panel's animation — see Animations.
speechBubblesSpeechBubble[]Replace the speech bubbles.
hotspotsHotspot[]Replace the hotspots.
audioAudioTrack[]Replace the panel audio.
videoVideoLayer[]Replace the panel video layers.
pluginsPluginInstance[]Replace panel plugins — see Extensions.
shareablebooleanOverride sharing permission.
age_rating_overridestringOverride the panel-level age rating.
preloadHintsIdentifier[]Override asset preload hints.
memoryBudgetHintnumber ≥ 0Override the memory budget hint.
contentWarningsIdentifier[]Override the content-warning references.

Compared to a full Panel, a PanelPartial cannot carry id, placement, accessibility, or nested variants (variants do not recurse).

Typical patterns

  • Choice reflection — a hotspot sets path.choice, and a later panel's variants render a left- or right-path version of the same beat.
  • Age-appropriate content — a variant with {"<": [{"var": "user.age"}, 16]} adds a blur overlay layer and a "content adjusted" text layer.
  • Entitlement-aware teasers — swap layers depending on an entitlement variable (the hard gate itself belongs in the paywall).

Example

From the complex sample (02_complex): panel p1-4 reacts to the path.choice variable set by hotspots on the previous panel.

{
  "panels": {
    "p1-4": {
      "title": { "en-US": "The Door" },
      "layers": [
        { "kind": "image", "id": "ly-p1-4-bg", "assetId": "img-p1-4", "z": 0 }
      ],
      "variants": [
        {
          "id": "var-left",
          "when": { "==": [{ "var": "path.choice" }, "left"] },
          "overrides": {
            "layers": [
              { "kind": "image", "id": "ly-p1-4-bg", "assetId": "img-p1-4", "z": 0 },
              { "kind": "image", "id": "ly-p1-4-ovl", "assetId": "img-overlay-left", "z": 1, "opacity": 0.4 },
              {
                "kind": "text", "id": "ly-p1-4-tx", "z": 2, "opacity": 0.95,
                "text": { "en-US": "Left path chosen.", "de-DE": "Linker Pfad gewählt." },
                "style": { "font": "Helvetica", "sizePt": 16, "color": "#ffffff",
                           "strokeColor": "#000000", "strokeWidth": 2 }
              }
            ]
          }
        },
        {
          "id": "var-right",
          "when": { "==": [{ "var": "path.choice" }, "right"] },
          "overrides": {
            "layers": [
              { "kind": "image", "id": "ly-p1-4-bg", "assetId": "img-p1-4", "z": 0 },
              { "kind": "image", "id": "ly-p1-4-ovr", "assetId": "img-overlay-right", "z": 1, "opacity": 0.4 }
            ]
          }
        }
      ]
    }
  }
}

Note how each variant repeats the background layer — overrides.layers replaces the whole stack.

Variants vs. other conditional mechanisms

MechanismGranularityUse when
variants (PanelVariant)Whole property groups of one panelThe panel's content differs meaningfully by state.
visibleIf on a layer/bubble/hotspot/trackSingle elementOne element toggles; the rest of the panel is unchanged.
Conditional graph edgesStory flowThe path differs — readers see different panels entirely.
Was this page helpful?