@panelwave/player 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -1,24 +1,217 @@
1
- # Player
2
-
3
- This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
4
-
5
- ## Code scaffolding
6
-
7
- Run `ng generate component component-name --project player` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project player`.
8
- > Note: Don't forget to add `--project player` or else it will be added to the default project in your `angular.json` file.
9
-
10
- ## Build
11
-
12
- Run `ng build player` to build the project. The build artifacts will be stored in the `dist/` directory.
13
-
14
- ## Publishing
15
-
16
- After building your library with `ng build player`, go to the dist folder `cd dist/player` and run `npm publish`.
17
-
18
- ## Running unit tests
19
-
20
- Run `ng test player` to execute the unit tests via [Karma](https://karma-runner.github.io).
21
-
22
- ## Further help
23
-
24
- To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
1
+ # @panelwave/player
2
+
3
+ **The open-source Angular player for interactive graphic novels.** It renders
4
+ [PanelWave](https://panelwave.org) manifests (`panelwave.json`): branching panel
5
+ graphs, layered artwork, comic speech balloons, hotspots, video panels, audio,
6
+ story variables, multilingual text and paywalls, all in one component.
7
+
8
+ [![npm](https://img.shields.io/npm/v/@panelwave/player.svg)](https://www.npmjs.com/package/@panelwave/player)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/panelwave/player/blob/master/LICENSE)
10
+ [![Angular](https://img.shields.io/badge/Angular-20-red)](https://angular.dev)
11
+
12
+ **[Live demo](https://panelwave.github.io/player/)** ·
13
+ **[Documentation](https://docs.panelwave.org/player/overview)** ·
14
+ **[Format spec](https://github.com/panelwave/schema)** ·
15
+ **[Source](https://github.com/panelwave/player)**
16
+
17
+ ---
18
+
19
+ ## What it does
20
+
21
+ A PanelWave story is a **directed graph of panels**. Each chapter has an entry
22
+ panel and edges between panels. Edges can carry a transition and a
23
+ [JSON Logic](https://jsonlogic.com) condition, so readers' choices and story
24
+ variables decide where the story goes. The player takes that manifest and turns
25
+ it into a complete reading experience:
26
+
27
+ - **Graph navigation:** branching and conditional paths, back/forward history,
28
+ resume from the last position, per-edge transitions.
29
+ - **Two view modes:** classic one-panel-at-a-time reading, or an
30
+ **infinite canvas** where panels sit on a 2D stage and the camera pans and
31
+ zooms between them.
32
+ - **Layered panels:** image, video, text, audio and plugin layers, with
33
+ responsive image variants (`w640`–`w2560`) and smart preloading.
34
+ - **Speech balloons:** an SVG lettering engine with 9 balloon types (normal,
35
+ thought, shout, whisper, connector, …). Tails, style presets and
36
+ per-character overrides are all configurable.
37
+ - **Hotspots:** clickable areas that navigate, set variables, open extras or
38
+ modals, or talk to plugins. They're keyboard-accessible and tracked.
39
+ - **Variables and variants:** five scopes (global, chapter, page, session,
40
+ persistent). Panel variants swap content based on variables, e.g. an
41
+ age-appropriate version.
42
+ - **Audio and video:** a WebAudio mixer (ambient, music, voice-over, SFX) and
43
+ sequenced video panels.
44
+ - **Localization:** switch languages at runtime with fallback chains,
45
+ per-locale assets and RTL support. The UI ships in English and German.
46
+ - **Monetization hooks:** paywall rules from the manifest (subscription,
47
+ purchase, age gates), evaluated against what the reader owns. Your app
48
+ handles checkout; the player never talks to a payment provider itself.
49
+ - **Accessibility:** full keyboard control, screen-reader announcements,
50
+ `prefers-reduced-motion`, content warnings, and no serious axe violations.
51
+ - **Reader toolbar:** table of contents, thumbnails, autoplay, settings,
52
+ share, like and bookmark.
53
+
54
+ Stories are authored in the PanelWave CMS or written by hand against the
55
+ [open JSON Schema](https://github.com/panelwave/schema). The player supports
56
+ format features through 1.4: video panels, edge-transition inheritance,
57
+ typography style presets and the infinite canvas.
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ npm install @panelwave/player @ngx-translate/core
63
+ ```
64
+
65
+ Peer dependencies: `@angular/core` and `@angular/common` **^20**,
66
+ `@ngx-translate/core` **^17**, `rxjs` **^7.8**.
67
+
68
+ ## Setup
69
+
70
+ **1. Providers.** The player loads manifests over HTTP and uses ngx-translate
71
+ for its UI strings:
72
+
73
+ ```typescript
74
+ // app.config.ts
75
+ import { ApplicationConfig, importProvidersFrom } from '@angular/core';
76
+ import { HttpClient, provideHttpClient } from '@angular/common/http';
77
+ import { TranslateLoader, TranslateModule, TranslationObject } from '@ngx-translate/core';
78
+ import { Observable } from 'rxjs';
79
+
80
+ class PlayerTranslateLoader implements TranslateLoader {
81
+ constructor(private http: HttpClient) {}
82
+ getTranslation(lang: string): Observable<TranslationObject> {
83
+ return this.http.get<TranslationObject>(`./assets/i18n/${lang}.json`);
84
+ }
85
+ }
86
+
87
+ export const appConfig: ApplicationConfig = {
88
+ providers: [
89
+ provideHttpClient(),
90
+ importProvidersFrom(
91
+ TranslateModule.forRoot({
92
+ loader: { provide: TranslateLoader, useClass: PlayerTranslateLoader, deps: [HttpClient] },
93
+ }),
94
+ ),
95
+ ],
96
+ };
97
+ ```
98
+
99
+ **2. Assets and fonts.** Copy the player's UI translations into your app,
100
+ and include the balloon lettering fonts:
101
+
102
+ ```jsonc
103
+ // angular.json → projects.<app>.architect.build.options
104
+ "assets": [
105
+ { "glob": "*.json", "input": "node_modules/@panelwave/player/src/assets/i18n", "output": "assets/i18n" }
106
+ ],
107
+ "styles": [
108
+ "node_modules/@panelwave/player/src/assets/fonts/balloon/balloon-fonts.css",
109
+ "src/styles.css"
110
+ ]
111
+ ```
112
+
113
+ The bundled fonts are open-licensed (SIL OFL 1.1: Bangers, Comic Neue,
114
+ Caveat, Anton and 10 more). The commercial Blambot font **Ames Pro** is not
115
+ included. If your works use it, license it from [blambot.com](https://blambot.com)
116
+ and add your own `@font-face`. Otherwise balloons fall back to Comic Neue.
117
+
118
+ ## Usage
119
+
120
+ ```typescript
121
+ import { Component } from '@angular/core';
122
+ import { PlayerShellComponent } from '@panelwave/player';
123
+
124
+ @Component({
125
+ selector: 'app-reader',
126
+ imports: [PlayerShellComponent],
127
+ template: `
128
+ <pw-player-shell
129
+ manifestUrl="/stories/my-story/panelwave.json"
130
+ locale="en-US"
131
+ [showToolbar]="true"
132
+ (panelChange)="onPanel($event.panel.id)"
133
+ (error)="onError($event)" />
134
+ `,
135
+ styles: `:host { display: block; height: 100dvh; }`,
136
+ })
137
+ export class ReaderComponent {
138
+ onPanel(id: string) { console.log('now showing', id); }
139
+ onError(err: Error) { console.error(err); }
140
+ }
141
+ ```
142
+
143
+ You can also pass a manifest object instead of a URL: `[manifest]="manifest"`
144
+ (type `PanelWaveManifest`).
145
+
146
+ ### Inputs
147
+
148
+ | Input | Type | Default | Description |
149
+ |---|---|---|---|
150
+ | `manifestUrl` | `string` | | Load the manifest from a URL |
151
+ | `manifest` | `PanelWaveManifest` | | Or pass the manifest object directly |
152
+ | `locale` | `LocaleCode` | `'en-US'` | Initial locale (BCP-47) |
153
+ | `initialChapterId` / `initialPanelId` | `string` | | Start at a specific position (otherwise: bookmark, then chapter entry) |
154
+ | `initialVariables` | `Record<string, unknown>` | | Seed story variables once at start. May set `readOnly` variables, e.g. a verified `user.age` from your account system |
155
+ | `showToolbar` | `boolean` | `false` | Show the reader toolbar |
156
+ | `autoplay` / `secondsPerPanel` | `boolean` / `number` | `false` / `5` | Auto-advance through panels |
157
+ | `reducedMotion` | `boolean` | `false` | Force reduced motion (the OS setting and the reader's preference also apply) |
158
+ | `viewModeOverride` | `'auto' \| 'panel' \| 'canvas'` | `'auto'` | Force panel or infinite-canvas view |
159
+ | `entitlementSnapshot` | `EntitlementSnapshot` | anonymous | What the reader owns; turns the manifest's `paywall.rules` on |
160
+ | `entitlementEndpoint` / `readerToken` | `string` | | Let the player fetch the snapshot itself (`{workId}` is substituted) |
161
+
162
+ ### Outputs
163
+
164
+ | Output | Payload | Fires when |
165
+ |---|---|---|
166
+ | `ready` | `void` | The manifest is loaded and the player is ready |
167
+ | `panelChange` | `{ panel, chapter }` | The reader moves to a new panel |
168
+ | `chapterChange` | `Chapter` | A chapter boundary is crossed |
169
+ | `variableChange` | `{ key, value }` | A story variable changes |
170
+ | `localeChange` | `LocaleCode` | The language is switched |
171
+ | `navigationAttempt` | `{ direction, target? }` | Any navigation attempt, allowed or not |
172
+ | `cameraChange` | `CameraState` | The canvas-view camera moves |
173
+ | `paywallAction` | `{ action, gate }` | The reader clicks purchase / subscribe / login / dismiss on a paywall |
174
+ | `ageVerified` | `AgeVerificationResult` | The reader answers an age gate |
175
+ | `likeChange` / `bookmarkChange` | `{ workId, … }` | Like or bookmark toggled (also stored locally) |
176
+ | `error` | `Error` | A loading or runtime error happens |
177
+
178
+ ### Paywalls
179
+
180
+ Declare rules in the manifest's `paywall` block. Then tell the player what the
181
+ reader owns, and handle checkout yourself:
182
+
183
+ ```html
184
+ <pw-player-shell
185
+ [manifestUrl]="url"
186
+ [entitlementSnapshot]="{ subscriptionTier: null, purchasedProductIds: ['chapter-2'], ageVerified: false }"
187
+ (paywallAction)="openCheckout($event.gate)" />
188
+ ```
189
+
190
+ Readers without access see the free preview and a paywall overlay, and
191
+ navigation stops at the gate. Works without paywall rules aren't affected.
192
+
193
+ ### Going further
194
+
195
+ The package also exports the services and building blocks behind the shell:
196
+ `PlayerStateService` (observable reading state), `VariableStoreService`,
197
+ `FlowEngineService`, `TranslationService`, `PluginHostService` (message bus
198
+ for sandboxed plugin layers), the `ComicBalloon` renderer with
199
+ `mergeBalloonConfig`, and all manifest types. See the
200
+ [documentation](https://docs.panelwave.org/player/overview) for the full API.
201
+
202
+ ## Browser support
203
+
204
+ Chrome / Edge 120+, Firefox 120+, Safari 17+ (desktop and iOS),
205
+ Android Chrome 120+.
206
+
207
+ ## Related packages
208
+
209
+ - [`@panelwave/types`](https://www.npmjs.com/package/@panelwave/types): TypeScript types for PanelWave manifests
210
+ - [`@panelwave/cli`](https://www.npmjs.com/package/@panelwave/cli): validate, bundle, diff and upgrade manifests
211
+ - [PanelWave format](https://github.com/panelwave/schema): the open JSON Schema (CC BY 4.0)
212
+
213
+ ## License
214
+
215
+ [MIT](https://github.com/panelwave/player/blob/master/LICENSE). The bundled
216
+ balloon fonts are under SIL OFL 1.1 (see `src/assets/fonts/balloon/LICENSES.md`),
217
+ and the UI icons are from [Lucide](https://lucide.dev) (ISC).