@energy8platform/game-engine 0.10.11 → 0.12.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 (50) hide show
  1. package/README.md +272 -74
  2. package/dist/index.cjs.js +1322 -296
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.d.ts +369 -46
  5. package/dist/index.esm.js +1323 -298
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/lua.cjs.js +8 -18
  8. package/dist/lua.cjs.js.map +1 -1
  9. package/dist/lua.d.ts +0 -2
  10. package/dist/lua.esm.js +8 -18
  11. package/dist/lua.esm.js.map +1 -1
  12. package/dist/react.cjs.js +2848 -35
  13. package/dist/react.cjs.js.map +1 -1
  14. package/dist/react.d.ts +17 -6
  15. package/dist/react.esm.js +2848 -36
  16. package/dist/react.esm.js.map +1 -1
  17. package/dist/ui.cjs.js +1913 -592
  18. package/dist/ui.cjs.js.map +1 -1
  19. package/dist/ui.d.ts +528 -46
  20. package/dist/ui.esm.js +1911 -594
  21. package/dist/ui.esm.js.map +1 -1
  22. package/dist/vite.cjs.js +1 -11
  23. package/dist/vite.cjs.js.map +1 -1
  24. package/dist/vite.d.ts +1 -1
  25. package/dist/vite.esm.js +1 -11
  26. package/dist/vite.esm.js.map +1 -1
  27. package/package.json +3 -18
  28. package/src/index.ts +3 -3
  29. package/src/lua/LuaEngine.ts +8 -18
  30. package/src/react/applyProps.ts +90 -2
  31. package/src/react/extendAll.ts +29 -6
  32. package/src/react/index.ts +1 -1
  33. package/src/react/jsx.d.ts +249 -0
  34. package/src/react/reconciler.ts +80 -7
  35. package/src/ui/BalanceDisplay.ts +31 -38
  36. package/src/ui/Button.ts +217 -53
  37. package/src/ui/FlexContainer.ts +529 -0
  38. package/src/ui/Label.ts +13 -0
  39. package/src/ui/Layout.ts +86 -87
  40. package/src/ui/Modal.ts +11 -1
  41. package/src/ui/Panel.ts +108 -36
  42. package/src/ui/ProgressBar.ts +85 -31
  43. package/src/ui/ScrollContainer.ts +397 -45
  44. package/src/ui/Slider.ts +241 -0
  45. package/src/ui/Toast.ts +47 -17
  46. package/src/ui/Toggle.ts +201 -0
  47. package/src/ui/WinDisplay.ts +51 -39
  48. package/src/ui/index.ts +9 -11
  49. package/src/ui/view.ts +28 -0
  50. package/src/vite/index.ts +1 -11
package/dist/ui.d.ts CHANGED
@@ -1,12 +1,155 @@
1
1
  import { Texture, Container, TextStyle, ColorSource } from 'pixi.js';
