@energy8platform/game-engine 0.2.1 → 0.3.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.
Files changed (59) hide show
  1. package/README.md +298 -28
  2. package/dist/animation.cjs.js +191 -1
  3. package/dist/animation.cjs.js.map +1 -1
  4. package/dist/animation.d.ts +117 -1
  5. package/dist/animation.esm.js +192 -3
  6. package/dist/animation.esm.js.map +1 -1
  7. package/dist/audio.cjs.js +66 -16
  8. package/dist/audio.cjs.js.map +1 -1
  9. package/dist/audio.d.ts +4 -0
  10. package/dist/audio.esm.js +66 -16
  11. package/dist/audio.esm.js.map +1 -1
  12. package/dist/core.cjs.js +306 -85
  13. package/dist/core.cjs.js.map +1 -1
  14. package/dist/core.d.ts +60 -1
  15. package/dist/core.esm.js +307 -86
  16. package/dist/core.esm.js.map +1 -1
  17. package/dist/debug.cjs.js +36 -68
  18. package/dist/debug.cjs.js.map +1 -1
  19. package/dist/debug.d.ts +4 -6
  20. package/dist/debug.esm.js +36 -68
  21. package/dist/debug.esm.js.map +1 -1
  22. package/dist/index.cjs.js +1247 -253
  23. package/dist/index.cjs.js.map +1 -1
  24. package/dist/index.d.ts +386 -41
  25. package/dist/index.esm.js +1247 -256
  26. package/dist/index.esm.js.map +1 -1
  27. package/dist/ui.cjs.js +757 -1
  28. package/dist/ui.cjs.js.map +1 -1
  29. package/dist/ui.d.ts +208 -2
  30. package/dist/ui.esm.js +756 -2
  31. package/dist/ui.esm.js.map +1 -1
  32. package/dist/vite.cjs.js +65 -68
  33. package/dist/vite.cjs.js.map +1 -1
  34. package/dist/vite.d.ts +17 -23
  35. package/dist/vite.esm.js +66 -68
  36. package/dist/vite.esm.js.map +1 -1
  37. package/package.json +4 -5
  38. package/src/animation/SpriteAnimation.ts +210 -0
  39. package/src/animation/Tween.ts +27 -1
  40. package/src/animation/index.ts +2 -0
  41. package/src/audio/AudioManager.ts +64 -15
  42. package/src/core/EventEmitter.ts +7 -1
  43. package/src/core/GameApplication.ts +18 -7
  44. package/src/core/SceneManager.ts +3 -1
  45. package/src/debug/DevBridge.ts +49 -80
  46. package/src/index.ts +6 -0
  47. package/src/input/InputManager.ts +26 -0
  48. package/src/loading/CSSPreloader.ts +7 -33
  49. package/src/loading/LoadingScene.ts +17 -41
  50. package/src/loading/index.ts +1 -0
  51. package/src/loading/logo.ts +95 -0
  52. package/src/types.ts +4 -0
  53. package/src/ui/BalanceDisplay.ts +14 -0
  54. package/src/ui/Button.ts +1 -1
  55. package/src/ui/Layout.ts +364 -0
  56. package/src/ui/ScrollContainer.ts +557 -0
  57. package/src/ui/index.ts +4 -0
  58. package/src/viewport/ViewportManager.ts +2 -0
  59. package/src/vite/index.ts +83 -83
