@codexo/exojs 0.6.8 → 0.6.9

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/dist/exo.esm.js CHANGED
@@ -6211,19 +6211,6 @@ const createCanvas = (options = {}) => {
6211
6211
  context.fillRect(0, 0, newCanvas.width, newCanvas.height);
6212
6212
  return newCanvas;
6213
6213
  };
6214
- const heightCache = new Map();
6215
- const determineFontHeight = (font) => {
6216
- if (!heightCache.has(font)) {
6217
- const body = document.body;
6218
- const dummy = document.createElement('div');
6219
- dummy.appendChild(document.createTextNode('M'));
6220
- dummy.setAttribute('style', `font: ${font};position:absolute;top:0;left:0`);
6221
- body.appendChild(dummy);
6222
- heightCache.set(font, dummy.offsetHeight);
6223
- body.removeChild(dummy);
6224
- }
6225
- return heightCache.get(font);
6226
- };
6227
6214
 
6228
6215
  class Texture {
6229
6216
  static _black = null;
@@ -17629,14 +17616,227 @@ class AnimatedSprite extends Sprite {
17629
17616
  }
17630
17617
  }
17631
17618
 
17619
+ const glyphPadding = 2;
17620
+ class ShelfPacker {
17621
+ _shelves = [];
17622
+ _width;
17623
+ _height;
17624
+ constructor(width, height) {
17625
+ this._width = width;
17626
+ this._height = height;
17627
+ }
17628
+ insert(width, height) {
17629
+ // Try existing shelves in order (ascending y)
17630
+ for (const shelf of this._shelves) {
17631
+ if (shelf.height >= height && shelf.cursorX + width <= this._width) {
17632
+ const x = shelf.cursorX;
17633
+ shelf.cursorX += width;
17634
+ return { x, y: shelf.y };
17635
+ }
17636
+ }
17637
+ // Create a new shelf at the bottom
17638
+ const last = this._shelves[this._shelves.length - 1];
17639
+ const bottomY = last === undefined ? 0 : last.y + last.height;
17640
+ if (bottomY + height > this._height) {
17641
+ throw new Error(`GlyphAtlas full — clear() and re-render, or instantiate with larger dims`);
17642
+ }
17643
+ this._shelves.push({ y: bottomY, height, cursorX: width });
17644
+ return { x: 0, y: bottomY };
17645
+ }
17646
+ reset() {
17647
+ this._shelves.length = 0;
17648
+ }
17649
+ }
17650
+ /**
17651
+ * A shared atlas that rasterizes glyphs on demand into an offscreen canvas
17652
+ * and wraps it as a Texture for use by the Mesh-based Text renderer.
17653
+ *
17654
+ * Glyphs are always rasterized in white so that runtime tinting via
17655
+ * `Mesh.tint` applies the fill color without requiring re-rasterization.
17656
+ *
17657
+ * Use `getDefaultGlyphAtlas()` from `atlas-singleton.ts` rather than
17658
+ * constructing directly.
17659
+ */
17660
+ class DynamicGlyphAtlas {
17661
+ texture;
17662
+ _canvas;
17663
+ _ctx;
17664
+ _packer;
17665
+ _cache = new Map();
17666
+ _width;
17667
+ _height;
17668
+ constructor(width = 1024, height = 1024) {
17669
+ this._width = width;
17670
+ this._height = height;
17671
+ // Use OffscreenCanvas when available, fall back to HTMLCanvasElement.
17672
+ // In jsdom / Node the global may be absent; createCanvas falls through
17673
+ // to document.createElement which jsdom provides.
17674
+ const canvas = typeof OffscreenCanvas !== 'undefined'
17675
+ ? new OffscreenCanvas(width, height)
17676
+ : document.createElement('canvas');
17677
+ if ('width' in canvas) {
17678
+ canvas.width = width;
17679
+ canvas.height = height;
17680
+ }
17681
+ this._canvas = canvas;
17682
+ const ctx = canvas.getContext('2d');
17683
+ if (ctx === null) {
17684
+ throw new Error('DynamicGlyphAtlas: could not obtain a 2D context.');
17685
+ }
17686
+ this._ctx = ctx;
17687
+ this._packer = new ShelfPacker(width, height);
17688
+ this.texture = new Texture(canvas);
17689
+ this.texture.setSize(width, height);
17690
+ }
17691
+ /**
17692
+ * Returns the cached GlyphInfo for the given character + font parameters,
17693
+ * rasterizing it into the atlas if not already present.
17694
+ */
17695
+ getGlyph(char, family, size, weight, style) {
17696
+ const key = `${char}:${family}:${size}:${weight}:${style}`;
17697
+ const cached = this._cache.get(key);
17698
+ if (cached !== undefined) {
17699
+ return cached;
17700
+ }
17701
+ const info = this._rasterize(char, family, size, weight, style, key);
17702
+ this._cache.set(key, info);
17703
+ // Bump texture version so GPU backends re-upload the canvas data.
17704
+ this.texture.updateSource();
17705
+ return info;
17706
+ }
17707
+ /**
17708
+ * Clears all cached glyphs and resets the atlas packer.
17709
+ * The underlying canvas pixels are also cleared.
17710
+ */
17711
+ clear() {
17712
+ this._cache.clear();
17713
+ this._packer.reset();
17714
+ this._ctx.clearRect(0, 0, this._width, this._height);
17715
+ this.texture.updateSource();
17716
+ }
17717
+ // -----------------------------------------------------------------------
17718
+ _rasterize(char, family, size, weight, fontStyle, _key) {
17719
+ const ctx = this._ctx;
17720
+ const padding = glyphPadding;
17721
+ ctx.font = `${fontStyle} ${weight} ${size}px ${family}`;
17722
+ ctx.textBaseline = 'alphabetic';
17723
+ ctx.fillStyle = '#ffffff';
17724
+ const metrics = ctx.measureText(char);
17725
+ const ascent = Math.ceil(metrics.fontBoundingBoxAscent
17726
+ ?? metrics.actualBoundingBoxAscent
17727
+ ?? size * 0.8);
17728
+ const descent = Math.ceil(metrics.fontBoundingBoxDescent
17729
+ ?? metrics.actualBoundingBoxDescent
17730
+ ?? size * 0.2);
17731
+ const advance = metrics.width;
17732
+ const glyphWidth = Math.max(1, Math.ceil((metrics.actualBoundingBoxLeft ?? 0) + (metrics.actualBoundingBoxRight ?? 0)) || Math.ceil(advance));
17733
+ const glyphHeight = Math.max(1, ascent + descent);
17734
+ const slotW = glyphWidth + padding * 2;
17735
+ const slotH = glyphHeight + padding * 2;
17736
+ const slot = this._packer.insert(slotW, slotH);
17737
+ // Draw the glyph white into the atlas slot
17738
+ ctx.fillText(char, slot.x + padding + (metrics.actualBoundingBoxLeft ?? 0), slot.y + padding + ascent);
17739
+ const info = {
17740
+ x: slot.x,
17741
+ y: slot.y,
17742
+ width: glyphWidth,
17743
+ height: glyphHeight,
17744
+ advance,
17745
+ ascent,
17746
+ uvLeft: slot.x / this._width,
17747
+ uvTop: slot.y / this._height,
17748
+ uvRight: (slot.x + slotW) / this._width,
17749
+ uvBottom: (slot.y + slotH) / this._height,
17750
+ };
17751
+ return info;
17752
+ }
17753
+ }
17754
+
17755
+ let _defaultAtlas = null;
17756
+ /**
17757
+ * Returns the shared process-wide glyph atlas, creating it lazily on first
17758
+ * call. All `Text` instances share this atlas so that identical glyph shapes
17759
+ * (same char + family + size + weight + style) are rasterized only once.
17760
+ */
17761
+ function getDefaultGlyphAtlas() {
17762
+ if (_defaultAtlas === null) {
17763
+ _defaultAtlas = new DynamicGlyphAtlas();
17764
+ }
17765
+ return _defaultAtlas;
17766
+ }
17767
+
17768
+ /**
17769
+ * Computes per-glyph quad placements for the given text and style.
17770
+ *
17771
+ * Handles `\n` line breaks and left/center/right alignment. No word-wrap,
17772
+ * no RTL, no ligature shaping — Unicode/diacritics are delegated to the
17773
+ * browser's font engine via canvas `fillText`.
17774
+ *
17775
+ * Returns an empty array for empty text.
17776
+ */
17777
+ function layoutText(text, style, atlas) {
17778
+ if (text.length === 0) {
17779
+ return [];
17780
+ }
17781
+ const { fontSize, fontFamily, fontWeight, fontStyle, lineHeight, align } = style;
17782
+ const computedLineHeight = fontSize * lineHeight;
17783
+ const lines = text.split('\n');
17784
+ // Pass 1: gather glyph info per line, track line widths
17785
+ const linePlacements = [];
17786
+ let maxLineWidth = 0;
17787
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
17788
+ const line = lines[lineIndex];
17789
+ const y = lineIndex * computedLineHeight;
17790
+ let cursorX = 0;
17791
+ const placements = [];
17792
+ for (const char of line) {
17793
+ const info = atlas.getGlyph(char, fontFamily, fontSize, fontWeight, fontStyle);
17794
+ placements.push({ info, x: cursorX, y });
17795
+ cursorX += info.advance;
17796
+ }
17797
+ const lineWidth = cursorX;
17798
+ if (lineWidth > maxLineWidth) {
17799
+ maxLineWidth = lineWidth;
17800
+ }
17801
+ linePlacements.push({ placements, width: lineWidth });
17802
+ }
17803
+ // Pass 2: apply alignment and build final GlyphPlacement array
17804
+ const result = [];
17805
+ for (const line of linePlacements) {
17806
+ let offsetX = 0;
17807
+ if (align === 'right') {
17808
+ offsetX = maxLineWidth - line.width;
17809
+ }
17810
+ else if (align === 'center') {
17811
+ offsetX = (maxLineWidth - line.width) / 2;
17812
+ }
17813
+ for (const { info, x, y } of line.placements) {
17814
+ result.push({
17815
+ x: x + offsetX,
17816
+ y,
17817
+ width: info.width,
17818
+ height: info.height,
17819
+ uvLeft: info.uvLeft,
17820
+ uvTop: info.uvTop,
17821
+ uvRight: info.uvRight,
17822
+ uvBottom: info.uvBottom,
17823
+ });
17824
+ }
17825
+ }
17826
+ return result;
17827
+ }
17828
+
17632
17829
  class TextStyle {
17633
17830
  _align;
17634
17831
  _fill;
17832
+ _fillColor;
17833
+ _lineHeight;
17635
17834
  _stroke;
17636
17835
  _strokeThickness;
17637
17836
  _fontSize;
17638
17837
  _fontWeight;
17639
17838
  _fontFamily;
17839
+ _fontStyle;
17640
17840
  _wordWrap;
17641
17841
  _wordWrapWidth;
17642
17842
  _baseline;
@@ -17647,11 +17847,14 @@ class TextStyle {
17647
17847
  constructor(options = {}) {
17648
17848
  this._align = options.align ?? 'left';
17649
17849
  this._fill = options.fill ?? 'black';
17850
+ this._fillColor = options.fillColor ?? Color.white.clone();
17851
+ this._lineHeight = options.lineHeight ?? 1.2;
17650
17852
  this._stroke = options.stroke ?? 'black';
17651
17853
  this._strokeThickness = options.strokeThickness ?? 1;
17652
17854
  this._fontSize = options.fontSize ?? 20;
17653
17855
  this._fontWeight = options.fontWeight ?? 'bold';
17654
17856
  this._fontFamily = options.fontFamily ?? 'Arial';
17857
+ this._fontStyle = options.fontStyle ?? 'normal';
17655
17858
  this._wordWrap = options.wordWrap ?? false;
17656
17859
  this._wordWrapWidth = options.wordWrapWidth ?? 100;
17657
17860
  this._baseline = options.baseline ?? 'alphabetic';
@@ -17677,6 +17880,31 @@ class TextStyle {
17677
17880
  this._dirty = true;
17678
17881
  }
17679
17882
  }
17883
+ /**
17884
+ * Runtime fill color applied via `Mesh.tint`. Glyphs are always
17885
+ * rasterized white; this color multiplies them at draw time so that
17886
+ * changing the color never requires re-rasterizing cached glyphs.
17887
+ */
17888
+ get fillColor() {
17889
+ return this._fillColor;
17890
+ }
17891
+ set fillColor(color) {
17892
+ this._fillColor = color;
17893
+ this._dirty = true;
17894
+ }
17895
+ /**
17896
+ * Line-height multiplier applied to `fontSize` when computing vertical
17897
+ * spacing between lines. Defaults to 1.2.
17898
+ */
17899
+ get lineHeight() {
17900
+ return this._lineHeight;
17901
+ }
17902
+ set lineHeight(lineHeight) {
17903
+ if (this._lineHeight !== lineHeight) {
17904
+ this._lineHeight = lineHeight;
17905
+ this._dirty = true;
17906
+ }
17907
+ }
17680
17908
  get stroke() {
17681
17909
  return this._stroke;
17682
17910
  }
@@ -17722,6 +17950,15 @@ class TextStyle {
17722
17950
  this._dirty = true;
17723
17951
  }
17724
17952
  }
17953
+ get fontStyle() {
17954
+ return this._fontStyle;
17955
+ }
17956
+ set fontStyle(fontStyle) {
17957
+ if (this._fontStyle !== fontStyle) {
17958
+ this._fontStyle = fontStyle;
17959
+ this._dirty = true;
17960
+ }
17961
+ }
17725
17962
  get wordWrap() {
17726
17963
  return this._wordWrap;
17727
17964
  }
@@ -17799,11 +18036,14 @@ class TextStyle {
17799
18036
  if (style !== this) {
17800
18037
  this.align = style.align;
17801
18038
  this.fill = style.fill;
18039
+ this._fillColor = style.fillColor.clone();
18040
+ this.lineHeight = style.lineHeight;
17802
18041
  this.stroke = style.stroke;
17803
18042
  this.strokeThickness = style.strokeThickness;
17804
18043
  this.fontSize = style.fontSize;
17805
18044
  this.fontWeight = style.fontWeight;
17806
18045
  this.fontFamily = style.fontFamily;
18046
+ this.fontStyle = style.fontStyle;
17807
18047
  this.wordWrap = style.wordWrap;
17808
18048
  this.wordWrapWidth = style.wordWrapWidth;
17809
18049
  this.baseline = style.baseline;
@@ -17819,26 +18059,81 @@ class TextStyle {
17819
18059
  }
17820
18060
  }
17821
18061
 
17822
- const newLinePattern = /(?:\r\n|\r|\n)/;
17823
- class Text extends Sprite {
18062
+ function buildMesh(placements, style) {
18063
+ const n = placements.length;
18064
+ const vertices = new Float32Array(n * 4 * 2);
18065
+ const uvs = new Float32Array(n * 4 * 2);
18066
+ const indices = new Uint16Array(n * 6);
18067
+ for (let i = 0; i < n; i++) {
18068
+ const p = placements[i];
18069
+ const v = i * 8;
18070
+ const u = i * 8;
18071
+ const idx = i * 6;
18072
+ const baseV = i * 4;
18073
+ // Vertices: TL, TR, BR, BL
18074
+ vertices[v + 0] = p.x;
18075
+ vertices[v + 1] = p.y;
18076
+ vertices[v + 2] = p.x + p.width;
18077
+ vertices[v + 3] = p.y;
18078
+ vertices[v + 4] = p.x + p.width;
18079
+ vertices[v + 5] = p.y + p.height;
18080
+ vertices[v + 6] = p.x;
18081
+ vertices[v + 7] = p.y + p.height;
18082
+ // UVs: TL, TR, BR, BL
18083
+ uvs[u + 0] = p.uvLeft;
18084
+ uvs[u + 1] = p.uvTop;
18085
+ uvs[u + 2] = p.uvRight;
18086
+ uvs[u + 3] = p.uvTop;
18087
+ uvs[u + 4] = p.uvRight;
18088
+ uvs[u + 5] = p.uvBottom;
18089
+ uvs[u + 6] = p.uvLeft;
18090
+ uvs[u + 7] = p.uvBottom;
18091
+ // Indices: [TL, TR, BR, TL, BR, BL]
18092
+ indices[idx + 0] = baseV + 0;
18093
+ indices[idx + 1] = baseV + 1;
18094
+ indices[idx + 2] = baseV + 2;
18095
+ indices[idx + 3] = baseV + 0;
18096
+ indices[idx + 4] = baseV + 2;
18097
+ indices[idx + 5] = baseV + 3;
18098
+ }
18099
+ const atlas = getDefaultGlyphAtlas();
18100
+ const mesh = new Mesh({
18101
+ vertices,
18102
+ uvs,
18103
+ indices,
18104
+ texture: atlas.texture,
18105
+ });
18106
+ mesh.tint = style.fillColor;
18107
+ return mesh;
18108
+ }
18109
+ /**
18110
+ * GPU-accelerated text node that rasterizes individual glyphs into a shared
18111
+ * atlas ({@link DynamicGlyphAtlas}) and renders them as a single quad-per-
18112
+ * glyph {@link Mesh} (one draw call per Text instance).
18113
+ *
18114
+ * Glyphs are always rasterized in white and tinted at runtime via
18115
+ * `Mesh.tint`; changing `style.fillColor` only updates the mesh tint —
18116
+ * no atlas re-rasterization is needed.
18117
+ *
18118
+ * The internal {@link Mesh} is the sole child of this {@link Container}.
18119
+ * All transform properties (position, rotation, scale, origin) are
18120
+ * inherited from {@link Container} → {@link RenderNode}.
18121
+ */
18122
+ class Text extends Container {
17824
18123
  _text;
17825
18124
  _style;
17826
- _canvas;
17827
- _context;
17828
- _dirty = true;
17829
- constructor(text, style, samplerOptions, canvas = document.createElement('canvas')) {
17830
- super(new Texture(canvas, samplerOptions));
18125
+ _mesh = null;
18126
+ constructor(text, style) {
18127
+ super();
17831
18128
  this._text = text;
17832
18129
  this._style = (style && style instanceof TextStyle) ? style : new TextStyle(style);
17833
- this._canvas = canvas;
17834
- this._context = canvas.getContext('2d');
17835
- this.updateTexture();
18130
+ this._rebuild();
17836
18131
  }
17837
18132
  get text() {
17838
18133
  return this._text;
17839
18134
  }
17840
- set text(text) {
17841
- this.setText(text);
18135
+ set text(value) {
18136
+ this.setText(value);
17842
18137
  }
17843
18138
  get style() {
17844
18139
  return this._style;
@@ -17846,98 +18141,43 @@ class Text extends Sprite {
17846
18141
  set style(style) {
17847
18142
  this.setStyle(style);
17848
18143
  }
17849
- get canvas() {
17850
- return this._canvas;
17851
- }
17852
- set canvas(canvas) {
17853
- this.setCanvas(canvas);
17854
- }
17855
18144
  setText(text) {
17856
18145
  if (this._text !== text) {
17857
18146
  this._text = text;
17858
- this._dirty = true;
18147
+ this._rebuild();
17859
18148
  }
17860
18149
  return this;
17861
18150
  }
17862
18151
  setStyle(style) {
17863
18152
  this._style = (style instanceof TextStyle) ? style : new TextStyle(style);
17864
- this._dirty = true;
17865
- return this;
17866
- }
17867
- setCanvas(canvas) {
17868
- if (this._canvas !== canvas) {
17869
- this._canvas = canvas;
17870
- this._context = this._getContext(canvas);
17871
- this._dirty = true;
17872
- this.texture.setSource.call(this.texture, canvas);
17873
- this.setTextureFrame(Rectangle.temp.set(0, 0, canvas.width, canvas.height));
17874
- }
18153
+ this._rebuild();
17875
18154
  return this;
17876
18155
  }
17877
- updateTexture() {
17878
- if (this._style && (this._dirty || this._style.dirty)) {
17879
- const canvas = this._canvas, context = this._context, style = this._style.apply(context), text = style.wordWrap ? this.getWordWrappedText() : this._text, lineHeight = determineFontHeight(context.font) + style.strokeThickness, lines = text.split(newLinePattern), lineMetrics = lines.map((line) => context.measureText(line)), maxLineWidth = lineMetrics.reduce((max, measure) => Math.max(max, measure.width), 0), canvasWidth = Math.ceil((maxLineWidth + style.strokeThickness) + (style.padding * 2)), canvasHeight = Math.ceil((lineHeight * lines.length) + (style.padding * 2));
17880
- if (canvasWidth !== canvas.width || canvasHeight !== canvas.height) {
17881
- canvas.width = canvasWidth;
17882
- canvas.height = canvasHeight;
17883
- this.setTextureFrame(Rectangle.temp.set(0, 0, canvasWidth, canvasHeight));
17884
- }
17885
- else {
17886
- context.clearRect(0, 0, canvasWidth, canvasHeight);
17887
- }
17888
- style.apply(context);
17889
- for (let i = 0; i < lines.length; i++) {
17890
- const metrics = lineMetrics[i], lineWidth = (maxLineWidth - metrics.width), offset = (style.align === 'right') ? lineWidth : lineWidth / 2, padding = style.padding + (style.strokeThickness / 2), lineX = metrics.actualBoundingBoxLeft + (style.align === 'left' ? 0 : offset) + padding, lineY = metrics.actualBoundingBoxAscent + (lineHeight * i) + padding;
17891
- if (style.stroke && style.strokeThickness) {
17892
- context.strokeText(lines[i], lineX, lineY);
17893
- }
17894
- if (style.fill) {
17895
- context.fillText(lines[i], lineX, lineY);
17896
- }
17897
- }
17898
- this.texture.updateSource();
17899
- this._dirty = false;
17900
- this._style.dirty = false;
17901
- }
17902
- return this;
17903
- }
17904
- getWordWrappedText() {
17905
- const context = this._context, wrapWidth = this._style.wordWrapWidth, lines = this._text.split('\n'), spaceWidth = context.measureText(' ').width;
17906
- let spaceLeft = wrapWidth, result = '';
17907
- for (let y = 0; y < lines.length; y++) {
17908
- const words = lines[y].split(' ');
17909
- if (y > 0) {
17910
- result += '\n';
17911
- }
17912
- for (let x = 0; x < words.length; x++) {
17913
- const word = words[x], wordWidth = context.measureText(word).width, pairWidth = wordWidth + spaceWidth;
17914
- if (pairWidth > spaceLeft) {
17915
- if (x > 0) {
17916
- result += '\n';
17917
- }
17918
- spaceLeft = wrapWidth;
17919
- }
17920
- else {
17921
- spaceLeft -= pairWidth;
17922
- }
17923
- result += `${word} `;
17924
- }
18156
+ destroy() {
18157
+ if (this._mesh !== null) {
18158
+ this._mesh.destroy();
18159
+ this._mesh = null;
17925
18160
  }
17926
- return result;
18161
+ super.destroy();
17927
18162
  }
17928
- render(backend) {
17929
- if (this.visible) {
17930
- this.updateTexture();
17931
- super.render(backend);
18163
+ // -----------------------------------------------------------------------
18164
+ _rebuild() {
18165
+ // Remove and discard the old mesh (if any).
18166
+ if (this._mesh !== null) {
18167
+ this.removeChild(this._mesh);
18168
+ this._mesh.destroy();
18169
+ this._mesh = null;
18170
+ }
18171
+ if (this._text.length === 0) {
18172
+ return;
17932
18173
  }
17933
- return this;
17934
- }
17935
- _getContext(canvas) {
17936
- const context = canvas.getContext('2d');
17937
- if (context === null) {
17938
- throw new Error('Could not create a 2D canvas context.');
18174
+ const atlas = getDefaultGlyphAtlas();
18175
+ const placements = layoutText(this._text, this._style, atlas);
18176
+ if (placements.length === 0) {
18177
+ return;
17939
18178
  }
17940
- return context;
18179
+ this._mesh = buildMesh(placements, this._style);
18180
+ this.addChild(this._mesh);
17941
18181
  }
17942
18182
  }
17943
18183
 
@@ -18519,5 +18759,5 @@ class IndexedDbStore {
18519
18759
  }
18520
18760
  }
18521
18761
 
18522
- export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign$1 as sign, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio, tau, trimRotation, webGl2PrimitiveArrayConstructors, webGl2PrimitiveByteSizeMapping, webGl2PrimitiveTypeNames };
18762
+ export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, DynamicGlyphAtlas, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, layoutText, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign$1 as sign, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio, tau, trimRotation, webGl2PrimitiveArrayConstructors, webGl2PrimitiveByteSizeMapping, webGl2PrimitiveTypeNames };
18523
18763
  //# sourceMappingURL=exo.esm.js.map