2
- import { FancyButton, ScrollBox } from '@pixi/ui';
3
- import { LayoutContainer } from '@pixi/layout/components';
2
+
3
+ /**
4
+ * Universal view input type for UI component visual slots.
5
+ *
6
+ * - `string` — texture name, resolved via `Sprite.from()`
7
+ * - `Texture` — wrapped in a `Sprite`
8
+ * - `Container` — used as-is (Sprite, Graphics, NineSliceSprite, AnimatedSprite, custom...)
9
+ */
10
+ type ViewInput = string | Texture | Container;
11
+ /**
12
+ * Resolve a ViewInput to a Container instance.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * resolveView('btn-idle') // → Sprite.from('btn-idle')
17
+ * resolveView(someTexture) // → new Sprite(someTexture)
18
+ * resolveView(myCustomContainer) // → myCustomContainer (as-is)
19
+ * resolveView(undefined) // → null
20
+ * ```
21
+ */
22
+ declare function resolveView(input: ViewInput | undefined | null): Container | null;
23
+
24
+ type FlexDirection = 'row' | 'column';
25
+ type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around';
26
+ type AlignItems = 'start' | 'center' | 'end' | 'stretch';
27
+ type AlignSelf = 'auto' | 'start' | 'center' | 'end' | 'stretch';
28
+ interface FlexItemConfig {
29
+ /** Flex grow factor (0 = fixed size) */
30
+ flexGrow?: number;
31
+ /** Flex shrink factor (0 = don't shrink, default: 1) */
32
+ flexShrink?: number;
33
+ /** Explicit width override for layout calculations */
34
+ layoutWidth?: number;
35
+ /** Explicit height override for layout calculations */
36
+ layoutHeight?: number;
37
+ /** Override parent's alignItems for this child */
38
+ alignSelf?: AlignSelf;
39
+ /** Exclude from flex layout (acts like position: absolute) */
40
+ flexExclude?: boolean;
41
+ }
42
+ interface FlexContainerConfig {
43
+ /** Layout direction (default: 'row') */
44
+ direction?: FlexDirection;
45
+ /** Main-axis distribution (default: 'start') */
46
+ justifyContent?: JustifyContent;
47
+ /** Cross-axis alignment (default: 'start') */
48
+ alignItems?: AlignItems;
49
+ /** Gap between children in pixels (default: 0) */
50
+ gap?: number;
51
+ /** Padding [top, right, bottom, left] or single number (default: 0) */
52
+ padding?: number | [number, number, number, number];
53
+ /** Enable wrapping to next line (default: false) */
54
+ flexWrap?: boolean;
55
+ /** Maximum width before wrapping (only with flexWrap) */
56
+ maxWidth?: number;
57
+ /** Maximum height before wrapping (only with flexWrap + column) */
58
+ maxHeight?: number;
59
+ /** Explicit container width (used for cross-axis alignment/stretch) */
60
+ width?: number;
61
+ /** Explicit container height (used for cross-axis alignment/stretch) */
62
+ height?: number;
63
+ }
64
+ /**
65
+ * Lightweight flexbox-like layout container for PixiJS.
66
+ *
67
+ * Supports row/column direction, justify/align, gap, padding, wrapping,
68
+ * and flex-grow distribution. Zero external dependencies.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const toolbar = new FlexContainer({
73
+ * direction: 'row',
74
+ * justifyContent: 'space-between',
75
+ * alignItems: 'center',
76
+ * gap: 16,
77
+ * padding: 12,
78
+ * });
79
+ *
80
+ * toolbar.addFlexChild(button1);
81
+ * toolbar.addFlexChild(button2);
82
+ * toolbar.resize(800, 60);
83
+ * ```
84
+ */
85
+ declare class FlexContainer extends Container {
86
+ readonly __uiComponent: true;
87
+ private _config;
88
+ private _padding;
89
+ private _maxWidth;
90
+ private _maxHeight;
91
+ /** @internal */ _explicitWidth: number;
92
+ /** @internal */ _explicitHeight: number;
93
+ private _layoutChildren;
94
+ private _layoutDirty;
95
+ constructor(config?: FlexContainerConfig);
96
+ /** Add a child with optional flex config. Also registers in flex layout. */
97
+ addFlexChild(child: Container, flexConfig?: FlexItemConfig): this;
98
+ /** Remove a child from flex layout and display list */
99
+ removeFlexChild(child: Container): this;
100
+ /** Remove all flex children */
101
+ clearFlexChildren(): this;
102
+ /**
103
+ * Override addChild so children automatically participate in flex layout.
104
+ * This enables declarative usage from React JSX.
105
+ */
106
+ addChild<T extends Container>(...children: T[]): T;
107
+ removeChild<T extends Container>(...children: T[]): T;
108
+ /** Get all flex layout children (read-only) */
109
+ get flexChildren(): readonly Container[];
110
+ /** Update the container size and recalculate layout */
111
+ resize(width: number, height: number): void;
112
+ /** Update layout direction */
113
+ setDirection(direction: FlexDirection): void;
114
+ /** Update justifyContent */
115
+ setJustifyContent(justify: JustifyContent): void;
116
+ /** Update alignItems */
117
+ setAlignItems(align: AlignItems): void;
118
+ /** Update gap */
119
+ setGap(gap: number): void;
120
+ /** Update padding */
121
+ setPadding(padding: number | [number, number, number, number]): void;
122
+ /**
123
+ * Recalculate and apply layout positions for all children.
124
+ * Called automatically by `resize()`. Call manually after
125
+ * adding/removing children without resize.
126
+ */
127
+ updateLayout(): void;
128
+ /** Computed content size (after layout) */
129
+ getContentSize(): {
130
+ width: number;
131
+ height: number;
132
+ };
133
+ /** React reconciler update hook — applies changed config props */
134
+ updateConfig(changed: Record<string, any>): void;
135
+ destroy(options?: boolean | {
136
+ children?: boolean;
137
+ texture?: boolean;
138
+ textureSource?: boolean;
139
+ }): void;
140
+ }
4
141
 
5
142
  type ButtonState = 'default' | 'hover' | 'pressed' | 'disabled';