package/README.md CHANGED
@@ -17,7 +17,21 @@ A universal casino game engine built on [PixiJS v8](https://pixijs.com/) and [@e
17
17
  - [Viewport & Scaling](#viewport--scaling)
18
18
  - [State Machine](#state-machine)
19
19
  - [Animation](#animation)
20
+ - [Tween](#tween)
21
+ - [Timeline](#timeline)
22
+ - [SpriteAnimation](#spriteanimation)
23
+ - [Spine Animations](#spine-animations)
20
24
  - [UI Components](#ui-components)
25
+ - [Layout](#layout)
26
+ - [ScrollContainer](#scrollcontainer)
27
+ - [Button](#button)
28
+ - [Label](#label)
29
+ - [BalanceDisplay](#balancedisplay)
30
+ - [WinDisplay](#windisplay)
31
+ - [ProgressBar](#progressbar)
32
+ - [Panel](#panel)
33
+ - [Modal](#modal)
34
+ - [Toast](#toast)
21
35
  - [Input](#input)
22
36
  - [Vite Configuration](#vite-configuration)
23
37
  - [DevBridge](#devbridge)
@@ -83,7 +97,7 @@ async function bootstrap() {
83
97
  debug: true,
84
98
  });
85
99
 
86
- game.scenes.register('game', GameScene as any);
100
+ game.scenes.register('game', GameScene);
87
101
 
88
102
  game.on('initialized', () => console.log('Engine initialized'));
89
103
  game.on('loaded', () => console.log('Assets loaded'));
@@ -105,7 +119,7 @@ bootstrap();
105
119
  | Package | Version | Required |
106
120
  | --- | --- | --- |
107
121
  | `pixi.js` | `^8.16.0` | Yes |
108
- | `@energy8platform/game-sdk` | `^2.5.0` | Yes |
122
+ | `@energy8platform/game-sdk` | `^2.6.0` | Yes |
109
123
  | `@pixi/sound` | `^6.0.0` | Optional — for audio |
110
124
  | `@esotericsoftware/spine-pixi-v8` | `~4.2.0` | Optional — for Spine animations |
111
125
 
@@ -118,8 +132,8 @@ import { GameApplication } from '@energy8platform/game-engine'; // full b
118
132
  import { Scene, SceneManager } from '@energy8platform/game-engine/core';
119
133
  import { AssetManager } from '@energy8platform/game-engine/assets';
120
134
  import { AudioManager } from '@energy8platform/game-engine/audio';
121
- import { Button, Label, Modal } from '@energy8platform/game-engine/ui';
122
- import { Tween, Timeline, Easing } from '@energy8platform/game-engine/animation';
135
+ import { Button, Label, Modal, Layout, ScrollContainer } from '@energy8platform/game-engine/ui';
136
+ import { Tween, Timeline, Easing, SpriteAnimation } from '@energy8platform/game-engine/animation';
123
137
  import { DevBridge, FPSOverlay } from '@energy8platform/game-engine/debug';
124
138
  import { defineGameConfig } from '@energy8platform/game-engine/vite';
125
139
  ```
@@ -146,7 +160,7 @@ import { defineGameConfig } from '@energy8platform/game-engine/vite';
146
160
 
147
161
  1. **CSS Preloader** — an instant HTML/CSS overlay shown while PixiJS initializes (inline SVG logo with a shimmer animation and "Loading..." text).
148
162
  2. **PixiJS initialization** — creates `Application`, initializes `ResizeObserver`.
149
- 3. **SDK handshake** — connects to the casino host (or DevBridge in dev mode).
163
+ 3. **SDK handshake** — connects to the casino host (or DevBridge in dev mode via shared `MemoryChannel`).
150
164
  4. **Canvas Loading Screen** — `LoadingScene` displays the SVG logo with an animated progress bar, `preload` bundle is loaded first.
151
165
  5. **Asset loading** — remaining bundles are loaded; the progress bar fills in real time.
152
166
  6. **Tap-to-start** — optional screen shown after loading (required on mobile for audio unlock).
@@ -169,6 +183,10 @@ import { defineGameConfig } from '@energy8platform/game-engine/vite';
169
183
  | `manifest` | `AssetManifest` | — | Asset manifest |
170
184
  | `audio` | `AudioConfig` | — | Audio configuration |
171
185
  | `sdk` | `object \| false` | — | SDK options; `false` to disable |
186
+ | `sdk.devMode` | `boolean` | `false` | Use in-memory channel instead of `postMessage` (no iframe needed) |
187
+ | `sdk.parentOrigin` | `string` | — | Expected parent origin for `postMessage` validation |
188
+ | `sdk.timeout` | `number` | — | SDK handshake timeout in ms |
189
+ | `sdk.debug` | `boolean` | — | Enable SDK debug logging |
172
190
  | `pixi` | `Partial<ApplicationOptions>` | — | PixiJS pass-through options |
173
191
  | `debug` | `boolean` | `false` | Enable FPS overlay |
174
192
 
@@ -261,9 +279,9 @@ export class GameScene extends Scene {
261
279
  const scenes = game.scenes;
262
280
 
263
281
  // Register scenes
264
- scenes.register('menu', MenuScene as any);
265
- scenes.register('game', GameScene as any);
266
- scenes.register('bonus', BonusScene as any);
282
+ scenes.register('menu', MenuScene);
283
+ scenes.register('game', GameScene);
284
+ scenes.register('bonus', BonusScene);
267
285
 
268
286
  // Navigate (replaces entire stack)
269
287
  await scenes.goto('game');
@@ -400,7 +418,7 @@ const audio = game.audio;
400
418
  audio.play('click', 'ui');
401
419
  audio.play('coin-drop', 'sfx', { volume: 0.8 });
402
420
 
403
- // Music with crossfade
421
+ // Music with crossfade (smooth volume transition between tracks)
404
422
  audio.playMusic('main-theme', 1000); // 1s crossfade
405
423
  audio.stopMusic();
406
424
 
@@ -542,13 +560,17 @@ await Tween.from(sprite, { scale: 0 }, 300, Easing.easeOutBack);
542
560
  // Animate between two sets of values
543
561
  await Tween.fromTo(sprite, { x: -100 }, { x: 500 }, 1000, Easing.easeInOutQuad);
544
562
 
545
- // Wait (useful in timelines or sequences)
563
+ // Wait (uses PixiJS Ticker for consistent timing)
546
564
  await Tween.delay(1000);
547
565
 
548
566
  // Cancel tweens
549
567
  Tween.killTweensOf(sprite);
550
568
  Tween.killAll();
551
569
 
570
+ // Full reset — kill all tweens and remove ticker listener
571
+ // Useful for cleanup between game instances, tests, or hot-reload
572
+ Tween.reset();
573
+
552
574
  // Supports nested properties
553
575
  await Tween.to(sprite, { 'scale.x': 2, 'position.y': 300 }, 500);
554
576
  ```
@@ -592,6 +614,59 @@ All 24 easing functions:
592
614
  | | | | `easeOutElastic` |
593
615
  | | | | `easeInElastic` |
594
616
 
617
+ ### SpriteAnimation
618
+
619
+ Frame-based animation helper wrapping PixiJS `AnimatedSprite`. Cheaper than Spine for simple frame sequences — perfect for coin showers, symbol animations, sparkle trails, and win celebrations.
620
+
621
+ ```typescript
622
+ import { SpriteAnimation } from '@energy8platform/game-engine';
623
+ import { Assets } from 'pixi.js';
624
+
625
+ // From an array of textures
626
+ const coinAnim = SpriteAnimation.create(coinTextures, {
627
+ fps: 30,
628
+ loop: true,
629
+ });
630
+ scene.container.addChild(coinAnim);
631
+
632
+ // From a spritesheet using a name prefix
633
+ const sheet = Assets.get('effects');
634
+ const sparkle = SpriteAnimation.fromSpritesheet(sheet, 'sparkle_', {
635
+ fps: 24,
636
+ loop: true,
637
+ });
638
+
639
+ // From a numbered range (e.g., 'explosion_00' to 'explosion_24')
640
+ const explosion = SpriteAnimation.fromRange(sheet, 'explosion_{i}', 0, 24, {
641
+ fps: 60,
642
+ loop: false,
643
+ onComplete: () => explosion.destroy(),
644
+ });
645
+
646
+ // From pre-loaded texture aliases
647
+ const anim = SpriteAnimation.fromAliases(
648
+ ['frame_0', 'frame_1', 'frame_2', 'frame_3'],
649
+ { fps: 12 },
650
+ );
651
+
652
+ // Fire-and-forget: play once and auto-destroy
653
+ const { sprite, finished } = SpriteAnimation.playOnce(coinTextures, {
654
+ fps: 30,
655
+ });
656
+ scene.container.addChild(sprite);
657
+ await finished; // resolves when animation completes
658
+ ```
659
+
660
+ #### SpriteAnimationConfig
661
+
662
+ | Property | Type | Default | Description |
663
+ | --- | --- | --- | --- |
664
+ | `fps` | `number` | `24` | Frames per second |
665
+ | `loop` | `boolean` | `true` | Whether to loop |
666
+ | `autoPlay` | `boolean` | `true` | Start playing immediately |
667
+ | `onComplete` | `() => void` | — | Callback when animation completes (non-looping) |
668
+ | `anchor` | `number \| { x, y }` | `0.5` | Anchor point |
669
+
595
670
  ### Spine Animations
596
671
 
597
672
  If `@esotericsoftware/spine-pixi-v8` is installed:
@@ -621,6 +696,136 @@ console.log(SpineHelper.getAnimationNames(spine));
621
696
 
622
697
  ## UI Components
623
698
 
699
+ ### Layout
700
+
701
+ Responsive layout container that automatically arranges children. Supports horizontal, vertical, grid, and wrap modes with alignment, padding, gap, anchor positioning, and viewport breakpoints.
702
+
703
+ ```typescript
704
+ import { Layout } from '@energy8platform/game-engine';
705
+
706
+ // Horizontal toolbar anchored to bottom-center
707
+ const toolbar = new Layout({
708
+ direction: 'horizontal',
709
+ gap: 20,
710
+ alignment: 'center',
711
+ anchor: 'bottom-center',
712
+ padding: 16,
713
+ breakpoints: {
714
+ 768: { direction: 'vertical', gap: 10 },
715
+ },
716
+ });
717
+
718
+ toolbar.addItem(spinButton);
719
+ toolbar.addItem(betLabel);
720
+ toolbar.addItem(balanceDisplay);
721
+ scene.container.addChild(toolbar);
722
+
723
+ // Update position on resize
724
+ toolbar.updateViewport(width, height);
725
+ ```
726
+
727
+ ```typescript
728
+ // Grid layout for a symbol paytable
729
+ const grid = new Layout({
730
+ direction: 'grid',
731
+ columns: 3,
732
+ gap: 16,
733
+ alignment: 'center',
734
+ anchor: 'center',
735
+ padding: [20, 40, 20, 40],
736
+ });
737
+
738
+ symbols.forEach((sym) => grid.addItem(sym));
739
+ grid.updateViewport(viewWidth, viewHeight);
740
+ ```
741
+
742
+ ```typescript
743
+ // Wrap layout — items flow and wrap to next line
744
+ const tags = new Layout({
745
+ direction: 'wrap',
746
+ gap: 8,
747
+ maxWidth: 600,
748
+ });
749
+ ```
750
+
751
+ #### LayoutConfig
752
+
753
+ | Property | Type | Default | Description |
754
+ | --- | --- | --- | --- |
755
+ | `direction` | `'horizontal' \| 'vertical' \| 'grid' \| 'wrap'` | `'vertical'` | Layout direction |
756
+ | `gap` | `number` | `0` | Gap between children (px) |
757
+ | `padding` | `number \| [top, right, bottom, left]` | `0` | Inner padding |
758
+ | `alignment` | `'start' \| 'center' \| 'end' \| 'stretch'` | `'start'` | Cross-axis alignment |
759
+ | `anchor` | `LayoutAnchor` | `'top-left'` | Position relative to viewport |
760
+ | `columns` | `number` | `2` | Column count (grid mode only) |
761
+ | `maxWidth` | `number` | `Infinity` | Max width before wrapping (wrap mode) |
762
+ | `autoLayout` | `boolean` | `true` | Auto-recalculate on add/remove |
763
+ | `breakpoints` | `Record<number, Partial<LayoutConfig>>` | — | Override config per viewport width |
764
+
765
+ **Anchor values:** `top-left`, `top-center`, `top-right`, `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`
766
+
767
+ ### ScrollContainer
768
+
769
+ Scrollable container with touch/drag, mouse wheel, inertia deceleration, elastic overscroll bounce, snap-to-item, and auto-hiding scrollbars. Ideal for paytables, settings, bet history, and any content that doesn't fit on screen.
770
+
771
+ ```typescript
772
+ import { ScrollContainer } from '@energy8platform/game-engine';
773
+
774
+ const scroll = new ScrollContainer({
775
+ width: 600,
776
+ height: 400,
777
+ direction: 'vertical',
778
+ showScrollbar: true,
779
+ elasticity: 0.3,
780
+ inertia: 0.92,
781
+ borderRadius: 12,
782
+ backgroundColor: 0x1a1a2e,
783
+ backgroundAlpha: 0.8,
784
+ });
785
+
786
+ // Build scrollable content
787
+ const list = new Container();
788
+ for (let i = 0; i < 50; i++) {
789
+ const row = createRow(i);
790
+ row.y = i * 40;
791
+ list.addChild(row);
792
+ }
793
+ scroll.setContent(list);
794
+
795
+ scene.container.addChild(scroll);
796
+ ```
797
+
798
+ ```typescript
799
+ // Programmatic scrolling
800
+ scroll.scrollTo(0, 200); // scroll to y=200 with animation
801
+ scroll.scrollTo(0, 200, false); // instant jump
802
+ scroll.scrollToItem(5); // snap to item index (when snapSize is set)
803
+
804
+ // Current position
805
+ const { x, y } = scroll.scrollPosition;
806
+
807
+ // Resize viewport
808
+ scroll.resize(newWidth, newHeight);
809
+ ```
810
+
811
+ #### ScrollContainerConfig
812
+
813
+ | Property | Type | Default | Description |
814
+ | --- | --- | --- | --- |
815
+ | `width` | `number` | — | Visible viewport width |
816
+ | `height` | `number` | — | Visible viewport height |
817
+ | `direction` | `'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Scroll direction |
818
+ | `showScrollbar` | `boolean` | `true` | Show scrollbar(s) |
819
+ | `scrollbarWidth` | `number` | `6` | Scrollbar width (px) |
820
+ | `scrollbarColor` | `number` | `0xffffff` | Scrollbar color |
821
+ | `scrollbarAlpha` | `number` | `0.4` | Scrollbar opacity |
822
+ | `elasticity` | `number` | `0.3` | Overscroll bounce (0 = none) |
823
+ | `inertia` | `number` | `0.92` | Deceleration factor (0 = instant stop) |
824
+ | `snapSize` | `number` | `0` | Snap to fixed increments (0 = disabled) |
825
+ | `backgroundColor` | `number` | — | Background color (transparent if omitted) |
826
+ | `backgroundAlpha` | `number` | `1` | Background opacity |
827
+ | `borderRadius` | `number` | `0` | Mask border radius |
828
+
624
829
  ### Button
625
830
 
626
831
  ```typescript
@@ -799,10 +1004,17 @@ if (input.isKeyDown('ArrowLeft')) {
799
1004
  input.lock();
800
1005
  // ... animation plays ...
801
1006
  input.unlock();
1007
+
1008
+ // Convert DOM canvas position to game-world coordinates
1009
+ // (accounts for viewport scaling and offset)
1010
+ const worldPos = input.getWorldPosition(canvasX, canvasY);
1011
+ console.log(worldPos.x, worldPos.y);
802
1012
  ```
803
1013
 
804
1014
  **Events:** `tap`, `press`, `release`, `move`, `swipe`, `keydown`, `keyup`
805
1015
 
1016
+ > **Note:** The viewport transform for coordinate mapping is wired up automatically by `GameApplication`. Call `getWorldPosition()` when you need to convert raw DOM coordinates to game-world space.
1017
+
806
1018
  ---
807
1019
 
808
1020
  ## Vite Configuration
@@ -815,28 +1027,31 @@ import { defineGameConfig } from '@energy8platform/game-engine/vite';
815
1027
 
816
1028
  export default defineGameConfig({
817
1029
  base: '/games/my-slot/',
818
- outDir: 'dist',
819
1030
  devBridge: true, // Auto-inject DevBridge in dev mode
820
- assetExtensions: [
821
- 'png', 'jpg', 'webp', 'avif',
822
- 'mp3', 'ogg', 'wav',
823
- 'json', 'atlas', 'skel',
824
- 'fnt', 'ttf', 'woff2',
825
- ],
1031
+ devBridgeConfig: './dev.config', // Custom config path (optional)
826
1032
  vite: {
827
1033
  // Additional Vite config overrides
828
1034
  },
829
1035
  });
830
1036
  ```
831
1037
 
1038
+ ### `GameConfig`
1039
+
1040
+ | Property | Type | Default | Description |
1041
+ | --- | --- | --- | --- |
1042
+ | `base` | `string` | `'/'` | Vite `base` path for deployment |
1043
+ | `devBridge` | `boolean` | `false` | Auto-inject DevBridge in dev mode |
1044
+ | `devBridgeConfig` | `string` | `'./dev.config'` | Path to DevBridge config file |
1045
+ | `vite` | `UserConfig` | — | Additional Vite config to merge |
1046
+
832
1047
  ### What `defineGameConfig` Provides
833
1048
 
834
- - **PixiJS optimizations**tree-shaking, proper externals handling
1049
+ - **Build target: ES2020+** modern output for all supported casino platforms
1050
+ - **Asset inlining** — files under 8KB are auto-inlined
1051
+ - **PixiJS chunk splitting** — `pixi.js` is extracted into a separate chunk for caching
835
1052
  - **DevBridge injection** — automatically available in dev mode via virtual module
836
- - **Asset handling** — preconfigured loader patterns for game assets
837
- - **HTML minification** — optimized production builds
838
- - **Gzip-friendly output** — chunking strategy optimized for compression
839
- - **Base path** — configurable for deployment subpaths
1053
+ - **Dev server** — port 3000, auto-open browser
1054
+ - **Dependency optimization** — `pixi.js` pre-bundled for faster dev starts
840
1055
 
841
1056
  ### Custom DevBridge Configuration
842
1057
 
@@ -858,13 +1073,15 @@ export default {
858
1073
  } satisfies DevBridgeConfig;
859
1074
  ```
860
1075
 
861
- This file is auto-imported by the Vite plugin when `devBridge: true`.
1076
+ This file is auto-imported by the Vite plugin when `devBridge: true`. The plugin injects a virtual module (`/@dev-bridge-entry.js`) that starts DevBridge **before** importing your app entry point, ensuring the `MemoryChannel` is ready when the SDK calls `ready()`.
862
1077
 
863
1078
  ---
864
1079
 
865
1080
  ## DevBridge
866
1081
 
867
- `DevBridge` simulates a casino host for local development. It intercepts `postMessage` calls from the SDK and responds with mock data.
1082
+ `DevBridge` simulates a casino host for local development. It uses the SDK's `Bridge` class in `devMode`, communicating with `CasinoGameSDK` through a shared in-memory `MemoryChannel` — no `postMessage` or iframe required.
1083
+
1084
+ > **Requires `@energy8platform/game-sdk` >= 2.6.0**
868
1085
 
869
1086
  ```typescript
870
1087
  import { DevBridge } from '@energy8platform/game-engine/debug';
@@ -876,7 +1093,10 @@ const bridge = new DevBridge({
876
1093
  networkDelay: 200,
877
1094
  debug: true,
878
1095
  gameConfig: {
1096
+ id: 'my-slot',
1097
+ type: 'slot',
879
1098
  viewport: { width: 1920, height: 1080 },
1099
+ betLevels: [0.1, 0.2, 0.5, 1, 2, 5, 10],
880
1100
  },
881
1101
  onPlay: ({ action, bet, roundId }) => {
882
1102
  // Return custom play result
@@ -885,7 +1105,7 @@ const bridge = new DevBridge({
885
1105
  },
886
1106
  });
887
1107
 
888
- bridge.start();
1108
+ bridge.start(); // Creates SDK Bridge({ devMode: true }) + registers handlers
889
1109
 
890
1110
  // Update balance programmatically
891
1111
  bridge.setBalance(5000);
@@ -894,6 +1114,8 @@ bridge.setBalance(5000);
894
1114
  bridge.destroy();
895
1115
  ```
896
1116
 
1117
+ When using the Vite plugin with `devBridge: true`, the SDK is automatically configured with `devMode: true` so both sides use the same `MemoryChannel`.
1118
+
897
1119
  ### Handled Messages
898
1120
 
899
1121
  | Message | Description |
@@ -920,7 +1142,7 @@ fps.toggle();
920
1142
  fps.hide();
921
1143
  ```
922
1144
 
923
- When `debug: true` is set in `GameApplicationConfig`, the FPS overlay is enabled automatically.
1145
+ When `debug: true` is set in `GameApplicationConfig`, the FPS overlay is created and shown automatically — no manual setup needed.
924
1146
 
925
1147
  The overlay displays:
926
1148
  - Average FPS
@@ -1077,9 +1299,10 @@ class Tween {
1077
1299
  static to(target: any, props: Record<string, number>, duration: number, easing?: EasingFunction, onUpdate?: (p: number) => void): Promise<void>;
1078
1300
  static from(target: any, props: Record<string, number>, duration: number, easing?, onUpdate?): Promise<void>;
1079
1301
  static fromTo(target: any, fromProps: Record<string, number>, toProps: Record<string, number>, duration: number, easing?, onUpdate?): Promise<void>;
1080
- static delay(ms: number): Promise<void>;
1302
+ static delay(ms: number): Promise<void>; // Uses PixiJS Ticker
1081
1303
  static killTweensOf(target: any): void;
1082
1304
  static killAll(): void;
1305
+ static reset(): void; // Kill all + remove ticker listener
1083
1306
  }
1084
1307
  ```
1085
1308
 
@@ -1110,10 +1333,56 @@ class InputManager extends EventEmitter<InputEvents> {
1110
1333
  lock(): void;
1111
1334
  unlock(): void;
1112
1335
  isKeyDown(key: string): boolean;
1336
+ setViewportTransform(scale: number, offsetX: number, offsetY: number): void;
1337
+ getWorldPosition(canvasX: number, canvasY: number): { x: number; y: number };
1338
+ destroy(): void;
1339
+ }
1340
+ ```
1341
+
1342
+ ### Layout
1343
+
1344
+ ```typescript
1345
+ class Layout extends Container {
1346
+ get items(): readonly Container[];
1347
+
1348
+ constructor(config?: LayoutConfig);
1349
+ addItem(child: Container): this;
1350
+ removeItem(child: Container): this;
1351
+ clearItems(): this;
1352
+ updateViewport(width: number, height: number): void;
1353
+ layout(): void;
1354
+ }
1355
+ ```
1356
+
1357
+ ### ScrollContainer
1358
+
1359
+ ```typescript
1360
+ class ScrollContainer extends Container {
1361
+ get content(): Container | null;
1362
+ get scrollPosition(): { x: number; y: number };
1363
+
1364
+ constructor(config: ScrollContainerConfig);
1365
+ setContent(content: Container): void;
1366
+ scrollTo(x: number, y: number, animate?: boolean): void;
1367
+ scrollToItem(index: number): void;
1368
+ resize(width: number, height: number): void;
1113
1369
  destroy(): void;
1114
1370
  }
1115
1371
  ```
1116
1372
 
1373
+ ### SpriteAnimation
1374
+
1375
+ ```typescript
1376
+ class SpriteAnimation {
1377
+ static create(textures: Texture[], config?: SpriteAnimationConfig): AnimatedSprite;
1378
+ static fromSpritesheet(sheet: Spritesheet, prefix: string, config?: SpriteAnimationConfig): AnimatedSprite;
1379
+ static fromRange(sheet: Spritesheet, pattern: string, start: number, end: number, config?: SpriteAnimationConfig): AnimatedSprite;
1380
+ static fromAliases(aliases: string[], config?: SpriteAnimationConfig): AnimatedSprite;
1381
+ static playOnce(textures: Texture[], config?: SpriteAnimationConfig): { sprite: AnimatedSprite; finished: Promise<void> };
1382
+ static getTexturesByPrefix(sheet: Spritesheet, prefix: string): Texture[];
1383
+ }
1384
+ ```
1385
+
1117
1386
  ### EventEmitter
1118
1387
 
1119
1388
  ```typescript
@@ -1121,7 +1390,8 @@ class EventEmitter<TEvents extends {}> {
1121
1390
  on<K>(event: K, handler: (data: TEvents[K]) => void): this;
1122
1391
  once<K>(event: K, handler: (data: TEvents[K]) => void): this;
1123
1392
  off<K>(event: K, handler: (data: TEvents[K]) => void): this;
1124
- emit<K>(event: K, data: TEvents[K]): void;
1393
+ // Void events can be emitted without a data argument
1394
+ emit<K>(event: K, ...args): void;
1125
1395
  removeAllListeners(event?: keyof TEvents): this;
1126
1396
  }
1127
1397
  ```