@caperjs/core 0.2.0 → 0.2.2

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.
Files changed (38) hide show
  1. package/build/defaults.mjs +23 -0
  2. package/build/index.mjs +16 -1
  3. package/build/internal/discovery.mjs +7 -6
  4. package/build/internal/paths.mjs +26 -0
  5. package/build/plugins/pwa.mjs +114 -8
  6. package/lib/{CaptionsPlugin-DKhbmJvH.js → CaptionsPlugin-DeGyPecB.js} +2 -2
  7. package/lib/{CaptionsPlugin-DKhbmJvH.js.map → CaptionsPlugin-DeGyPecB.js.map} +1 -1
  8. package/lib/{DataAdapter-BZFTkFQ4.js → DataAdapter-DeI2kIxC.js} +2 -2
  9. package/lib/{DataAdapter-BZFTkFQ4.js.map → DataAdapter-DeI2kIxC.js.map} +1 -1
  10. package/lib/{DebugRenderer-C7X-nlXE.js → DebugRenderer-wjV0tMwL.js} +2 -2
  11. package/lib/{DebugRenderer-C7X-nlXE.js.map → DebugRenderer-wjV0tMwL.js.map} +1 -1
  12. package/lib/{DevToolsPlugin-P-atJ-5U.js → DevToolsPlugin-D4iWQwkO.js} +2 -2
  13. package/lib/{DevToolsPlugin-P-atJ-5U.js.map → DevToolsPlugin-D4iWQwkO.js.map} +1 -1
  14. package/lib/{GSAPPlugin-CeH9275z.js → GSAPPlugin-DQTyIwcC.js} +2 -2
  15. package/lib/{GSAPPlugin-CeH9275z.js.map → GSAPPlugin-DQTyIwcC.js.map} +1 -1
  16. package/lib/{LayoutPlugin-iZ3k6RsK.js → LayoutPlugin-vR_h-BaG.js} +4 -4
  17. package/lib/{LayoutPlugin-iZ3k6RsK.js.map → LayoutPlugin-vR_h-BaG.js.map} +1 -1
  18. package/lib/{SpinePlugin-BWiavCpO.js → SpinePlugin-DJ-PpxFj.js} +2 -2
  19. package/lib/{SpinePlugin-BWiavCpO.js.map → SpinePlugin-DJ-PpxFj.js.map} +1 -1
  20. package/lib/{StatsPlugin-CBpzDJL0.js → StatsPlugin-BYNnKYOm.js} +2 -2
  21. package/lib/{StatsPlugin-CBpzDJL0.js.map → StatsPlugin-BYNnKYOm.js.map} +1 -1
  22. package/lib/{VoiceOverPlugin-YaiKJtJ6.js → VoiceOverPlugin-BLSbq3DU.js} +2 -2
  23. package/lib/{VoiceOverPlugin-YaiKJtJ6.js.map → VoiceOverPlugin-BLSbq3DU.js.map} +1 -1
  24. package/lib/caper.mjs +3 -3
  25. package/lib/caper.mjs.map +1 -1
  26. package/lib/core/Application.d.ts +30 -1
  27. package/lib/core/Application.d.ts.map +1 -1
  28. package/lib/core/create.d.ts +28 -1
  29. package/lib/core/create.d.ts.map +1 -1
  30. package/lib/core/index.d.ts +1 -1
  31. package/lib/core/index.d.ts.map +1 -1
  32. package/lib/{registries-qQmLeN0b.js → registries-aN0y0Xha.js} +26 -11
  33. package/lib/{registries-qQmLeN0b.js.map → registries-aN0y0Xha.js.map} +1 -1
  34. package/package.json +1 -1
  35. package/src/core/Application.ts +51 -0
  36. package/src/core/create.ts +30 -1
  37. package/src/core/index.ts +1 -1
  38. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caperjs/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "title": "Caper",
5
5
  "description": "An opinionated HTML game framework built on PixiJS v8",
