Getting StartedDemo App

Demo App

The PanelWave Player demo — try bundled works or your own manifest, preview phone/tablet/desktop frames, and inspect variables, events and performance in the dev-tools drawer.

The player repository ships a small Angular application, projects/demo, that embeds pw-player-shell. It is the reference integration, the host of the end-to-end test suite, and a handy tool for checking a manifest before you publish it.

Open the live demo

Rebuilt and redeployed from the repository on every push, so it always runs the latest player.

To run it locally, see Development & Contributing.

Loading a work

The header offers three ways to pick what to read:

  • Bundled demos — Sample Comic (panel and page view, hotspots, extras), Video Sequencing (video panels that play one after another in page view) and Infinite Canvas (a format 1.4 canvas chapter). Their manifests live in projects/demo/src/assets and make good starting points for your own.
  • Manifest URL or path — type any URL and press Load. Cross-origin URLs need CORS headers on the server. The manifest of a published work sends them: https://read.panelwave.org/api/public/read/{team}/{work}/manifest (the public, anonymous view — paid panels arrive as x-locked stubs) or https://read.panelwave.org/api/public/review/{token}/manifest for a review link.
  • Open file… — pick a local panelwave.json. It is read in the browser and never uploaded; a file that isn't valid JSON shows an error banner.

The player is re-created on every switch, so each work starts cleanly.

Responsive preview frames

The Preview selector renders the player inside a fixed-size frame, so you can check layouts and lettering without resizing the window:

FrameSize (CSS px)?device=
Fill windowthe whole windowfill
Phone390 × 844phone
Phone landscape844 × 390phone-landscape
Tablet820 × 1180tablet
Desktop1440 × 900desktop

The frame contains everything the player renders — its toolbar and dialogs position themselves inside it, just as they would in a host app's container of that size.

Dev tools

Dev tools (or ?devtools=1) opens a drawer next to the player with three tabs:

  • Variables — a live inspector over all five variable scopes (global, chapter, page, session, persistent). Watch hotspots, edge actions and branch choices change story state as you read.
  • Events — a log of the shell's outputs (ready, panelChange, chapterChange, variableChange, localeChange, navigationAttempt, error) with their payloads, newest first. Each navigation logs exactly one panelChange.
  • Performance — frames per second, JS heap size (Chromium browsers), manifest load time, and the number of panel changes.

The dev tools are not available in embed mode. The Debug overlay switch outlines every layer, hotspot and speech bubble the player renders — useful for spotting a hotspot that sits in the wrong place or a layer that doesn't cover its panel.

URL parameters

Everything the header does can be preset in the URL, which makes demo links easy to share:

ParameterEffect
?manifest=<url>Load this manifest instead of the sample (e.g. a published work's manifest URL, see above)
?device=<id>Start in a preview frame (see the table above)
?devtools=1Open the dev-tools drawer on load
?vars=<url-encoded JSON>Seed story variables, e.g. ?vars={"user.age":12} — passed as initialVariables, so read-only variables can be set too
?byUrl=1Hand the player the manifest URL (its manifestUrl input) instead of the parsed object, so the shell loads the work itself — use it to check the manifestUrl path, e.g. ?manifest=<url>&byUrl=1
?entitlements=<tokens>Read as a reader who owns something, e.g. ?entitlements=premium,purchased:ch-3,age-verified — passed as the shell's entitlementSnapshot, see Simulated entitlements
?deny=<panelId>[,<panelId>…]Install an entitlement adapter that refuses these panels, to try the paywall path without a backend (an adapter gates navigation only — refused panels still render, see Custom access checks)
?embed=1Embed mode (see below)

Example: https://panelwave.github.io/player/?device=phone&devtools=1&vars={"user.age":16}

Simulated entitlements

?entitlements= takes a comma-separated list of tokens — the syntax of the CMS preview's entitlement simulator — and turns it into the entitlementSnapshot the demo passes to the shell, so you can read your own paid and age-gated panels without a backend:

TokenSnapshot
basic, premium, prosubscriptionTier set to that tier (with several, the highest wins)
purchased:<productId><productId> added to purchasedProductIds
age-verifiedageVerified: true with an age that passes any minimum
free, anything elseNothing

Without the parameter the shell keeps its anonymous reader: paid and age-gated panels show the locked placeholder and the gate. The same tokens can arrive as the entitlements array of an embed config.

Embed mode

With ?embed=1, or automatically when the demo runs inside an iframe, the header is hidden and the demo waits for its host to send the work via postMessage:

iframe.contentWindow.postMessage({
  type: 'config',
  data: {
    manifest,                 // PanelWaveManifest object
    locale: 'de-DE',          // optional
    autoplay: false,          // optional
    viewMode: 'canvas',       // optional: 'auto' | 'panel' | 'canvas'
    variables: { 'user.age': 21 },  // optional initial variables
    entitlements: ['premium', 'purchased:ch-3', 'age-verified'],  // optional, see Simulated entitlements
  },
}, '*');

Each config message re-creates the player with the new work. This is how the PanelWave CMS runs its preview — the preview is the real player, not a copy of it.