@codexo/exojs 0.15.0 → 0.15.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.
- package/CHANGELOG.md +94 -0
- package/dist/esm/animation/Tween.d.ts.map +1 -1
- package/dist/esm/animation/Tween.js +6 -4
- package/dist/esm/animation/Tween.js.map +1 -1
- package/dist/esm/audio/AudioManager.d.ts.map +1 -1
- package/dist/esm/audio/AudioManager.js +14 -4
- package/dist/esm/audio/AudioManager.js.map +1 -1
- package/dist/esm/audio/Playable.d.ts +6 -1
- package/dist/esm/audio/Playable.d.ts.map +1 -1
- package/dist/esm/core/Application.d.ts.map +1 -1
- package/dist/esm/core/Application.js +2 -0
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/core/BuildInfo.js +2 -2
- package/dist/esm/core/SceneNode.d.ts +10 -1
- package/dist/esm/core/SceneNode.d.ts.map +1 -1
- package/dist/esm/core/SceneNode.js +10 -1
- package/dist/esm/core/SceneNode.js.map +1 -1
- package/dist/esm/debug/BoundingBoxesLayer.d.ts.map +1 -1
- package/dist/esm/debug/BoundingBoxesLayer.js +2 -1
- package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
- package/dist/esm/debug/HitTestLayer.js +4 -4
- package/dist/esm/debug/HitTestLayer.js.map +1 -1
- package/dist/esm/debug/PerformanceLayer.js +1 -1
- package/dist/esm/debug/PerformanceLayer.js.map +1 -1
- package/dist/esm/debug/RenderPassInspectorLayer.js +2 -2
- package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -1
- package/dist/esm/input/InputManager.d.ts.map +1 -1
- package/dist/esm/input/InputManager.js +12 -3
- package/dist/esm/input/InputManager.js.map +1 -1
- package/dist/esm/math/AbstractVector.d.ts +4 -3
- package/dist/esm/math/AbstractVector.d.ts.map +1 -1
- package/dist/esm/math/AbstractVector.js +5 -4
- package/dist/esm/math/AbstractVector.js.map +1 -1
- package/dist/esm/math/ObservableVector.d.ts +2 -0
- package/dist/esm/math/ObservableVector.d.ts.map +1 -1
- package/dist/esm/math/ObservableVector.js +9 -0
- package/dist/esm/math/ObservableVector.js.map +1 -1
- package/dist/esm/math/Polygon.d.ts.map +1 -1
- package/dist/esm/math/Polygon.js +4 -1
- package/dist/esm/math/Polygon.js.map +1 -1
- package/dist/esm/math/collision-detection.d.ts.map +1 -1
- package/dist/esm/math/collision-detection.js +13 -13
- package/dist/esm/math/collision-detection.js.map +1 -1
- package/dist/esm/math/collision-primitives.d.ts +1 -1
- package/dist/esm/math/collision-primitives.d.ts.map +1 -1
- package/dist/esm/math/collision-primitives.js +4 -1
- package/dist/esm/math/collision-primitives.js.map +1 -1
- package/dist/esm/rendering/primitives/Graphics.d.ts +7 -0
- package/dist/esm/rendering/primitives/Graphics.d.ts.map +1 -1
- package/dist/esm/rendering/primitives/Graphics.js +20 -6
- package/dist/esm/rendering/primitives/Graphics.js.map +1 -1
- package/dist/esm/rendering/sprite/AnimatedSprite.d.ts +1 -0
- package/dist/esm/rendering/sprite/AnimatedSprite.d.ts.map +1 -1
- package/dist/esm/rendering/sprite/AnimatedSprite.js +18 -1
- package/dist/esm/rendering/sprite/AnimatedSprite.js.map +1 -1
- package/dist/esm/rendering/sprite/Sprite.d.ts.map +1 -1
- package/dist/esm/rendering/sprite/Sprite.js +8 -0
- package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
- package/dist/esm/rendering/text/TextLayout.d.ts.map +1 -1
- package/dist/esm/rendering/text/TextLayout.js +2 -3
- package/dist/esm/rendering/text/TextLayout.js.map +1 -1
- package/dist/esm/resources/Loader.d.ts.map +1 -1
- package/dist/esm/resources/Loader.js +20 -3
- package/dist/esm/resources/Loader.js.map +1 -1
- package/dist/esm/resources/coreAssetBindings.d.ts +11 -0
- package/dist/esm/resources/coreAssetBindings.d.ts.map +1 -1
- package/dist/esm/resources/coreAssetBindings.js +10 -2
- package/dist/esm/resources/coreAssetBindings.js.map +1 -1
- package/dist/exo.debug.esm.js +1 -1
- package/dist/exo.debug.esm.js.map +1 -1
- package/dist/exo.esm.js +1 -1
- package/dist/exo.esm.js.map +1 -1
- package/dist/exo.iife.js +157 -46
- package/dist/exo.iife.js.map +1 -1
- package/dist/exo.iife.min.js +1 -1
- package/dist/exo.iife.min.js.map +1 -1
- package/package.json +1 -1
package/dist/exo.iife.js
CHANGED
|
@@ -419,8 +419,10 @@ var Exo = (function (exports) {
|
|
|
419
419
|
this._onStart?.();
|
|
420
420
|
}
|
|
421
421
|
this._elapsed += deltaSeconds;
|
|
422
|
-
// Clamp to duration for this cycle
|
|
423
|
-
|
|
422
|
+
// Clamp to duration for this cycle, remembering the overshoot so it can
|
|
423
|
+
// carry into the next repeat cycle below.
|
|
424
|
+
const overflow = this._elapsed - this._duration;
|
|
425
|
+
if (overflow >= 0) {
|
|
424
426
|
this._elapsed = this._duration;
|
|
425
427
|
}
|
|
426
428
|
// Apply interpolation.
|
|
@@ -438,8 +440,8 @@ var Exo = (function (exports) {
|
|
|
438
440
|
if (this._yoyo) {
|
|
439
441
|
this._direction = this._direction === 1 ? -1 : 1;
|
|
440
442
|
}
|
|
441
|
-
// Reset elapsed for next cycle; carry
|
|
442
|
-
|
|
443
|
+
// Reset elapsed for next cycle; carry the overshoot (at most one
|
|
444
|
+
// extra cycle per update call).
|
|
443
445
|
this._elapsed = overflow > 0 ? Math.min(overflow, this._duration) : 0;
|
|
444
446
|
// Apply progress for any overflow.
|
|
445
447
|
if (overflow > 0) {
|
|
@@ -1769,12 +1771,13 @@ var Exo = (function (exports) {
|
|
|
1769
1771
|
*/
|
|
1770
1772
|
class AbstractVector {
|
|
1771
1773
|
/**
|
|
1772
|
-
* Angle of this vector in radians, measured from the positive
|
|
1773
|
-
* (
|
|
1774
|
-
* preserving its {@link length}. Mutates in
|
|
1774
|
+
* Angle of this vector in radians, measured from the positive X-axis
|
|
1775
|
+
* (the same convention as `PolarVector.phi`). Setting this rotates the
|
|
1776
|
+
* vector to the new angle while preserving its {@link length}. Mutates in
|
|
1777
|
+
* place.
|
|
1775
1778
|
*/
|
|
1776
1779
|
get angle() {
|
|
1777
|
-
return Math.atan2(this.
|
|
1780
|
+
return Math.atan2(this.y, this.x);
|
|
1778
1781
|
}
|
|
1779
1782
|
set angle(angle) {
|
|
1780
1783
|
const length = this.length;
|
|
@@ -2089,7 +2092,10 @@ var Exo = (function (exports) {
|
|
|
2089
2092
|
const normY = (y1 - y2) / ry;
|
|
2090
2093
|
return normX * normX + normY * normY <= 1;
|
|
2091
2094
|
};
|
|
2092
|
-
const intersectionPointPoly$1 = (point, { points }) =>
|
|
2095
|
+
const intersectionPointPoly$1 = (point, { x: offsetX, y: offsetY, points }) =>
|
|
2096
|
+
// Shift the point into the polygon's local space so its x/y position
|
|
2097
|
+
// offset is honoured (the local `points` never carry the offset).
|
|
2098
|
+
polygonContainsPoint({ x: point.x - offsetX, y: point.y - offsetY }, points);
|
|
2093
2099
|
const intersectionLineLineSegments = (a1, a2, b1, b2) => {
|
|
2094
2100
|
const denominator = (a2.x - a1.x) * (b2.y - b1.y) - (b2.x - b1.x) * (a2.y - a1.y);
|
|
2095
2101
|
if (Math.abs(denominator) <= epsilon$1) {
|
|
@@ -2317,8 +2323,13 @@ var Exo = (function (exports) {
|
|
|
2317
2323
|
if (getVoronoiRegion(edgeX, edgeY, pointX, pointY) !== VoronoiRegion.right) {
|
|
2318
2324
|
return false;
|
|
2319
2325
|
}
|
|
2320
|
-
|
|
2321
|
-
|
|
2326
|
+
// In the right region the closest polygon feature is the *next* vertex, so
|
|
2327
|
+
// both the region refinement and the distance test use `circle - nextPoint`
|
|
2328
|
+
// (mirrors the right-region branch of getCollisionPolygonCircle).
|
|
2329
|
+
const positionBx = circleX - nextPoint.x;
|
|
2330
|
+
const positionBy = circleY - nextPoint.y;
|
|
2331
|
+
const region = getVoronoiRegion(nextEdge.x, nextEdge.y, positionBx, positionBy);
|
|
2332
|
+
return region === VoronoiRegion.left && getVectorLength(positionBx, positionBy) > radius;
|
|
2322
2333
|
};
|
|
2323
2334
|
const shouldExcludeMiddleVoronoi = (pointX, pointY, radius, edgeX, edgeY) => {
|
|
2324
2335
|
const normalX = edgeY;
|
|
@@ -2331,15 +2342,10 @@ var Exo = (function (exports) {
|
|
|
2331
2342
|
return distance > 0 && Math.abs(distance) > radius;
|
|
2332
2343
|
};
|
|
2333
2344
|
const intersectionCirclePoly = ({ x: cx, y: cy, radius }, { x: px, y: py, points, edges }) => {
|
|
2334
|
-
// Frame transform:
|
|
2335
|
-
//
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
// below combine them with the negated-offset circle position to reach the
|
|
2339
|
-
// same value as a positively-offset frame would. Don't flip without
|
|
2340
|
-
// re-deriving the Voronoi math.
|
|
2341
|
-
const circleX = px - cx;
|
|
2342
|
-
const circleY = py - cy;
|
|
2345
|
+
// Frame transform: the circle centre expressed in the polygon's local space
|
|
2346
|
+
// (circle.position - poly.position), matching getCollisionPolygonCircle.
|
|
2347
|
+
const circleX = cx - px;
|
|
2348
|
+
const circleY = cy - py;
|
|
2343
2349
|
const len = points.length;
|
|
2344
2350
|
for (let i = 0; i < len; i++) {
|
|
2345
2351
|
// i, prev, next are all valid indices into the parallel length-`len`
|
|
@@ -2428,8 +2434,8 @@ var Exo = (function (exports) {
|
|
|
2428
2434
|
difference.destroy();
|
|
2429
2435
|
return null;
|
|
2430
2436
|
}
|
|
2431
|
-
const projectionN = difference.
|
|
2432
|
-
const projectionV =
|
|
2437
|
+
const projectionN = difference.normalize();
|
|
2438
|
+
const projectionV = projectionN.clone().multiply(overlap);
|
|
2433
2439
|
return {
|
|
2434
2440
|
shapeA: circleA,
|
|
2435
2441
|
shapeB: circleB,
|
|
@@ -2942,10 +2948,19 @@ var Exo = (function (exports) {
|
|
|
2942
2948
|
this._owner?._onObservableChange(this._channel);
|
|
2943
2949
|
}
|
|
2944
2950
|
}
|
|
2951
|
+
// The getters must be redeclared alongside the setter overrides: a
|
|
2952
|
+
// setter-only accessor on the subclass prototype would shadow the whole
|
|
2953
|
+
// inherited accessor pair, leaving `get` undefined.
|
|
2954
|
+
get angle() {
|
|
2955
|
+
return Math.atan2(this._y, this._x);
|
|
2956
|
+
}
|
|
2945
2957
|
set angle(angle) {
|
|
2946
2958
|
const length = this.length;
|
|
2947
2959
|
this.set(Math.cos(angle) * length, Math.sin(angle) * length);
|
|
2948
2960
|
}
|
|
2961
|
+
get length() {
|
|
2962
|
+
return Math.sqrt(this._x * this._x + this._y * this._y);
|
|
2963
|
+
}
|
|
2949
2964
|
set length(magnitude) {
|
|
2950
2965
|
const angle = this.angle;
|
|
2951
2966
|
this.set(Math.cos(angle) * magnitude, Math.sin(angle) * magnitude);
|
|
@@ -4808,9 +4823,19 @@ var Exo = (function (exports) {
|
|
|
4808
4823
|
this._registered.set('master', this.master);
|
|
4809
4824
|
this._registered.set('music', this.music);
|
|
4810
4825
|
this._registered.set('sound', this.sound);
|
|
4811
|
-
|
|
4812
|
-
this
|
|
4813
|
-
|
|
4826
|
+
if (isAudioContextReady()) {
|
|
4827
|
+
// The shared context is already running — this manager was constructed
|
|
4828
|
+
// after the one-shot ready signal fired (e.g. a second Application in
|
|
4829
|
+
// the same process; the buses above would otherwise consume the signal
|
|
4830
|
+
// before this handler registers). Dispatch the unlock on a microtask so
|
|
4831
|
+
// subscribers registered right after construction still observe it.
|
|
4832
|
+
queueMicrotask(() => this.onUnlock.dispatch());
|
|
4833
|
+
}
|
|
4834
|
+
else {
|
|
4835
|
+
onAudioContextReady.add(() => {
|
|
4836
|
+
this.onUnlock.dispatch();
|
|
4837
|
+
});
|
|
4838
|
+
}
|
|
4814
4839
|
}
|
|
4815
4840
|
/**
|
|
4816
4841
|
* When `true`, the master bus is muted while `document.hidden` is true.
|
|
@@ -6607,6 +6632,9 @@ var Exo = (function (exports) {
|
|
|
6607
6632
|
const length = Math.sqrt(axis.x * axis.x + axis.y * axis.y) || 1;
|
|
6608
6633
|
const nx = axis.x / length;
|
|
6609
6634
|
const ny = axis.y / length;
|
|
6635
|
+
// World-space projection: the polygon's x/y offset shifts every vertex by
|
|
6636
|
+
// the same amount, so it contributes a constant term along the axis.
|
|
6637
|
+
const offset = nx * this._position.x + ny * this._position.y;
|
|
6610
6638
|
const points = this._points;
|
|
6611
6639
|
let min = Infinity;
|
|
6612
6640
|
let max = -Infinity;
|
|
@@ -6619,7 +6647,7 @@ var Exo = (function (exports) {
|
|
|
6619
6647
|
if (projection > max)
|
|
6620
6648
|
max = projection;
|
|
6621
6649
|
}
|
|
6622
|
-
return result.set(min, max);
|
|
6650
|
+
return result.set(min + offset, max + offset);
|
|
6623
6651
|
}
|
|
6624
6652
|
contains(x, y) {
|
|
6625
6653
|
return intersectionPointPoly(Vector.temp.set(x, y), this);
|
|
@@ -7289,9 +7317,18 @@ var Exo = (function (exports) {
|
|
|
7289
7317
|
this._invalidateSubtreeTransform();
|
|
7290
7318
|
this._invalidateBoundsCascade();
|
|
7291
7319
|
}
|
|
7320
|
+
/**
|
|
7321
|
+
* Re-derive `origin` from the fractional anchor and the CURRENT local
|
|
7322
|
+
* bounds. Uses local (untransformed) bounds on purpose: the transform
|
|
7323
|
+
* multiplies the origin by scale itself, so deriving from world bounds
|
|
7324
|
+
* would double-apply scale whenever the anchor is set after scaling.
|
|
7325
|
+
* Subclasses whose local bounds change after construction (e.g. a sprite
|
|
7326
|
+
* switching to a texture sub-frame) must call this to keep an anchored
|
|
7327
|
+
* node anchored.
|
|
7328
|
+
*/
|
|
7292
7329
|
_updateOrigin() {
|
|
7293
7330
|
const { x, y } = this._anchor;
|
|
7294
|
-
const { width, height } = this.
|
|
7331
|
+
const { width, height } = this.getLocalBounds();
|
|
7295
7332
|
this.setOrigin(width * x, height * y);
|
|
7296
7333
|
}
|
|
7297
7334
|
}
|
|
@@ -13108,9 +13145,18 @@ var Exo = (function (exports) {
|
|
|
13108
13145
|
existing._refreshBrowserGamepad(browserGamepad);
|
|
13109
13146
|
}
|
|
13110
13147
|
}
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13148
|
+
// Two pads can vanish in the same poll, and the compact strategy's shift
|
|
13149
|
+
// re-points map entries while this loop runs — so resolve each browser
|
|
13150
|
+
// index against the LIVE map at dispatch time instead of a pre-loop
|
|
13151
|
+
// entries snapshot (a stale pad reference would disconnect the wrong,
|
|
13152
|
+
// already-repurposed slot and leave a ghost `connected` pad behind).
|
|
13153
|
+
for (const browserIndex of [...this.gamepadsByBrowserIndex.keys()]) {
|
|
13154
|
+
if (seenBrowserIndices.has(browserIndex)) {
|
|
13155
|
+
continue;
|
|
13156
|
+
}
|
|
13157
|
+
const pad = this.gamepadsByBrowserIndex.get(browserIndex);
|
|
13158
|
+
this.gamepadsByBrowserIndex.delete(browserIndex);
|
|
13159
|
+
if (pad !== undefined) {
|
|
13114
13160
|
this.handleGamepadDisconnect(pad);
|
|
13115
13161
|
}
|
|
13116
13162
|
}
|
|
@@ -16342,6 +16388,14 @@ var Exo = (function (exports) {
|
|
|
16342
16388
|
this.width = width;
|
|
16343
16389
|
this.height = height;
|
|
16344
16390
|
}
|
|
16391
|
+
// The local bounds changed size — re-derive the origin from the
|
|
16392
|
+
// fractional anchor, or an anchored sprite keeps the OLD bounds' pixel
|
|
16393
|
+
// origin and renders offset by the size difference (an anchored sprite
|
|
16394
|
+
// switching from the full atlas to its first animation frame used to
|
|
16395
|
+
// land hundreds of pixels off-canvas).
|
|
16396
|
+
if (this.anchor.x !== 0 || this.anchor.y !== 0) {
|
|
16397
|
+
this._updateOrigin();
|
|
16398
|
+
}
|
|
16345
16399
|
this.invalidateCache();
|
|
16346
16400
|
return this;
|
|
16347
16401
|
}
|
|
@@ -16618,13 +16672,12 @@ var Exo = (function (exports) {
|
|
|
16618
16672
|
const extraPerGap = (maxLineWidth - line.width) / gaps;
|
|
16619
16673
|
let wordIdx = -1;
|
|
16620
16674
|
let prevWasSpace = true;
|
|
16621
|
-
const spaceAdv = provider.getGlyph(' ', fontSize).advance;
|
|
16622
16675
|
for (const entry of line.placements) {
|
|
16623
|
-
if (prevWasSpace && entry.
|
|
16676
|
+
if (prevWasSpace && entry.char !== ' ') {
|
|
16624
16677
|
wordIdx++;
|
|
16625
16678
|
prevWasSpace = false;
|
|
16626
16679
|
}
|
|
16627
|
-
else if (!prevWasSpace && entry.
|
|
16680
|
+
else if (!prevWasSpace && entry.char === ' ') {
|
|
16628
16681
|
prevWasSpace = true;
|
|
16629
16682
|
}
|
|
16630
16683
|
result.push({
|
|
@@ -33408,14 +33461,22 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
33408
33461
|
* parent's source. `new URL(ref, source)` only works when `source` is an
|
|
33409
33462
|
* absolute URL; loaders are frequently called with relative paths (e.g.
|
|
33410
33463
|
* `assets/demo/fonts/x.fnt`), so fall back to a synthetic base and strip it.
|
|
33464
|
+
* A root-absolute source (`/assets/demo/fonts/x.fnt`) must yield a
|
|
33465
|
+
* root-absolute result again — dropping the leading slash would make the
|
|
33466
|
+
* browser re-resolve the page image against the document base URL.
|
|
33467
|
+
* @internal exported for tests
|
|
33411
33468
|
*/
|
|
33412
33469
|
function resolveSubAssetPath(ref, source) {
|
|
33470
|
+
if (/^(?:[a-z][a-z\d+.-]*:|\/\/|\/)/i.test(ref)) {
|
|
33471
|
+
return ref;
|
|
33472
|
+
}
|
|
33413
33473
|
try {
|
|
33414
33474
|
return new URL(ref, source).href;
|
|
33415
33475
|
}
|
|
33416
33476
|
catch {
|
|
33417
33477
|
const base = 'https://exojs.invalid/';
|
|
33418
|
-
|
|
33478
|
+
const resolved = new URL(ref, base + source.replace(/^\/+/, '')).href.slice(base.length);
|
|
33479
|
+
return source.startsWith('/') ? `/${resolved}` : resolved;
|
|
33419
33480
|
}
|
|
33420
33481
|
}
|
|
33421
33482
|
// ---------------------------------------------------------------------------
|
|
@@ -34334,6 +34395,13 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
34334
34395
|
* instead if you need to await completion.
|
|
34335
34396
|
*/
|
|
34336
34397
|
backgroundLoad() {
|
|
34398
|
+
// Start a fresh progress batch only when idle; a re-entrant call while the
|
|
34399
|
+
// queue is draining extends the running batch instead (mirrors the
|
|
34400
|
+
// accounting in _loadSingleBackground).
|
|
34401
|
+
if (this._backgroundQueue.length === 0 && this._backgroundActive === 0) {
|
|
34402
|
+
this._backgroundLoaded = 0;
|
|
34403
|
+
this._backgroundTotal = 0;
|
|
34404
|
+
}
|
|
34337
34405
|
for (const [type, entries] of this._manifest) {
|
|
34338
34406
|
for (const [alias, entry] of entries) {
|
|
34339
34407
|
if (this._hasResource(type, alias))
|
|
@@ -34341,16 +34409,17 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
34341
34409
|
const key = this._key(type, alias);
|
|
34342
34410
|
if (this._inFlight.has(key))
|
|
34343
34411
|
continue;
|
|
34412
|
+
if (this._isQueuedInBackground(type, alias))
|
|
34413
|
+
continue;
|
|
34344
34414
|
this._backgroundQueue.push({
|
|
34345
34415
|
type,
|
|
34346
34416
|
alias,
|
|
34347
34417
|
path: entry.path,
|
|
34348
34418
|
options: entry.options,
|
|
34349
34419
|
});
|
|
34420
|
+
this._backgroundTotal++;
|
|
34350
34421
|
}
|
|
34351
34422
|
}
|
|
34352
|
-
this._backgroundTotal = this._backgroundQueue.length;
|
|
34353
|
-
this._backgroundLoaded = 0;
|
|
34354
34423
|
this._drainBackground();
|
|
34355
34424
|
}
|
|
34356
34425
|
/**
|
|
@@ -35109,7 +35178,16 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
35109
35178
|
if (leftPrototype !== rightPrototype) {
|
|
35110
35179
|
return false;
|
|
35111
35180
|
}
|
|
35112
|
-
|
|
35181
|
+
// Same-prototype instances compare structurally by their own enumerable
|
|
35182
|
+
// keys — the registerManifest contract allows deeply-equal options of any
|
|
35183
|
+
// shared class, not just plain objects. Built-ins whose state is NOT
|
|
35184
|
+
// carried in enumerable own keys need explicit handling: Dates compare by
|
|
35185
|
+
// timestamp; other exotic containers stay reference-only (Object.is above)
|
|
35186
|
+
// so two distinct-but-similar instances never count as equivalent.
|
|
35187
|
+
if (left instanceof Date) {
|
|
35188
|
+
return left.getTime() === right.getTime();
|
|
35189
|
+
}
|
|
35190
|
+
if (left instanceof Map || left instanceof Set || left instanceof RegExp || left instanceof ArrayBuffer || ArrayBuffer.isView(left)) {
|
|
35113
35191
|
return false;
|
|
35114
35192
|
}
|
|
35115
35193
|
const leftObject = left;
|
|
@@ -36661,12 +36739,26 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36661
36739
|
this.addChild(this._createStrokeMesh(data));
|
|
36662
36740
|
return this;
|
|
36663
36741
|
}
|
|
36742
|
+
/**
|
|
36743
|
+
* Stroke a shape's perimeter. Shape builders return their outline OPEN
|
|
36744
|
+
* (first point not repeated), but `buildPath` only closes a path whose
|
|
36745
|
+
* first and last points coincide — so the closing segment (e.g. a
|
|
36746
|
+
* rectangle's left edge) went missing. Repeat the first point here.
|
|
36747
|
+
*/
|
|
36748
|
+
_strokeClosedOutline(points) {
|
|
36749
|
+
if (points.length >= 4) {
|
|
36750
|
+
this.drawPath([...points, points[0], points[1]]);
|
|
36751
|
+
}
|
|
36752
|
+
else {
|
|
36753
|
+
this.drawPath(points);
|
|
36754
|
+
}
|
|
36755
|
+
}
|
|
36664
36756
|
/** Fill a closed polygon defined by `[x0,y0, x1,y1, ...]` and optionally stroke its outline. */
|
|
36665
36757
|
drawPolygon(path) {
|
|
36666
36758
|
const data = buildPolygon(path);
|
|
36667
36759
|
this._appendFill(data);
|
|
36668
36760
|
if (this._lineWidth > 0) {
|
|
36669
|
-
this.
|
|
36761
|
+
this._strokeClosedOutline(data.points);
|
|
36670
36762
|
}
|
|
36671
36763
|
return this;
|
|
36672
36764
|
}
|
|
@@ -36675,7 +36767,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36675
36767
|
const data = buildCircle(centerX, centerY, radius);
|
|
36676
36768
|
this._appendFill(data);
|
|
36677
36769
|
if (this._lineWidth > 0) {
|
|
36678
|
-
this.
|
|
36770
|
+
this._strokeClosedOutline(data.points);
|
|
36679
36771
|
}
|
|
36680
36772
|
return this;
|
|
36681
36773
|
}
|
|
@@ -36684,7 +36776,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36684
36776
|
const data = buildEllipse(centerX, centerY, radiusX, radiusY);
|
|
36685
36777
|
this._appendFill(data);
|
|
36686
36778
|
if (this._lineWidth > 0) {
|
|
36687
|
-
this.
|
|
36779
|
+
this._strokeClosedOutline(data.points);
|
|
36688
36780
|
}
|
|
36689
36781
|
return this;
|
|
36690
36782
|
}
|
|
@@ -36693,7 +36785,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36693
36785
|
const data = buildRectangle(x, y, width, height);
|
|
36694
36786
|
this._appendFill(data);
|
|
36695
36787
|
if (this._lineWidth > 0) {
|
|
36696
|
-
this.
|
|
36788
|
+
this._strokeClosedOutline(data.points);
|
|
36697
36789
|
}
|
|
36698
36790
|
return this;
|
|
36699
36791
|
}
|
|
@@ -36706,7 +36798,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36706
36798
|
const data = buildRoundedRectangle(x, y, width, height, radius);
|
|
36707
36799
|
this._appendFill(data);
|
|
36708
36800
|
if (this._lineWidth > 0) {
|
|
36709
|
-
this.
|
|
36801
|
+
this._strokeClosedOutline(data.points);
|
|
36710
36802
|
}
|
|
36711
36803
|
return this;
|
|
36712
36804
|
}
|
|
@@ -36718,7 +36810,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36718
36810
|
const data = buildStar(centerX, centerY, points, radius, innerRadius, rotation);
|
|
36719
36811
|
this._appendFill(data);
|
|
36720
36812
|
if (this._lineWidth > 0) {
|
|
36721
|
-
this.
|
|
36813
|
+
this._strokeClosedOutline(data.points);
|
|
36722
36814
|
}
|
|
36723
36815
|
return this;
|
|
36724
36816
|
}
|
|
@@ -36885,6 +36977,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
36885
36977
|
_clips = new Map();
|
|
36886
36978
|
_currentClipName = null;
|
|
36887
36979
|
_currentFrameIndex = 0;
|
|
36980
|
+
_hasAppliedFrame = false;
|
|
36888
36981
|
_playing = false;
|
|
36889
36982
|
_repeatOverride = null;
|
|
36890
36983
|
_elapsedFrameTimeMs = 0;
|
|
@@ -37165,7 +37258,23 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
37165
37258
|
*/
|
|
37166
37259
|
_applyFrame(clip, frameIndex) {
|
|
37167
37260
|
// In-bounds by every call site's own guard.
|
|
37168
|
-
this.
|
|
37261
|
+
if (this._hasAppliedFrame) {
|
|
37262
|
+
// Frame-to-frame advance: keep the current pixel size so differently
|
|
37263
|
+
// sized frames don't visibly pop.
|
|
37264
|
+
this.setTextureFrame(clip.frames[frameIndex], false);
|
|
37265
|
+
}
|
|
37266
|
+
else {
|
|
37267
|
+
// First application: the sprite still shows the full source texture
|
|
37268
|
+
// (usually the whole atlas), so "keep the pixel size" would inflate the
|
|
37269
|
+
// scale by atlasSize/frameSize and the sprite would render blown up far
|
|
37270
|
+
// beyond the canvas. Snap the logical size to the frame instead — while
|
|
37271
|
+
// preserving the user's scale, which `resetSize` would reset to 1.
|
|
37272
|
+
const scaleX = this.scale.x;
|
|
37273
|
+
const scaleY = this.scale.y;
|
|
37274
|
+
this.setTextureFrame(clip.frames[frameIndex], true);
|
|
37275
|
+
this.scale.set(scaleX, scaleY);
|
|
37276
|
+
this._hasAppliedFrame = true;
|
|
37277
|
+
}
|
|
37169
37278
|
const offset = clip.frameOffsets?.[frameIndex];
|
|
37170
37279
|
if (offset) {
|
|
37171
37280
|
this.getLocalBounds().setPosition(offset.x, offset.y);
|
|
@@ -39574,6 +39683,8 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
39574
39683
|
gamepadSlotStrategy: inputOptions.gamepadSlotStrategy ?? defaultInputSettings.gamepadSlotStrategy,
|
|
39575
39684
|
pointerDistanceThreshold: inputOptions.pointerDistanceThreshold ?? defaultInputSettings.pointerDistanceThreshold,
|
|
39576
39685
|
},
|
|
39686
|
+
...(appSettings.seed !== undefined && { seed: appSettings.seed }),
|
|
39687
|
+
...(appSettings.fixedTimeStep !== undefined && { fixedTimeStep: appSettings.fixedTimeStep }),
|
|
39577
39688
|
};
|
|
39578
39689
|
// Capture extension snapshot before constructing extension-sensitive subsystems.
|
|
39579
39690
|
this._snapshot = appSettings.extensions === undefined ? getGlobalSnapshotInternal() : buildSnapshot([...(appSettings.extensions ?? [])]);
|
|
@@ -40139,8 +40250,8 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
40139
40250
|
}
|
|
40140
40251
|
|
|
40141
40252
|
const buildInfo = Object.freeze({
|
|
40142
|
-
version: "0.15.
|
|
40143
|
-
revision: "
|
|
40253
|
+
version: "0.15.2",
|
|
40254
|
+
revision: "e3df957",
|
|
40144
40255
|
development: false,
|
|
40145
40256
|
});
|
|
40146
40257
|
|