@panelwave/player 1.2.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as rxjs from 'rxjs';
2
2
  import { Observable } from 'rxjs';
3
3
  import * as i0 from '@angular/core';
4
- import { OnDestroy, EventEmitter, OnInit, OnChanges, SimpleChanges, AfterViewInit, ElementRef } from '@angular/core';
4
+ import { OnDestroy, EventEmitter, OnInit, OnChanges, AfterViewChecked, SimpleChanges, AfterViewInit, ElementRef } from '@angular/core';
5
5
  import { SafeHtml } from '@angular/platform-browser';
6
6
  import * as _panelwave_player from '@panelwave/player';
7
7
 
@@ -36,6 +36,11 @@ interface Panel {
36
36
  audio?: PanelAudioTrack[];
37
37
  /** Array of panel variants based on conditions (optional) */
38
38
  variants?: PanelVariant[];
39
+ /**
40
+ * Animation of the panel while it is shown (schema `PanelAnimations`):
41
+ * layer keyframes (schema 1.6+) and/or a camera move.
42
+ */
43
+ animations?: PanelAnimations;
39
44
  /** Whether this panel can be shared socially (optional) */
40
45
  shareable?: boolean;
41
46
  /** Override for age rating (optional) */
@@ -48,6 +53,14 @@ interface Panel {
48
53
  memoryBudgetHint?: number;
49
54
  /** Plugin instances for this panel (optional) */
50
55
  plugins?: PluginInstance$1[];
56
+ /**
57
+ * Server-side paywall stub: public manifests strip the content of paid
58
+ * panels and set this flag. The player renders a lock placeholder instead
59
+ * of layers, bubbles and hotspots (see `isLockedPanel`).
60
+ */
61
+ 'x-locked'?: boolean;
62
+ /** Custom extension properties starting with x- (format 1.7+) */
63
+ [key: `x-${string}`]: unknown;
51
64
  }
52
65
  /**
53
66
  * Manifest audio role (schema `AudioTrack.role`). `ui` plays on the SFX bus,
@@ -71,6 +84,60 @@ interface PanelAudioTrack {
71
84
  /** JSON Logic condition; the track only plays when it evaluates true (optional) */
72
85
  visibleIf?: JsonLogic;
73
86
  }
87
+ /**
88
+ * Layer property a keyframe animates (schema 1.6+).
89
+ *
90
+ * - `opacity`: 0-1, replaces the layer's opacity
91
+ * - `transform.x` / `transform.y`: offset from the layer's resting position as a
92
+ * fraction of the panel's width / height (0.1 = 10 % right / down)
93
+ * - `transform.scale`: scale factor around the layer's center (1 = unchanged)
94
+ * - `transform.rotation`: degrees clockwise around the layer's center
95
+ * - `blur`: blur radius in px at a panel width of 1024 px (scaled with the rendered panel)
96
+ * - `brightness` / `contrast` / `saturate`: multiplier (1 = unchanged)
97
+ */
98
+ type AnimatableProperty = 'opacity' | 'transform.x' | 'transform.y' | 'transform.scale' | 'transform.rotation' | 'blur' | 'brightness' | 'contrast' | 'saturate';
99
+ /** Easing names the schema allows on animations and keyframes. */
100
+ type AnimationEasing = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out';
101
+ /**
102
+ * One keyframe of a layer animation (schema `AnimationKeyframe`, 1.6+).
103
+ */
104
+ interface AnimationKeyframe {
105
+ /** Keyframe identifier (optional) */
106
+ id?: string;
107
+ /** Id of the animated layer (`Panel.layers[].id`) */
108
+ layerId: string;
109
+ /** Animated property */
110
+ property: AnimatableProperty;
111
+ /** Position on the animation's timeline in milliseconds */
112
+ timeMs: number;
113
+ /** Property value at this keyframe (units: see {@link AnimatableProperty}) */
114
+ value: number;
115
+ /** Easing from this keyframe to the next one of the same track (default `linear`) */
116
+ easing?: AnimationEasing;
117
+ }
118
+ /**
119
+ * Panel animation (schema `PanelAnimations`).
120
+ */
121
+ interface PanelAnimations {
122
+ /** Human-friendly name (authoring aid) */
123
+ name?: string;
124
+ /** Camera move start (normalized rect of the panel) */
125
+ startViewportRect?: NormalizedRect;
126
+ /** Camera move end (normalized rect of the panel) */
127
+ endViewportRect?: NormalizedRect;
128
+ /** Total running time; when omitted, keyframes run until their last keyframe */
129
+ durationMs?: number;
130
+ /** Easing of the camera move */
131
+ easing?: AnimationEasing;
132
+ /** Restart from 0 when durationMs is reached (default false) */
133
+ loop?: boolean;
134
+ /**
135
+ * Layer keyframes. Keyframes with the same layerId + property form a track;
136
+ * values hold before the first / after the last keyframe and are interpolated
137
+ * in between with the earlier keyframe's easing.
138
+ */
139
+ keyframes?: AnimationKeyframe[];
140
+ }
74
141
  /**
75
142
  * Format-specific view configuration
76
143
  */