6
6
  "bin": {
@@ -1,6 +1,7 @@
1
1
  import { gsap } from 'gsap';
2
2
  import type {
3
3
  AppConfig,
4
+ CaperPWA,
4
5
  IApplication,
5
6
  IApplicationOptions,
6
7
  ICaperAutomation,
@@ -166,6 +167,24 @@ export class Application extends PIXIPApplication implements IApplication {
166
167
  public onPluginError = new Signal<
167
168
  (detail: { id: string; phase: 'initialize' | 'postInitialize'; error: unknown }) => void
168
169
  >();
170
+ /**
171
+ * Emitted when the browser offers its PWA install prompt, so a game can show its
172
+ * own in-pixi install UI.
173
+ *
174
+ * The browser usually fires this before the first scene exists, and signals do not
175
+ * replay — so UI that offers an install button must ALSO check `app.pwa?.canInstall`
176
+ * when it mounts. And `app.pwa.promptInstall()` only works from inside a user
177
+ * gesture, i.e. a button's click/tap handler, never a timer or a game event.
178
+ */
179
+ public onPwaInstallAvailable = new Signal<() => void>();
180
+ /**
181
+ * Emitted when a new build is waiting to take over. Call `app.pwa.applyUpdate()`
182
+ * to activate it — the page reloads once the new worker takes control.
183
+ *
184
+ * Use `pwa: { update: 'manual' }` in the vite preset to suppress caper's default
185
+ * DOM banner and present this in-game instead.
186
+ */
187
+ public onPwaUpdateAvailable = new Signal<() => void>();
169
188
  // plugins
170
189
  public readonly _plugins: Map<string, IPlugin> = new Map();
171
190
  // default plugins
@@ -201,6 +220,14 @@ export class Application extends PIXIPApplication implements IApplication {
201
220
  return this._env;
202
221
  }
203
222
 
223
+ /**
224
+ * The `Caper.pwa` facade, or undefined when the app was built without the vite
225
+ * preset's `pwa` option. See {@link CaperPWA} for the install/update timing rules.
226
+ */
227
+ get pwa(): CaperPWA | undefined {
228
+ return (globalThis as any).Caper?.pwa;
229
+ }
230
+
204
231
  get debugContainer(): PIXIContainer {
205
232
  if (!this._debugContainer) {
206
233
  this._debugContainer = new PIXIContainer();
@@ -749,6 +776,8 @@ export class Application extends PIXIPApplication implements IApplication {
749
776
  }
750
777
  }
751
778
 
779
+ this._connectPwaSignals();
780
+
752
781
  this.webEvents.onVisibilityChanged.connect((visible) => {
753
782
  if (visible) {
754
783
  this.audio.restore();
@@ -764,6 +793,28 @@ export class Application extends PIXIPApplication implements IApplication {
764
793
  await this.postInitialize();
765
794
  }
766
795
 
796
+ /**
797
+ * Republishes the `Caper.pwa` callbacks as app signals. The existing handlers are
798
+ * wrapped rather than replaced — clobbering them would cost `update: 'prompt'` its
799
+ * default banner, and an app that assigned an early handler its handler.
800
+ */
801
+ private _connectPwaSignals(): void {
802
+ const pwa = this.pwa;
803
+ if (!pwa) return;
804
+
805
+ const onCanInstall = pwa.onCanInstall;
806
+ pwa.onCanInstall = () => {
807
+ onCanInstall?.();
808
+ this.onPwaInstallAvailable.emit();
809
+ };
810
+
811
+ const onNeedRefresh = pwa.onNeedRefresh;
812
+ pwa.onNeedRefresh = () => {
813
+ onNeedRefresh?.();
814
+ this.onPwaUpdateAvailable.emit();
815
+ };
816
+ }
817
+
767
818
  /**
768
819
  * User-overridable post-initialization hook, invoked after all framework wiring is
769
820
  * complete. Override to perform app setup that depends on a fully initialized
@@ -11,13 +11,42 @@ import { AppConfig } from './types';
11
11
 
12
12
  type App = AppTypeOverrides['App'];
13
13
 
14
- interface CaperPWA {
14
+ /**
15
+ * The `Caper.pwa` facade installed by the vite preset's runtime snippet. Reachable
16
+ * from game code as `app.pwa`, which is `undefined` when the app was built without
17
+ * the `pwa` option.
18
+ *
19
+ * Two timing rules matter:
20
+ *
21
+ * - `beforeinstallprompt` often fires before any scene exists, and signals do not
22
+ * replay. UI that offers an install button must check `app.pwa?.canInstall` when
23
+ * it mounts AND connect to `app.onPwaInstallAvailable` for the later case.
24
+ * - Browsers only honour {@link CaperPWA.promptInstall} from inside a user gesture.
25
+ * Call it from a click/tap handler — an overlay with an Install button. Calling it
26
+ * from a timer, a scene transition, or a game-over event is silently ignored.
27
+ */
28
+ export interface CaperPWA {
15
29
  readonly info: any;
16
30
  register: () => void;
17
31
  onRegisteredSW: (swScriptUrl: string) => void;
18
32
  offlineReady: () => void;
33
+ /** Called when a new build is waiting. Defaults to caper's update banner; assign to replace it. */
19
34
  onNeedRefresh?: () => void;
20
35
  onRegisterError?: (error: any) => void;
36
+
37
+ /** True once a new build is waiting to take over. */
38
+ updateAvailable: boolean;
39
+ /** Activate the waiting worker; the page reloads once it takes control. */
40
+ applyUpdate: () => void;
41
+
42
+ /** True once the browser has offered an install prompt to stash. */
43
+ canInstall: boolean;
44
+ /** Called when the browser offers the install prompt. */
45
+ onCanInstall?: () => void;
46
+ /** Called after the app is installed. */
47
+ onInstalled?: () => void;
48
+ /** Show the stashed install prompt. Resolves null when there is nothing to show. */
49
+ promptInstall: () => Promise<'accepted' | 'dismissed' | null>;
21
50
  }
22
51
  interface CaperGlobal {
23
52
  APP_NAME: string;
package/src/core/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './config';
2
- export { create, createContainer } from './create';
2
+ export { create, createContainer, type CaperPWA } from './create';
3
3
  export * from './globals';
4
4
  export * from './interfaces';
5
5
  export * from './registries';
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is auto-generated during the build process.
2
- export const version: string = '0.2.0';
2
+ export const version: string = '0.2.2';
3
3
  export const pixiVersion: string = '8.19.0';