6
143
  interface ButtonConfig {
7
- /** Default texture/sprite for each state (optional uses Graphics if not provided) */
8
- textures?: Partial<Record<ButtonState, string | Texture>>;
9
- /** Width (for Graphics-based button) */
144
+ /** Custom view for default state (string texture name, Texture, or Container) */
145
+ defaultView?: ViewInput;
146
+ /** Custom view for hover state */
147
+ hoverView?: ViewInput;
148
+ /** Custom view for pressed state */
149
+ pressedView?: ViewInput;
150
+ /** Custom view for disabled state */
151
+ disabledView?: ViewInput;
152
+ /** Width (for Graphics-based button, ignored when custom views provided) */
10
153
  width?: number;
11
154
  /** Height (for Graphics-based button) */
12
155
  height?: number;
@@ -20,67 +163,138 @@ interface ButtonConfig {
20
163
  animationDuration?: number;
21
164
  /** Start disabled */
22
165
  disabled?: boolean;
23
- /** Button text */
166
+ /** Button text (rendered on top of the view) */
24
167
  text?: string;
25
168
  /** Button text style */
26
169
  textStyle?: Record<string, unknown>;
170
+ /** Press callback */
171
+ onPress?: () => void;
27
172
  }
28
173
  /**
29
- * Interactive button component powered by `@pixi/ui` FancyButton.
174
+ * Interactive button with per-state custom views and animations.
30
175
  *
31
- * Supports both texture-based and Graphics-based rendering with
32
- * per-state views, press animation, and text.
176
+ * Each visual state accepts a `ViewInput`: texture name, Texture, or any Container
177
+ * (Sprite, NineSliceSprite, AnimatedSprite, custom artwork, etc).
178
+ * Falls back to colored Graphics when no custom view is provided.
33
179
  *
34
180
  * @example
35
181
  * ```ts
182
+ * // Graphics-based (quick prototyping)
36
183
  * const btn = new Button({
37
184
  * width: 200, height: 60, borderRadius: 12,
38
185
  * colors: { default: 0x22aa22, hover: 0x33cc33 },
39
186
  * text: 'SPIN',
187
+ * onPress: () => spin(),
188
+ * });
189
+ *
190
+ * // Asset-based (production art)
191
+ * const btn = new Button({
192
+ * defaultView: 'btn-idle',
193
+ * hoverView: 'btn-hover',
194
+ * pressedView: 'btn-pressed',
195
+ * disabledView: 'btn-disabled',
196
+ * text: 'SPIN',
197
+ * onPress: () => spin(),
40
198
  * });
41
199
  *
42
- * btn.onPress.connect(() => console.log('Clicked!'));
43
- * scene.container.addChild(btn);
200
+ * // Custom Container view
201
+ * const btn = new Button({
202
+ * defaultView: myAnimatedSprite,
203
+ * text: 'SPIN',
204
+ * });
44
205
  * ```
45
206
  */
46
- declare class Button extends FancyButton {
47
- private _buttonConfig;
207
+ declare class Button extends Container {
208
+ readonly __uiComponent: true;
209
+ private _views;
210
+ private _state;
211
+ private _enabled;
212
+ private _config;
213
+ private _textObj;
214
+ /** Press callback */
215
+ onPress?: () => void;
48
216
  constructor(config?: ButtonConfig);
217
+ /** Current button state */
218
+ get state(): ButtonState;
49
219
  /** Enable the button */
50
220
  enable(): void;
51
221
  /** Disable the button */
52
222
  disable(): void;
223
+ /** Whether the button is enabled */
224
+ get enabled(): boolean;
225
+ set enabled(value: boolean);
53
226
  /** Whether the button is disabled */
54
227
  get disabled(): boolean;
228
+ /** Update button text */
229
+ set text(value: string);
230
+ private _buildViews;
231
+ private _rebuildViews;
232
+ private _setState;
233
+ private _onPointerOver;
234
+ private _onPointerOut;
235
+ private _onPointerDown;
236
+ private _onPointerUp;
237
+ private _onPointerUpOutside;
238
+ /** React reconciler update hook */
239
+ updateConfig(changed: Record<string, any>): void;
240
+ destroy(options?: boolean | {
241
+ children?: boolean;
242
+ texture?: boolean;
243
+ textureSource?: boolean;
244
+ }): void;
55
245
  }
56
246
 
57
247
  interface ProgressBarConfig {
248
+ /** Width of the bar */
58
249
  width?: number;
250
+ /** Height of the bar */
59
251
  height?: number;
252
+ /** Corner radius (for Graphics-based bar) */
60
253
  borderRadius?: number;
254
+ /** Fill color (for Graphics-based bar, ignored when fillView provided) */
61
255
  fillColor?: number;
256
+ /** Track background color (for Graphics-based bar, ignored when trackView provided) */
62
257
  trackColor?: number;
258
+ /** Border color */
63
259
  borderColor?: number;
260
+ /** Border width */
64
261
  borderWidth?: number;
65
262
  /** Animated fill (smoothly interpolate) */
66
263
  animated?: boolean;
67
264
  /** Animation speed (0..1 per frame, default: 0.1) */
68
265
  animationSpeed?: number;
266
+ /** Custom track background (string texture name, Texture, or Container) */
267
+ trackView?: ViewInput;
268
+ /** Custom fill bar (string texture name, Texture, or Container) */
269
+ fillView?: ViewInput;
69
270
  }
70
271
  /**
71
- * Horizontal progress bar powered by `@pixi/ui` ProgressBar.
272
+ * Horizontal progress bar with optional custom track/fill views.
72
273
  *
73
- * Provides optional smooth animated fill via per-frame `update()`.
274
+ * Supports asset-based skinning: provide `trackView` and/or `fillView`
275
+ * as texture names, Textures, or any Container (NineSliceSprite, custom artwork, etc).
276
+ * Falls back to colored Graphics when no custom views are provided.
74
277
  *
75
278
  * @example
76
279
  * ```ts
280
+ * // Graphics-based (quick prototyping)
77
281
  * const bar = new ProgressBar({ width: 300, height: 20, fillColor: 0x22cc22 });
78
- * scene.container.addChild(bar);
79
- * bar.progress = 0.5; // 50%
282
+ * bar.progress = 0.5;
283
+ *
284
+ * // Asset-based (production art)
285
+ * const bar = new ProgressBar({
286
+ * width: 300, height: 20,
287
+ * trackView: 'bar-track',
288
+ * fillView: new NineSliceSprite({ texture: 'bar-fill', ... }),
289
+ * });
290
+ * bar.progress = 0.75;
80
291
  * ```
81
292
  */
82
293
  declare class ProgressBar extends Container {
83
- private _bar;
294
+ readonly __uiComponent: true;
295
+ private _track;
296
+ private _fill;
297
+ private _fillMask;
84
298
  private _borderGfx;
85
299
  private _config;
86
300
  private _progress;
@@ -93,6 +307,9 @@ declare class ProgressBar extends Container {
93
307
  * Call each frame if animated is true.
94
308
  */
95
309
  update(_dt: number): void;
310
+ /** React reconciler update hook */
311
+ updateConfig(changed: Record<string, any>): void;
312
+ private updateMask;
96
313
  }
97
314
 
98
315
  interface LabelConfig {
@@ -117,6 +334,7 @@ interface LabelConfig {
117
334
  * ```
118
335
  */
119
336
  declare class Label extends Container {
337
+ readonly __uiComponent: true;
120
338
  private _text;
121
339
  private _maxWidth;
122
340
  private _autoFit;
@@ -140,6 +358,8 @@ declare class Label extends Container {
140
358
  * Format a number with thousands separators.
141
359
  */
142
360
  setNumber(value: number, decimals?: number, locale?: string): void;
361
+ /** React reconciler update hook */
362
+ updateConfig(changed: Record<string, any>): void;
143
363
  private fitText;
144
364
  }
145
365
 
@@ -164,12 +384,14 @@ interface PanelConfig {
164
384
  nineSliceBorders?: [number, number, number, number];
165
385
  /** Padding inside the panel */
166
386
  padding?: number;
387
+ /** Flex layout config for content */
388
+ layout?: Partial<FlexContainerConfig>;
167
389
  }
168
390
  /**
169
- * Background panel powered by `@pixi/layout` LayoutContainer.
391
+ * Background panel with optional flexbox content layout.
170
392
  *
171
393
  * Supports both Graphics-based (color + border) and 9-slice sprite backgrounds.
172
- * Children added to `content` participate in flexbox layout automatically.
394
+ * Children added via `addContent()` participate in flex layout automatically.
173
395
  *
174
396
  * @example
175
397
  * ```ts
@@ -184,13 +406,32 @@ interface PanelConfig {
184
406
  * });
185
407
  * ```
186
408
  */
187
- declare class Panel extends LayoutContainer {
409
+ declare class Panel extends Container {
410
+ readonly __uiComponent: true;
411
+ private _bg;
412
+ private _content;
413
+ private _internalSetup;
188
414
  private _panelConfig;
189
415
  constructor(config?: PanelConfig);
190
- /** Access the content container (children added here participate in layout) */
191
- get content(): Container;
416
+ /** Access the content flex container — add children here for layout */
417
+ get content(): FlexContainer;
418
+ /** Convenience: add a child to the content layout */
419
+ addContent(child: Container): this;
192
420
  /** Resize the panel */
193
421
  setSize(width: number, height: number): void;
422
+ /**
423
+ * Override addChild so external children are routed to content FlexContainer.
424
+ * Enables `<panel><label /><button /></panel>` in React JSX.
425
+ */
426
+ addChild<T extends Container>(...children: T[]): T;
427
+ removeChild<T extends Container>(...children: T[]): T;
428
+ /** React reconciler update hook */
429
+ updateConfig(changed: Record<string, any>): void;
430
+ destroy(options?: boolean | {
431
+ children?: boolean;
432
+ texture?: boolean;
433
+ textureSource?: boolean;
434
+ }): void;
194
435
  }
195
436
 
196
437
  interface BalanceDisplayConfig {
@@ -213,7 +454,7 @@ interface BalanceDisplayConfig {
213
454
  * Reactive balance display component.
214
455
  *
215
456
  * Automatically formats currency and can animate value changes
216
- * with a smooth countup/countdown effect.
457
+ * with a smooth countup/countdown effect using engine Tween.
217
458
  *
218
459
  * @example
219
460
  * ```ts
@@ -225,13 +466,14 @@ interface BalanceDisplayConfig {
225
466
  * ```
226
467
  */
227
468
  declare class BalanceDisplay extends Container {
469
+ readonly __uiComponent: true;
228
470
  private _prefixLabel;
229
471
  private _valueLabel;
230
472
  private _config;
231
473
  private _currentValue;
232
474
  private _displayedValue;
233
- private _animating;
234
- private _animationCancelled;
475
+ /** Internal target for Tween animation */
476
+ private _tweenTarget;
235
477
  constructor(config?: BalanceDisplayConfig);
236
478
  /** Current displayed value */
237
479
  get value(): number;
@@ -246,6 +488,13 @@ declare class BalanceDisplay extends Container {
246
488
  private animateValue;
247
489
  private updateDisplay;
248
490
  private layoutLabels;
491
+ /** React reconciler update hook */
492
+ updateConfig(changed: Record<string, any>): void;
493
+ destroy(options?: boolean | {
494
+ children?: boolean;
495
+ texture?: boolean;
496
+ textureSource?: boolean;
497
+ }): void;
249
498
  }
250
499
 
251
500
  interface WinDisplayConfig {
@@ -264,7 +513,7 @@ interface WinDisplayConfig {
264
513
  * Win amount display with countup animation.
265
514
  *
266
515
  * Shows a dramatic countup from 0 to the win amount, with optional
267
- * scale pop effect — typical of slot games.
516
+ * scale pop effect — typical of slot games. Uses engine Tween system.
268
517
  *
269
518
  * @example
270
519
  * ```ts
@@ -275,9 +524,11 @@ interface WinDisplayConfig {
275
524
  * ```
276
525
  */
277
526
  declare class WinDisplay extends Container {
527
+ readonly __uiComponent: true;
278
528
  private _label;
279
529
  private _config;
280
- private _cancelCountup;
530
+ /** Internal target for Tween countup */
531
+ private _tweenTarget;
281
532
  constructor(config?: WinDisplayConfig);
282
533
  /**
283
534
  * Show a win with countup animation.
@@ -295,6 +546,13 @@ declare class WinDisplay extends Container {
295
546
  */
296
547
  hide(): void;
297
548
  private displayAmount;
549
+ /** React reconciler update hook */
550
+ updateConfig(changed: Record<string, any>): void;
551
+ destroy(options?: boolean | {
552
+ children?: boolean;
553
+ texture?: boolean;
554
+ textureSource?: boolean;
555
+ }): void;
298
556
  }
299
557
 
300
558
  interface ModalConfig {
@@ -311,7 +569,7 @@ interface ModalConfig {
311
569
  * Modal overlay component.
312
570
  * Shows content on top of a dark overlay with enter/exit animations.
313
571
  *
314
- * The content container uses `@pixi/layout` for automatic centering.
572
+ * Content is automatically centered via position calculations.
315
573
  *
316
574
  * @example
317
575
  * ```ts
@@ -322,6 +580,7 @@ interface ModalConfig {
322
580
  * ```
323
581
  */
324
582
  declare class Modal extends Container {
583
+ readonly __uiComponent: true;
325
584
  private _overlay;
326
585
  private _contentContainer;
327
586
  private _config;
@@ -341,6 +600,8 @@ declare class Modal extends Container {
341
600
  * Hide the modal with animation.
342
601
  */
343
602
  hide(): Promise<void>;
603
+ /** React reconciler update hook */
604
+ updateConfig(changed: Record<string, any>): void;
344
605
  }
345
606
 
346
607
  type ToastType = 'info' | 'success' | 'warning' | 'error';
@@ -349,6 +610,8 @@ interface ToastConfig {
349
610
  duration?: number;
350
611
  /** Toast position from bottom */
351
612
  bottomOffset?: number;
613
+ /** Custom background view (string texture name, Texture, or Container). Sized to fit text. */
614
+ backgroundView?: ViewInput;
352
615
  }
353
616
  /**
354
617
  * Toast notification component for displaying transient messages.
@@ -361,10 +624,12 @@ interface ToastConfig {
361
624
  * ```
362
625
  */
363
626
  declare class Toast extends Container {
627
+ readonly __uiComponent: true;
364
628
  private _bg;
629
+ private _customBg;
365
630
  private _text;
366
631
  private _config;
367
- private _dismissTimeout;
632
+ private _dismissPending;
368
633
  constructor(config?: ToastConfig);
369
634
  /**
370
635
  * Show a toast message.
@@ -374,6 +639,13 @@ declare class Toast extends Container {
374
639
  * Dismiss the toast.
375
640
  */
376
641
  dismiss(): Promise<void>;
642
+ /** React reconciler update hook */
643
+ updateConfig(changed: Record<string, any>): void;
644
+ destroy(options?: boolean | {
645
+ children?: boolean;
646
+ texture?: boolean;
647
+ textureSource?: boolean;
648
+ }): void;
377
649
  }
378
650
 
379
651
  type LayoutDirection = 'horizontal' | 'vertical' | 'grid' | 'wrap';
@@ -400,7 +672,7 @@ interface LayoutConfig {
400
672
  breakpoints?: Record<number, Partial<LayoutConfig>>;
401
673
  }
402
674
  /**
403
- * Responsive layout container powered by `@pixi/layout` (Yoga flexbox engine).
675
+ * Responsive layout container powered by a lightweight built-in flex layout solver.
404
676
  *
405
677
  * Supports horizontal, vertical, grid, and wrap layout modes with
406
678
  * alignment, padding, gap, and viewport-anchor positioning.
@@ -427,6 +699,7 @@ interface LayoutConfig {
427
699
  * ```
428
700
  */
429
701
  declare class Layout extends Container {
702
+ readonly __uiComponent: true;
430
703
  private _layoutConfig;
431
704
  private _padding;
432
705
  private _anchor;
@@ -435,6 +708,7 @@ declare class Layout extends Container {
435
708
  private _items;
436
709
  private _viewportWidth;
437
710
  private _viewportHeight;
711
+ private _flex;
438
712
  constructor(config?: LayoutConfig);
439
713
  /** Add an item to the layout */
440
714
  addItem(child: Container): this;
@@ -450,9 +724,16 @@ declare class Layout extends Container {
450
724
  */
451
725
  updateViewport(width: number, height: number): void;
452
726
  private applyLayoutStyles;
453
- private applyGridChildWidth;
727
+ private buildFlexItemConfig;
454
728
  private applyAnchor;
455
729
  private resolveConfig;
730
+ /** React reconciler update hook */
731
+ updateConfig(changed: Record<string, any>): void;
732
+ destroy(options?: boolean | {
733
+ children?: boolean;
734
+ texture?: boolean;
735
+ textureSource?: boolean;
736
+ }): void;
456
737
  }
457
738
 
458
739
  type ScrollDirection = 'vertical' | 'horizontal' | 'both';
@@ -471,18 +752,23 @@ interface ScrollContainerConfig {
471
752
  elementsMargin?: number;
472
753
  /** Padding */
473
754
  padding?: number;
474
- /** Disable dynamic rendering (render all items even when offscreen) */
475
- disableDynamicRendering?: boolean;
476
755
  /** Disable easing/inertia */
477
756
  disableEasing?: boolean;
478
- /** Global scroll scroll even when mouse is not over the component */
479
- globalScroll?: boolean;
757
+ /** Show scrollbar indicator (default: false) */
758
+ scrollbar?: boolean;
759
+ /** Custom scrollbar thumb view (string texture name, Texture, or Container) */
760
+ thumbView?: ViewInput;
761
+ /** Scrollbar width in px (default: 6) */
762
+ scrollbarWidth?: number;
763
+ /** Scrollbar padding from edge (default: 4) */
764
+ scrollbarPadding?: number;
765
+ /** Scrollbar color (when no thumbView, default: 0xaaaaaa) */
766
+ scrollbarColor?: number;
767
+ /** Scrollbar alpha (default: 0.5) */
768
+ scrollbarAlpha?: number;
480
769
  }
481
770
  /**
482
- * Scrollable container powered by `@pixi/ui` ScrollBox.
483
- *
484
- * Provides touch/drag scrolling, mouse wheel support, inertia, and
485
- * dynamic rendering optimization for off-screen items.
771
+ * Scrollable container with touch/drag, mouse wheel, and inertia.
486
772
  *
487
773
  * @example
488
774
  * ```ts
@@ -500,21 +786,217 @@ interface ScrollContainerConfig {
500
786
  * scene.container.addChild(scroll);
501
787
  * ```
502
788
  */
503
- declare class ScrollContainer extends ScrollBox {
789
+ declare class ScrollContainer extends Container {
790
+ readonly __uiComponent: true;
791
+ private _viewport;
792
+ private _internalSetup;
793
+ private _content;
794
+ private _maskGfx;
795
+ private _bg;
504
796
  private _scrollConfig;
797
+ private _items;
798
+ private _scrollbar;
799
+ private _scrollbarConfig;
800
+ private _dragging;
801
+ private _dragStart;
802
+ private _contentStart;
803
+ private _velocity;
804
+ private _lastDragPos;
805
+ private _lastDragTime;
806
+ private _inertiaActive;
807
+ private _onTickBound;
808
+ private _onWheelBound;
505
809
  constructor(config: ScrollContainerConfig);
506
- /** Set scrollable content. Replaces any existing content. */
810
+ /**
811
+ * Override addChild so external children are routed to scroll content.
812
+ * Enables `<scrollContainer><label /><panel /></scrollContainer>` in React JSX.
813
+ */
814
+ addChild<T extends Container>(...children: T[]): T;
815
+ removeChild<T extends Container>(...children: T[]): T;
816
+ /** React reconciler update hook */
817
+ updateConfig(changed: Record<string, any>): void;
818
+ /** Enable mouse wheel scrolling (call after adding to stage) */
819
+ enableWheel(canvas: HTMLCanvasElement): void;
820
+ /** Set scrollable content. Replaces any existing items. */
507
821
  setContent(content: Container): void;
508
822
  /** Add a single item */
509
- addItem(...items: Container[]): Container;
510
- /** Scroll to make a specific item/child visible */
823
+ addItem(child: Container): this;
824
+ /** Remove all items */
825
+ clearItems(): void;
826
+ /** Get items */
827
+ get items(): readonly Container[];
828
+ /** Scroll to make a specific item index visible */
511
829
  scrollToItem(index: number): void;
512
830
  /** Current scroll position */
513
831
  get scrollPosition(): {
514
832
  x: number;
515
833
  y: number;
516
834
  };
835
+ /** Resize the scroll viewport */
836
+ setViewportSize(width: number, height: number): void;
837
+ private layoutItems;
838
+ private _onPointerDown;
839
+ private _onPointerMove;
840
+ private _onPointerUp;
841
+ private startInertia;
842
+ private stopInertia;
843
+ private _inertiaTick;
844
+ private _onWheel;
845
+ private clampScroll;
846
+ private updateScrollbar;
847
+ destroy(options?: boolean | {
848
+ children?: boolean;
849
+ texture?: boolean;
850
+ textureSource?: boolean;
851
+ }): void;
852
+ }
853
+
854
+ interface SliderConfig {
855
+ /** Minimum value (default: 0) */
856
+ min?: number;
857
+ /** Maximum value (default: 1) */
858
+ max?: number;
859
+ /** Step increment (0 = continuous, default: 0) */
860
+ step?: number;
861
+ /** Initial value (default: min) */
862
+ value?: number;
863
+ /** Track width in pixels (default: 200) */
864
+ width?: number;
865
+ /** Track height in pixels (default: 8) */
866
+ height?: number;
867
+ /** Corner radius for Graphics-based track/fill (default: 4) */
868
+ borderRadius?: number;
869
+ /** Track background color (ignored when trackView provided) */
870
+ trackColor?: number;
871
+ /** Fill bar color (ignored when fillView provided) */
872
+ fillColor?: number;
873
+ /** Handle radius (for Graphics-based handle, default: 12) */
874
+ handleRadius?: number;
875
+ /** Handle color (for Graphics-based handle, ignored when handleView provided) */
876
+ handleColor?: number;
877
+ /** Custom track background view */
878
+ trackView?: ViewInput;
879
+ /** Custom fill bar view */
880
+ fillView?: ViewInput;
881
+ /** Custom handle view */
882
+ handleView?: ViewInput;
883
+ /** Called when value changes during drag */
884
+ onUpdate?: (value: number) => void;
885
+ /** Called when drag ends */
886
+ onChange?: (value: number) => void;
887
+ }
888
+ /**
889
+ * Draggable slider with customizable track, fill, and handle views.
890
+ *
891
+ * @example
892
+ * ```ts
893
+ * const volume = new Slider({
894
+ * min: 0, max: 1, value: 0.5,
895
+ * width: 200, height: 8,
896
+ * fillColor: 0xffd700,
897
+ * onUpdate: (v) => console.log('Volume:', v),
898
+ * });
899
+ * ```
900
+ */
901
+ declare class Slider extends Container {
902
+ readonly __uiComponent: true;
903
+ private _track;
904
+ private _fill;
905
+ private _fillMask;
906
+ private _handle;
907
+ private _config;
908
+ private _value;
909
+ private _dragging;
910
+ onUpdate: ((value: number) => void) | null;
911
+ onChange: ((value: number) => void) | null;
912
+ constructor(config?: SliderConfig);
913
+ /** Current value */
914
+ get value(): number;
915
+ set value(v: number);
916
+ get min(): number;
917
+ get max(): number;
918
+ /** React reconciler update hook */
919
+ updateConfig(changed: Record<string, any>): void;
920
+ private _fraction;
921
+ private _applyStep;
922
+ private _updateVisuals;
923
+ private _valueFromPointer;
924
+ private _onPointerDown;
925
+ private _onPointerMove;
926
+ private _onPointerUp;
927
+ destroy(options?: boolean | {
928
+ children?: boolean;
929
+ texture?: boolean;
930
+ textureSource?: boolean;
931
+ }): void;
932
+ }
933
+
934
+ interface ToggleConfig {
935
+ /** Initial state (default: false) */
936
+ value?: boolean;
937
+ /** Custom view for the ON state */
938
+ onView?: ViewInput;
939
+ /** Custom view for the OFF state */
940
+ offView?: ViewInput;
941
+ /** Width (for Graphics-based toggle, default: 52) */
942
+ width?: number;
943
+ /** Height (for Graphics-based toggle, default: 28) */
944
+ height?: number;
945
+ /** Track color when ON (ignored when custom views provided) */
946
+ onColor?: number;
947
+ /** Track color when OFF (ignored when custom views provided) */
948
+ offColor?: number;
949
+ /** Handle color (for Graphics-based toggle) */
950
+ handleColor?: number;
951
+ /** Handle radius (for Graphics-based toggle, default: auto) */
952
+ handleRadius?: number;
953
+ /** Animation duration in ms (default: 200) */
954
+ animationDuration?: number;
955
+ /** Called when value changes */
956
+ onChange?: (value: boolean) => void;
957
+ }
958
+ /**
959
+ * Toggle switch with two states.
960
+ *
961
+ * Supports custom ON/OFF views or auto-generated Graphics-based toggle.
962
+ * Click to toggle, or use `forceSwitch(value)` programmatically.
963
+ *
964
+ * @example
965
+ * ```ts
966
+ * const mute = new Toggle({
967
+ * value: false,
968
+ * onColor: 0x22cc22,
969
+ * onChange: (on) => audioManager.mute(!on),
970
+ * });
971
+ * ```
972
+ */
973
+ declare class Toggle extends Container {
974
+ readonly __uiComponent: true;
975
+ private _value;
976
+ private _onView;
977
+ private _offView;
978
+ private _handle;
979
+ private _trackGfx;
980
+ private _config;
981
+ private _useCustomViews;
982
+ onChange: ((value: boolean) => void) | null;
983
+ constructor(config?: ToggleConfig);
984
+ /** Current toggle state */
985
+ get value(): boolean;
986
+ set value(v: boolean);
987
+ /** Programmatically switch to a specific state with animation */
988
+ forceSwitch(value: boolean): void;
989
+ /** React reconciler update hook */
990
+ updateConfig(changed: Record<string, any>): void;
991
+ private _onTap;
992
+ private _animateToState;
993
+ private _drawTrack;
994
+ destroy(options?: boolean | {
995
+ children?: boolean;
996
+ texture?: boolean;
997
+ textureSource?: boolean;
998
+ }): void;
517
999
  }
518
1000
 
519
- export { BalanceDisplay, Button, Label, Layout, Modal, Panel, ProgressBar, ScrollContainer, Toast, WinDisplay };
520
- export type { BalanceDisplayConfig, ButtonConfig, ButtonState, LabelConfig, LayoutAlignment, LayoutAnchor, LayoutConfig, LayoutDirection, ModalConfig, PanelConfig, ProgressBarConfig, ScrollContainerConfig, ScrollDirection, ToastConfig, ToastType, WinDisplayConfig };
1001
+ export { BalanceDisplay, Button, FlexContainer, Label, Layout, Modal, Panel, ProgressBar, ScrollContainer, Slider, Toast, Toggle, WinDisplay, resolveView };
1002
+ export type { AlignItems, AlignSelf, BalanceDisplayConfig, ButtonConfig, ButtonState, FlexContainerConfig, FlexDirection, FlexItemConfig, JustifyContent, LabelConfig, LayoutAlignment, LayoutAnchor, LayoutConfig, LayoutDirection, ModalConfig, PanelConfig, ProgressBarConfig, ScrollContainerConfig, ScrollDirection, SliderConfig, ToastConfig, ToastType, ToggleConfig, ViewInput, WinDisplayConfig };