{"_id":"@animastor/web-player","name":"@animastor/web-player","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@animastor/web-player","version":"0.1.0","description":"Preact/Web UI module: Animastor Web Player — the browser playback engine (queue/preload/gapless/IU-cycling/state machine/video buffer gate) plus the Play surface. NOT a platform-independent or domain module: media elements (HTMLAudioElement/HTMLVideoEleme","keywords":["animastor","player","playback","preact","web-ui","frontend","ui-component","signals","vbook","ports-and-adapters"],"type":"module","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"sideEffects":false,"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","prepublishOnly":"npm run typecheck && npm run test && npm run build"},"peerDependencies":{"@preact/signals":">=1.0.0","preact":">=10.5.0"},"devDependencies":{"@preact/signals":"^1.3.0","@preact/preset-vite":"^2.9.0","happy-dom":"^20.14.0","preact":"^10.24.0","tsup":"^8.3.5","typescript":"^5.6.0","vitest":"^4.1.10"},"license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Animastor/animastor.git","directory":"packages/animastor-web-player"},"homepage":"https://github.com/Animastor/animastor/tree/main/packages/animastor-web-player#readme","bugs":{"url":"https://github.com/Animastor/animastor/issues"},"_id":"@animastor/web-player@0.1.0","gitHead":"8bae2802e329b24d85dc10baae6456299c666223","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-S2fTZkMvVfzY0xZPvzNk54f2A+NyEdSrOLX6lqLtaV5OobWER8rF9Ij6qrFELLMWIzhDnGrRMg7+hlFU/Cws9w==","shasum":"84c747311b062bbf9e242f99add3a5367c03877c","tarball":"https://registry.npmjs.org/@animastor/web-player/-/web-player-0.1.0.tgz","fileCount":6,"unpackedSize":269665,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDvuQPVlEACG9uGvuN0hAj/KVEWuSxmQKV+2wuwxLdvsgIhAMwLwhRoF21FUJBUJe+zhPv7WeRYMS13VlD2SKZapuKt"}]},"_npmUser":{"name":"animastor","email":"admin@animastor.in"},"directories":{},"maintainers":[{"name":"animastor","email":"admin@animastor.in"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/web-player_0.1.0_1789219667205_0.4972456740829563"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-12T13:27:46.930Z","0.1.0":"2026-09-12T13:27:47.332Z","modified":"2026-09-12T13:27:47.553Z"},"maintainers":[{"name":"animastor","email":"admin@animastor.in"}],"description":"Preact/Web UI module: Animastor Web Player — the browser playback engine (queue/preload/gapless/IU-cycling/state machine/video buffer gate) plus the Play surface. NOT a platform-independent or domain module: media elements (HTMLAudioElement/HTMLVideoEleme","homepage":"https://github.com/Animastor/animastor/tree/main/packages/animastor-web-player#readme","keywords":["animastor","player","playback","preact","web-ui","frontend","ui-component","signals","vbook","ports-and-adapters"],"repository":{"type":"git","url":"git+https://github.com/Animastor/animastor.git","directory":"packages/animastor-web-player"},"bugs":{"url":"https://github.com/Animastor/animastor/issues"},"license":"MIT","readme":"# @animastor/web-player\n\nThe browser playback engine and Play surface for Animastor, packaged as a standalone Preact module.\n\n> **Scope — Preact/Web UI + engine module.** This package is a **specialized Web/Frontend UI module** built on **Preact** (+ `@preact/signals`), for embedding into browser-based Animastor hosts (`frontends/app`). It is **not** a platform-independent or domain module: it renders DOM through Preact JSX and drives browser media APIs (`HTMLAudioElement`/`HTMLVideoElement`, Cache API, `requestAnimationFrame`, `sessionStorage`, `document.visibilitychange`). It is **not intended for Android/native UI** — the Android player (`PlaybackViewModel.kt` / `PlayFragment.kt`) remains a separate native implementation with contractual parity (`ANDROID_WEB_PARITY.md`); this package does not target it directly and shares no code with it. The **backend playback contour** is a separate package (`@animastor/player`) — the two relate only over frozen HTTP endpoints, and this package must never depend on it.\n\nThe Player owns no host infrastructure. Every host dependency — session identity (`bookId`/`buildId`), generation-completion events, shared position writes, the invalidation bus, HTTP with the `/api/v1` base, desktop-shell detection, i18n, the icon kit — arrives through the [`PlayerPorts`](#playerports) contract injected as a prop / at wiring time. The package never imports host stores, the API client, i18n, the desktop module or the icon kit, so it can be mounted by any **Preact** host that implements the ports.\n\n## Install\n\n```sh\nnpm install @animastor/web-player\n```\n\nPeer dependencies (must be provided by the host):\n\n- `preact` >= 10.5\n- `@preact/signals` >= 1\n\n## Usage\n\nThe engine outlives the page, so wiring has two moments: wire the engine once at composition-root load, and render the page with the same ports object.\n\n```tsx\nimport { render } from 'preact';\nimport { PlayPage, wirePlaybackCoordination, wirePlaybackLifecycle, type PlayerPorts } from '@animastor/web-player';\n\nconst ports: PlayerPorts = {\n  session: { bookId, buildId },                          // generateStore singletons, passed by reference\n  generation: { onPlaybackPrepared },                    // full payload: scenes + coverImage + softRefresh\n  position: { navigateTo },                              // shared position writes\n  invalidations: { onResourceInvalidated, isBookResource }, // pure consumer of the freshness bus\n  http: { getJson, getBlob, retryWithBackoff, videoUrl },   // videoUrl: direct <video> src builder\n  shellMode: { isDesktop },                              // desktop/mobile shell fork\n  i18n: { t },                                           // typed Player i18n keys\n  icons: { Play, Pause, VolumeUp, VolumeOff, Image, ImageOff, Videocam, VideocamOff, Subtitles, SubtitlesOff, Fullscreen, FullscreenExit },\n};\n\nwirePlaybackCoordination(ports);   // engine composition (runs once, before engine use)\nwirePlaybackLifecycle();           // visibility/pagehide lifecycle listeners\n\nrender(<PlayPage path=\"/play\" ports={ports} />, document.getElementById('app'));\n```\n\n## Public API\n\n| Export | Kind | Purpose |\n|---|---|---|\n| `PlayPage` | component | The Play surface; takes `{ path?: string; ports: PlayerPorts }` |\n| `wirePlaybackCoordination` | function | Wires the engine to the host ports (call once at composition root) |\n| `wirePlaybackLifecycle` | function | Installs document visibility + pagehide/pageshow lifecycle listeners |\n| `seekToPosition` | function | External seek entry (host navigator/Edit carousel parity) |\n| `closeBook` | function | Player release on book close (host fileStore `player` seam) |\n| `invalidateDeletedScene` | function | Queue/cache eviction when a scene is deleted |\n| `invalidateDeletedChapter` | function | Queue/cache eviction when a chapter is deleted |\n| `clearMediaCache` | function | Cache API media eviction (Settings \"clear cache\") |\n| `PlayerPorts` | type | The full host contract (8 ports, see below) |\n| Individual port types | types | `PlayerSessionPort`, `PlayerGenerationPort`, `PlayerPositionPort`, `PlayerInvalidationsPort`, `PlayerHttpPort`, `PlayerShellModePort`, `PlayerI18nPort`, `PlayerIconsPort` |\n| Payload types | types | `PlayerActivePosition`, `PlaybackPreparedEvent`, `PlayerResourceInvalidationEvent`, `PlayerI18nKey`, `PlayerIconProps`, `PlayerIconComponent` |\n\n### PlayerPorts\n\n| Port | Role |\n|---|---|\n| `session` (`PlayerSessionPort`) | Shared session identity signals (`bookId`/`buildId`) — host singletons passed by reference; the package keeps only an internal projection and is not a second source of truth |\n| `generation` (`PlayerGenerationPort`) | Generation-completion events (full payload — deliberately not narrowed) |\n| `position` (`PlayerPositionPort`) | Shared active position — write direction |\n| `invalidations` (`PlayerInvalidationsPort`) | Resource invalidation bus — pure consumer |\n| `http` (`PlayerHttpPort`) | JSON/blob fetch with retry/backoff + `videoUrl` for the direct `<video>` src |\n| `shellMode` (`PlayerShellModePort`) | Desktop/mobile shell fork (host `matchMedia`) |\n| `i18n` (`PlayerI18nPort`) | `t` for the Player's i18n keys (dictionary stays host-owned) |\n| `icons` (`PlayerIconsPort`) | 12 icon components (Play, Pause, VolumeUp/Off, Image/Off, Videocam/Off, Subtitles/Off, Fullscreen/Exit) |\n\n## Behavior contract\n\n- Engine state (queue, preload, gapless transitions, IU cycling, video buffer gate) lives in module-scope singletons and survives tab switches; the engine mounts a hidden host `div` to `document.body` exactly once via `wirePlayback*` (single-instance requirement — one package instance per host).\n- Session identity: `bookId`/`buildId` are **host-owned** (the port signals are the host singletons); the package's internal projection is set by the generation event and never re-exported.\n- Position restore: the last playback position is persisted under the `animastor:playbackPosition` `sessionStorage` key and re-attached on mount (bfcache restores via `pageshow`).\n- Media cache: scene audio/video/IU images are cached in the browser Cache API under the `animastor-media` cache name with a `buildId`-scoped key grammar; deleted scene/chapter invalidations evict entries; `clearMediaCache` clears the cache (the count is user-visible in host Settings).\n- Video: the direct `<video>` src is built by the host-provided `videoUrl` (progressive Range streaming — no fetch).\n- CSS/asset contract: the surface renders host-owned `.play-*` class names and the host-owned curtains asset; no CSS is bundled in the package.\n- HTTP surface: the engine consumes a strict 6-endpoint subset of the backend playback contract (`GET /book/:bookId`, scene `status`/`storyboard`/`audio`/`video`, `iu-image`) — wire-level only; no code dependency on any backend package.\n\n## Package boundary\n\n- The package imports only `preact`, `preact/hooks`, `preact/jsx-runtime` and `@preact/signals`.\n- Host stores, `api/client`, i18n, desktop, icons and adapter modules are **forbidden** inside the package (enforced by boundary tests in the repository and in the package itself).\n- `@animastor/web-player → host` = forbidden; `host → @animastor/web-player` = allowed through the public entry point only.\n- **Technology boundary**: `@animastor/web-player` is a **Preact/Web module** — not a cross-platform package. The Android player is a separate parity implementation, and the backend playback contour is the separate `@animastor/player` package.\n\n## Development\n\n```sh\nnpm install\nnpm run typecheck   # tsc --noEmit\nnpm run test        # vitest (engine characterization + boundary tests)\nnpm run build       # tsup → dist/ (ESM + d.ts + sourcemaps)\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-2d7236d314cbce953dca5825b2f3070b"}