@@ -334,10 +401,12 @@ interface BalloonConfig {
334
401
  balloonType: BalloonType;
335
402
  /** 0-1 (0=rectangle, 1=ellipse) */
336
403
  cornerRadius: number;
337
- /** Pixels */
404
+ /** Authored width in px — the floor; with textFit 'grow' the body grows for longer text */
338
405
  maxWidth: number;
339
- /** Pixels */
406
+ /** Authored height in px — the floor; with textFit 'grow' the body grows for longer text */
340
407
  maxHeight: number;
408
+ /** grow (default): the balloon grows when the text needs more room; fixed: keeps the authored size (schema 1.8.0) */
409
+ textFit?: 'grow' | 'fixed';
341
410
  /** CSS font-family */
342
411
  fontFamily: string;
343
412
  /** Pixels */
@@ -348,6 +417,8 @@ interface BalloonConfig {
348
417
  strokeColor: string;
349
418
  /** Hex color */
350
419
  fillColor: string;
420
+ /** Hex color of the lettering (default #000000; schema 1.7.0) */
421
+ textColor?: string;
351
422
  tail: TailConfig;
352
423
  hideBorder: HideBorderConfig;
353
424
  }
@@ -370,6 +441,12 @@ interface Hotspot {
370
441
  label: LocalizedString;
371
442
  /** Localized accessibility label (optional, overrides label for screen readers) */
372
443
  ariaLabel?: LocalizedString;
444
+ /**
445
+ * How readers see it (schema 1.7.0): `area` = invisible click area, `button` = the
446
+ * label shown as a button, `auto` (default) = button when the panel's goTo hotspots
447
+ * lead to two or more panels (a choice), else area.
448
+ */
449
+ display?: 'auto' | 'button' | 'area';
373
450
  /** Action to perform when activated */
374
451
  action: HotspotAction;
375
452
  /** Condition for hotspot visibility (optional) */
@@ -422,7 +499,7 @@ type HotspotAction = HotspotGoToAction | HotspotSetVariablesAction | HotspotOpen
422
499
  */
423
500
  interface HotspotGoToAction {
424
501
  type: 'goTo';
425
- /** Target panel ID */
502
+ /** Target panel ID: any panel of the work, including one in another chapter */
426
503
  to: string;
427
504
  /** Variable mutations applied before navigating (optional) */
428
505
  mutations?: Mutation[];
@@ -686,9 +763,9 @@ interface Graph {
686
763
  * Edge connecting two panels with optional conditions
687
764
  */
688
765
  interface Edge {
689
- /** Source panel ID */
766
+ /** Source panel ID (a panel of the chapter that holds this graph) */
690
767
  from: string;
691
- /** Target panel ID */
768
+ /** Target panel ID: any panel of the work; one in another chapter switches the reader to that chapter */
692
769
  to: string;
693
770
  /** Condition that must be true for this edge to be traversable (optional) */
694
771
  condition?: JsonLogic;
@@ -706,6 +783,11 @@ interface Edge {
706
783
  priority?: number;
707
784
  /** Localized label for this edge (optional, for UI) */
708
785
  label?: Record<string, string>;
786
+ /**
787
+ * Editor edge metadata (schema `Edge.mutations`): the CMS keeps the choice
788
+ * label in an `{ op: 'meta', edgeType: { label } }` descriptor here.
789
+ */
790
+ mutations?: Record<string, unknown>[];
709
791
  }
710
792
  /**
711
793
  * Optional metadata for graph nodes
@@ -1396,6 +1478,29 @@ interface Page {
1396
1478
  /** Transition effect when leaving this page */
1397
1479
  out?: Transition;
1398
1480
  };
1481
+ /** Visual properties of the page (optional) */
1482
+ visual?: PageVisual;
1483
+ }
1484
+ /**
1485
+ * Visual properties of a page (schema Page.visual)
1486
+ */
1487
+ interface PageVisual {
1488
+ /**
1489
+ * Page background color (CSS hex) — the space between and around the
1490
+ * panels. Falls back to settings.typography.default_page_bg_color.
1491
+ */
1492
+ background_color?: string;
1493
+ /** Background image asset ID or URI */
1494
+ background_image?: string;
1495
+ /** Background texture asset ID or URI */
1496
+ background_texture?: string;
1497
+ /** Page margins in pixels */
1498
+ margins?: {
1499
+ top?: number;
1500
+ right?: number;
1501
+ bottom?: number;
1502
+ left?: number;
1503
+ };
1399
1504
  }
1400
1505
  /**
1401
1506
  * Page layout configuration
@@ -1554,8 +1659,8 @@ interface OutputPreset {
1554
1659
  interface Extras {
1555
1660
  /** Cover image(s) (optional) */
1556
1661
  cover?: ExtraItem;
1557
- /** Alternative covers (optional) */
1558
- alt_cover?: ExtraItem;
1662
+ /** Alternative cover(s): one block, or several (array form, schema 1.6+) */
1663
+ alt_cover?: ExtraItem | ExtraItem[];
1559
1664
  /** Character sheets (optional) */
1560
1665
  character_sheets?: ExtraItem[];
1561
1666
  /** Author information (optional) */
@@ -1587,6 +1692,12 @@ interface ExtraItem {
1587
1692
  shareable?: boolean;
1588
1693
  /** Whether this extra is behind a paywall (optional) */
1589
1694
  gated?: boolean;
1695
+ /** Character sheets: the character shown (first of characterIds for ensemble sheets) */
1696
+ characterId?: string;
1697
+ /** Character sheets: all characters shown on an ensemble sheet (schema 1.6+) */
1698
+ characterIds?: string[];
1699
+ /** Custom extension properties starting with x- (format 1.7+) */
1700
+ [key: `x-${string}`]: unknown;
1590
1701
  }
1591
1702
  /**
1592
1703
  * Image in an extra item
@@ -2404,6 +2515,8 @@ declare class PlayerStateService {
2404
2515
  declare class ManifestService {
2405
2516
  private manifest;
2406
2517
  private indexes;
2518
+ /** Absolute URL the current manifest was fetched from (null for object manifests). */
2519
+ private manifestUrl;
2407
2520
  private readonly http;
2408
2521
  /**
2409
2522
  * Load manifest from a URL
@@ -2425,6 +2538,12 @@ declare class ManifestService {
2425
2538
  * Get the current manifest
2426
2539
  */
2427
2540
  getManifest(): PanelWaveManifest | null;
2541
+ /**
2542
+ * The URL the current manifest was loaded from, absolute — the last
2543
+ * fallback for relative asset references (AssetUrlService); null when the
2544
+ * manifest was supplied as an object.
2545
+ */
2546
+ getManifestUrl(): string | null;
2428
2547
  /**
2429
2548
  * Check if a manifest is loaded
2430
2549
  */
@@ -2529,6 +2648,20 @@ declare class ManifestService {
2529
2648
  static ɵprov: i0.ɵɵInjectableDeclaration<ManifestService>;
2530
2649
  }
2531
2650
 
2651
+ /**
2652
+ * Turns manifest asset references (`src`, poster, portrait, thumbnail…) into
2653
+ * loadable URLs: absolute ones pass through, relative ones resolve against
2654
+ * the loaded manifest's `assets.base` (per category, then `mediaBase`) and,
2655
+ * failing that, the URL the manifest itself came from. One place for the
2656
+ * rule every layer/overlay used to re-implement with `baseUrl + src`.
2657
+ */
2658
+ declare class AssetUrlService {
2659
+ private readonly manifestService;
2660
+ resolve(src: string | undefined | null, category?: AssetCategory): string;
2661
+ static ɵfac: i0.ɵɵFactoryDeclaration<AssetUrlService, never>;
2662
+ static ɵprov: i0.ɵɵInjectableDeclaration<AssetUrlService>;
2663
+ }
2664
+
2532
2665
  /**
2533
2666
  * Variable Store Service
2534
2667
  * Provides scoped variable storage with mutations and persistence
@@ -2789,6 +2922,19 @@ declare class FlowEngineService {
2789
2922
  * @returns Navigation result with next panel and transition
2790
2923
  */
2791
2924
  getNextPanel(graph: Graph, currentPanelId: string, context: Record<string, unknown>, defaultTransition?: Transition, defaultCameraMove?: CameraMove): NavigationResult;
2925
+ /**
2926
+ * Next panel within a chapter. A chapter WITH edges uses the graph
2927
+ * ({@link getNextPanel}, conditions and priorities included). A chapter
2928
+ * without any edges follows its reading order (entry, then
2929
+ * `chapter.panels` key order) with the format defaults; null after the
2930
+ * last panel.
2931
+ */
2932
+ getNextInChapter(chapter: Chapter, currentPanelId: string, context: Record<string, unknown>, defaultTransition?: Transition, defaultCameraMove?: CameraMove): NavigationResult;
2933
+ /**
2934
+ * Previous panel(s) within a chapter: the sources of edges into the panel,
2935
+ * or — in a chapter without edges — the panel before it in reading order.
2936
+ */
2937
+ getPreviousInChapter(chapter: Chapter, currentPanelId: string): string[];
2792
2938
  /**
2793
2939
  * Camera move to play when navigating BACK from `currentPanelId` to
2794
2940
  * `previousPanelId`: the move of the edge originally traversed
@@ -2993,6 +3139,10 @@ declare class ImageCacheService {
2993
3139
  * Support for createImageBitmap
2994
3140
  */
2995
3141
  private readonly supportsImageBitmap;
3142
+ /** Images warmed for `<img>` rendering (see preload), least recent first. */
3143
+ private warmed;
3144
+ /** How many warmed images stay referenced (a few panels/pages ahead). */
3145
+ private readonly WARM_LIMIT;
2996
3146
  /**
2997
3147
  * Load an image from cache or network
2998
3148
  */
@@ -3018,9 +3168,16 @@ declare class ImageCacheService {
3018
3168
  */
3019
3169
  private evictLRU;
3020
3170
  /**
3021
- * Preload an image
3171
+ * Preload an image for an upcoming `<img>`: loads it the way an `<img>`
3172
+ * does (same URL, no CORS request) and decodes it, then keeps the element
3173
+ * alive so the browser's memory cache serves the next `<img src>` with the
3174
+ * decoded pixels — the panel appears in the frame it mounts, without the
3175
+ * blank gap a cold load (or a fetch()/ImageBitmap copy the `<img>` never
3176
+ * uses) leaves between autoplay panels.
3022
3177
  */
3023
3178
  preload(url: string): Promise<void>;
3179
+ /** Load and decode an image through an `Image` element. */
3180
+ private warmImage;
3024
3181
  /**
3025
3182
  * Preload multiple images
3026
3183
  */
@@ -3716,6 +3873,12 @@ declare class VisibilityService implements OnDestroy {
3716
3873
  * Auto-advance coupling (§4.3.6): when the last queue slot completes its pass
3717
3874
  * the sequencer emits {@link queueComplete}; the host advances the page/panel
3718
3875
  * only when autoplay is on.
3876
+ *
3877
+ * Image holds: with a page timeline (see {@link start}) the panels without a
3878
+ * sequenced video hold the sequence for their dwell time, in reading order —
3879
+ * video A, image B (2 s), image C (4 s), video D plays A, waits 6 s, plays D,
3880
+ * so the reader has time for the art between the videos. Images before the
3881
+ * first video delay it; images after the last one delay `queueComplete`.
3719
3882
  */
3720
3883
 
3721
3884
  /**
@@ -3764,6 +3927,15 @@ interface SequencedVideo extends SequencedVideoInfo {
3764
3927
  /** Optional hook invoked right before a stalled slot is skipped. */
3765
3928
  onStallSkip?(): void;
3766
3929
  }
3930
+ /**
3931
+ * One panel of the page in reading order, with the time a panel without a
3932
+ * sequenced video holds the sequence (its autoplay dwell time).
3933
+ */
3934
+ interface PageTimelineEntry {
3935
+ panelId: string;
3936
+ /** Dwell time in ms; ignored for panels whose videos play in the sequence. */
3937
+ holdMs: number;
3938
+ }
3767
3939
  /** Default stall-skip timeout: 10 s (§7). */
3768
3940
  declare const DEFAULT_STALL_TIMEOUT_MS = 10000;
3769
3941
  declare class VideoSequencerService implements OnDestroy {
@@ -3785,6 +3957,12 @@ declare class VideoSequencerService implements OnDestroy {
3785
3957
  private running;
3786
3958
  /** Stall-skip timer for the active slot. */
3787
3959
  private stallTimer?;
3960
+ /** The page in reading order, with each panel's hold time. */
3961
+ private timeline;
3962
+ /** Timeline index of the last slot that played (-1: none yet). */
3963
+ private timelinePosition;
3964
+ /** Pending image hold before the next slot (or before `queueComplete`). */
3965
+ private holdTimer?;
3788
3966
  /**
3789
3967
  * Stall-skip timeout (ms). If the active slot makes no progress for this
3790
3968
  * long the sequencer skips it (§7). Injectable via {@link setStallTimeout}
@@ -3809,8 +3987,12 @@ declare class VideoSequencerService implements OnDestroy {
3809
3987
  * visibility changes so newly-visible videos append and leaving ones drop.
3810
3988
  * Already-registered sequenced videos (components reused across a page
3811
3989
  * change) are re-observed and re-queued.
3990
+ *
3991
+ * @param timeline The page's panels in reading order with their hold times.
3992
+ * Panels without a sequenced video hold the sequence for that long
3993
+ * between the videos. Omitted: the videos play back to back.
3812
3994
  */
3813
- start(): void;
3995
+ start(timeline?: readonly PageTimelineEntry[]): void;
3814
3996
  /** Stop the sequence and release all observers/timers. */
3815
3997
  reset(): void;
3816
3998
  ngOnDestroy(): void;
@@ -3862,9 +4044,18 @@ declare class VideoSequencerService implements OnDestroy {
3862
4044
  private completeActiveSlot;
3863
4045
  /**
3864
4046
  * Advance to the next queue slot, or emit `queueComplete` when the queue is
3865
- * exhausted.
4047
+ * exhausted — each after holding for the image panels in between.
3866
4048
  */
3867
4049
  private advance;
4050
+ /**
4051
+ * Total hold of the image panels between the last played slot and the
4052
+ * timeline index `target` (exclusive). Panels whose videos are sequenced
4053
+ * never hold: they play, or were skipped as not visible.
4054
+ */
4055
+ private holdBefore;
4056
+ /** Index of a panel in the page timeline, or -1. */
4057
+ private timelineIndex;
4058
+ private clearHoldTimer;
3868
4059
  /** Activate the head slot of the queue (all its sequenced videos). */
3869
4060
  private playNext;
3870
4061
  private armStallTimer;
@@ -3951,9 +4142,16 @@ declare class PreloadService {
3951
4142
  /** Low-priority items handed to requestIdleCallback but not started yet. */
3952
4143
  private idlePending;
3953
4144
  private readonly imageCache;
4145
+ private readonly paywall;
3954
4146
  constructor();
3955
4147
  /**
3956
- * Add item to preload queue
4148
+ * Add item to preload queue.
4149
+ *
4150
+ * Items of a panel the paywall locks for the reader (the renderers show
4151
+ * its placeholder) are skipped: gated artwork is not fetched ahead of the
4152
+ * gate. A later call after the lock lifts preloads them. Only panel ids
4153
+ * the paywall knows are judged; items without one (or with a legacy index
4154
+ * id from preloadNext) load as before.
3957
4155
  */
3958
4156
  add(item: PreloadItem): void;
3959
4157
  /**
@@ -3972,6 +4170,8 @@ declare class PreloadService {
3972
4170
  * Predict next indices based on direction
3973
4171
  */
3974
4172
  private predict;
4173
+ /** Does the paywall lock this (known) panel for the reader? */
4174
+ private isLockedPanel;
3975
4175
  /**
3976
4176
  * Clear queue
3977
4177
  */
@@ -4221,6 +4421,10 @@ declare class TrackingService {
4221
4421
  * by `refId` (see `isExtraLocked`).
4222
4422
  * - A gated panel unlocks when the gating rule's requirement is satisfied by
4223
4423
  * the reader's entitlement snapshot.
4424
+ * - Age requirements are NOT subject to that precedence: every rule that
4425
+ * applies to a panel (its panel rules, its chapter's rules, every work
4426
+ * rule; each outside its own preview) and carries an age must be met first.
4427
+ * A chapter preview or a free panel rule never bypasses a work age gate.
4224
4428
  */
4225
4429
 
4226
4430
  type EvaluatorEntitlementType = 'free' | 'subscription' | 'purchase' | 'age_gate';
@@ -4367,16 +4571,41 @@ declare class PaywallService {
4367
4571
  private chapterOrder;
4368
4572
  private manifest;
4369
4573
  private products;
4574
+ /** Panels the server stripped for this reader (`"x-locked": true`). */
4575
+ private lockedPanels;
4576
+ /** Decisions per panel for the current rules + snapshot (cleared on change). */
4577
+ private decisions;
4578
+ /** False while a host entitlement adapter decides access (see setEnforced). */
4579
+ private enforced;
4370
4580
  private snapshotSubject;
4371
4581
  readonly snapshot$: Observable<EntitlementSnapshot>;
4582
+ private changesSubject;
4583
+ /**
4584
+ * Fires whenever a lock can flip: new manifest, new snapshot, enforcement
4585
+ * change or clear(). Renderers re-check `isPanelLocked` on it.
4586
+ */
4587
+ readonly changes$: Observable<void>;
4372
4588
  /** Load the rules and reading order from a manifest. Safe to call repeatedly. */
4373
4589
  setManifest(manifest: PanelWaveManifest | null): void;
4374
4590
  /** `paywall.products` by id (format 1.6); the first entry wins on duplicate ids. */
4375
4591
  static productsFromManifest(manifest: PanelWaveManifest | null): Map<string, PaywallProduct>;
4376
4592
  /** Replace what the reader owns (after sign-in, or a completed purchase). */
4377
4593
  setSnapshot(snapshot: EntitlementSnapshot | null | undefined): void;
4594
+ /**
4595
+ * Whether the rules are this service's to enforce. The shell turns it off
4596
+ * while a host `entitlementAdapter` decides access (the adapter wins over
4597
+ * manifest rules): the rules then still describe gates, but renderers no
4598
+ * longer lock panels by them (`x-locked` stubs stay locked regardless).
4599
+ */
4600
+ setEnforced(enforced: boolean): void;
4601
+ /**
4602
+ * Should renderers show the locked placeholder for this panel? True when
4603
+ * the rules are enforced here and the reader's snapshot does not open it.
4604
+ * Memoized per rules + snapshot, so it is cheap to call from templates.
4605
+ */
4606
+ isPanelLocked(panelId: string): boolean;
4378
4607
  getSnapshot(): EntitlementSnapshot;
4379
- /** True when the work carries no paywall rules at all. */
4608
+ /** True when the work carries no paywall rules and no locked panels. */
4380
4609
  get isFreeWork(): boolean;
4381
4610
  /** Reading-order index used for preview counting, or -1 when unknown. */
4382
4611
  indexOf(panelId: string): number;
@@ -4386,8 +4615,16 @@ declare class PaywallService {
4386
4615
  * An unknown panel id gets `MAX_SAFE_INTEGER` as its index so it falls
4387
4616
  * OUTSIDE any free preview: a panel the reading order does not know about
4388
4617
  * must not be handed out as a free sample.
4618
+ *
4619
+ * Defence in depth: a panel the server stripped (`"x-locked": true`) is
4620
+ * locked whatever the rules say — its content is not in the manifest, so
4621
+ * neither a free preview nor an entitlement can show it. The applying
4622
+ * rule's own lock reason is kept while it locks; otherwise the reason is
4623
+ * the rule's purchase/subscription requirement, else `purchase_required`
4624
+ * (never the age, which would re-open the age gate forever on a stub).
4389
4625
  */
4390
4626
  evaluate(panelId: string): AccessDecision;
4627
+ private decide;
4391
4628
  /** Is this extras block locked by an extras-scoped rule the reader does not satisfy? */
4392
4629
  isExtraLocked(extraId: string): boolean;
4393
4630
  /** Convenience: may the reader open this panel? */
@@ -4418,6 +4655,8 @@ declare class PaywallService {
4418
4655
  private get defaultLocale();
4419
4656
  /** Reset to a manifest-less, entitlement-less state. */
4420
4657
  clear(): void;
4658
+ /** Drop memoized decisions and tell renderers. */
4659
+ private changed;
4421
4660
  /**
4422
4661
  * Reader-facing wording for a lock reason. Kept here rather than in the
4423
4662
  * overlay so the same sentence is used wherever a gate is explained.
@@ -5018,6 +5257,13 @@ declare class PlayerService {
5018
5257
  static ɵprov: i0.ɵɵInjectableDeclaration<PlayerService>;
5019
5258
  }
5020
5259
 
5260
+ /**
5261
+ * True when a panel is a server-side paywall stub: public manifests strip
5262
+ * the content of paid panels and flag them `"x-locked": true`. Only the
5263
+ * boolean `true` counts (a `"true"` string is not a lock).
5264
+ */
5265
+ declare function isLockedPanel(panel: Panel | null | undefined): boolean;
5266
+
5021
5267
  /**
5022
5268
  * Video Config Utilities
5023
5269
  * Resolves the effective VideoLayer playback config from layer fields,
@@ -5096,6 +5342,16 @@ declare function balloonConfigToTailOptions(config: BalloonConfig): {
5096
5342
  curveAmount: number;
5097
5343
  } | null;
5098
5344
 
5345
+ /**
5346
+ * How a balloon treats text that needs more room than its authored size
5347
+ * (`maxWidth × maxHeight`, schema 1.8 `BalloonConfig.textFit`):
5348
+ * - `grow` (default): the balloon grows beyond the authored size until the
5349
+ * text fits — proportionally first (the shape keeps its aspect ratio), then
5350
+ * in height; see {@link BALLOON_GROWTH_MAX}.
5351
+ * - `fixed`: the balloon keeps its authored size and the text spills over the
5352
+ * edges (pre-1.8 behaviour); `textOverflows` reports it.
5353
+ */
5354
+ type BalloonTextFit = 'grow' | 'fixed';
5099
5355
  interface BalloonPadding {
5100
5356
  top: number;
5101
5357
  right: number;
@@ -5103,12 +5359,18 @@ interface BalloonPadding {
5103
5359
  left: number;
5104
5360
  }
5105
5361
  interface BalloonOptions {
5362
+ /** Authored width in px; 0 = natural width. With textFit 'grow' the body may become wider. */
5106
5363
  maxWidth: number;
5364
+ /** Authored height in px; 0 = natural height. With textFit 'grow' the body may become taller. */
5107
5365
  maxHeight: number;
5366
+ /** What happens when the text needs more room than the authored size (default 'grow'). */
5367
+ textFit: BalloonTextFit;
5108
5368
  padding: BalloonPadding;
5109
5369
  strokeWidth: number;
5110
5370
  strokeColor: string;
5111
5371
  fillColor: string;
5372
+ /** Lettering colour (CSS colour; BalloonConfig.textColor, schema 1.7.0). */
5373
+ textColor: string;
5112
5374
  tailWidth: number;
5113
5375
  cornerRadius: number;
5114
5376
  fontFamily: string;
@@ -5144,9 +5406,20 @@ interface CutOptions {
5144
5406
  bottom?: boolean;
5145
5407
  }
5146
5408
  interface BalloonRenderResult {
5409
+ /** Rendered body width (the authored width, or more when the balloon grew). */
5147
5410
  width: number;
5411
+ /** Rendered body height (the authored height, or more when the balloon grew). */
5148
5412
  height: number;
5413
+ /** The authored body size the growth started from (maxWidth/maxHeight, or the natural size for 0). */
5414
+ authoredWidth: number;
5415
+ authoredHeight: number;
5416
+ /** True when the body is larger than the authored size because the text needed more room. */
5417
+ grown: boolean;
5418
+ /** Proportional growth factor applied to the authored size (1 when not grown). */
5419
+ growth: number;
5149
5420
  svg: SVGSVGElement;
5421
+ /** True when the text needs more height than the body gives it (textFit 'fixed' only). */
5422
+ textOverflows: boolean;
5150
5423
  balloon: ComicBalloon;
5151
5424
  update: (newText?: string, newTailOptions?: TailOptions | null) => BalloonRenderResult;
5152
5425
  updateTail: (newTailOptions: TailOptions | null) => BalloonRenderResult;
@@ -5246,6 +5519,177 @@ declare function resolvePanelVariant(panel: Panel, context: VariantContext, forc
5246
5519
  */
5247
5520
  declare function resolvePanels(panels: Record<string, Panel>, context: VariantContext): Record<string, Panel>;
5248
5521
 
5522
+ /**
5523
+ * Page view format selection. A chapter carries one page sequence per output
5524
+ * format (`Page.layout.format`): mobile, tablet, desktop, big screen, print…
5525
+ * The player shows the sequence that suits the screen best and keeps the
5526
+ * others out of page navigation, the TOC and the page lookup.
5527
+ */
5528
+
5529
+ /** Screen classes the format preference lists are keyed by. */
5530
+ type ScreenClass = 'phone' | 'tablet' | 'desktop' | 'bigscreen';
5531
+ /**
5532
+ * Classify the player's viewport. `width`/`height` are CSS px, `dpr` the
5533
+ * device pixel ratio: a 4K screen at 150 % or 200 % scaling still counts as
5534
+ * a big screen, a laptop at 125 % does not.
5535
+ */
5536
+ declare function screenClassFor(width: number, height: number, dpr?: number): ScreenClass;
5537
+ /** The output format a page is laid out for; null for legacy pages without one. */
5538
+ declare function pageFormatOf(page: Page | null | undefined): string | null;
5539
+ /** Distinct formats of the given pages, in first-seen order. */
5540
+ declare function pageFormatsOf(pages: readonly Page[] | null | undefined): string[];
5541
+ /**
5542
+ * Formats ranked for a screen class: its preference list, then any formats
5543
+ * it does not name (closest aspect ratio to `aspect` first). Only formats in
5544
+ * `available` are returned.
5545
+ */
5546
+ declare function rankPageFormats(available: readonly string[], screen: ScreenClass, aspect?: number): string[];
5547
+ /**
5548
+ * The page format to show on this screen, or null when the pages carry no
5549
+ * format at all. `preferred` (a host override) wins when pages exist for it.
5550
+ */
5551
+ declare function pickPageFormat(available: readonly string[], width: number, height: number, dpr?: number, preferred?: string | null): string | null;
5552
+ /**
5553
+ * The page sequence of one format. Pages without a format (legacy) belong to
5554
+ * every sequence; a null format means "all pages".
5555
+ */
5556
+ declare function pagesForFormat(pages: readonly Page[] | null | undefined, format: string | null): Page[];
5557
+ /** Width / height of a page's frame: its canvas size, else its format's aspect, else 16:9. */
5558
+ declare function pageAspectRatio(page: Page | null | undefined): number;
5559
+
5560
+ /**
5561
+ * Reading position as a URL: page view and panel view get their own
5562
+ * addresses, so a reader can bookmark or share exactly what they see.
5563
+ *
5564
+ * ?page=pg-D3 page view, page `pg-D3`
5565
+ * ?panel=ch1-p022 panel view (and canvas view), panel `ch1-p022`
5566
+ * (neither) the cover / the start of the work
5567
+ *
5568
+ * Ids are the manifest's page and panel ids. A page id belongs to one output
5569
+ * format; the player falls back to the page showing the same panels when the
5570
+ * reader's screen uses another format.
5571
+ */
5572
+ /** What the player shows: the cover, a page, a single panel or the canvas. */
5573
+ type PlayerView = 'cover' | 'page' | 'panel' | 'canvas';
5574
+ /** The reader's position, emitted by the shell's `locationChange` output. */
5575
+ interface PlayerLocation {
5576
+ view: PlayerView;
5577
+ /** Chapter of the current panel (absent on the cover of an empty work). */
5578
+ chapterId?: string;
5579
+ /** Current panel (page view: the panel the reader is on). */
5580
+ panelId?: string;
5581
+ /** Open page (page view only). */
5582
+ pageId?: string;
5583
+ }
5584
+ /** URL query parameters the position uses. */
5585
+ declare const LOCATION_PARAMS: {
5586
+ readonly page: "page";
5587
+ readonly panel: "panel";
5588
+ };
5589
+ /** The position a URL's query string asks for (page wins over panel). */
5590
+ declare function parseLocationSearch(search: string): {
5591
+ pageId?: string;
5592
+ panelId?: string;
5593
+ };
5594
+ /**
5595
+ * The URL for a position: `href` with the position's query parameter set and
5596
+ * every other parameter kept (e.g. `embed`). `drop` removes further
5597
+ * parameters (a share link leaves out `embed`).
5598
+ */
5599
+ declare function locationUrl(href: string, location: PlayerLocation, drop?: readonly string[]): string;
5600
+
5601
+ /**
5602
+ * Page background color. The page color fills the space between and around
5603
+ * the panels in page view and the frame around the panel in panel view, so a
5604
+ * reader moving from a white page to a black one sees the switch at the
5605
+ * first panel of the new page.
5606
+ */
5607
+
5608
+ /** Used when neither the page nor the work sets a color. */
5609
+ declare const DEFAULT_PAGE_BACKGROUND = "#1a1a1a";
5610
+ /**
5611
+ * The page's background color: `page.visual.background_color`, else the
5612
+ * work's `settings.typography.default_page_bg_color`, else
5613
+ * {@link DEFAULT_PAGE_BACKGROUND}. Values that are not CSS hex colors are
5614
+ * skipped.
5615
+ */
5616
+ declare function resolvePageBackground(page: Page | null | undefined, settings: Settings | null | undefined): string;
5617
+
5618
+ /**
5619
+ * Extras Viewer Component
5620
+ * Displays bonus content gallery
5621
+ */
5622
+
5623
+ /**
5624
+ * Extra item type
5625
+ */
5626
+ type ExtraType = 'cover' | 'art' | 'bts' | 'interview' | 'other';
5627
+ /**
5628
+ * Extra item definition
5629
+ */
5630
+ interface Extra {
5631
+ id: string;
5632
+ type: ExtraType;
5633
+ title: LocalizedString;
5634
+ description?: LocalizedString;
5635
+ thumbnail?: string;
5636
+ asset?: string;
5637
+ mediaType?: 'image' | 'video' | 'audio' | 'document';
5638
+ gated?: boolean;
5639
+ tags?: string[];
5640
+ /** Character sheets: names of the characters shown (one, or several on an ensemble sheet). */
5641
+ characters?: LocalizedString[];
5642
+ }
5643
+
5644
+ /**
5645
+ * Map the manifest's keyed `extras` blocks (schema $defs/ExtraBlock) to the
5646
+ * flat list the extras viewer renders — including the media each block
5647
+ * carries, resolved through the asset catalog.
5648
+ *
5649
+ * ExtraBlock media, in schema terms:
5650
+ * - `images[] { assetId, caption }`, `video[] (VideoLayer)`, `audio[] (AudioTrack)`
5651
+ * reference catalog assets by id;
5652
+ * - `url` / `thumbnail` are direct links (thumbnail may also be an asset id);
5653
+ * - `contentType` (image | video | audio | pdf | text) states the kind explicitly.
5654
+ * Previously only id/title/text were passed on, so every extra rendered as an
5655
+ * empty image.
5656
+ */
5657
+
5658
+ /** Just the catalog shape this module reads (image / video / audio items). */
5659
+ interface CatalogLike {
5660
+ category?: string;
5661
+ variants?: {
5662
+ src: string;
5663
+ w?: number;
5664
+ direction?: string;
5665
+ }[];
5666
+ poster?: {
5667
+ src: string;
5668
+ };
5669
+ }
5670
+ type AssetLookup = (assetId: string) => CatalogLike | null | undefined;
5671
+
5672
+ /**
5673
+ * Thumbnails for navigation surfaces (thumbnail strip, TOC) and the work's
5674
+ * cover. Panels carry no thumbnail field of their own: the thumbnail is a
5675
+ * small rendition of the panel's artwork, resolved through the asset catalog.
5676
+ */
5677
+
5678
+ /** Width (physical px) a thumbnail tile is rendered at. */
5679
+ declare const THUMBNAIL_WIDTH = 320;
5680
+ /**
5681
+ * The thumbnail source of a panel: an explicit `thumbnail`, else its
5682
+ * bottom-most visible image layer (the artwork the panel is drawn on), else
5683
+ * the poster of its first video layer. Empty when the panel has no artwork.
5684
+ */
5685
+ declare function panelThumbnailSrc(panel: Panel | null | undefined, lookup: AssetLookup, width?: number): string;
5686
+ /**
5687
+ * The work's cover image: `meta.cover` (asset id or URL), else the
5688
+ * `extras.cover` block (its image, link or thumbnail). A gated cover block
5689
+ * is not shown. Empty when the work has no cover.
5690
+ */
5691
+ declare function coverImageSrc(manifest: PanelWaveManifest | null | undefined, lookup: AssetLookup, width?: number): string;
5692
+
5249
5693
  /**
5250
5694
  * Renders an inlined Lucide icon by name (e.g. `lucideX`).
5251
5695
  *
@@ -5282,6 +5726,19 @@ interface Character {
5282
5726
  role?: string;
5283
5727
  }
5284
5728
 
5729
+ /**
5730
+ * Viewport Component
5731
+ * Main rendering container for panels with pan/zoom support
5732
+ */
5733
+
5734
+ /** A panel the viewport should warm ahead of time (see `preloadTargets`). */
5735
+ interface ViewportPreloadTarget {
5736
+ panelId: string;
5737
+ panel: Panel;
5738
+ /** Share of the panel container (panel view) or page canvas (page view) width it renders at; default 1. */
5739
+ widthFraction?: number;
5740
+ }
5741
+
5285
5742
  /**
5286
5743
  * Camera state: world coordinates of the viewport center plus zoom factor
5287
5744
  * (world-to-screen scale).
@@ -5527,30 +5984,6 @@ interface Preferences {
5527
5984
  highContrast: boolean;
5528
5985
  }
5529
5986
 
5530
- /**
5531
- * Extras Viewer Component
5532
- * Displays bonus content gallery
5533
- */
5534
-
5535
- /**
5536
- * Extra item type
5537
- */
5538
- type ExtraType = 'cover' | 'art' | 'bts' | 'interview' | 'other';
5539
- /**
5540
- * Extra item definition
5541
- */
5542
- interface Extra {
5543
- id: string;
5544
- type: ExtraType;
5545
- title: LocalizedString;
5546
- description?: LocalizedString;
5547
- thumbnail?: string;
5548
- asset?: string;
5549
- mediaType?: 'image' | 'video' | 'audio' | 'document';
5550
- gated?: boolean;
5551
- tags?: string[];
5552
- }
5553
-
5554
5987
  /**
5555
5988
  * Age Gate Component
5556
5989
  * Displays age verification UI for restricted content
@@ -5699,6 +6132,15 @@ declare class BranchChooserComponent {
5699
6132
  /**
5700
6133
  * Entitlement adapter interface
5701
6134
  * Provides entitlement and paywall functionality
6135
+ *
6136
+ * An adapter decides NAVIGATION only. It wins over the manifest's paywall
6137
+ * rules, so with an adapter the rules no longer lock rendering: a panel the
6138
+ * adapter refuses is still rendered. A move to it is stopped at the gate,
6139
+ * but a refused entry panel (initial load, bookmark resume) gets the paywall
6140
+ * raised OVER its rendered content, and page / canvas view show it in full.
6141
+ * Hosts must not rely on an adapter to hide content: strip it on the server
6142
+ * (`"x-locked": true` stubs stay locked regardless) or pass an
6143
+ * `entitlementSnapshot`, which locks rendering as well.
5702
6144
  */
5703
6145
  interface EntitlementAdapter {
5704
6146
  /**
@@ -5718,7 +6160,7 @@ interface EntitlementAdapter {
5718
6160
  * Player Shell Component
5719
6161
  * Main orchestrator for the PanelWave player
5720
6162
  */
5721
- declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6163
+ declare class PlayerShellComponent implements OnInit, OnChanges, AfterViewChecked, OnDestroy {
5722
6164
  /**
5723
6165
  * Manifest to load
5724
6166
  */
@@ -5728,7 +6170,9 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
5728
6170
  */
5729
6171
  manifestUrl?: string;
5730
6172
  /**
5731
- * Entitlement adapter for paywall integration
6173
+ * Entitlement adapter for paywall integration. Gates navigation only: a
6174
+ * refused entry panel gets the paywall over its rendered content (see
6175
+ * {@link EntitlementAdapter}); don't rely on it to hide content.
5732
6176
  */
5733
6177
  entitlementAdapter?: EntitlementAdapter;
5734
6178
  /**
@@ -5807,17 +6251,55 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
5807
6251
  */
5808
6252
  initialChapterId?: string;
5809
6253
  /**
5810
- * Initial panel ID
6254
+ * Initial panel ID. Without `initialChapterId` the chapter holding the
6255
+ * panel is looked up. A panel link opens in panel view.
5811
6256
  */
5812
6257
  initialPanelId?: string;
6258
+ /**
6259
+ * Initial page (manifest page id, e.g. from a `?page=` link): opens that
6260
+ * page in page view. On a screen whose page format differs, the page
6261
+ * showing the same panels opens. Wins over `initialPanelId`.
6262
+ */
6263
+ initialPageId?: string;
6264
+ /**
6265
+ * View to open in. Default: page view when the work has pages (after the
6266
+ * cover), panel view for a panel link.
6267
+ */
6268
+ initialViewMode?: 'page' | 'panel';
6269
+ /**
6270
+ * Link the share dialog offers. Default: the current address with the
6271
+ * reading position (`?page=` / `?panel=`, see `locationUrl`).
6272
+ */
6273
+ shareUrl?: string;
6274
+ /**
6275
+ * The reading position changed: cover, page, panel or canvas — for hosts
6276
+ * that keep it in the address bar (`locationUrl`) so pages and panels
6277
+ * can be bookmarked and shared.
6278
+ */
6279
+ locationChange: EventEmitter<PlayerLocation>;
5813
6280
  /**
5814
6281
  * Enable autoplay
5815
6282
  */
5816
6283
  autoplay: boolean;
5817
6284
  /**
5818
- * Seconds per panel in autoplay mode
6285
+ * Seconds per panel in autoplay mode. With the default author timing this
6286
+ * only applies to panels without an authored `durationMs` (and the cover);
6287
+ * once the reader picks a speed in the toolbar it applies to every panel.
5819
6288
  */
5820
6289
  secondsPerPanel: number;
6290
+ /**
6291
+ * Page view format: 'auto' (default) shows the page sequence of the
6292
+ * authored output format that suits the screen (phone → mobile-portrait,
6293
+ * 4K → bigscreen-landscape, …); a format id forces that sequence when the
6294
+ * work has pages for it.
6295
+ */
6296
+ pageFormat: string;
6297
+ /**
6298
+ * Show the work's cover (`meta.cover` / `extras.cover`) before the first
6299
+ * panel when reading starts at the beginning. It also heads the thumbnail
6300
+ * strip and the table of contents.
6301
+ */
6302
+ showCover: boolean;
5821
6303
  /**
5822
6304
  * Force reduced motion (host override). Reduced motion is also on when the
5823
6305
  * reader enabled it in Settings or the OS asks for it — see `motionReduced`.
@@ -5915,6 +6397,8 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
5915
6397
  * Current page (for page view)
5916
6398
  */
5917
6399
  currentPage?: Page;
6400
+ /** Cache for {@link pageBackground}: the page lookup runs once per panel. */
6401
+ private pageBackgroundCache;
5918
6402
  /**
5919
6403
  * Current chapter
5920
6404
  */
@@ -6026,6 +6510,21 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6026
6510
  * reveal modes and revisit-jumps).
6027
6511
  */
6028
6512
  visitedPanelIds: string[];
6513
+ /**
6514
+ * Page view and choices: the reader's choices so far (choice panel →
6515
+ * the panel the chosen hotspot jumped to). Panels off the chosen path —
6516
+ * and the branches of choices still ahead — show as placeholders in page
6517
+ * view; pages made up of off-path panels only are skipped.
6518
+ */
6519
+ private madeChoices;
6520
+ private branchGraph;
6521
+ /** Placeholders in page view (off the path, or behind a choice not made yet). */
6522
+ hiddenPanelIds: ReadonlySet<string>;
6523
+ /** Off the chosen path for good (pages of these only are skipped). */
6524
+ private unchosenPanelIds;
6525
+ private refreshBranchVisibility;
6526
+ /** A page whose panels are all off the chosen path: page navigation skips it. */
6527
+ private isPageOffPath;
6029
6528
  /**
6030
6529
  * Autoplay timer
6031
6530
  */
@@ -6034,6 +6533,25 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6034
6533
  * Autoplay enabled state
6035
6534
  */
6036
6535
  autoplayEnabled: boolean;
6536
+ /**
6537
+ * Autoplay dwell time source: 'author' plays each panel for its authored
6538
+ * `durationMs` (the CMS timeline), 'manual' for the reader's chosen
6539
+ * `secondsPerPanel`.
6540
+ */
6541
+ autoplayTiming: 'author' | 'manual';
6542
+ /** Page format of the page sequence page view shows (null: pages carry none). */
6543
+ activePageFormat: string | null;
6544
+ /** Cover image (screen-sized and thumbnail), empty when the work has none. */
6545
+ coverUrl: string;
6546
+ coverThumbUrl: string;
6547
+ /** The cover is shown in place of the story (before the first panel). */
6548
+ coverVisible: boolean;
6549
+ /** Upcoming panels the viewport warms (reading-order look-ahead). */
6550
+ preloadTargets: ViewportPreloadTarget[];
6551
+ /** PanelWave icon on the button that opens the toolbar. */
6552
+ readonly panelwaveIcon = "data:image/webp;base64,UklGRsAIAABXRUJQVlA4WAoAAAAQAAAAXwAAXwAAQUxQSEYBAAABkFvbkiJJPzPGAWYql4YcIS+6RyQ72ATSUBqRmaEiI/4sU5wVdyNiAvDVJAlt4wtbr3T+4c6X7cWxViRJ+N4sGGqc0xmk87w5BMnfIall+o5uajGYmvN+SpJ8Q9C1QSvGQK0Y1zshX8kYOWBtDNZqHlTIADJ69qgMWLnfgwxA1qgMWbmSEwSzrBl0zSkIqht6VM7rYaBJZdjKJjqO6XE5jzsmWRh44eQiNTLl0g4tMufRC//yPbz//v8XwJfoXrdokRk3F6mRKecnWCIrnOw8pcflPO7AHDUuZROobuhROW8qCGZZR1VzBoIkq9SYlMs5ARk9u9SIlHs9yAAyBndZWzRW87BCxpeCznVasUisGDe6Ifi6JJm6p5uWGEzNeT8jyPh2Fgw1zugM0nneGIJkfG+ShNax+e1X+p/mfN+ZH21FkoSvAlZQOCBUBwAAMCcAnQEqYABgAD49GIlDIiGhGOxlwCADxLEAYIrA6v8eP1X9i9HKuv5Xx19vbFX23fCT/ZeznlVf1A9ID+zew39Ov2c94f/D+pH9UP1N+AD+3fyDrIv1y9gD9gPTg9mz9nP2S9qe8VfrXKepEvtb+Z4bfc3/M+RP/L60B6gXaz/O/0TkG+sH+I+yX3ifyx5kzwD+gexF/Lf916P//J/kfS79Mf8/2K/6N/wP7jwp/6qmmH+Bke5fvpsKYgnbbHJ+5JNbzvovUMpGvFbPhSdXv4mudq7J3JpY+cd3YB+FrXSjO96Z1uqRSupyQKMks88O+qrrWcCv/IXTVsPZTiSVfG0F//RIHkujLTn7aNVcxMJ1qPdwfGRVjHu/zw25uaCx4k7Z+2qRHnHZ4Fv3LQDFvsllIbtdMVUEb7/s3vvk2y/D1AD+/4jx3hcTfhp2Fc0QpOSuEo0+XD2JgL78MEuNS4cD3szjG5u9ubfRvbb5E2Q9L4cjoTCGeuYUuTkaXDUbXaIVIBowYBor0PL95qme/l8L/c+jdWXBYSqk6+qDjlExFrNPtFND4UXmi7c+8/z/xKyetEEaVl96Rin/3FdLds5JrGII0SetRvv6p1TcPzBw1uo9NsxeB5tSANP1M791mBUwujUIXL+IxCMifqxpvLBFtFFa++zxc5cP3FUm85BSP/Cyk+2/WF6t8Zaw7bjyT1LOr4K56SaX6v/HkDsk7SF/8KprdETZPjtmEhrLD4RdS32Sxar50fJsW3OsG7fvnGgjvNa1pd7lt94v+mK4Mtr3ZNjw7qR/6G3+6Z/VM5r+Oxqa/m/KspviOYmWJQNJCER4+LDZ83GrGlNFQUT9skMKLmZvPfNbDuPXSqtjYXYkzKF4HwI5+nN6IG4Z2KPE+W1FUdiAlawAABwyJlahyiS/J9pxcipXizhve8YHG+Vl45/YURvvxY90ouentqgzpcEKPe7p7FLZaxcGChS2+zpH4T6s71Ovgg0QjMYHS76F2/I5mmklWr1ZRzesPETuNgw4JNu7o59og0/M/yGP8PQpTc87BiRwsJOkNJeYgBz85b+s6pFKhcn+dVQwMl+eluHcbj+BhrOhsUJB8UkB1phz3gMdxhsP5qx7+Dljmp5mhCtfFhejzwiLmMgSW1OgYQx8+P6S+JS6QdFVEgT0v/8/etNl3pWWZT9UpQm8ei9u03e11Ma93WFye0luqxuBfwnT+buQ7v0CY79n50q/4Wy/3i/QkaFBrO1mnykE82bs2O+ltFr5B821XqhQ8lKkQCgv18RXH98NTQTefkopusNNFb7/hXZLkewml5Xv1la/j4ZuQHowMeGIQHgNJ4AolpQ6S3TMkGnL2qzPiT3W75oNRwziMG+QgoSHuViyv64arFzYRwRCCq1FW5uFCiOOiiNudZqHnLI6yJXd823R2YznyRErj3O7fKW39fejyi/XNGQ5kdSIHEQKNgzGYFiQxkJ3ChQsakfAojOHyoswxfRZVCKiR6JTv7Q8vYc2a9QPtSMv2S7HgwJ0GPJepptro1F0YesT0e69qvGRdxWG6bfaAQolbdo6JxWEbNCtxTqLW184Kq6ttULPn2u7v1V7WFgkLO2PeFu394i4YF/08/fg7WbsP1HphLTpZmzzweaWlWIJhWH8YYcN+OxGKpIi0Z1FuznImzsRzQOF9Xc2T3eX9pHtr0QqixFizTt65n44mVGkl34jEs0MdVtIoCW56/58M+HHfjUk53MdPLOP1qMpt2Ks9p0CLrh04kNz/2jpjDout/WQqFwu5uGrj4J2F9Sv+AZi0pJkzu00A0jqNKnyJ1qikL/zyJClNINpUAYQ1ubYxUcy/Rd25s3ySipFU55NyUZWfXoZNkM/zZdP/6wsqqdU476WNeflerRVBfCX5tWHOMTMQbtmawbx7UQySm7pBK+Ntoo/IeFxyXqyFYrLz7ZkpInDBv9OK0lv+qCI8hFKDaCLyR19j/w/RrYxsFEHo/+PYcV0fuleAOSKodrWNm95a8kpbpB6iMipeiFlaZDkYs1yqn0XDVHOX1Z4/EJ68eqXkCYh8gIOQHx9R3BRIDOrw/kPdbeg1C5uOD5jnzHVnuyGH0svJHvQIM7iUlYrMc1x5xVuStPjRo4gknNs+k+PWwSdrMQVoNrMe+RLnoxURWUjjb7j3bnxLJ9Qq9SKJzUjTcyO62UF9iK/aoI/IJT/SDmuF2PWG8N99VR3QOi+cYE7FH272alWsjaPnbB6aUlSFnFuOJC8GAc0+mZqvoIl+oXncngAMUQPlGV30HZbH/MQ8v/7A4679grPQnyRcHdabNUje/PJS+RQsvUgRUVHUIMFCAczD9orXM2Nkwcfl30oUq4RAEoQ+oz5LyTIJhWSndtGwYb5/1drF/pMi7wMWMi66iLxCxrN87d1ZW3kBEEgeRNW/3CpBCX/0WPlqVNRmUs2z5skWXqzzNfb5FsqVva833/A+SX4Wu5onPUBNA2RXLK3+JchJR4Xl20AAA==";
6553
+ /** Panels on the current page (page view): all of them are "current" in the thumbnail strip. */
6554
+ get currentPagePanelIds(): string[];
6037
6555
  /**
6038
6556
  * Speech-bubble toggle state. Every bubble is implicitly subject to this
6039
6557
  * (schema 1.3) — per-bubble visibleIf is reserved for story logic.
@@ -6120,6 +6638,13 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6120
6638
  private readonly translationService;
6121
6639
  private readonly canvasCamera;
6122
6640
  private readonly paywallService;
6641
+ private readonly assetUrl;
6642
+ private readonly preloadService;
6643
+ private readonly host;
6644
+ /** The player is shown in fullscreen (kept in sync with the browser, Esc included). */
6645
+ isFullscreen: boolean;
6646
+ /** The browser can show the player in fullscreen (not e.g. on iPhone Safari). */
6647
+ readonly fullscreenAvailable: boolean;
6123
6648
  /** ngOnInit ran: later input changes are live updates, not initial values. */
6124
6649
  private initialized;
6125
6650
  /** The state subscriptions are set up once per instance, not per (re)load. */
@@ -6184,13 +6709,6 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6184
6709
  * navigation, so session_start precedes the first panel_view.
6185
6710
  */
6186
6711
  private startAnalyticsSession;
6187
- /**
6188
- * Deterministic reading order for a chapter: breadth-first over the graph
6189
- * from the entry panel(s), then any unreachable panels in declaration
6190
- * order (branching narratives have no single true order — BFS approximates
6191
- * "distance from start", which is what the funnel needs).
6192
- */
6193
- private readingOrderForChapter;
6194
6712
  /**
6195
6713
  * Coarse device class for analytics breakdowns (matches the dashboard's
6196
6714
  * device segments): touch + narrow = phone, touch + wide = tablet,
@@ -6209,7 +6727,10 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6209
6727
  * identity, as getCurrentPanelId() does.
6210
6728
  */
6211
6729
  private panelIdOf;
6212
- /** An end panel (no outgoing edges) of the manifest's last chapter. */
6730
+ /**
6731
+ * An end panel of the manifest's last chapter: no outgoing edges, or —
6732
+ * in a chapter without edges — the last panel in reading order.
6733
+ */
6213
6734
  private isEndOfWork;
6214
6735
  /**
6215
6736
  * Close the analytics session exactly once: emit `session_end` and flush
@@ -6242,6 +6763,13 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6242
6763
  * blocked attempt never changes story state.
6243
6764
  */
6244
6765
  navigateToPanel(chapterId: string, panelId: string, transition?: Transition, cameraMove?: CameraMove, mutations?: Mutation[]): Promise<void>;
6766
+ /**
6767
+ * Raise the gate in front of a panel the reader may not open: the age gate
6768
+ * for an unanswered age requirement (answered in-player), the paywall
6769
+ * otherwise. A host-supplied adapter still wins — it is the documented
6770
+ * override. Returns true when a gate was raised.
6771
+ */
6772
+ private raiseGateIfBlocked;
6245
6773
  /**
6246
6774
  * Rebuild the flat variable context handed to the viewport/canvas for
6247
6775
  * hotspot visibleIf evaluation. New object identity per call so OnPush
@@ -6259,6 +6787,11 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6259
6787
  * Keep the audio engine's playing set in step with the effective panel
6260
6788
  * (variant-resolved, so a variant's `audio` override wins) and the
6261
6789
  * variable context its tracks' `visibleIf` conditions read.
6790
+ *
6791
+ * A panel the renderers lock (age gate, paywall, `x-locked` stub) stays
6792
+ * silent: it syncs with no panel, which stops its tracks. The shell
6793
+ * re-syncs on `PaywallService.changes$`, so the audio starts once the age
6794
+ * is confirmed or the purchase lands.
6262
6795
  */
6263
6796
  private syncPanelAudio;
6264
6797
  /**
@@ -6347,6 +6880,21 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6347
6880
  * Toolbar event handlers
6348
6881
  */
6349
6882
  onToggleView(): void;
6883
+ /** Toolbar fullscreen button: show the player in fullscreen, or go back to the browser view. */
6884
+ toggleFullscreen(): void;
6885
+ /** Follow fullscreen changes from any source (button, Esc, F11-less browser UI). */
6886
+ onFullscreenChange(): void;
6887
+ /**
6888
+ * Double-click on the viewport: a panel in page view opens large in panel
6889
+ * view; in panel view the reader goes back to the page.
6890
+ */
6891
+ onPanelDoubleClick(panelId: string | null): void;
6892
+ /** Viewport previous arrow: the previous page in page view, else the previous panel. */
6893
+ onViewportPrevious(): void;
6894
+ /** Viewport next arrow: the next page in page view, else the next panel. */
6895
+ onViewportNext(): void;
6896
+ /** Switch to a view mode, setting up the page / video sequence / camera it needs. */
6897
+ private setViewMode;
6350
6898
  /** Land the canvas camera on the current panel (entering canvas view). */
6351
6899
  private jumpCameraToCurrentPanel;
6352
6900
  /**
@@ -6406,6 +6954,13 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6406
6954
  onPreferencesChange(prefs: Preferences): void;
6407
6955
  onToggleAutoplay(): void;
6408
6956
  onSecondsPerPanelChange(seconds: number): void;
6957
+ /** Toolbar: back to the author's timing ('author') or the reader's speed ('manual'). */
6958
+ onAutoplayTimingChange(timing: 'author' | 'manual'): void;
6959
+ /**
6960
+ * Seconds shown next to the autoplay controls: the reader's speed, or with
6961
+ * the author's timing the current panel's (page's) authored dwell time.
6962
+ */
6963
+ get autoplaySecondsDisplay(): number;
6409
6964
  onToggleThumbnails(): void;
6410
6965
  onOpenToc(): void;
6411
6966
  onOpenSettings(): void;
@@ -6434,8 +6989,8 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6434
6989
  * override; navigation keeps it per panel.
6435
6990
  */
6436
6991
  onCycleAlternative(): void;
6437
- /** Open the branch chooser with the paths currently open from this panel. */
6438
- onShowBranches(): void;
6992
+ /** Open the branch chooser with the paths currently open from this panel (or `panelId`). */
6993
+ onShowBranches(panelId?: string): void;
6439
6994
  onOpenExtras(): void;
6440
6995
  /** Toggle the reader's like for this work (persisted on the device). */
6441
6996
  onLike(): void;
@@ -6446,6 +7001,25 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6446
7001
  */
6447
7002
  onBookmark(): void;
6448
7003
  onShare(): void;
7004
+ /** Link in the open share dialog. */
7005
+ shareLink: string;
7006
+ /**
7007
+ * What to share: the host's `shareUrl`, else the current address with the
7008
+ * reading position — the page in page view, the panel in panel view, the
7009
+ * work itself on the cover. `embed` is dropped: the link opens the full
7010
+ * reader.
7011
+ */
7012
+ private buildShareLink;
7013
+ /** The reading position: cover, page (with its id), panel or canvas. */
7014
+ get currentLocation(): PlayerLocation;
7015
+ /** Last position reported through `locationChange`. */
7016
+ private lastLocationKey;
7017
+ /**
7018
+ * Report a changed reading position. Checked after every render: the
7019
+ * position changes in many places (navigation, view toggle, cover, page
7020
+ * format). Page view reports the page, not each panel the reader focuses.
7021
+ */
7022
+ ngAfterViewChecked(): void;
6449
7023
  onOpenComments(): void;
6450
7024
  /**
6451
7025
  * Modal close handlers
@@ -6463,6 +7037,7 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6463
7037
  onTocNavigate(target: {
6464
7038
  chapterId: string;
6465
7039
  panelId?: string;
7040
+ cover?: boolean;
6466
7041
  }): void;
6467
7042
  /**
6468
7043
  * Handle thumbnail navigation
@@ -6470,6 +7045,7 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6470
7045
  onThumbnailNavigate(target: {
6471
7046
  chapterId: string;
6472
7047
  panelId: string;
7048
+ cover?: boolean;
6473
7049
  }): void;
6474
7050
  /**
6475
7051
  * Keyboard shortcut handler
@@ -6506,6 +7082,24 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6506
7082
  * timer.
6507
7083
  */
6508
7084
  private startAutoplay;
7085
+ /** Run the wall-clock autoplay step: show progress, advance after `durationMs`. */
7086
+ private armAutoplayTimer;
7087
+ /** One autoplay step: leave the cover, turn the page (page view) or go to the next panel. */
7088
+ private autoplayAdvance;
7089
+ /** The reader is on the work's last panel (page view: its last page). */
7090
+ private atEndOfWork;
7091
+ /** Dwell time of one panel: authored `durationMs`, or the reader's seconds per panel. */
7092
+ private panelDwellMs;
7093
+ /** The current page's panel ids in reading order (placement order without one). */
7094
+ private pageReadingOrderIds;
7095
+ /**
7096
+ * Start the page-view video sequence. Image panels between the videos hold
7097
+ * it for their dwell time (authored `durationMs`, else the reader's seconds
7098
+ * per panel), so the art gets read before the next video starts.
7099
+ */
7100
+ private startPageSequence;
7101
+ /** Dwell time of what is on screen: the current panel, or every panel of the current page. */
7102
+ private currentDwellMs;
6509
7103
  /**
6510
7104
  * Stop autoplay
6511
7105
  */
@@ -6556,26 +7150,124 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6556
7150
  */
6557
7151
  private stopAutoplayProgress;
6558
7152
  /**
6559
- * Find the page that contains the current panel
7153
+ * The page (of the active format's page sequence) that shows a panel —
7154
+ * by default the current one. A panel the sequence leaves out lands on the
7155
+ * page closest before it in reading order.
6560
7156
  */
6561
7157
  private findPageContainingPanel;
6562
7158
  /**
6563
- * Navigate to next page (in page view mode)
6564
- */
6565
- navigateToNextPage(): void;
7159
+ * Background color of the page the reader is on — the open page in page
7160
+ * view, the page holding the current panel in panel view — so the frame
7161
+ * switches color exactly when the first panel of the next page appears.
7162
+ */
7163
+ get pageBackground(): string;
7164
+ /**
7165
+ * Open the initial view: page view (default; `initialViewMode` overrides)
7166
+ * on `page` — or, when that page is not in the screen's page format, the
7167
+ * page showing the current panel. Canvas chapters and hosts that force a
7168
+ * view mode keep theirs. Behind the cover the page sequence waits until
7169
+ * the cover is left.
7170
+ */
7171
+ private enterInitialView;
7172
+ /** A page by its manifest id, in any chapter and format. */
7173
+ private findPageById;
7174
+ /** The chapter that holds a panel. */
7175
+ private findChapterOfPanel;
7176
+ /** First panel of a page in reading order (placement order without one). */
7177
+ private firstPanelOf;
7178
+ /** The chapter's pages in the active page format (legacy pages without a format included). */
7179
+ chapterPages(chapter: Chapter | undefined): Page[];
7180
+ /**
7181
+ * Pick the page sequence for the current screen (or the host's
7182
+ * `pageFormat`). In page view a change of format re-opens the page that
7183
+ * shows the current panel in the new sequence.
7184
+ */
7185
+ private updatePageFormat;
7186
+ onWindowResize(): void;
7187
+ /**
7188
+ * After a jump to a panel (TOC, thumbnails, chapter change, next/previous):
7189
+ * the cover gives way, page view opens the page showing the panel, and the
7190
+ * look-ahead follows.
7191
+ */
7192
+ private afterJump;
7193
+ /** The chapter before (-1) or after (+1) the current one. */
7194
+ private adjacentChapter;
7195
+ private isFirstChapter;
7196
+ /** The panel a page starts with: first in its reading order, else its first placement. */
7197
+ private firstPanelIdOf;
7198
+ /** Show a page of the current chapter, its first panel becoming the current one. */
7199
+ private showPage;
7200
+ /**
7201
+ * Page view across a chapter boundary: the first (+1) or last (-1) page of
7202
+ * the adjacent chapter. The move goes through the panel gates like any
7203
+ * other; a blocked move stays put.
7204
+ */
7205
+ private turnToAdjacentChapter;
7206
+ /**
7207
+ * Navigate to next page (in page view mode); past the chapter's last page
7208
+ * to the next chapter. From the cover, the story starts.
7209
+ */
7210
+ navigateToNextPage(): Promise<void>;
7211
+ /** Make the cover visible (thumbnail strip, TOC, back from the first panel/page). */
7212
+ showCoverPage(): void;
7213
+ /** Leave the cover: the story starts at the current (first) panel or page. */
7214
+ hideCover(): void;
7215
+ /**
7216
+ * While the cover is up the viewport is not mounted, so its look-ahead
7217
+ * cannot warm what comes first. Warm it here: the first panel (page view:
7218
+ * the current page's panels) at the rendition a freshly mounted panel
7219
+ * starts with (the catalog's primary variant, before layout knows its
7220
+ * width) — the story then appears without a load gap.
7221
+ */
7222
+ private warmBehindCover;
7223
+ /** Resolve the cover image from `meta.cover` / `extras.cover` through the asset catalog. */
7224
+ private resolveCover;
7225
+ /** The work's title in the current locale (cover alt text). */
7226
+ get workTitle(): string;
7227
+ /**
7228
+ * Reading-order look-ahead for the viewport's preloader: the next panels
7229
+ * (panel view) or the next pages' panels (page view), crossing into the
7230
+ * next chapter, so autoplay and paging never wait for artwork.
7231
+ */
7232
+ private updatePreloadTargets;
6566
7233
  /**
6567
7234
  * Restart the page-view video sequence (and autoplay arming) after the
6568
7235
  * current page changed.
6569
7236
  */
6570
7237
  private onPageChanged;
6571
7238
  /**
6572
- * Navigate to previous page (in page view mode)
7239
+ * Page view shows a whole page at once, so the per-panel navigation gate
7240
+ * never runs: panels the paywall locks render as placeholders. When some of
7241
+ * them only wait for the reader's age, ask once for the page (the highest
7242
+ * minimum age among them); confirming unlocks them in place.
7243
+ */
7244
+ private promptAgeGateForPage;
7245
+ /**
7246
+ * Page view: the reader activated a locked panel's placeholder. Raise the
7247
+ * gate that unlocks it in place, without moving: the age gate when only
7248
+ * the age is missing, otherwise the paywall for that panel (the same gate
7249
+ * a panel move would raise). A panel that is not locked raises nothing.
7250
+ */
7251
+ onLockedPanelActivate(panelId: string): void;
7252
+ /**
7253
+ * Ask once for the age the given panels wait for (the highest minimum
7254
+ * age among those locked only by their age), with no pending move:
7255
+ * confirming unlocks them in place.
6573
7256
  */
6574
- navigateToPreviousPage(): void;
7257
+ private promptAgeGate;
6575
7258
  /**
6576
- * Get available locales from manifest
7259
+ * Navigate to previous page (in page view mode); before the chapter's
7260
+ * first page to the previous chapter's last page, before the work's first
7261
+ * page to the cover.
7262
+ */
7263
+ navigateToPreviousPage(): Promise<void>;
7264
+ /**
7265
+ * Languages the work can be read in (the toolbar shows the language switch
7266
+ * when there are several): `meta.locales` plus the languages the content
7267
+ * is translated into. Computed once per manifest.
6577
7268
  */
6578
7269
  get availableLocales(): LocaleCode[];
7270
+ private localeCache?;
6579
7271
  /**
6580
7272
  * Get characters from manifest mapped to roster format
6581
7273
  */
@@ -6637,8 +7329,19 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6637
7329
  * "Choices". A closed conditional edge does not count.
6638
7330
  */
6639
7331
  get hasBranchesAhead(): boolean;
6640
- /** Outgoing edges of the current panel whose conditions pass right now. */
7332
+ /** Outgoing edges of the current panel (or `fromPanelId`) whose conditions pass right now. */
6641
7333
  private openEdges;
7334
+ /**
7335
+ * The current panel is a decision: two or more open paths carry an authored
7336
+ * choice label. "Next" then asks the reader instead of following one of them.
7337
+ */
7338
+ private isDecisionAhead;
7339
+ /**
7340
+ * Page view: a decision on the current page the reader has not taken yet
7341
+ * (the last one in reading order). Turning the page would only show the
7342
+ * placeholders of its branches, so "next" asks instead.
7343
+ */
7344
+ private pendingDecisionOnPage;
6642
7345
  /** Open outgoing edges with reader-facing labels. */
6643
7346
  private computeBranchChoices;
6644
7347
  private branchLabel;
@@ -6646,7 +7349,7 @@ declare class PlayerShellComponent implements OnInit, OnChanges, OnDestroy {
6646
7349
  /** Traverse the chosen edge (its transition / camera move / mutations apply). */
6647
7350
  onBranchChosen(choice: BranchChoice): Promise<void>;
6648
7351
  static ɵfac: i0.ɵɵFactoryDeclaration<PlayerShellComponent, never>;
6649
- static ɵcmp: i0.ɵɵComponentDeclaration<PlayerShellComponent, "pw-player-shell", never, { "manifest": { "alias": "manifest"; "required": false; }; "manifestUrl": { "alias": "manifestUrl"; "required": false; }; "entitlementAdapter": { "alias": "entitlementAdapter"; "required": false; }; "entitlementSnapshot": { "alias": "entitlementSnapshot"; "required": false; }; "entitlementEndpoint": { "alias": "entitlementEndpoint"; "required": false; }; "readerToken": { "alias": "readerToken"; "required": false; }; "initialVariables": { "alias": "initialVariables"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "initialChapterId": { "alias": "initialChapterId"; "required": false; }; "initialPanelId": { "alias": "initialPanelId"; "required": false; }; "autoplay": { "alias": "autoplay"; "required": false; }; "secondsPerPanel": { "alias": "secondsPerPanel"; "required": false; }; "reducedMotion": { "alias": "reducedMotion"; "required": false; }; "showToolbar": { "alias": "showToolbar"; "required": false; }; "viewModeOverride": { "alias": "viewModeOverride"; "required": false; }; }, { "paywallAction": "paywallAction"; "ageVerified": "ageVerified"; "likeChange": "likeChange"; "bookmarkChange": "bookmarkChange"; "ready": "ready"; "panelChange": "panelChange"; "chapterChange": "chapterChange"; "error": "error"; "localeChange": "localeChange"; "variableChange": "variableChange"; "navigationAttempt": "navigationAttempt"; "cameraChange": "cameraChange"; }, never, never, true, never>;
7352
+ static ɵcmp: i0.ɵɵComponentDeclaration<PlayerShellComponent, "pw-player-shell", never, { "manifest": { "alias": "manifest"; "required": false; }; "manifestUrl": { "alias": "manifestUrl"; "required": false; }; "entitlementAdapter": { "alias": "entitlementAdapter"; "required": false; }; "entitlementSnapshot": { "alias": "entitlementSnapshot"; "required": false; }; "entitlementEndpoint": { "alias": "entitlementEndpoint"; "required": false; }; "readerToken": { "alias": "readerToken"; "required": false; }; "initialVariables": { "alias": "initialVariables"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "initialChapterId": { "alias": "initialChapterId"; "required": false; }; "initialPanelId": { "alias": "initialPanelId"; "required": false; }; "initialPageId": { "alias": "initialPageId"; "required": false; }; "initialViewMode": { "alias": "initialViewMode"; "required": false; }; "shareUrl": { "alias": "shareUrl"; "required": false; }; "autoplay": { "alias": "autoplay"; "required": false; }; "secondsPerPanel": { "alias": "secondsPerPanel"; "required": false; }; "pageFormat": { "alias": "pageFormat"; "required": false; }; "showCover": { "alias": "showCover"; "required": false; }; "reducedMotion": { "alias": "reducedMotion"; "required": false; }; "showToolbar": { "alias": "showToolbar"; "required": false; }; "viewModeOverride": { "alias": "viewModeOverride"; "required": false; }; }, { "paywallAction": "paywallAction"; "ageVerified": "ageVerified"; "likeChange": "likeChange"; "bookmarkChange": "bookmarkChange"; "locationChange": "locationChange"; "ready": "ready"; "panelChange": "panelChange"; "chapterChange": "chapterChange"; "error": "error"; "localeChange": "localeChange"; "variableChange": "variableChange"; "navigationAttempt": "navigationAttempt"; "cameraChange": "cameraChange"; }, never, never, true, never>;
6650
7353
  }
6651
7354
 
6652
7355
  /**
@@ -6711,9 +7414,11 @@ declare class CanvasStageComponent implements OnInit, OnChanges, OnDestroy {
6711
7414
  cameraChange: EventEmitter<CameraState>;
6712
7415
  readonly camera: CanvasCameraService;
6713
7416
  private readonly manifestService;
7417
+ private readonly assetUrlService;
6714
7418
  private readonly preloadService;
6715
7419
  private readonly elementRef;
6716
7420
  private readonly cdr;
7421
+ private readonly paywall;
6717
7422
  private readonly destroy$;
6718
7423
  /** Current world transform CSS for `.canvas-world`. */
6719
7424
  worldTransform: string;
@@ -6782,6 +7487,12 @@ declare class CanvasStageComponent implements OnInit, OnChanges, OnDestroy {
6782
7487
  /** Balloon lettering scale (same DIN-A4 reference as the panel viewport). */
6783
7488
  getReadingScale(): number;
6784
7489
  isCurrent(panelId: string): boolean;
7490
+ /**
7491
+ * Show the locked placeholder instead of the panel's content: a server
7492
+ * stub (`"x-locked": true`), or a panel the paywall rules lock for the
7493
+ * reader's current snapshot (age gate not yet answered, not purchased).
7494
+ */
7495
+ isLocked(panel: Panel | null | undefined, panelId?: string | null): boolean;
6785
7496
  trackPlacement(_index: number, entry: StagePlacement): string;
6786
7497
  private freeRoamAllowed;
6787
7498
  onPointerDown(event: PointerEvent): void;
@@ -6857,6 +7568,14 @@ declare class SpeechBubblesComponent implements OnChanges, AfterViewInit, OnDest
6857
7568
  }>;
6858
7569
  /** Rendered balloon containers, keyed by bubble ID */
6859
7570
  private renderedBalloons;
7571
+ /**
7572
+ * Font specs ("15px 'Ames Italic', sans-serif") whose loading this overlay
7573
+ * already requested. Web fonts load lazily on first use, so the first
7574
+ * render may have measured with a fallback face while document.fonts.ready
7575
+ * had long resolved (no font was in flight yet). Each new spec is loaded
7576
+ * explicitly and the balloons re-render once it arrives.
7577
+ */
7578
+ private fontsRequested;
6860
7579
  /** ResizeObserver for container size tracking */
6861
7580
  private resizeObserver;
6862
7581
  private initialized;
@@ -6887,6 +7606,12 @@ declare class SpeechBubblesComponent implements OnChanges, AfterViewInit, OnDest
6887
7606
  * Render all speech balloons into the DOM
6888
7607
  */
6889
7608
  renderAllBalloons(): void;
7609
+ /**
7610
+ * Request every font spec the balloons use that was not requested before;
7611
+ * re-render once a face that was not yet available arrives, so balloons
7612
+ * measured with a fallback face are laid out again with the real one.
7613
+ */
7614
+ private ensureFontsLoaded;
6890
7615
  /**
6891
7616
  * Handle bubble click (called from template for any fallback interaction)
6892
7617
  */
@@ -6912,6 +7637,11 @@ declare class HotspotsOverlayComponent implements OnChanges {
6912
7637
  * Hotspots of the current panel (manifest shape)
6913
7638
  */
6914
7639
  hotspots: Hotspot[];
7640
+ /**
7641
+ * The panel's speech bubbles: a choice hotspot whose label is already
7642
+ * lettered as a bubble keeps its invisible area under `display: auto`.
7643
+ */
7644
+ bubbles: SpeechBubble[];
6915
7645
  /**
6916
7646
  * Current locale for label resolution
6917
7647
  */
@@ -6950,7 +7680,25 @@ declare class HotspotsOverlayComponent implements OnChanges {
6950
7680
  * Hotspots passing their visibleIf condition
6951
7681
  */
6952
7682
  visibleHotspots: Hotspot[];
7683
+ /**
7684
+ * Hotspots shown as labelled buttons: `display: "button"`, and with `auto`
7685
+ * (the default) the goTo hotspots of a panel whose hotspots lead to two or
7686
+ * more panels (a decision). `area` — and any other auto hotspot — stays an
7687
+ * invisible area over the artwork (a door, a phone, a painted button).
7688
+ */
7689
+ choiceIds: ReadonlySet<string>;
6953
7690
  ngOnChanges(): void;
7691
+ /** The visible button text of a choice hotspot (its label), or '' for plain areas. */
7692
+ choiceText(h: Hotspot): string;
7693
+ /** Bounding box (container units) of a hotspot shape — where its button label sits. */
7694
+ boundsOf(s: HotspotShape): {
7695
+ x: number;
7696
+ y: number;
7697
+ width: number;
7698
+ height: number;
7699
+ };
7700
+ /** Label font size: fits the button height, readable but never huge. */
7701
+ choiceFontSize(h: Hotspot): number;
6954
7702
  /**
6955
7703
  * Accessible label: ariaLabel wins over label, falls back to the id
6956
7704
  */
@@ -6983,7 +7731,7 @@ declare class HotspotsOverlayComponent implements OnChanges {
6983
7731
  private centroidOf;
6984
7732
  private clamp01;
6985
7733
  static ɵfac: i0.ɵɵFactoryDeclaration<HotspotsOverlayComponent, never>;
6986
- static ɵcmp: i0.ɵɵComponentDeclaration<HotspotsOverlayComponent, "pw-hotspots-overlay", never, { "hotspots": { "alias": "hotspots"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "containerWidth": { "alias": "containerWidth"; "required": false; }; "containerHeight": { "alias": "containerHeight"; "required": false; }; "context": { "alias": "context"; "required": false; }; "interactive": { "alias": "interactive"; "required": false; }; "showIndicators": { "alias": "showIndicators"; "required": false; }; }, { "hotspotActivate": "hotspotActivate"; }, never, never, true, never>;
7734
+ static ɵcmp: i0.ɵɵComponentDeclaration<HotspotsOverlayComponent, "pw-hotspots-overlay", never, { "hotspots": { "alias": "hotspots"; "required": false; }; "bubbles": { "alias": "bubbles"; "required": false; }; "locale": { "alias": "locale"; "required": false; }; "containerWidth": { "alias": "containerWidth"; "required": false; }; "containerHeight": { "alias": "containerHeight"; "required": false; }; "context": { "alias": "context"; "required": false; }; "interactive": { "alias": "interactive"; "required": false; }; "showIndicators": { "alias": "showIndicators"; "required": false; }; }, { "hotspotActivate": "hotspotActivate"; }, never, never, true, never>;
6987
7735
  }
6988
7736
 
6989
7737
  /**
@@ -7098,6 +7846,7 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7098
7846
  private readonly sequencer;
7099
7847
  private readonly audioEngine;
7100
7848
  private readonly cdr;
7849
+ private readonly assetUrl;
7101
7850
  /** Follows the player-wide Audio toggle (engine master mute). */
7102
7851
  private masterMuteSub?;
7103
7852
  private readonly host;
@@ -7105,8 +7854,6 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7105
7854
  src: string;
7106
7855
  /** Reverse-variant URL used for the pingpong backward pass (empty if none). */
7107
7856
  reverseSrc: string;
7108
- /** Base URL for resolving relative paths. */
7109
- baseUrl: string;
7110
7857
  /** Poster image URL. */
7111
7858
  poster: string;
7112
7859
  /** Show native controls. */
@@ -7202,6 +7949,8 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7202
7949
  private registeredWithSequencer;
7203
7950
  /** Whether this video is currently the sequencer's active slot member. */
7204
7951
  private activatedBySequencer;
7952
+ /** An `on-view` video started by hovering it (page view), not by the sequence. */
7953
+ private hoverPlaying;
7205
7954
  /**
7206
7955
  * What triggered the most recent playback, for tracking payloads. Set when
7207
7956
  * playback starts (sequencer / view / hover / click).
@@ -7215,6 +7964,7 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7215
7964
  private readonly onTimeUpdateBound;
7216
7965
  getVideoUrl(): string;
7217
7966
  getPosterUrl(): string;
7967
+ /** Absolute URLs as-is; relative ones via the manifest's assets.base / manifest URL. */
7218
7968
  private resolveUrl;
7219
7969
  private get video();
7220
7970
  private get startTimeSec();
@@ -7250,14 +8000,27 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7250
8000
  /** Called from the template once the <video> element is available. */
7251
8001
  onLoadedMetadata(): void;
7252
8002
  private handleViewActiveChange;
7253
- /** Click / tap handler (on-click toggle). */
8003
+ /**
8004
+ * Click / tap handler: on-click layers toggle; any other video that is
8005
+ * not playing (waiting for its turn in the page sequence, finished, or
8006
+ * paused) starts on a click.
8007
+ */
7254
8008
  onClick(): void;
7255
8009
  /** Keyboard handler (Enter / Space) for on-click layers. */
7256
8010
  onKeydown(event: KeyboardEvent): void;
7257
- /** Mouse enter — on-hover start (page view only). */
8011
+ /**
8012
+ * Mouse enter — on-hover start (page view only). An `on-view` video in page
8013
+ * view that is not playing (still waiting for its turn in the sequence, or
8014
+ * finished) plays while the pointer rests on it too.
8015
+ */
7258
8016
  onMouseEnter(): void;
7259
- /** Mouse leave — on-hover pause keeping position. */
8017
+ /**
8018
+ * Mouse leave — on-hover pause keeping position; an `on-view` video the
8019
+ * hover started pauses too, unless the sequence took it over meanwhile.
8020
+ */
7260
8021
  onMouseLeave(): void;
8022
+ /** The video is not playing: never started, paused or finished. */
8023
+ private isIdle;
7261
8024
  private togglePlayback;
7262
8025
  /** Whether this layer participates in keyboard interaction. */
7263
8026
  isKeyboardInteractive(): boolean;
@@ -7362,7 +8125,7 @@ declare class VideoLayerComponent implements OnInit, OnChanges, OnDestroy {
7362
8125
  private scheduleFrameStep;
7363
8126
  private stopFrameStepping;
7364
8127
  static ɵfac: i0.ɵɵFactoryDeclaration<VideoLayerComponent, never>;
7365
- static ɵcmp: i0.ɵɵComponentDeclaration<VideoLayerComponent, "pw-video-layer", never, { "src": { "alias": "src"; "required": false; }; "reverseSrc": { "alias": "reverseSrc"; "required": false; }; "baseUrl": { "alias": "baseUrl"; "required": false; }; "poster": { "alias": "poster"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "playMode": { "alias": "playMode"; "required": false; }; "startMode": { "alias": "startMode"; "required": false; }; "muted": { "alias": "muted"; "required": false; }; "startAtMs": { "alias": "startAtMs"; "required": false; }; "loopFromMs": { "alias": "loopFromMs"; "required": false; }; "streaming": { "alias": "streaming"; "required": false; }; "viewMode": { "alias": "viewMode"; "required": false; }; "viewActive": { "alias": "viewActive"; "required": false; }; "reducedMotion": { "alias": "reducedMotion"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "videoId": { "alias": "videoId"; "required": false; }; "panelId": { "alias": "panelId"; "required": false; }; "assetId": { "alias": "assetId"; "required": false; }; "placementId": { "alias": "placementId"; "required": false; }; "readingOrderIndex": { "alias": "readingOrderIndex"; "required": false; }; "placementZ": { "alias": "placementZ"; "required": false; }; "placementY": { "alias": "placementY"; "required": false; }; "placementX": { "alias": "placementX"; "required": false; }; }, { "videoPlay": "videoPlay"; "videoPause": "videoPause"; "videoEnd": "videoEnd"; "videoLoop": "videoLoop"; "passComplete": "passComplete"; "videoError": "videoError"; }, never, never, true, never>;
8128
+ static ɵcmp: i0.ɵɵComponentDeclaration<VideoLayerComponent, "pw-video-layer", never, { "src": { "alias": "src"; "required": false; }; "reverseSrc": { "alias": "reverseSrc"; "required": false; }; "poster": { "alias": "poster"; "required": false; }; "controls": { "alias": "controls"; "required": false; }; "playMode": { "alias": "playMode"; "required": false; }; "startMode": { "alias": "startMode"; "required": false; }; "muted": { "alias": "muted"; "required": false; }; "startAtMs": { "alias": "startAtMs"; "required": false; }; "loopFromMs": { "alias": "loopFromMs"; "required": false; }; "streaming": { "alias": "streaming"; "required": false; }; "viewMode": { "alias": "viewMode"; "required": false; }; "viewActive": { "alias": "viewActive"; "required": false; }; "reducedMotion": { "alias": "reducedMotion"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; "videoId": { "alias": "videoId"; "required": false; }; "panelId": { "alias": "panelId"; "required": false; }; "assetId": { "alias": "assetId"; "required": false; }; "placementId": { "alias": "placementId"; "required": false; }; "readingOrderIndex": { "alias": "readingOrderIndex"; "required": false; }; "placementZ": { "alias": "placementZ"; "required": false; }; "placementY": { "alias": "placementY"; "required": false; }; "placementX": { "alias": "placementX"; "required": false; }; }, { "videoPlay": "videoPlay"; "videoPause": "videoPause"; "videoEnd": "videoEnd"; "videoLoop": "videoLoop"; "passComplete": "passComplete"; "videoError": "videoError"; }, never, never, true, never>;
7366
8129
  }
7367
8130
 
7368
8131
  declare class PlayerComponent {
@@ -7370,5 +8133,5 @@ declare class PlayerComponent {
7370
8133
  static ɵcmp: i0.ɵɵComponentDeclaration<PlayerComponent, "pw-player", never, {}, {}, never, never, true, never>;
7371
8134
  }
7372
8135
 
7373
- export { ANONYMOUS_READER, ActionModalComponent, AgeGateComponent, AudioEngineService, BranchChooserComponent, CANVAS_PANEL_BUDGET, CanvasCameraService, CanvasStageComponent, ComicBalloon, DEFAULT_BALLOON_CONFIG, DEFAULT_STALL_TIMEOUT_MS, DEFAULT_VIDEO_MUTED, DEFAULT_VIDEO_PLAY_MODE, DEFAULT_VIDEO_START_MODE, EntitlementError, EntitlementService, ExportService, FlowEngineService, HotspotActionService, HotspotsOverlayComponent, HttpEntitlementAdapter, ImageCacheService, ManifestService, MockEntitlementAdapter, NullEntitlementAdapter, PANEL_AUDIO_LEAVE_FADE_MS, PanelAudioService, PaywallOverlayComponent, PaywallService, PlayerComponent, PlayerEvent, PlayerService, PlayerShellComponent, PlayerStateService, PluginHostService, PluginSandboxComponent, PreloadService, PwIconComponent, RESERVED_NAMESPACES, SpeechBubblesComponent, TrackingService, TranslationService, UserGestureService, VISIBILITY_THRESHOLD, VariableStoreService, VideoControllerService, VideoLayerComponent, VideoSequencerService, VisibilityService, applyVariantOverrides, balloonConfigToRenderOptions, balloonConfigToTailOptions, busForRole, chapterOrderFromManifest, createBalloon, evaluatePanelAccess, evaluateWorkAccess, findWorkGateRule, fromManifestRule, isExtraLocked, mergeBalloonConfig, readingOrderFromManifest, resolveMuted, resolvePanelVariant, resolvePanels, resolvePlayMode, resolveStartMode, resolveVideoConfig, rulesFromManifest, satisfiesRule, selectVariant, toEntitlementStatus };
7374
- export type { AccessDecision, AgeVerificationResult, AssetBase, AssetCatalogItem, AssetCatalogItemAudio, AssetCatalogItemImage, AssetCatalogItemJson, AssetCatalogItemPluginPayload, AssetCatalogItemSubtitle, AssetCatalogItemVector, AssetCatalogItemVideo, AssetCategory, AssetCommon, AssetRef, AssetReference, AssetVariant, Assets, AudioLayer, AudioRole, AudioTrack, AudioVariant, BalloonConfig, BalloonConfigOverride, BalloonOptions, BalloonRenderResult, BalloonType, Bookmark, BoundingBox, BranchChoice, BubbleStyle, BubbleTail, CameraMove, CameraMovePath, CameraState, CameraZoomProfile, CanvasBackground, CanvasCameraPolicy, CanvasDecoration, CanvasFitMode, CanvasFreeRoam, CanvasLayout, CanvasOverviewPolicy, CanvasPlacement, CanvasRevealMode, Chapter, Character$1 as Character, ContentWarning, Creator, DecisionEvent, DeepLinkTarget, DeviceVariables, Edge, EffectiveVideoConfig, EntitlementAdapter$1 as EntitlementAdapter, EntitlementContext, EntitlementErrorCode, EntitlementSnapshot, EntitlementSnapshotResponse, EntitlementStatus, EntitlementVariables, ErrorEvent$1 as ErrorEvent, EvaluatorEntitlementType, EvaluatorRule, EvaluatorScope, ExtraImage, ExtraItem, Extras, FormatView, Graph, HideBorderConfig, Hotspot, HotspotAction, HotspotCircle, HotspotGoToAction, HotspotOpenExtrasAction, HotspotOpenModalAction, HotspotPluginEventAction, HotspotPolygon, HotspotRect, HotspotSetVariablesAction, HotspotShape, HotspotUiEffect, HttpEntitlementAdapterConfig, ImageLayer, ImageVariant, JsonLogic, JsonLogicExpression, JsonValue, JsonVariant, Layer, LayerKind, LayerViewMode, LocaleCode, LocalizedString, LockReason, Meta, Mutation, MutationOperation, NavigationPath, NodeMetadata, NormalizedPoint, NormalizedRect, OutputFormat, OutputPreset, OverlayState, Page, PageLayout, Panel, PanelAudioRole, PanelAudioTrack, PanelChangeEvent, PanelPartial, PanelPlacement, PanelRef, PanelVariant, PanelWaveManifest, PanelwaveHeader, Paywall, PaywallAction, PaywallEvent, PaywallGate$1 as PaywallGate, PaywallProduct, PaywallRule, PlaybackState, PlayerError, PlayerErrorCode, PlayerEventData, PlayerOptions, PlayerPanelChangeEvent, PlayerPreferences, PlayerState, PlayerStatistics, PluginInstance$1 as PluginInstance, PluginLayer, PreferenceVariables, PreloadItem, PreloadPriority, PreloadSettings, PreloadStatus$1 as PreloadStatus, PreviewInfo, PurchaseInfo, ReadingProgress, ResolvedPanel, ResolvedPanelAudio, SequenceAudioTrack, SequencedVideo, SequencedVideoInfo, Settings, SpeechBubble, StagePlacement, SubtitleVariant, TailConfig, TailCurve, TailOptions, TextLayer, TextStyle, Tracking, TrackingConfig$1 as TrackingConfig, TrackingEvent, Transform, Transition, TraversalOptions, TraversalResult, UIDefaults, UISettings, UserInfo, UserVariables, VariableChangeEvent, VariableContext, VariableDefinition, VariableMutation, VariableScope, VariableStore, VariableType, VariableValidationResult, Variables, VariantContext, VectorVariant, VideoEvent, VideoLayer, VideoPlayMode, VideoPoster, VideoStartMode, VideoState, VideoStatus, VideoTrackingPayload, VideoTrigger, VideoVariant, ViewMode, ViewportState, VisibilityChange, WorldPoint, WorldRect };
8136
+ export { ANONYMOUS_READER, ActionModalComponent, AgeGateComponent, AssetUrlService, AudioEngineService, BranchChooserComponent, CANVAS_PANEL_BUDGET, CanvasCameraService, CanvasStageComponent, ComicBalloon, DEFAULT_BALLOON_CONFIG, DEFAULT_PAGE_BACKGROUND, DEFAULT_STALL_TIMEOUT_MS, DEFAULT_VIDEO_MUTED, DEFAULT_VIDEO_PLAY_MODE, DEFAULT_VIDEO_START_MODE, EntitlementError, EntitlementService, ExportService, FlowEngineService, HotspotActionService, HotspotsOverlayComponent, HttpEntitlementAdapter, ImageCacheService, LOCATION_PARAMS, ManifestService, MockEntitlementAdapter, NullEntitlementAdapter, PANEL_AUDIO_LEAVE_FADE_MS, PanelAudioService, PaywallOverlayComponent, PaywallService, PlayerComponent, PlayerEvent, PlayerService, PlayerShellComponent, PlayerStateService, PluginHostService, PluginSandboxComponent, PreloadService, PwIconComponent, RESERVED_NAMESPACES, SpeechBubblesComponent, THUMBNAIL_WIDTH, TrackingService, TranslationService, UserGestureService, VISIBILITY_THRESHOLD, VariableStoreService, VideoControllerService, VideoLayerComponent, VideoSequencerService, VisibilityService, applyVariantOverrides, balloonConfigToRenderOptions, balloonConfigToTailOptions, busForRole, chapterOrderFromManifest, coverImageSrc, createBalloon, evaluatePanelAccess, evaluateWorkAccess, findWorkGateRule, fromManifestRule, isExtraLocked, isLockedPanel, locationUrl, mergeBalloonConfig, pageAspectRatio, pageFormatOf, pageFormatsOf, pagesForFormat, panelThumbnailSrc, parseLocationSearch, pickPageFormat, rankPageFormats, readingOrderFromManifest, resolveMuted, resolvePageBackground, resolvePanelVariant, resolvePanels, resolvePlayMode, resolveStartMode, resolveVideoConfig, rulesFromManifest, satisfiesRule, screenClassFor, selectVariant, toEntitlementStatus };
8137
+ export type { AccessDecision, AgeVerificationResult, AnimatableProperty, AnimationEasing, AnimationKeyframe, AssetBase, AssetCatalogItem, AssetCatalogItemAudio, AssetCatalogItemImage, AssetCatalogItemJson, AssetCatalogItemPluginPayload, AssetCatalogItemSubtitle, AssetCatalogItemVector, AssetCatalogItemVideo, AssetCategory, AssetCommon, AssetRef, AssetReference, AssetVariant, Assets, AudioLayer, AudioRole, AudioTrack, AudioVariant, BalloonConfig, BalloonConfigOverride, BalloonOptions, BalloonRenderResult, BalloonType, Bookmark, BoundingBox, BranchChoice, BubbleStyle, BubbleTail, CameraMove, CameraMovePath, CameraState, CameraZoomProfile, CanvasBackground, CanvasCameraPolicy, CanvasDecoration, CanvasFitMode, CanvasFreeRoam, CanvasLayout, CanvasOverviewPolicy, CanvasPlacement, CanvasRevealMode, Chapter, Character$1 as Character, ContentWarning, Creator, DecisionEvent, DeepLinkTarget, DeviceVariables, Edge, EffectiveVideoConfig, EntitlementAdapter$1 as EntitlementAdapter, EntitlementContext, EntitlementErrorCode, EntitlementSnapshot, EntitlementSnapshotResponse, EntitlementStatus, EntitlementVariables, ErrorEvent$1 as ErrorEvent, EvaluatorEntitlementType, EvaluatorRule, EvaluatorScope, ExtraImage, ExtraItem, Extras, FormatView, Graph, HideBorderConfig, Hotspot, HotspotAction, HotspotCircle, HotspotGoToAction, HotspotOpenExtrasAction, HotspotOpenModalAction, HotspotPluginEventAction, HotspotPolygon, HotspotRect, HotspotSetVariablesAction, HotspotShape, HotspotUiEffect, HttpEntitlementAdapterConfig, ImageLayer, ImageVariant, JsonLogic, JsonLogicExpression, JsonValue, JsonVariant, Layer, LayerKind, LayerViewMode, LocaleCode, LocalizedString, LockReason, Meta, Mutation, MutationOperation, NavigationPath, NodeMetadata, NormalizedPoint, NormalizedRect, OutputFormat, OutputPreset, OverlayState, Page, PageLayout, PageVisual, Panel, PanelAnimations, PanelAudioRole, PanelAudioTrack, PanelChangeEvent, PanelPartial, PanelPlacement, PanelRef, PanelVariant, PanelWaveManifest, PanelwaveHeader, Paywall, PaywallAction, PaywallEvent, PaywallGate$1 as PaywallGate, PaywallProduct, PaywallRule, PlaybackState, PlayerError, PlayerErrorCode, PlayerEventData, PlayerLocation, PlayerOptions, PlayerPanelChangeEvent, PlayerPreferences, PlayerState, PlayerStatistics, PlayerView, PluginInstance$1 as PluginInstance, PluginLayer, PreferenceVariables, PreloadItem, PreloadPriority, PreloadSettings, PreloadStatus$1 as PreloadStatus, PreviewInfo, PurchaseInfo, ReadingProgress, ResolvedPanel, ResolvedPanelAudio, ScreenClass, SequenceAudioTrack, SequencedVideo, SequencedVideoInfo, Settings, SpeechBubble, StagePlacement, SubtitleVariant, TailConfig, TailCurve, TailOptions, TextLayer, TextStyle, Tracking, TrackingConfig$1 as TrackingConfig, TrackingEvent, Transform, Transition, TraversalOptions, TraversalResult, UIDefaults, UISettings, UserInfo, UserVariables, VariableChangeEvent, VariableContext, VariableDefinition, VariableMutation, VariableScope, VariableStore, VariableType, VariableValidationResult, Variables, VariantContext, VectorVariant, VideoEvent, VideoLayer, VideoPlayMode, VideoPoster, VideoStartMode, VideoState, VideoStatus, VideoTrackingPayload, VideoTrigger, VideoVariant, ViewMode, ViewportState, VisibilityChange, WorldPoint, WorldRect };