@peekling/runtime 0.1.0 → 0.1.1
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/README.md +59 -8
- package/dist/canvas-renderer.d.ts +17 -0
- package/dist/canvas-renderer.d.ts.map +1 -0
- package/dist/canvas-renderer.js +192 -0
- package/dist/canvas.d.ts +5 -0
- package/dist/canvas.d.ts.map +1 -0
- package/dist/canvas.js +6 -0
- package/dist/configuration-validation.d.ts.map +1 -1
- package/dist/configuration-validation.js +176 -1
- package/dist/content.d.ts +3 -0
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +33 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +4 -1
- package/dist/interaction.d.ts +37 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +207 -0
- package/dist/overrides.d.ts +8 -0
- package/dist/overrides.d.ts.map +1 -1
- package/dist/overrides.js +18 -16
- package/dist/path-sampler.d.ts +9 -0
- package/dist/path-sampler.d.ts.map +1 -0
- package/dist/path-sampler.js +47 -0
- package/dist/peekling.css +1 -1
- package/dist/peekling.css.sri +1 -1
- package/dist/peekling.js +1368 -86
- package/dist/peekling.js.sri +1 -1
- package/dist/peekling.min.js +1 -1
- package/dist/peekling.min.js.sri +1 -1
- package/dist/plan-compiler.d.ts +2 -0
- package/dist/plan-compiler.d.ts.map +1 -1
- package/dist/plan-compiler.js +71 -14
- package/dist/plan.d.ts +27 -1
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +281 -22
- package/dist/registry.js +2 -2
- package/dist/renderer.d.ts +18 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +1 -0
- package/dist/runtime-validation.d.ts.map +1 -1
- package/dist/runtime-validation.js +35 -0
- package/dist/runtime.d.ts +49 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +365 -14
- package/dist/targets.d.ts +11 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +106 -0
- package/dist/types.d.ts +61 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
package/dist/peekling.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @peekling/runtime 0.1.
|
|
1
|
+
/*! @peekling/runtime 0.1.1 | Copyright 2026 Prajwal S. Venkateshmurthy | Apache-2.0 */
|
|
2
2
|
"use strict";
|
|
3
3
|
(() => {
|
|
4
4
|
// packages/runtime/src/runtime-diagnostics.ts
|
|
@@ -748,6 +748,8 @@
|
|
|
748
748
|
#name;
|
|
749
749
|
#nameSelection;
|
|
750
750
|
#nameItem;
|
|
751
|
+
#userHidden = false;
|
|
752
|
+
#hasVisibleSurface = false;
|
|
751
753
|
#destroyed = false;
|
|
752
754
|
constructor(document, options = {}) {
|
|
753
755
|
this.#document = document;
|
|
@@ -819,6 +821,16 @@
|
|
|
819
821
|
if (surface.seen !== generation) this.#removeSurface(surface);
|
|
820
822
|
if (this.#destroyed) return;
|
|
821
823
|
}
|
|
824
|
+
let visible = false;
|
|
825
|
+
for (const surface of this.#surfaces.values()) {
|
|
826
|
+
if (!surface.host.hidden) {
|
|
827
|
+
visible = true;
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
this.#hasVisibleSurface = visible;
|
|
832
|
+
const hidden = this.#userHidden || !visible;
|
|
833
|
+
if (this.#host.hidden !== hidden) this.#host.hidden = hidden;
|
|
822
834
|
const viewportChanged = viewport.width !== this.#viewportWidth || viewport.height !== this.#viewportHeight;
|
|
823
835
|
const placementChanged = viewportChanged || position.x !== this.#positionX || position.y !== this.#positionY || character.width !== this.#characterWidth || character.height !== this.#characterHeight;
|
|
824
836
|
this.#positionX = position.x;
|
|
@@ -900,14 +912,26 @@
|
|
|
900
912
|
}
|
|
901
913
|
this.#placementDirty = false;
|
|
902
914
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
915
|
+
}
|
|
916
|
+
setUserHidden(hidden) {
|
|
917
|
+
if (this.#destroyed) return false;
|
|
918
|
+
const wasHidden = this.#userHidden;
|
|
919
|
+
this.#userHidden = hidden;
|
|
920
|
+
this.#host.hidden = hidden || !this.#hasVisibleSurface;
|
|
921
|
+
if (wasHidden && !hidden && !this.#host.hidden) {
|
|
922
|
+
for (const surface of this.#surfaces.values()) {
|
|
923
|
+
if (!surface.host.hidden) surface.measureDirty = true;
|
|
908
924
|
}
|
|
925
|
+
this.#placementDirty = true;
|
|
926
|
+
this.#wake();
|
|
909
927
|
}
|
|
910
|
-
|
|
928
|
+
return !this.#userHidden;
|
|
929
|
+
}
|
|
930
|
+
toggleUserHidden() {
|
|
931
|
+
return this.setUserHidden(!this.#userHidden);
|
|
932
|
+
}
|
|
933
|
+
get userHidden() {
|
|
934
|
+
return this.#userHidden;
|
|
911
935
|
}
|
|
912
936
|
#select(selection, item, generation) {
|
|
913
937
|
for (const region of CONTENT_REGIONS) {
|
|
@@ -1460,11 +1484,10 @@
|
|
|
1460
1484
|
true
|
|
1461
1485
|
);
|
|
1462
1486
|
} else if (event === "window.scroll") {
|
|
1463
|
-
listen(
|
|
1464
|
-
this.#
|
|
1465
|
-
"scroll",
|
|
1466
|
-
|
|
1467
|
-
);
|
|
1487
|
+
listen(this.#window, "scroll", (input) => {
|
|
1488
|
+
this.#clearPointer();
|
|
1489
|
+
this.#captureObserved("window.scroll", input);
|
|
1490
|
+
});
|
|
1468
1491
|
} else if (event === "window.focus") {
|
|
1469
1492
|
listen(
|
|
1470
1493
|
this.#window,
|
|
@@ -1531,6 +1554,211 @@
|
|
|
1531
1554
|
return incoming[policy.sessionField] === prior[policy.sessionField] && Number.isSafeInteger(incoming[policy.revisionField]) && Number.isSafeInteger(prior[policy.revisionField]) && incoming[policy.revisionField] > prior[policy.revisionField];
|
|
1532
1555
|
}
|
|
1533
1556
|
|
|
1557
|
+
// packages/runtime/src/interaction.ts
|
|
1558
|
+
var CharacterInteractionController = class {
|
|
1559
|
+
ready;
|
|
1560
|
+
#document;
|
|
1561
|
+
#host;
|
|
1562
|
+
#root;
|
|
1563
|
+
#button;
|
|
1564
|
+
#badge;
|
|
1565
|
+
#styles;
|
|
1566
|
+
#options;
|
|
1567
|
+
#buttonRule;
|
|
1568
|
+
#badgeRule;
|
|
1569
|
+
#indicator;
|
|
1570
|
+
#label;
|
|
1571
|
+
#position = { x: 0, y: 0 };
|
|
1572
|
+
#pointerId;
|
|
1573
|
+
#startPointer = { x: 0, y: 0 };
|
|
1574
|
+
#lastPointer = { x: 0, y: 0 };
|
|
1575
|
+
#startPosition = { x: 0, y: 0 };
|
|
1576
|
+
#velocity = { x: 0, y: 0 };
|
|
1577
|
+
#lastTime = 0;
|
|
1578
|
+
#moved = false;
|
|
1579
|
+
#suppressClick = false;
|
|
1580
|
+
#destroyed = false;
|
|
1581
|
+
constructor(options) {
|
|
1582
|
+
this.#options = options;
|
|
1583
|
+
this.#document = options.document;
|
|
1584
|
+
this.#label = options.label;
|
|
1585
|
+
this.#host = options.document.createElement("div");
|
|
1586
|
+
this.#host.setAttribute("data-peekling-interaction", "");
|
|
1587
|
+
this.#root = this.#host.attachShadow({ mode: "closed" });
|
|
1588
|
+
this.#styles = new ShadowStyleSheet(
|
|
1589
|
+
options.document,
|
|
1590
|
+
this.#root,
|
|
1591
|
+
options.styles
|
|
1592
|
+
);
|
|
1593
|
+
this.#button = options.document.createElement("button");
|
|
1594
|
+
this.#button.type = "button";
|
|
1595
|
+
this.#button.className = "peekling-character-hit";
|
|
1596
|
+
this.#button.setAttribute("aria-label", options.label);
|
|
1597
|
+
if (options.expanded !== void 0) {
|
|
1598
|
+
this.#button.setAttribute("aria-expanded", String(options.expanded));
|
|
1599
|
+
}
|
|
1600
|
+
this.#button.toggleAttribute("data-peekling-draggable", options.draggable);
|
|
1601
|
+
this.#badge = options.document.createElement("span");
|
|
1602
|
+
this.#badge.className = "peekling-character-indicator";
|
|
1603
|
+
this.#badge.setAttribute("aria-hidden", "true");
|
|
1604
|
+
this.#button.append(this.#badge);
|
|
1605
|
+
this.#root.append(this.#button);
|
|
1606
|
+
this.ready = this.#styles.ready.then(() => {
|
|
1607
|
+
if (this.#destroyed) return;
|
|
1608
|
+
this.#buttonRule = this.#styles.addRule(".peekling-character-hit");
|
|
1609
|
+
this.#badgeRule = this.#styles.addRule(".peekling-character-indicator");
|
|
1610
|
+
this.#syncIndicatorColor();
|
|
1611
|
+
});
|
|
1612
|
+
void this.ready.catch(() => {
|
|
1613
|
+
});
|
|
1614
|
+
this.#button.addEventListener("click", this.#click);
|
|
1615
|
+
if (options.draggable) {
|
|
1616
|
+
this.#button.addEventListener("pointerdown", this.#pointerDown);
|
|
1617
|
+
this.#button.addEventListener("pointermove", this.#pointerMove);
|
|
1618
|
+
this.#button.addEventListener("pointerup", this.#pointerUp);
|
|
1619
|
+
this.#button.addEventListener("pointercancel", this.#pointerCancel);
|
|
1620
|
+
}
|
|
1621
|
+
this.updateIndicator(options.indicator);
|
|
1622
|
+
this.#repair();
|
|
1623
|
+
}
|
|
1624
|
+
render(position, character, lift = 0) {
|
|
1625
|
+
if (this.#destroyed) return;
|
|
1626
|
+
this.#repair();
|
|
1627
|
+
this.#position = { x: position.x, y: position.y - lift };
|
|
1628
|
+
const rule = this.#buttonRule;
|
|
1629
|
+
if (!rule) return;
|
|
1630
|
+
const left = position.x - character.width / 2;
|
|
1631
|
+
const top = position.y - character.height / 2 - lift;
|
|
1632
|
+
rule.width = `${character.width}px`;
|
|
1633
|
+
rule.height = `${character.height}px`;
|
|
1634
|
+
rule.transform = `translate3d(${left}px,${top}px,0)`;
|
|
1635
|
+
}
|
|
1636
|
+
setHidden(hidden) {
|
|
1637
|
+
if (!this.#destroyed) this.#host.toggleAttribute("hidden", hidden);
|
|
1638
|
+
}
|
|
1639
|
+
setExpanded(expanded) {
|
|
1640
|
+
if (!this.#destroyed && this.#button.hasAttribute("aria-expanded")) {
|
|
1641
|
+
this.#button.setAttribute("aria-expanded", String(expanded));
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
updateIndicator(indicator) {
|
|
1645
|
+
if (this.#destroyed) return;
|
|
1646
|
+
this.#indicator = indicator ?? void 0;
|
|
1647
|
+
this.#syncIndicatorColor();
|
|
1648
|
+
const visible = Boolean(
|
|
1649
|
+
indicator && indicator.visible !== false && (indicator.kind !== "count" || (indicator.count ?? 0) > 0)
|
|
1650
|
+
);
|
|
1651
|
+
this.#badge.hidden = !visible;
|
|
1652
|
+
if (!visible || !indicator) {
|
|
1653
|
+
this.#badge.textContent = "";
|
|
1654
|
+
this.#button.setAttribute("aria-label", this.#label);
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const kind = indicator.kind ?? "dot";
|
|
1658
|
+
this.#badge.dataset.kind = kind;
|
|
1659
|
+
this.#badge.textContent = kind === "count" ? String(Math.min(99, indicator.count ?? 0)) : "";
|
|
1660
|
+
this.#button.setAttribute(
|
|
1661
|
+
"aria-label",
|
|
1662
|
+
`${this.#label}. ${indicator.label}`
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
#syncIndicatorColor() {
|
|
1666
|
+
if (this.#badgeRule) {
|
|
1667
|
+
this.#badgeRule.backgroundColor = this.#indicator?.color ?? "";
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
destroy() {
|
|
1671
|
+
if (this.#destroyed) return;
|
|
1672
|
+
this.#destroyed = true;
|
|
1673
|
+
this.#styles.destroy();
|
|
1674
|
+
this.#host.remove();
|
|
1675
|
+
}
|
|
1676
|
+
#click = () => {
|
|
1677
|
+
if (this.#suppressClick) {
|
|
1678
|
+
this.#suppressClick = false;
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
this.#options.onPress();
|
|
1682
|
+
};
|
|
1683
|
+
#pointerDown = (event) => {
|
|
1684
|
+
if (this.#destroyed || this.#pointerId !== void 0 || !event.isPrimary && event.pointerType !== "mouse" || event.pointerType === "mouse" && event.button !== 0) {
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
this.#pointerId = event.pointerId;
|
|
1688
|
+
this.#startPointer = { x: event.clientX, y: event.clientY };
|
|
1689
|
+
this.#lastPointer = { ...this.#startPointer };
|
|
1690
|
+
this.#startPosition = { ...this.#position };
|
|
1691
|
+
this.#velocity = { x: 0, y: 0 };
|
|
1692
|
+
this.#lastTime = event.timeStamp;
|
|
1693
|
+
this.#moved = false;
|
|
1694
|
+
try {
|
|
1695
|
+
this.#button.setPointerCapture(event.pointerId);
|
|
1696
|
+
} catch {
|
|
1697
|
+
}
|
|
1698
|
+
this.#options.onDragStart();
|
|
1699
|
+
};
|
|
1700
|
+
#pointerMove = (event) => {
|
|
1701
|
+
if (event.pointerId !== this.#pointerId) return;
|
|
1702
|
+
const dx = event.clientX - this.#startPointer.x;
|
|
1703
|
+
const dy = event.clientY - this.#startPointer.y;
|
|
1704
|
+
if (!this.#moved && Math.hypot(dx, dy) >= 4) this.#moved = true;
|
|
1705
|
+
const elapsed = Math.max(
|
|
1706
|
+
8,
|
|
1707
|
+
Math.min(100, event.timeStamp - this.#lastTime)
|
|
1708
|
+
);
|
|
1709
|
+
const sampleX = (event.clientX - this.#lastPointer.x) * 1e3 / elapsed;
|
|
1710
|
+
const sampleY = (event.clientY - this.#lastPointer.y) * 1e3 / elapsed;
|
|
1711
|
+
this.#velocity = {
|
|
1712
|
+
x: sampleX * 0.65 + this.#velocity.x * 0.35,
|
|
1713
|
+
y: sampleY * 0.65 + this.#velocity.y * 0.35
|
|
1714
|
+
};
|
|
1715
|
+
this.#lastPointer = { x: event.clientX, y: event.clientY };
|
|
1716
|
+
this.#lastTime = event.timeStamp;
|
|
1717
|
+
this.#options.onDragMove(
|
|
1718
|
+
{
|
|
1719
|
+
x: this.#startPosition.x + dx,
|
|
1720
|
+
y: this.#startPosition.y + dy
|
|
1721
|
+
},
|
|
1722
|
+
this.#velocity
|
|
1723
|
+
);
|
|
1724
|
+
};
|
|
1725
|
+
#pointerUp = (event) => {
|
|
1726
|
+
if (event.pointerId !== this.#pointerId) return;
|
|
1727
|
+
this.#finishPointer(event, this.#moved, this.#velocity);
|
|
1728
|
+
};
|
|
1729
|
+
#pointerCancel = (event) => {
|
|
1730
|
+
if (event.pointerId !== this.#pointerId) return;
|
|
1731
|
+
this.#finishPointer(event, false, { x: 0, y: 0 });
|
|
1732
|
+
};
|
|
1733
|
+
#finishPointer(event, moved, velocity) {
|
|
1734
|
+
const pointerId = this.#pointerId;
|
|
1735
|
+
this.#pointerId = void 0;
|
|
1736
|
+
if (pointerId !== void 0) {
|
|
1737
|
+
try {
|
|
1738
|
+
this.#button.releasePointerCapture(pointerId);
|
|
1739
|
+
} catch {
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
this.#suppressClick = moved;
|
|
1743
|
+
this.#options.onDragEnd(velocity, moved, {
|
|
1744
|
+
x: event.clientX,
|
|
1745
|
+
y: event.clientY
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
#repair() {
|
|
1749
|
+
if (this.#destroyed) return;
|
|
1750
|
+
connectRuntimeHost(this.#host, this.#document, "data-peekling-interaction");
|
|
1751
|
+
if (this.#root.host !== this.#host || this.#button.getRootNode() !== this.#root) {
|
|
1752
|
+
throw new Error(
|
|
1753
|
+
runtimeMessage(
|
|
1754
|
+
"interaction.root",
|
|
1755
|
+
"Peekling interaction root structure was changed"
|
|
1756
|
+
)
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
|
|
1534
1762
|
// packages/runtime/src/direction.ts
|
|
1535
1763
|
var OCTANTS = ["E", "SE", "S", "SW", "W", "NW", "N", "NE"];
|
|
1536
1764
|
function directionTo(from, to) {
|
|
@@ -2949,8 +3177,8 @@
|
|
|
2949
3177
|
}
|
|
2950
3178
|
|
|
2951
3179
|
// packages/runtime/src/registry.ts
|
|
2952
|
-
var PEEK_REFERENCE_URL = true ? "https://cdn.jsdelivr.net/npm/@peekling/pack-peek@0.1.
|
|
2953
|
-
var PEEK_REFERENCE_SHA256 = true ? "
|
|
3180
|
+
var PEEK_REFERENCE_URL = true ? "https://cdn.jsdelivr.net/npm/@peekling/pack-peek@0.1.1/character.json" : "https://cdn.jsdelivr.net/npm/@peekling/pack-peek@0.1.1/character.json";
|
|
3181
|
+
var PEEK_REFERENCE_SHA256 = true ? "9a2e2a41e85f7c4b8d3487a3655db40872675bd9c0780e139a946eabdf71d75f" : "9a2e2a41e85f7c4b8d3487a3655db40872675bd9c0780e139a946eabdf71d75f";
|
|
2954
3182
|
var REGISTRY = {
|
|
2955
3183
|
peek: Object.freeze({
|
|
2956
3184
|
url: PEEK_REFERENCE_URL,
|
|
@@ -3840,7 +4068,7 @@
|
|
|
3840
4068
|
);
|
|
3841
4069
|
}
|
|
3842
4070
|
const state = input.state === void 0 ? void 0 : compileState(input.state, `${path}.state`, context);
|
|
3843
|
-
const motion = input.motion === void 0 ? void 0 : compileMotion(input.motion, `${path}.motion
|
|
4071
|
+
const motion = input.motion === void 0 ? void 0 : compileMotion(input.motion, `${path}.motion`, context);
|
|
3844
4072
|
const surfaces = input.surfaces === void 0 ? [] : input.surfaces;
|
|
3845
4073
|
if (!Array.isArray(surfaces) || surfaces.length > SURFACE_LIMIT) {
|
|
3846
4074
|
fail(
|
|
@@ -4010,19 +4238,81 @@
|
|
|
4010
4238
|
}
|
|
4011
4239
|
return freeze({ kind: "capability", name: input.capability });
|
|
4012
4240
|
}
|
|
4013
|
-
function compileMotion(input, path) {
|
|
4241
|
+
function compileMotion(input, path, context) {
|
|
4014
4242
|
object(input, path);
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4243
|
+
switch (input.type) {
|
|
4244
|
+
case "follow-pointer":
|
|
4245
|
+
closed3(input, ["type", "speed", "arrivalRadius"], path);
|
|
4246
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4247
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4248
|
+
break;
|
|
4249
|
+
case "horizontal-patrol":
|
|
4250
|
+
closed3(input, ["type", "speed", "edgeInset"], path);
|
|
4251
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4252
|
+
bounded(input.edgeInset, `${path}.edgeInset`, 0, 1e3);
|
|
4253
|
+
break;
|
|
4254
|
+
case "viewport-traverse":
|
|
4255
|
+
closed3(input, ["type", "speed", "edgeInset", "clockwise"], path);
|
|
4256
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4257
|
+
bounded(input.edgeInset, `${path}.edgeInset`, 0, 1e3);
|
|
4258
|
+
if (input.clockwise !== void 0 && typeof input.clockwise !== "boolean") {
|
|
4259
|
+
fail("invalid-motion", `${path}.clockwise`, "must be boolean");
|
|
4260
|
+
}
|
|
4261
|
+
break;
|
|
4262
|
+
case "move-to":
|
|
4263
|
+
closed3(input, ["type", "x", "y", "speed", "arrivalRadius"], path);
|
|
4264
|
+
bounded(input.x, `${path}.x`, -1e5, 1e5);
|
|
4265
|
+
bounded(input.y, `${path}.y`, -1e5, 1e5);
|
|
4266
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4267
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4268
|
+
break;
|
|
4269
|
+
case "move-to-target":
|
|
4270
|
+
closed3(
|
|
4271
|
+
input,
|
|
4272
|
+
["type", "target", "anchor", "speed", "arrivalRadius"],
|
|
4273
|
+
path
|
|
4274
|
+
);
|
|
4275
|
+
id(input.target, `${path}.target`, "Target");
|
|
4276
|
+
if (context.targets && !context.targets.has(input.target)) {
|
|
4277
|
+
fail(
|
|
4278
|
+
"unknown-target",
|
|
4279
|
+
`${path}.target`,
|
|
4280
|
+
`references unknown target ${input.target}`
|
|
4281
|
+
);
|
|
4282
|
+
}
|
|
4283
|
+
if (input.anchor !== void 0 && !["center", "top", "right", "bottom", "left"].includes(input.anchor)) {
|
|
4284
|
+
fail("invalid-motion", `${path}.anchor`, "is not supported");
|
|
4285
|
+
}
|
|
4286
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4287
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4288
|
+
break;
|
|
4289
|
+
case "jump-to":
|
|
4290
|
+
closed3(input, ["type", "x", "y", "duration", "height"], path);
|
|
4291
|
+
bounded(input.x, `${path}.x`, -1e5, 1e5);
|
|
4292
|
+
bounded(input.y, `${path}.y`, -1e5, 1e5);
|
|
4293
|
+
bounded(input.duration, `${path}.duration`, 100, 1e4);
|
|
4294
|
+
bounded(input.height, `${path}.height`, 0, 2e3);
|
|
4295
|
+
break;
|
|
4296
|
+
case "svg-path": {
|
|
4297
|
+
closed3(input, ["type", "path", "duration", "loop", "relative"], path);
|
|
4298
|
+
if (typeof input.path !== "string" || input.path.length < 1 || input.path.length > 4096 || /[\0\r\n]/.test(input.path)) {
|
|
4299
|
+
fail("invalid-path", `${path}.path`, "must be bounded SVG path data");
|
|
4300
|
+
}
|
|
4301
|
+
if (context.validatePath && !context.validatePath(input.path)) {
|
|
4302
|
+
fail("invalid-path", `${path}.path`, "must be valid SVG path data");
|
|
4303
|
+
}
|
|
4304
|
+
bounded(input.duration, `${path}.duration`, 100, 6e4);
|
|
4305
|
+
for (const field of ["loop", "relative"]) {
|
|
4306
|
+
if (input[field] !== void 0 && typeof input[field] !== "boolean") {
|
|
4307
|
+
fail("invalid-motion", `${path}.${field}`, "must be boolean");
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
break;
|
|
4311
|
+
}
|
|
4312
|
+
default:
|
|
4313
|
+
fail("invalid-motion", `${path}.type`, "is not a supported motion type");
|
|
4018
4314
|
}
|
|
4019
|
-
|
|
4020
|
-
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4021
|
-
return freeze({
|
|
4022
|
-
type: "follow-pointer",
|
|
4023
|
-
...input.speed === void 0 ? {} : { speed: input.speed },
|
|
4024
|
-
...input.arrivalRadius === void 0 ? {} : { arrivalRadius: input.arrivalRadius }
|
|
4025
|
-
});
|
|
4315
|
+
return freeze({ ...input });
|
|
4026
4316
|
}
|
|
4027
4317
|
function compileSurface(input, path, context, allowPayload) {
|
|
4028
4318
|
object(input, path);
|
|
@@ -4363,7 +4653,25 @@
|
|
|
4363
4653
|
thresholds: [...thresholds].sort((left, right) => left - right)
|
|
4364
4654
|
};
|
|
4365
4655
|
}
|
|
4366
|
-
function
|
|
4656
|
+
function createPresetPlan(preset, locomotion) {
|
|
4657
|
+
const state = locomotion ? { capability: "locomotion" } : { state: "idle" };
|
|
4658
|
+
if (preset === "still") {
|
|
4659
|
+
return {
|
|
4660
|
+
baseline: {
|
|
4661
|
+
channels: ["state"],
|
|
4662
|
+
state: { state: "idle" }
|
|
4663
|
+
}
|
|
4664
|
+
};
|
|
4665
|
+
}
|
|
4666
|
+
if (preset === "bottom-patrol" || preset === "viewport-roam") {
|
|
4667
|
+
return {
|
|
4668
|
+
baseline: {
|
|
4669
|
+
channels: ["motion", "state"],
|
|
4670
|
+
state,
|
|
4671
|
+
motion: preset === "bottom-patrol" ? { type: "horizontal-patrol", speed: DEFAULT_SPEED } : { type: "viewport-traverse", speed: DEFAULT_SPEED }
|
|
4672
|
+
}
|
|
4673
|
+
};
|
|
4674
|
+
}
|
|
4367
4675
|
return {
|
|
4368
4676
|
baseline: {
|
|
4369
4677
|
channels: ["state"],
|
|
@@ -4389,6 +4697,12 @@
|
|
|
4389
4697
|
#eventState = createPlanEventState();
|
|
4390
4698
|
#activeChannels = /* @__PURE__ */ new Map();
|
|
4391
4699
|
#activeSurfaces = /* @__PURE__ */ new Map();
|
|
4700
|
+
#patrolDirections = /* @__PURE__ */ new WeakMap();
|
|
4701
|
+
#traversePhases = /* @__PURE__ */ new WeakMap();
|
|
4702
|
+
#jumpOwner;
|
|
4703
|
+
#jumpState;
|
|
4704
|
+
#pathOwner;
|
|
4705
|
+
#pathState;
|
|
4392
4706
|
#activeInterrupts = [];
|
|
4393
4707
|
#surfaceVersion = 0;
|
|
4394
4708
|
#lastEventStatus;
|
|
@@ -4476,24 +4790,81 @@
|
|
|
4476
4790
|
if (state?.kind === "capability") {
|
|
4477
4791
|
output.capability = state.name;
|
|
4478
4792
|
}
|
|
4479
|
-
const
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
const
|
|
4485
|
-
if (
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4793
|
+
const motionOwner = channels.get("motion");
|
|
4794
|
+
const motion = motionOwner?.motion;
|
|
4795
|
+
const settleCapability = () => {
|
|
4796
|
+
if (output.capability !== "locomotion") return;
|
|
4797
|
+
delete output.capability;
|
|
4798
|
+
const baseline = this.#baselineState();
|
|
4799
|
+
if (!output.state && baseline) output.state = baseline;
|
|
4800
|
+
};
|
|
4801
|
+
if (motion?.type !== "jump-to") {
|
|
4802
|
+
this.#jumpOwner = void 0;
|
|
4803
|
+
this.#jumpState = void 0;
|
|
4804
|
+
}
|
|
4805
|
+
if (motion?.type !== "svg-path") {
|
|
4806
|
+
this.#pathOwner = void 0;
|
|
4807
|
+
this.#pathState = void 0;
|
|
4808
|
+
}
|
|
4809
|
+
if (motion?.type === "horizontal-patrol" && world.characterSize) {
|
|
4810
|
+
const [direction, request] = evaluateHorizontalPatrol(
|
|
4811
|
+
motion,
|
|
4812
|
+
world,
|
|
4813
|
+
this.#patrolDirections.get(motionOwner) ?? true
|
|
4814
|
+
);
|
|
4815
|
+
this.#patrolDirections.set(motionOwner, direction);
|
|
4816
|
+
if (request) output.motion = request;
|
|
4817
|
+
} else if (motion?.type === "viewport-traverse" && world.characterSize) {
|
|
4818
|
+
const [phase, request] = evaluateViewportTraverse(
|
|
4819
|
+
motion,
|
|
4820
|
+
world,
|
|
4821
|
+
this.#traversePhases.get(motionOwner)
|
|
4822
|
+
);
|
|
4823
|
+
this.#traversePhases.set(motionOwner, phase);
|
|
4824
|
+
if (request) output.motion = request;
|
|
4825
|
+
} else if (motion?.type === "follow-pointer") {
|
|
4826
|
+
const request = world.pointer ? motionToward(
|
|
4827
|
+
motion,
|
|
4828
|
+
world.position,
|
|
4829
|
+
world.pointer.x,
|
|
4830
|
+
world.pointer.y,
|
|
4831
|
+
motion.arrivalRadius,
|
|
4832
|
+
world
|
|
4833
|
+
) : void 0;
|
|
4834
|
+
if (request) output.motion = request;
|
|
4835
|
+
else settleCapability();
|
|
4836
|
+
} else if (motion?.type === "move-to") {
|
|
4837
|
+
const request = motionToward(
|
|
4838
|
+
motion,
|
|
4839
|
+
world.position,
|
|
4840
|
+
motion.x,
|
|
4841
|
+
motion.y,
|
|
4842
|
+
motion.arrivalRadius,
|
|
4843
|
+
world
|
|
4844
|
+
);
|
|
4845
|
+
if (request) output.motion = request;
|
|
4846
|
+
else settleCapability();
|
|
4847
|
+
} else if (motion?.type === "move-to-target") {
|
|
4848
|
+
const target = world.targets?.[motion.target];
|
|
4849
|
+
const point = target && world.characterSize ? targetPoint(target, motion.anchor, world.characterSize) : void 0;
|
|
4850
|
+
const request = point ? motionToward(
|
|
4851
|
+
motion,
|
|
4852
|
+
world.position,
|
|
4853
|
+
point.x,
|
|
4854
|
+
point.y,
|
|
4855
|
+
motion.arrivalRadius,
|
|
4856
|
+
world
|
|
4857
|
+
) : void 0;
|
|
4858
|
+
if (request) output.motion = { ...request, trackTarget: true };
|
|
4859
|
+
else settleCapability();
|
|
4860
|
+
} else if (motion?.type === "jump-to") {
|
|
4861
|
+
const request = this.#evaluateJump(motionOwner, motion, world);
|
|
4862
|
+
if (request) output.motion = request;
|
|
4863
|
+
else settleCapability();
|
|
4864
|
+
} else if (motion?.type === "svg-path") {
|
|
4865
|
+
const request = this.#evaluatePath(motionOwner, motion, world);
|
|
4866
|
+
if (request) output.motion = request;
|
|
4867
|
+
else settleCapability();
|
|
4497
4868
|
}
|
|
4498
4869
|
const selected = /* @__PURE__ */ new Map();
|
|
4499
4870
|
for (const surface of this.#plan.baseline.surfaces) {
|
|
@@ -4532,6 +4903,12 @@
|
|
|
4532
4903
|
this.#activeChannels.clear();
|
|
4533
4904
|
this.#activeSurfaces.clear();
|
|
4534
4905
|
this.#activeInterrupts = [];
|
|
4906
|
+
this.#patrolDirections = /* @__PURE__ */ new WeakMap();
|
|
4907
|
+
this.#traversePhases = /* @__PURE__ */ new WeakMap();
|
|
4908
|
+
this.#jumpOwner = void 0;
|
|
4909
|
+
this.#jumpState = void 0;
|
|
4910
|
+
this.#pathOwner = void 0;
|
|
4911
|
+
this.#pathState = void 0;
|
|
4535
4912
|
this.#eventState.ordering.clear();
|
|
4536
4913
|
this.#eventState.sessions.clear();
|
|
4537
4914
|
this.#lastEventStatus = void 0;
|
|
@@ -4557,17 +4934,75 @@
|
|
|
4557
4934
|
const state = this.#plan.baseline.state;
|
|
4558
4935
|
return state?.kind === "state" ? state.name : void 0;
|
|
4559
4936
|
}
|
|
4937
|
+
#evaluateJump(owner, effect, world) {
|
|
4938
|
+
if (this.#jumpOwner !== owner || !this.#jumpState) {
|
|
4939
|
+
this.#jumpOwner = owner;
|
|
4940
|
+
this.#jumpState = {
|
|
4941
|
+
startedAt: world.now,
|
|
4942
|
+
from: { ...world.position }
|
|
4943
|
+
};
|
|
4944
|
+
}
|
|
4945
|
+
const duration = effect.duration ?? 800;
|
|
4946
|
+
const progress = Math.max(
|
|
4947
|
+
0,
|
|
4948
|
+
Math.min(1, (world.now - this.#jumpState.startedAt) / duration)
|
|
4949
|
+
);
|
|
4950
|
+
const target = boundedPoint(effect, world);
|
|
4951
|
+
const desired = {
|
|
4952
|
+
x: this.#jumpState.from.x + (target.x - this.#jumpState.from.x) * progress,
|
|
4953
|
+
y: this.#jumpState.from.y + (target.y - this.#jumpState.from.y) * progress
|
|
4954
|
+
};
|
|
4955
|
+
const lift = progress === 0 || progress === 1 ? 0 : Math.sin(Math.PI * progress) * (effect.height ?? world.characterSize?.height ?? 32);
|
|
4956
|
+
const request = directMotion(world.position, desired, lift);
|
|
4957
|
+
if (progress < 1 || request.maxDistance) return request;
|
|
4958
|
+
return;
|
|
4959
|
+
}
|
|
4960
|
+
#evaluatePath(owner, effect, world) {
|
|
4961
|
+
const sample = world.samplePath;
|
|
4962
|
+
if (!sample) return;
|
|
4963
|
+
const first = sample(effect.path, 0);
|
|
4964
|
+
if (!first) return;
|
|
4965
|
+
if (this.#pathOwner !== owner || !this.#pathState) {
|
|
4966
|
+
this.#pathOwner = owner;
|
|
4967
|
+
this.#pathState = {
|
|
4968
|
+
startedAt: world.now,
|
|
4969
|
+
offset: effect.relative === false ? { x: 0, y: 0 } : {
|
|
4970
|
+
x: world.position.x - first.x,
|
|
4971
|
+
y: world.position.y - first.y
|
|
4972
|
+
}
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
const duration = effect.duration ?? 4e3;
|
|
4976
|
+
const elapsed = Math.max(0, world.now - this.#pathState.startedAt);
|
|
4977
|
+
const complete = effect.loop !== true && elapsed >= duration;
|
|
4978
|
+
const progress = effect.loop ? elapsed % duration / duration : Math.min(1, elapsed / duration);
|
|
4979
|
+
const point = sample(effect.path, progress);
|
|
4980
|
+
if (!point) return;
|
|
4981
|
+
const desired = {
|
|
4982
|
+
x: point.x + this.#pathState.offset.x,
|
|
4983
|
+
y: point.y + this.#pathState.offset.y
|
|
4984
|
+
};
|
|
4985
|
+
const request = directMotion(world.position, boundedPoint(desired, world));
|
|
4986
|
+
if (!complete || request.maxDistance) return request;
|
|
4987
|
+
return;
|
|
4988
|
+
}
|
|
4560
4989
|
#isContinuous(rule, world) {
|
|
4561
4990
|
const condition = rule.when;
|
|
4562
4991
|
if (condition.source !== "browser") return false;
|
|
4563
4992
|
if (condition.event === "pointer.move") {
|
|
4564
4993
|
if (!world.pointer) return false;
|
|
4565
4994
|
const motion = rule.effect.motion;
|
|
4566
|
-
if (!motion) return true;
|
|
4567
|
-
return
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4995
|
+
if (!motion || motion.type !== "follow-pointer") return true;
|
|
4996
|
+
return Boolean(
|
|
4997
|
+
motionToward(
|
|
4998
|
+
motion,
|
|
4999
|
+
world.position,
|
|
5000
|
+
world.pointer.x,
|
|
5001
|
+
world.pointer.y,
|
|
5002
|
+
motion.arrivalRadius,
|
|
5003
|
+
world
|
|
5004
|
+
)
|
|
5005
|
+
);
|
|
4571
5006
|
}
|
|
4572
5007
|
if (condition.event !== "section.visibility") return false;
|
|
4573
5008
|
const section = world.sections?.[condition.selector];
|
|
@@ -4610,6 +5045,128 @@
|
|
|
4610
5045
|
function completionSource(name) {
|
|
4611
5046
|
return browserCompletionEvent(name) ? "browser" : "application";
|
|
4612
5047
|
}
|
|
5048
|
+
function evaluateHorizontalPatrol(effect, world, direction) {
|
|
5049
|
+
const halfWidth = world.characterSize.width / 2;
|
|
5050
|
+
const inset = effect.edgeInset ?? 0;
|
|
5051
|
+
const left = Math.min(world.viewport.width / 2, halfWidth + inset);
|
|
5052
|
+
const right = world.viewport.width - left;
|
|
5053
|
+
const halfHeight = world.characterSize.height / 2;
|
|
5054
|
+
const y = Math.max(halfHeight, world.viewport.height - halfHeight);
|
|
5055
|
+
let request = motionToward(
|
|
5056
|
+
effect,
|
|
5057
|
+
world.position,
|
|
5058
|
+
direction ? right : left,
|
|
5059
|
+
y
|
|
5060
|
+
);
|
|
5061
|
+
if (!request) {
|
|
5062
|
+
direction = !direction;
|
|
5063
|
+
request = motionToward(effect, world.position, direction ? right : left, y);
|
|
5064
|
+
}
|
|
5065
|
+
return [direction, request];
|
|
5066
|
+
}
|
|
5067
|
+
function evaluateViewportTraverse(effect, world, phase) {
|
|
5068
|
+
const inset = effect.edgeInset ?? 0;
|
|
5069
|
+
const halfWidth = world.characterSize.width / 2;
|
|
5070
|
+
const halfHeight = world.characterSize.height / 2;
|
|
5071
|
+
const left = Math.min(world.viewport.width / 2, halfWidth + inset);
|
|
5072
|
+
const right = Math.max(left, world.viewport.width - left);
|
|
5073
|
+
const top = Math.min(world.viewport.height / 2, halfHeight + inset);
|
|
5074
|
+
const bottom = Math.max(top, world.viewport.height - halfHeight - inset);
|
|
5075
|
+
const points = [
|
|
5076
|
+
{ x: left, y: bottom },
|
|
5077
|
+
{ x: right, y: bottom },
|
|
5078
|
+
{ x: right, y: top },
|
|
5079
|
+
{ x: left, y: top }
|
|
5080
|
+
];
|
|
5081
|
+
if (phase === void 0) {
|
|
5082
|
+
phase = points.reduce(
|
|
5083
|
+
(nearest, point, index) => Math.hypot(point.x - world.position.x, point.y - world.position.y) < Math.hypot(
|
|
5084
|
+
points[nearest].x - world.position.x,
|
|
5085
|
+
points[nearest].y - world.position.y
|
|
5086
|
+
) ? index : nearest,
|
|
5087
|
+
0
|
|
5088
|
+
);
|
|
5089
|
+
}
|
|
5090
|
+
let target = points[phase];
|
|
5091
|
+
let request = motionToward(effect, world.position, target.x, target.y);
|
|
5092
|
+
if (!request) {
|
|
5093
|
+
const direction = effect.clockwise === false ? -1 : 1;
|
|
5094
|
+
phase = (phase + direction + points.length) % points.length;
|
|
5095
|
+
target = points[phase];
|
|
5096
|
+
request = motionToward(effect, world.position, target.x, target.y);
|
|
5097
|
+
}
|
|
5098
|
+
return [phase, request];
|
|
5099
|
+
}
|
|
5100
|
+
function targetPoint(target, anchor = "center", character) {
|
|
5101
|
+
const center = {
|
|
5102
|
+
x: target.left + target.width / 2,
|
|
5103
|
+
y: target.top + target.height / 2
|
|
5104
|
+
};
|
|
5105
|
+
switch (anchor) {
|
|
5106
|
+
case "top":
|
|
5107
|
+
return { x: center.x, y: target.top - character.height / 2 };
|
|
5108
|
+
case "right":
|
|
5109
|
+
return { x: target.right + character.width / 2, y: center.y };
|
|
5110
|
+
case "bottom":
|
|
5111
|
+
return { x: center.x, y: target.bottom + character.height / 2 };
|
|
5112
|
+
case "left":
|
|
5113
|
+
return { x: target.left - character.width / 2, y: center.y };
|
|
5114
|
+
default:
|
|
5115
|
+
return center;
|
|
5116
|
+
}
|
|
5117
|
+
}
|
|
5118
|
+
function boundedPoint(point, world) {
|
|
5119
|
+
const size = world.characterSize;
|
|
5120
|
+
if (!size) return { x: point.x, y: point.y };
|
|
5121
|
+
return {
|
|
5122
|
+
x: Math.max(
|
|
5123
|
+
size.width / 2,
|
|
5124
|
+
Math.min(world.viewport.width - size.width / 2, point.x)
|
|
5125
|
+
),
|
|
5126
|
+
y: Math.max(
|
|
5127
|
+
size.height / 2,
|
|
5128
|
+
Math.min(world.viewport.height - size.height / 2, point.y)
|
|
5129
|
+
)
|
|
5130
|
+
};
|
|
5131
|
+
}
|
|
5132
|
+
function directMotion(position, target, lift = 0) {
|
|
5133
|
+
const dx = target.x - position.x;
|
|
5134
|
+
const dy = target.y - position.y;
|
|
5135
|
+
const distance = Math.hypot(dx, dy);
|
|
5136
|
+
return {
|
|
5137
|
+
x: distance ? dx / distance : 0,
|
|
5138
|
+
y: distance ? dy / distance : 0,
|
|
5139
|
+
speed: 0,
|
|
5140
|
+
maxDistance: distance,
|
|
5141
|
+
lift,
|
|
5142
|
+
direct: true
|
|
5143
|
+
};
|
|
5144
|
+
}
|
|
5145
|
+
function motionToward(effect, position, x, y, arrivalRadius = 0, bounds) {
|
|
5146
|
+
const size = bounds?.characterSize;
|
|
5147
|
+
const viewport = bounds?.viewport;
|
|
5148
|
+
if (size && viewport) {
|
|
5149
|
+
const pointerX = x;
|
|
5150
|
+
const pointerY = y;
|
|
5151
|
+
x = Math.max(size.width / 2, Math.min(viewport.width - size.width / 2, x));
|
|
5152
|
+
y = Math.max(
|
|
5153
|
+
size.height / 2,
|
|
5154
|
+
Math.min(viewport.height - size.height / 2, y)
|
|
5155
|
+
);
|
|
5156
|
+
if (x !== pointerX || y !== pointerY) arrivalRadius = 0;
|
|
5157
|
+
}
|
|
5158
|
+
const dx = x - position.x;
|
|
5159
|
+
const dy = y - position.y;
|
|
5160
|
+
const distance = Math.hypot(dx, dy);
|
|
5161
|
+
const maxDistance = distance - arrivalRadius;
|
|
5162
|
+
if (maxDistance <= 4) return;
|
|
5163
|
+
return {
|
|
5164
|
+
x: dx / distance,
|
|
5165
|
+
y: dy / distance,
|
|
5166
|
+
speed: effect.speed ?? DEFAULT_SPEED,
|
|
5167
|
+
maxDistance
|
|
5168
|
+
};
|
|
5169
|
+
}
|
|
4613
5170
|
|
|
4614
5171
|
// packages/runtime/src/configuration-validation.ts
|
|
4615
5172
|
var collectConfigurationFaults = !compactRuntimeDiagnostics;
|
|
@@ -4621,6 +5178,10 @@
|
|
|
4621
5178
|
"atlasUrl",
|
|
4622
5179
|
"styles",
|
|
4623
5180
|
"plan",
|
|
5181
|
+
"preset",
|
|
5182
|
+
"targets",
|
|
5183
|
+
"interaction",
|
|
5184
|
+
"indicator",
|
|
4624
5185
|
"content",
|
|
4625
5186
|
"bindings",
|
|
4626
5187
|
"theme",
|
|
@@ -4652,6 +5213,14 @@
|
|
|
4652
5213
|
if (options.format !== void 0 && options.format !== 1) {
|
|
4653
5214
|
reportConfigurationFault("unsupported-format", "$.format", fault);
|
|
4654
5215
|
}
|
|
5216
|
+
if (options.plan !== void 0 && options.preset !== void 0) {
|
|
5217
|
+
reportConfigurationFault("incompatible-behavior", "$.preset", fault);
|
|
5218
|
+
}
|
|
5219
|
+
if (options.preset !== void 0 && !["companion", "still", "bottom-patrol", "viewport-roam"].includes(
|
|
5220
|
+
options.preset
|
|
5221
|
+
)) {
|
|
5222
|
+
reportConfigurationFault("invalid-preset", "$.preset", fault);
|
|
5223
|
+
}
|
|
4655
5224
|
if (options.character !== void 0) {
|
|
4656
5225
|
if (typeof options.character !== "string" || !NAME_PATTERN.test(options.character)) {
|
|
4657
5226
|
reportConfigurationFault("invalid-character", "$.character", fault);
|
|
@@ -4737,6 +5306,12 @@
|
|
|
4737
5306
|
if (collectConfigurationFaults) content = {};
|
|
4738
5307
|
}
|
|
4739
5308
|
validateBindings(options.bindings, content, fault);
|
|
5309
|
+
validateTargets(options.targets, fault);
|
|
5310
|
+
validateInteraction(options.interaction, options.targets, fault);
|
|
5311
|
+
validateIndicator(options.indicator, fault);
|
|
5312
|
+
if (options.interaction === false && options.indicator !== void 0) {
|
|
5313
|
+
reportConfigurationFault("incompatible-indicator", "$.indicator", fault);
|
|
5314
|
+
}
|
|
4740
5315
|
validateTheme(options.theme, fault);
|
|
4741
5316
|
validateDiagnostics(options.diagnostics, fault);
|
|
4742
5317
|
validateAccessibility(options.accessibility, fault);
|
|
@@ -4747,6 +5322,201 @@
|
|
|
4747
5322
|
}
|
|
4748
5323
|
return content;
|
|
4749
5324
|
}
|
|
5325
|
+
function validateInteraction(interaction, targets, fault) {
|
|
5326
|
+
if (interaction === void 0 || interaction === false) return;
|
|
5327
|
+
const checked = shape(
|
|
5328
|
+
interaction,
|
|
5329
|
+
"invalid-interaction",
|
|
5330
|
+
"$.interaction",
|
|
5331
|
+
[
|
|
5332
|
+
"press",
|
|
5333
|
+
"pressEvent",
|
|
5334
|
+
"drag",
|
|
5335
|
+
"throw",
|
|
5336
|
+
"dragState",
|
|
5337
|
+
"riseState",
|
|
5338
|
+
"fallState",
|
|
5339
|
+
"landState",
|
|
5340
|
+
"gravity",
|
|
5341
|
+
"maxThrowSpeed",
|
|
5342
|
+
"bounce",
|
|
5343
|
+
"floorInset",
|
|
5344
|
+
"label",
|
|
5345
|
+
"contentInitiallyHidden",
|
|
5346
|
+
"clearIndicatorOnPress",
|
|
5347
|
+
"catchTarget",
|
|
5348
|
+
"catchAnchor",
|
|
5349
|
+
"catchMargin",
|
|
5350
|
+
"catchEvent"
|
|
5351
|
+
],
|
|
5352
|
+
fault
|
|
5353
|
+
);
|
|
5354
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5355
|
+
const value = checked;
|
|
5356
|
+
if (value.press !== void 0 && ![
|
|
5357
|
+
"toggle-content",
|
|
5358
|
+
"show-content",
|
|
5359
|
+
"hide-content",
|
|
5360
|
+
"emit",
|
|
5361
|
+
"none"
|
|
5362
|
+
].includes(value.press)) {
|
|
5363
|
+
reportConfigurationFault(
|
|
5364
|
+
"invalid-interaction",
|
|
5365
|
+
"$.interaction.press",
|
|
5366
|
+
fault
|
|
5367
|
+
);
|
|
5368
|
+
}
|
|
5369
|
+
if (value.pressEvent !== void 0 && (typeof value.pressEvent !== "string" || !EVENT_NAME_PATTERN.test(value.pressEvent))) {
|
|
5370
|
+
reportConfigurationFault(
|
|
5371
|
+
"invalid-interaction-event",
|
|
5372
|
+
"$.interaction.pressEvent",
|
|
5373
|
+
fault
|
|
5374
|
+
);
|
|
5375
|
+
}
|
|
5376
|
+
if (value.press === "emit" && value.pressEvent === void 0) {
|
|
5377
|
+
reportConfigurationFault(
|
|
5378
|
+
"missing-interaction-event",
|
|
5379
|
+
"$.interaction.pressEvent",
|
|
5380
|
+
fault
|
|
5381
|
+
);
|
|
5382
|
+
}
|
|
5383
|
+
if (value.pressEvent !== void 0 && value.press !== void 0 && value.press !== "emit") {
|
|
5384
|
+
reportConfigurationFault(
|
|
5385
|
+
"incompatible-interaction-event",
|
|
5386
|
+
"$.interaction.pressEvent",
|
|
5387
|
+
fault
|
|
5388
|
+
);
|
|
5389
|
+
}
|
|
5390
|
+
for (const field of [
|
|
5391
|
+
"drag",
|
|
5392
|
+
"throw",
|
|
5393
|
+
"contentInitiallyHidden",
|
|
5394
|
+
"clearIndicatorOnPress"
|
|
5395
|
+
]) {
|
|
5396
|
+
if (value[field] !== void 0 && typeof value[field] !== "boolean") {
|
|
5397
|
+
reportConfigurationFault(
|
|
5398
|
+
"invalid-interaction",
|
|
5399
|
+
`$.interaction.${field}`,
|
|
5400
|
+
fault
|
|
5401
|
+
);
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
for (const field of [
|
|
5405
|
+
"dragState",
|
|
5406
|
+
"riseState",
|
|
5407
|
+
"fallState",
|
|
5408
|
+
"landState"
|
|
5409
|
+
]) {
|
|
5410
|
+
if (value[field] !== void 0 && (typeof value[field] !== "string" || !STATE_NAME_PATTERN.test(value[field]))) {
|
|
5411
|
+
reportConfigurationFault(
|
|
5412
|
+
"invalid-interaction-state",
|
|
5413
|
+
`$.interaction.${field}`,
|
|
5414
|
+
fault
|
|
5415
|
+
);
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
for (const [field, minimum, maximum] of [
|
|
5419
|
+
["gravity", 0, 1e4],
|
|
5420
|
+
["maxThrowSpeed", 0, 1e4],
|
|
5421
|
+
["bounce", 0, 1],
|
|
5422
|
+
["floorInset", 0, 1e3],
|
|
5423
|
+
["catchMargin", 0, 1e3]
|
|
5424
|
+
]) {
|
|
5425
|
+
const item = value[field];
|
|
5426
|
+
if (item !== void 0 && (typeof item !== "number" || !Number.isFinite(item) || item < minimum || item > maximum)) {
|
|
5427
|
+
reportConfigurationFault(
|
|
5428
|
+
"invalid-interaction-range",
|
|
5429
|
+
`$.interaction.${field}`,
|
|
5430
|
+
fault
|
|
5431
|
+
);
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
if (value.label !== void 0 && !text2(value.label, 120)) {
|
|
5435
|
+
reportConfigurationFault(
|
|
5436
|
+
"invalid-interaction-label",
|
|
5437
|
+
"$.interaction.label",
|
|
5438
|
+
fault
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5441
|
+
if (value.catchTarget !== void 0 && (typeof value.catchTarget !== "string" || !NAME_PATTERN.test(value.catchTarget) || !Object.hasOwn(targets ?? {}, value.catchTarget))) {
|
|
5442
|
+
reportConfigurationFault(
|
|
5443
|
+
"invalid-catch-target",
|
|
5444
|
+
"$.interaction.catchTarget",
|
|
5445
|
+
fault
|
|
5446
|
+
);
|
|
5447
|
+
}
|
|
5448
|
+
if (value.catchAnchor !== void 0 && !["center", "top", "right", "bottom", "left"].includes(
|
|
5449
|
+
value.catchAnchor
|
|
5450
|
+
)) {
|
|
5451
|
+
reportConfigurationFault(
|
|
5452
|
+
"invalid-catch-anchor",
|
|
5453
|
+
"$.interaction.catchAnchor",
|
|
5454
|
+
fault
|
|
5455
|
+
);
|
|
5456
|
+
}
|
|
5457
|
+
if (value.catchEvent !== void 0 && (typeof value.catchEvent !== "string" || !EVENT_NAME_PATTERN.test(value.catchEvent))) {
|
|
5458
|
+
reportConfigurationFault(
|
|
5459
|
+
"invalid-interaction-event",
|
|
5460
|
+
"$.interaction.catchEvent",
|
|
5461
|
+
fault
|
|
5462
|
+
);
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
function validateIndicator(indicator, fault) {
|
|
5466
|
+
if (indicator === void 0) return;
|
|
5467
|
+
const checked = shape(
|
|
5468
|
+
indicator,
|
|
5469
|
+
"invalid-indicator",
|
|
5470
|
+
"$.indicator",
|
|
5471
|
+
["kind", "count", "label", "color", "visible"],
|
|
5472
|
+
fault
|
|
5473
|
+
);
|
|
5474
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5475
|
+
const value = checked;
|
|
5476
|
+
if (value.kind !== void 0 && value.kind !== "dot" && value.kind !== "count") {
|
|
5477
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.kind", fault);
|
|
5478
|
+
}
|
|
5479
|
+
if (!text2(value.label, 120)) {
|
|
5480
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.label", fault);
|
|
5481
|
+
}
|
|
5482
|
+
if (value.count !== void 0 && (typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0 || value.count > 999)) {
|
|
5483
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.count", fault);
|
|
5484
|
+
}
|
|
5485
|
+
if (value.color !== void 0 && !isSurfaceColor(value.color)) {
|
|
5486
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.color", fault);
|
|
5487
|
+
}
|
|
5488
|
+
if (value.visible !== void 0 && typeof value.visible !== "boolean") {
|
|
5489
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.visible", fault);
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
function validateTargets(targets, fault) {
|
|
5493
|
+
if (targets === void 0) return;
|
|
5494
|
+
const checked = shape(
|
|
5495
|
+
targets,
|
|
5496
|
+
"invalid-targets",
|
|
5497
|
+
"$.targets",
|
|
5498
|
+
void 0,
|
|
5499
|
+
fault
|
|
5500
|
+
);
|
|
5501
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5502
|
+
const entries = Object.entries(checked);
|
|
5503
|
+
if (entries.length > 16) {
|
|
5504
|
+
reportConfigurationFault("target-limit", "$.targets", fault);
|
|
5505
|
+
}
|
|
5506
|
+
for (const [id2, selector2] of entries) {
|
|
5507
|
+
if (!NAME_PATTERN.test(id2)) {
|
|
5508
|
+
reportConfigurationFault("invalid-target", `$.targets.${id2}`, fault, id2);
|
|
5509
|
+
}
|
|
5510
|
+
if (typeof selector2 !== "string" || selector2.length < 1 || selector2.length > 256 || /[\0\r\n]/.test(selector2)) {
|
|
5511
|
+
reportConfigurationFault(
|
|
5512
|
+
"invalid-target-selector",
|
|
5513
|
+
`$.targets.${id2}`,
|
|
5514
|
+
fault,
|
|
5515
|
+
id2
|
|
5516
|
+
);
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
4750
5520
|
function validRuntimeName(value) {
|
|
4751
5521
|
return value === void 0 || typeof value === "boolean" || text2(value, 80);
|
|
4752
5522
|
}
|
|
@@ -4975,7 +5745,8 @@
|
|
|
4975
5745
|
if (options.plan !== void 0) {
|
|
4976
5746
|
try {
|
|
4977
5747
|
compilePlan(options.plan, {
|
|
4978
|
-
contentIds: new Set(Object.keys(content))
|
|
5748
|
+
contentIds: new Set(Object.keys(content)),
|
|
5749
|
+
targets: new Set(Object.keys(options.targets ?? {}))
|
|
4979
5750
|
});
|
|
4980
5751
|
} catch (cause) {
|
|
4981
5752
|
fail2(
|
|
@@ -5056,6 +5827,40 @@
|
|
|
5056
5827
|
return `${detail ?? field} must be a function`;
|
|
5057
5828
|
case "invalid-plan":
|
|
5058
5829
|
return detail ?? "Plan is invalid";
|
|
5830
|
+
case "incompatible-behavior":
|
|
5831
|
+
return "Choose preset or plan, not both";
|
|
5832
|
+
case "invalid-preset":
|
|
5833
|
+
return "preset must be companion, still, bottom-patrol, or viewport-roam";
|
|
5834
|
+
case "invalid-targets":
|
|
5835
|
+
return "targets must be an object of target IDs and CSS selectors";
|
|
5836
|
+
case "target-limit":
|
|
5837
|
+
return "targets supports at most 16 entries";
|
|
5838
|
+
case "invalid-target":
|
|
5839
|
+
return "target IDs must be bounded lowercase IDs";
|
|
5840
|
+
case "invalid-target-selector":
|
|
5841
|
+
return "target selectors must be bounded CSS selector text";
|
|
5842
|
+
case "invalid-interaction":
|
|
5843
|
+
return "interaction contains an unsupported value";
|
|
5844
|
+
case "invalid-interaction-event":
|
|
5845
|
+
return "interaction events must be bounded application Event names";
|
|
5846
|
+
case "missing-interaction-event":
|
|
5847
|
+
return "pressEvent is required when press is emit";
|
|
5848
|
+
case "incompatible-interaction-event":
|
|
5849
|
+
return "pressEvent can be used only with the emit press action";
|
|
5850
|
+
case "invalid-interaction-state":
|
|
5851
|
+
return "interaction states must be valid Pack State names";
|
|
5852
|
+
case "invalid-interaction-range":
|
|
5853
|
+
return "interaction physics value is outside its supported range";
|
|
5854
|
+
case "invalid-interaction-label":
|
|
5855
|
+
return "interaction label must be short plain text";
|
|
5856
|
+
case "invalid-catch-target":
|
|
5857
|
+
return "catchTarget must reference a configured target";
|
|
5858
|
+
case "invalid-catch-anchor":
|
|
5859
|
+
return "catchAnchor is not supported";
|
|
5860
|
+
case "invalid-indicator":
|
|
5861
|
+
return "indicator must include a label and valid dot or count settings";
|
|
5862
|
+
case "incompatible-indicator":
|
|
5863
|
+
return "indicator requires character interaction";
|
|
5059
5864
|
default:
|
|
5060
5865
|
return detail ?? code;
|
|
5061
5866
|
}
|
|
@@ -5168,21 +5973,26 @@
|
|
|
5168
5973
|
delete output.state;
|
|
5169
5974
|
}
|
|
5170
5975
|
const motion = item.effect.motion;
|
|
5171
|
-
if (motion
|
|
5172
|
-
const
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5976
|
+
if (motion?.type === "horizontal-patrol") {
|
|
5977
|
+
const [direction, request] = evaluateHorizontalPatrol(
|
|
5978
|
+
motion,
|
|
5979
|
+
world,
|
|
5980
|
+
item.patrolDirection
|
|
5981
|
+
);
|
|
5982
|
+
item.patrolDirection = direction;
|
|
5983
|
+
if (request) output.motion = request;
|
|
5984
|
+
else delete output.motion;
|
|
5985
|
+
} else if (motion?.type === "follow-pointer" && world.pointer && world.position) {
|
|
5986
|
+
const request = motionToward(
|
|
5987
|
+
motion,
|
|
5988
|
+
world.position,
|
|
5989
|
+
world.pointer.x,
|
|
5990
|
+
world.pointer.y,
|
|
5991
|
+
motion.arrivalRadius,
|
|
5992
|
+
world
|
|
5993
|
+
);
|
|
5994
|
+
if (request) output.motion = request;
|
|
5995
|
+
else delete output.motion;
|
|
5186
5996
|
}
|
|
5187
5997
|
for (const surface of item.effect.surfaces) {
|
|
5188
5998
|
surfaces.set(
|
|
@@ -5249,6 +6059,7 @@
|
|
|
5249
6059
|
startedAt: 0,
|
|
5250
6060
|
deadline: 0,
|
|
5251
6061
|
status: "rejected",
|
|
6062
|
+
patrolDirection: true,
|
|
5252
6063
|
handle,
|
|
5253
6064
|
finish
|
|
5254
6065
|
});
|
|
@@ -5556,6 +6367,13 @@
|
|
|
5556
6367
|
this.host.setAttribute("aria-hidden", "true");
|
|
5557
6368
|
}
|
|
5558
6369
|
};
|
|
6370
|
+
var createAtlasRenderer = (options) => new AtlasRenderer(
|
|
6371
|
+
options.document,
|
|
6372
|
+
options.pack,
|
|
6373
|
+
options.atlasUrl,
|
|
6374
|
+
options.scale,
|
|
6375
|
+
options.styles
|
|
6376
|
+
);
|
|
5559
6377
|
|
|
5560
6378
|
// packages/runtime/src/resolver.ts
|
|
5561
6379
|
var ALIASES = {
|
|
@@ -5799,6 +6617,142 @@
|
|
|
5799
6617
|
}
|
|
5800
6618
|
}
|
|
5801
6619
|
|
|
6620
|
+
// packages/runtime/src/path-sampler.ts
|
|
6621
|
+
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
6622
|
+
var SvgPathSampler = class {
|
|
6623
|
+
#document;
|
|
6624
|
+
#cache = /* @__PURE__ */ new Map();
|
|
6625
|
+
constructor(document) {
|
|
6626
|
+
this.#document = document;
|
|
6627
|
+
}
|
|
6628
|
+
validate(path) {
|
|
6629
|
+
return this.#geometry(path) !== void 0;
|
|
6630
|
+
}
|
|
6631
|
+
sample(path, progress) {
|
|
6632
|
+
const geometry = this.#geometry(path);
|
|
6633
|
+
if (!geometry) return;
|
|
6634
|
+
const bounded2 = Math.max(0, Math.min(1, progress));
|
|
6635
|
+
try {
|
|
6636
|
+
const point = geometry.element.getPointAtLength(
|
|
6637
|
+
geometry.length * bounded2
|
|
6638
|
+
);
|
|
6639
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return;
|
|
6640
|
+
return { x: point.x, y: point.y };
|
|
6641
|
+
} catch {
|
|
6642
|
+
return;
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
#geometry(path) {
|
|
6646
|
+
const cached = this.#cache.get(path);
|
|
6647
|
+
if (cached) return cached;
|
|
6648
|
+
if (this.#cache.size >= 16) return;
|
|
6649
|
+
const element = this.#document.createElementNS(
|
|
6650
|
+
SVG_NAMESPACE,
|
|
6651
|
+
"path"
|
|
6652
|
+
);
|
|
6653
|
+
element.setAttribute("d", path);
|
|
6654
|
+
try {
|
|
6655
|
+
const length = element.getTotalLength();
|
|
6656
|
+
if (!Number.isFinite(length) || length <= 0) return;
|
|
6657
|
+
const geometry = Object.freeze({ element, length });
|
|
6658
|
+
this.#cache.set(path, geometry);
|
|
6659
|
+
return geometry;
|
|
6660
|
+
} catch {
|
|
6661
|
+
return;
|
|
6662
|
+
}
|
|
6663
|
+
}
|
|
6664
|
+
};
|
|
6665
|
+
|
|
6666
|
+
// packages/runtime/src/targets.ts
|
|
6667
|
+
var TargetTracker = class {
|
|
6668
|
+
#document;
|
|
6669
|
+
#window;
|
|
6670
|
+
#selectors;
|
|
6671
|
+
#elements = /* @__PURE__ */ new Map();
|
|
6672
|
+
#wake;
|
|
6673
|
+
#resizeObserver;
|
|
6674
|
+
#mutationObserver;
|
|
6675
|
+
#snapshot = Object.freeze({});
|
|
6676
|
+
#dirty = true;
|
|
6677
|
+
#destroyed = false;
|
|
6678
|
+
constructor(document, window, selectors, wake) {
|
|
6679
|
+
this.#document = document;
|
|
6680
|
+
this.#window = window;
|
|
6681
|
+
this.#selectors = selectors;
|
|
6682
|
+
this.#wake = wake;
|
|
6683
|
+
const browserWindow = window;
|
|
6684
|
+
this.#resizeObserver = browserWindow.ResizeObserver ? new browserWindow.ResizeObserver(() => this.refresh()) : void 0;
|
|
6685
|
+
this.#mutationObserver = browserWindow.MutationObserver ? new browserWindow.MutationObserver(() => this.refresh()) : void 0;
|
|
6686
|
+
this.#mutationObserver?.observe(document.documentElement, {
|
|
6687
|
+
attributes: true,
|
|
6688
|
+
attributeFilter: ["class", "id"],
|
|
6689
|
+
childList: true,
|
|
6690
|
+
subtree: true
|
|
6691
|
+
});
|
|
6692
|
+
window.addEventListener("resize", this.#markDirty, { passive: true });
|
|
6693
|
+
window.addEventListener("scroll", this.#markDirty, {
|
|
6694
|
+
capture: true,
|
|
6695
|
+
passive: true
|
|
6696
|
+
});
|
|
6697
|
+
}
|
|
6698
|
+
snapshot(force = false) {
|
|
6699
|
+
if (this.#destroyed) return Object.freeze({});
|
|
6700
|
+
if (force) this.#dirty = true;
|
|
6701
|
+
if (!this.#dirty) return this.#snapshot;
|
|
6702
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
6703
|
+
for (const [id2, selector2] of Object.entries(this.#selectors)) {
|
|
6704
|
+
let element = this.#elements.get(id2);
|
|
6705
|
+
if (!element?.isConnected) {
|
|
6706
|
+
if (element) this.#resizeObserver?.unobserve(element);
|
|
6707
|
+
element = this.#document.querySelector(selector2);
|
|
6708
|
+
if (element) {
|
|
6709
|
+
this.#elements.set(id2, element);
|
|
6710
|
+
this.#resizeObserver?.observe(element);
|
|
6711
|
+
} else {
|
|
6712
|
+
this.#elements.delete(id2);
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
if (!element) continue;
|
|
6716
|
+
const rect = element.getBoundingClientRect();
|
|
6717
|
+
if (!Number.isFinite(rect.left) || !Number.isFinite(rect.top) || !Number.isFinite(rect.width) || !Number.isFinite(rect.height)) {
|
|
6718
|
+
continue;
|
|
6719
|
+
}
|
|
6720
|
+
output[id2] = Object.freeze({
|
|
6721
|
+
left: rect.left,
|
|
6722
|
+
top: rect.top,
|
|
6723
|
+
right: rect.right,
|
|
6724
|
+
bottom: rect.bottom,
|
|
6725
|
+
width: rect.width,
|
|
6726
|
+
height: rect.height
|
|
6727
|
+
});
|
|
6728
|
+
}
|
|
6729
|
+
this.#snapshot = Object.freeze(output);
|
|
6730
|
+
this.#dirty = false;
|
|
6731
|
+
return this.#snapshot;
|
|
6732
|
+
}
|
|
6733
|
+
contains(id2, point, margin = 0) {
|
|
6734
|
+
const target = this.snapshot(true)[id2];
|
|
6735
|
+
return Boolean(
|
|
6736
|
+
target && point.x >= target.left - margin && point.x <= target.right + margin && point.y >= target.top - margin && point.y <= target.bottom + margin
|
|
6737
|
+
);
|
|
6738
|
+
}
|
|
6739
|
+
refresh = () => {
|
|
6740
|
+
if (this.#destroyed) return;
|
|
6741
|
+
this.#dirty = true;
|
|
6742
|
+
this.#wake();
|
|
6743
|
+
};
|
|
6744
|
+
destroy() {
|
|
6745
|
+
if (this.#destroyed) return;
|
|
6746
|
+
this.#destroyed = true;
|
|
6747
|
+
this.#resizeObserver?.disconnect();
|
|
6748
|
+
this.#mutationObserver?.disconnect();
|
|
6749
|
+
this.#window.removeEventListener("resize", this.#markDirty);
|
|
6750
|
+
this.#window.removeEventListener("scroll", this.#markDirty, true);
|
|
6751
|
+
this.#elements.clear();
|
|
6752
|
+
}
|
|
6753
|
+
#markDirty = () => this.refresh();
|
|
6754
|
+
};
|
|
6755
|
+
|
|
5802
6756
|
// packages/runtime/src/visibility.ts
|
|
5803
6757
|
var PREFERENCE_KEY = "peekling:site-preference";
|
|
5804
6758
|
var SESSION_KEY = "peekling:hidden-session";
|
|
@@ -6157,6 +7111,10 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6157
7111
|
var SUSPEND_PAGE = 2;
|
|
6158
7112
|
var SUSPEND_SITE = 4;
|
|
6159
7113
|
var MAX_TIMER_DELAY = 2147483647;
|
|
7114
|
+
var DEFAULT_GRAVITY = 1800;
|
|
7115
|
+
var DEFAULT_THROW_SPEED = 1800;
|
|
7116
|
+
var DEFAULT_BOUNCE = 0.35;
|
|
7117
|
+
var DEFAULT_FLOOR_INSET = 8;
|
|
6160
7118
|
var EMPTY_CONTENT_SELECTIONS = Object.freeze([]);
|
|
6161
7119
|
function browserSelectorIsValid(document, selector2) {
|
|
6162
7120
|
try {
|
|
@@ -6220,10 +7178,21 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6220
7178
|
}
|
|
6221
7179
|
return input;
|
|
6222
7180
|
}
|
|
7181
|
+
function checkedIndicator(input) {
|
|
7182
|
+
if (input === null) return;
|
|
7183
|
+
const value = snapshotConfiguration(input);
|
|
7184
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || value.kind !== void 0 && value.kind !== "dot" && value.kind !== "count" || typeof value.label !== "string" || value.label.length < 1 || value.label.length > 120 || /[\u0000-\u001f\u007f]/.test(value.label) || value.count !== void 0 && (!Number.isInteger(value.count) || value.count < 0 || value.count > 999) || value.color !== void 0 && !isSurfaceColor(value.color) || value.visible !== void 0 && typeof value.visible !== "boolean") {
|
|
7185
|
+
throw new TypeError(
|
|
7186
|
+
runtimeMessage("indicator.invalid", "Indicator is invalid")
|
|
7187
|
+
);
|
|
7188
|
+
}
|
|
7189
|
+
return value;
|
|
7190
|
+
}
|
|
6223
7191
|
var PeeklingRuntime = class _PeeklingRuntime {
|
|
6224
|
-
static hatch(input) {
|
|
7192
|
+
static hatch(input, rendererFactory = createAtlasRenderer) {
|
|
6225
7193
|
return new _PeeklingRuntime(
|
|
6226
|
-
hatchOptions(input)
|
|
7194
|
+
hatchOptions(input),
|
|
7195
|
+
rendererFactory
|
|
6227
7196
|
);
|
|
6228
7197
|
}
|
|
6229
7198
|
/** Package-internal presentation update used only by the Web Component. */
|
|
@@ -6259,7 +7228,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6259
7228
|
#loaded;
|
|
6260
7229
|
#renderer;
|
|
6261
7230
|
#contentRenderer;
|
|
7231
|
+
#interactionController;
|
|
6262
7232
|
#sections;
|
|
7233
|
+
#targets;
|
|
6263
7234
|
#input;
|
|
6264
7235
|
#raf = 0;
|
|
6265
7236
|
#planTimer = 0;
|
|
@@ -6295,10 +7266,18 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6295
7266
|
#instanceId;
|
|
6296
7267
|
#diagnostics;
|
|
6297
7268
|
#styles;
|
|
7269
|
+
#rendererFactory;
|
|
6298
7270
|
#rejectedOverrideId = 0;
|
|
6299
7271
|
#reportedNotReadyEvent = false;
|
|
6300
7272
|
#reportedNotReadyOverride = false;
|
|
6301
|
-
|
|
7273
|
+
#trackTargets = false;
|
|
7274
|
+
#pathSampler;
|
|
7275
|
+
#indicator;
|
|
7276
|
+
#dragging = false;
|
|
7277
|
+
#throwing = false;
|
|
7278
|
+
#throwVelocity = { x: 0, y: 0 };
|
|
7279
|
+
#landUntil = 0;
|
|
7280
|
+
constructor(options = {}, rendererFactory = createAtlasRenderer) {
|
|
6302
7281
|
options = snapshotConfiguration(options);
|
|
6303
7282
|
const document = options.document ?? globalThis.document;
|
|
6304
7283
|
const window = options.window ?? globalThis.window;
|
|
@@ -6308,7 +7287,10 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6308
7287
|
);
|
|
6309
7288
|
this.#document = document;
|
|
6310
7289
|
this.#window = window;
|
|
7290
|
+
this.#pathSampler = new SvgPathSampler(document);
|
|
6311
7291
|
this.#options = options;
|
|
7292
|
+
this.#indicator = options.indicator;
|
|
7293
|
+
this.#rendererFactory = rendererFactory;
|
|
6312
7294
|
this.#now = window.performance?.now?.bind(window.performance) ?? Date.now;
|
|
6313
7295
|
this.#instanceId = `instance:${Math.floor(this.#now())}:${Math.random().toString(36).slice(2, 8)}`;
|
|
6314
7296
|
this.#diagnostics = new DiagnosticChannel({
|
|
@@ -6433,6 +7415,28 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6433
7415
|
this.#setSuspended(SUSPEND_HOST, false);
|
|
6434
7416
|
this.#notice("lifecycle.resumed", "info", "lifecycle");
|
|
6435
7417
|
}
|
|
7418
|
+
refreshTargets() {
|
|
7419
|
+
this.#targets?.refresh();
|
|
7420
|
+
}
|
|
7421
|
+
setIndicator(indicator) {
|
|
7422
|
+
if (this.#destroyed) return;
|
|
7423
|
+
this.#indicator = checkedIndicator(indicator);
|
|
7424
|
+
this.#interactionController?.updateIndicator(this.#indicator);
|
|
7425
|
+
}
|
|
7426
|
+
setContentVisible(visible) {
|
|
7427
|
+
if (this.#destroyed || !this.#contentRenderer) return false;
|
|
7428
|
+
const expanded = this.#contentRenderer.setUserHidden(!visible);
|
|
7429
|
+
this.#interactionController?.setExpanded(expanded);
|
|
7430
|
+
this.#wake();
|
|
7431
|
+
return expanded;
|
|
7432
|
+
}
|
|
7433
|
+
toggleContent() {
|
|
7434
|
+
if (this.#destroyed || !this.#contentRenderer) return false;
|
|
7435
|
+
const expanded = this.#contentRenderer.toggleUserHidden();
|
|
7436
|
+
this.#interactionController?.setExpanded(expanded);
|
|
7437
|
+
this.#wake();
|
|
7438
|
+
return expanded;
|
|
7439
|
+
}
|
|
6436
7440
|
destroy() {
|
|
6437
7441
|
this.#destroy("destroyed");
|
|
6438
7442
|
}
|
|
@@ -6446,7 +7450,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6446
7450
|
this.#input?.destroy();
|
|
6447
7451
|
this.#plan?.reset();
|
|
6448
7452
|
this.#sections?.destroy();
|
|
7453
|
+
this.#targets?.destroy();
|
|
6449
7454
|
this.#contentRenderer?.destroy();
|
|
7455
|
+
this.#interactionController?.destroy();
|
|
6450
7456
|
this.#renderer?.destroy();
|
|
6451
7457
|
this.#unregisterVisibility?.();
|
|
6452
7458
|
this.#unregisterVisibility = void 0;
|
|
@@ -6476,10 +7482,20 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6476
7482
|
async #initialize() {
|
|
6477
7483
|
try {
|
|
6478
7484
|
const validateSelector = (selector2) => browserSelectorIsValid(this.#document, selector2);
|
|
7485
|
+
const targetIds = new Set(Object.keys(this.#options.targets ?? {}));
|
|
7486
|
+
for (const selector2 of Object.values(this.#options.targets ?? {})) {
|
|
7487
|
+
if (!validateSelector(selector2)) {
|
|
7488
|
+
throw new TypeError(
|
|
7489
|
+
runtimeMessage("target.selector", "Target selector is invalid")
|
|
7490
|
+
);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
6479
7493
|
if (this.#options.plan !== void 0) {
|
|
6480
7494
|
compilePlan(this.#options.plan, {
|
|
6481
7495
|
contentIds: new Set(Object.keys(this.#content)),
|
|
6482
|
-
|
|
7496
|
+
targets: targetIds,
|
|
7497
|
+
validateSelector,
|
|
7498
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6483
7499
|
});
|
|
6484
7500
|
}
|
|
6485
7501
|
const browserWindow = this.#window;
|
|
@@ -6547,12 +7563,14 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6547
7563
|
locomotion ? ["locomotion"] : []
|
|
6548
7564
|
);
|
|
6549
7565
|
const compiled = compilePlan(
|
|
6550
|
-
this.#options.plan ??
|
|
7566
|
+
this.#options.plan ?? createPresetPlan(this.#options.preset ?? "companion", locomotion),
|
|
6551
7567
|
{
|
|
6552
7568
|
states: new Set(Object.keys(loaded.content.states)),
|
|
6553
7569
|
capabilities,
|
|
6554
7570
|
contentIds: new Set(Object.keys(this.#content)),
|
|
6555
|
-
|
|
7571
|
+
targets: targetIds,
|
|
7572
|
+
validateSelector,
|
|
7573
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6556
7574
|
}
|
|
6557
7575
|
);
|
|
6558
7576
|
this.#plan = new PlanRuntime(compiled);
|
|
@@ -6560,7 +7578,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6560
7578
|
{
|
|
6561
7579
|
states: new Set(Object.keys(loaded.content.states)),
|
|
6562
7580
|
capabilities,
|
|
6563
|
-
contentIds: new Set(Object.keys(this.#content))
|
|
7581
|
+
contentIds: new Set(Object.keys(this.#content)),
|
|
7582
|
+
targets: targetIds,
|
|
7583
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6564
7584
|
},
|
|
6565
7585
|
this.#now,
|
|
6566
7586
|
(message) => this.#diagnose(message, "override.rejected", "warning", "override")
|
|
@@ -6588,21 +7608,45 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6588
7608
|
(loaded.content.atlas.logicalWidth ?? loaded.content.atlas.cellWidth) * scale,
|
|
6589
7609
|
(loaded.content.atlas.logicalHeight ?? loaded.content.atlas.cellHeight) * scale
|
|
6590
7610
|
);
|
|
6591
|
-
this.#renderer =
|
|
6592
|
-
this.#document,
|
|
6593
|
-
loaded.content,
|
|
6594
|
-
loaded.atlasObjectUrl,
|
|
7611
|
+
this.#renderer = this.#rendererFactory({
|
|
7612
|
+
document: this.#document,
|
|
7613
|
+
pack: loaded.content,
|
|
7614
|
+
atlasUrl: loaded.atlasObjectUrl,
|
|
6595
7615
|
scale,
|
|
6596
|
-
this.#styles
|
|
6597
|
-
);
|
|
7616
|
+
styles: this.#styles
|
|
7617
|
+
});
|
|
6598
7618
|
if (Object.keys(this.#content).length || this.#displayName !== void 0) {
|
|
6599
7619
|
this.#ensureContentRenderer();
|
|
6600
7620
|
}
|
|
7621
|
+
if (this.#options.interaction !== false) {
|
|
7622
|
+
const interaction = this.#options.interaction ?? {};
|
|
7623
|
+
const pressAction = interaction.press ?? (interaction.pressEvent ? "emit" : "toggle-content");
|
|
7624
|
+
const controlsContent = Boolean(this.#contentRenderer) && (pressAction === "toggle-content" || pressAction === "show-content" || pressAction === "hide-content");
|
|
7625
|
+
if (interaction.contentInitiallyHidden) {
|
|
7626
|
+
this.#contentRenderer?.setUserHidden(true);
|
|
7627
|
+
}
|
|
7628
|
+
this.#interactionController = new CharacterInteractionController({
|
|
7629
|
+
document: this.#document,
|
|
7630
|
+
styles: this.#styles,
|
|
7631
|
+
label: interaction.label ?? `Interact with ${loaded.content.displayName || "Peekling"}`,
|
|
7632
|
+
draggable: interaction.drag !== false,
|
|
7633
|
+
...controlsContent ? { expanded: !interaction.contentInitiallyHidden } : {},
|
|
7634
|
+
...this.#indicator ? { indicator: this.#indicator } : {},
|
|
7635
|
+
onPress: () => this.#handleCharacterPress(),
|
|
7636
|
+
onDragStart: () => this.#startCharacterDrag(),
|
|
7637
|
+
onDragMove: (position, velocity) => this.#moveCharacterDrag(position, velocity),
|
|
7638
|
+
onDragEnd: (velocity, moved, pointer) => this.#endCharacterDrag(velocity, moved, pointer)
|
|
7639
|
+
});
|
|
7640
|
+
if (interaction.contentInitiallyHidden) {
|
|
7641
|
+
this.#interactionController.setExpanded(false);
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
6601
7644
|
try {
|
|
6602
7645
|
await Promise.all([
|
|
6603
7646
|
this.#visibilityReady,
|
|
6604
7647
|
this.#renderer.ready,
|
|
6605
|
-
this.#contentRenderer?.ready
|
|
7648
|
+
this.#contentRenderer?.ready,
|
|
7649
|
+
this.#interactionController?.ready
|
|
6606
7650
|
]);
|
|
6607
7651
|
} catch (cause) {
|
|
6608
7652
|
this.#diagnoseStyleFailure(cause);
|
|
@@ -6610,6 +7654,14 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6610
7654
|
}
|
|
6611
7655
|
const requirements = compiledPlanSectionRequirements(compiled);
|
|
6612
7656
|
this.#createInput();
|
|
7657
|
+
if (targetIds.size) {
|
|
7658
|
+
this.#targets = new TargetTracker(
|
|
7659
|
+
this.#document,
|
|
7660
|
+
this.#window,
|
|
7661
|
+
this.#options.targets,
|
|
7662
|
+
() => this.#wake()
|
|
7663
|
+
);
|
|
7664
|
+
}
|
|
6613
7665
|
if (requirements.selectors.length) {
|
|
6614
7666
|
this.#sections = new SectionTracker(
|
|
6615
7667
|
this.#document,
|
|
@@ -6621,6 +7673,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6621
7673
|
);
|
|
6622
7674
|
}
|
|
6623
7675
|
this.#renderer.setHidden(this.#siteHidden);
|
|
7676
|
+
this.#interactionController?.setHidden(this.#siteHidden);
|
|
6624
7677
|
if (this.#suspensions) {
|
|
6625
7678
|
this.#input?.setSuspended(true);
|
|
6626
7679
|
this.#sections?.setSuspended(true);
|
|
@@ -6684,6 +7737,129 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6684
7737
|
});
|
|
6685
7738
|
return this.#contentRenderer;
|
|
6686
7739
|
}
|
|
7740
|
+
#handleCharacterPress() {
|
|
7741
|
+
if (this.#destroyed) return;
|
|
7742
|
+
const interaction = this.#options.interaction || {};
|
|
7743
|
+
if (interaction.clearIndicatorOnPress === true && this.#indicator) {
|
|
7744
|
+
this.setIndicator(null);
|
|
7745
|
+
}
|
|
7746
|
+
const action = interaction.press ?? (interaction.pressEvent ? "emit" : "toggle-content");
|
|
7747
|
+
if (action === "emit") {
|
|
7748
|
+
if (interaction.pressEvent) this.emit(interaction.pressEvent);
|
|
7749
|
+
return;
|
|
7750
|
+
}
|
|
7751
|
+
if (action === "none") return;
|
|
7752
|
+
if (action === "show-content") this.setContentVisible(true);
|
|
7753
|
+
else if (action === "hide-content") this.setContentVisible(false);
|
|
7754
|
+
else this.toggleContent();
|
|
7755
|
+
}
|
|
7756
|
+
#startCharacterDrag() {
|
|
7757
|
+
if (this.#destroyed || this.#siteHidden) return;
|
|
7758
|
+
this.#dragging = true;
|
|
7759
|
+
this.#throwing = false;
|
|
7760
|
+
this.#landUntil = 0;
|
|
7761
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7762
|
+
this.#wake();
|
|
7763
|
+
}
|
|
7764
|
+
#moveCharacterDrag(position, velocity) {
|
|
7765
|
+
if (!this.#dragging || this.#destroyed) return;
|
|
7766
|
+
const size = this.#characterSize();
|
|
7767
|
+
this.#position = size ? clampPosition(
|
|
7768
|
+
position,
|
|
7769
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7770
|
+
size.width,
|
|
7771
|
+
size.height
|
|
7772
|
+
) : { ...position };
|
|
7773
|
+
this.#throwVelocity = { ...velocity };
|
|
7774
|
+
this.#wake();
|
|
7775
|
+
}
|
|
7776
|
+
#endCharacterDrag(velocity, moved, pointer) {
|
|
7777
|
+
if (!this.#dragging || this.#destroyed) return;
|
|
7778
|
+
this.#dragging = false;
|
|
7779
|
+
if (!moved) {
|
|
7780
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7781
|
+
this.#wake();
|
|
7782
|
+
return;
|
|
7783
|
+
}
|
|
7784
|
+
const interaction = this.#options.interaction || {};
|
|
7785
|
+
if (interaction.catchTarget && this.#targets?.contains(
|
|
7786
|
+
interaction.catchTarget,
|
|
7787
|
+
pointer,
|
|
7788
|
+
interaction.catchMargin ?? 24
|
|
7789
|
+
) && this.#catchCharacter(interaction.catchTarget)) {
|
|
7790
|
+
return;
|
|
7791
|
+
}
|
|
7792
|
+
if (this.#reducedMotion) {
|
|
7793
|
+
this.#landCharacter();
|
|
7794
|
+
return;
|
|
7795
|
+
}
|
|
7796
|
+
if (interaction.throw === false) {
|
|
7797
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7798
|
+
this.#wake();
|
|
7799
|
+
return;
|
|
7800
|
+
}
|
|
7801
|
+
const maximum = interaction.maxThrowSpeed ?? DEFAULT_THROW_SPEED;
|
|
7802
|
+
const magnitude = Math.hypot(velocity.x, velocity.y);
|
|
7803
|
+
const factor = magnitude > maximum && magnitude ? maximum / magnitude : 1;
|
|
7804
|
+
this.#throwVelocity = {
|
|
7805
|
+
x: velocity.x * factor,
|
|
7806
|
+
y: velocity.y * factor
|
|
7807
|
+
};
|
|
7808
|
+
this.#throwing = true;
|
|
7809
|
+
this.#wake();
|
|
7810
|
+
}
|
|
7811
|
+
#characterSize() {
|
|
7812
|
+
const loaded = this.#loaded?.content;
|
|
7813
|
+
if (!loaded) return;
|
|
7814
|
+
const scale = this.#options.scale ?? loaded.defaultScale;
|
|
7815
|
+
return {
|
|
7816
|
+
width: (loaded.atlas.logicalWidth ?? loaded.atlas.cellWidth) * scale,
|
|
7817
|
+
height: (loaded.atlas.logicalHeight ?? loaded.atlas.cellHeight) * scale
|
|
7818
|
+
};
|
|
7819
|
+
}
|
|
7820
|
+
#landCharacter() {
|
|
7821
|
+
const size = this.#characterSize();
|
|
7822
|
+
if (size) {
|
|
7823
|
+
const floorInset = (this.#options.interaction || {}).floorInset ?? DEFAULT_FLOOR_INSET;
|
|
7824
|
+
this.#position = clampPosition(
|
|
7825
|
+
{
|
|
7826
|
+
x: this.#position.x,
|
|
7827
|
+
y: this.#window.innerHeight - size.height / 2 - floorInset
|
|
7828
|
+
},
|
|
7829
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7830
|
+
size.width,
|
|
7831
|
+
size.height
|
|
7832
|
+
);
|
|
7833
|
+
}
|
|
7834
|
+
this.#dragging = false;
|
|
7835
|
+
this.#throwing = false;
|
|
7836
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7837
|
+
this.#landUntil = this.#now() + 360;
|
|
7838
|
+
this.#wake();
|
|
7839
|
+
}
|
|
7840
|
+
#catchCharacter(targetId) {
|
|
7841
|
+
const target = this.#targets?.snapshot(true)[targetId];
|
|
7842
|
+
const size = this.#characterSize();
|
|
7843
|
+
if (!target || !size) return false;
|
|
7844
|
+
const interaction = this.#options.interaction || {};
|
|
7845
|
+
const point = characterTargetPoint(
|
|
7846
|
+
target,
|
|
7847
|
+
interaction.catchAnchor ?? "center",
|
|
7848
|
+
size
|
|
7849
|
+
);
|
|
7850
|
+
this.#position = clampPosition(
|
|
7851
|
+
point,
|
|
7852
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7853
|
+
size.width,
|
|
7854
|
+
size.height
|
|
7855
|
+
);
|
|
7856
|
+
this.#throwing = false;
|
|
7857
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7858
|
+
this.#landUntil = this.#now() + 360;
|
|
7859
|
+
if (interaction.catchEvent) this.emit(interaction.catchEvent);
|
|
7860
|
+
this.#wake();
|
|
7861
|
+
return true;
|
|
7862
|
+
}
|
|
6687
7863
|
#diagnose(message, code = "runtime.notice", severity = "warning", phase = "internal", eventId, metadata, cause) {
|
|
6688
7864
|
this.#diagnostics.emit({
|
|
6689
7865
|
code,
|
|
@@ -6770,6 +7946,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6770
7946
|
if (hidden === this.#siteHidden) return;
|
|
6771
7947
|
this.#siteHidden = hidden;
|
|
6772
7948
|
this.#renderer?.setHidden(hidden);
|
|
7949
|
+
this.#interactionController?.setHidden(hidden);
|
|
6773
7950
|
if (this.#destroyed) return;
|
|
6774
7951
|
if (hidden && this.#contentRenderer) {
|
|
6775
7952
|
this.#contentRenderer.renderSurfaces(
|
|
@@ -6785,6 +7962,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6785
7962
|
if (this.#destroyed) return;
|
|
6786
7963
|
}
|
|
6787
7964
|
if (hidden) {
|
|
7965
|
+
this.#dragging = false;
|
|
7966
|
+
this.#throwing = false;
|
|
7967
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
6788
7968
|
this.#overrides?.clear("dismissed");
|
|
6789
7969
|
this.#setSuspended(SUSPEND_SITE, true);
|
|
6790
7970
|
this.#notice("lifecycle.dismissed", "info", "lifecycle");
|
|
@@ -6880,8 +8060,13 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6880
8060
|
const loaded = this.#loaded;
|
|
6881
8061
|
this.#densityUpgrade = loaded.upgrade(required).then((changed) => {
|
|
6882
8062
|
if (changed && !this.#destroyed && this.#loaded === loaded) {
|
|
6883
|
-
this.#renderer
|
|
6884
|
-
|
|
8063
|
+
const renderer = this.#renderer;
|
|
8064
|
+
if (!renderer) return;
|
|
8065
|
+
return Promise.resolve(
|
|
8066
|
+
renderer.swapAtlas(loaded.content, loaded.atlasObjectUrl)
|
|
8067
|
+
).then(() => {
|
|
8068
|
+
if (!this.#destroyed && this.#loaded === loaded) this.#wake();
|
|
8069
|
+
});
|
|
6885
8070
|
}
|
|
6886
8071
|
}).catch((error) => {
|
|
6887
8072
|
if (!this.#destroyed)
|
|
@@ -6953,10 +8138,13 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6953
8138
|
pointer: input.pointer,
|
|
6954
8139
|
position: this.#position,
|
|
6955
8140
|
viewport,
|
|
8141
|
+
characterSize,
|
|
6956
8142
|
lastActivityAt: input.lastActivityAt,
|
|
6957
8143
|
reducedMotion: this.#reducedMotion,
|
|
6958
8144
|
pageVisible: !this.#document.hidden,
|
|
6959
8145
|
sections,
|
|
8146
|
+
targets: this.#targets?.snapshot(this.#trackTargets),
|
|
8147
|
+
samplePath: (path, progress) => this.#pathSampler.sample(path, progress),
|
|
6960
8148
|
reaction
|
|
6961
8149
|
};
|
|
6962
8150
|
return {
|
|
@@ -6977,11 +8165,26 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6977
8165
|
overrides.observeEvent(reaction.name, reaction.source);
|
|
6978
8166
|
}
|
|
6979
8167
|
const request = overrides.compose(ordinary, world);
|
|
8168
|
+
this.#trackTargets = request.motion?.trackTarget === true;
|
|
6980
8169
|
if (this.#reducedMotion) {
|
|
6981
8170
|
delete request.motion;
|
|
6982
8171
|
if (request.capability === "locomotion") delete request.capability;
|
|
6983
8172
|
if (!request.state) request.state = "idle";
|
|
6984
8173
|
}
|
|
8174
|
+
const interaction = this.#options.interaction || {};
|
|
8175
|
+
if (this.#dragging) {
|
|
8176
|
+
delete request.motion;
|
|
8177
|
+
delete request.capability;
|
|
8178
|
+
request.state = interaction.dragState ?? "scroll:fly";
|
|
8179
|
+
} else if (this.#throwing) {
|
|
8180
|
+
delete request.motion;
|
|
8181
|
+
delete request.capability;
|
|
8182
|
+
request.state = this.#throwVelocity.y < 0 ? interaction.riseState ?? "scroll:fly" : interaction.fallState ?? "scroll:fall";
|
|
8183
|
+
} else if (this.#landUntil > world.now) {
|
|
8184
|
+
delete request.motion;
|
|
8185
|
+
delete request.capability;
|
|
8186
|
+
request.state = interaction.landState ?? "success";
|
|
8187
|
+
}
|
|
6985
8188
|
const diagnostics = [];
|
|
6986
8189
|
if (reaction) {
|
|
6987
8190
|
this.#seenReaction = reaction.id;
|
|
@@ -7040,19 +8243,74 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7040
8243
|
}
|
|
7041
8244
|
return this.#frameActive(frame);
|
|
7042
8245
|
}
|
|
8246
|
+
#advanceThrow(snapshot) {
|
|
8247
|
+
if (!this.#throwing) return;
|
|
8248
|
+
const interaction = this.#options.interaction || {};
|
|
8249
|
+
const dt = snapshot.frame.stepMs / 1e3;
|
|
8250
|
+
const bounce = interaction.bounce ?? DEFAULT_BOUNCE;
|
|
8251
|
+
const halfWidth = snapshot.characterSize.width / 2;
|
|
8252
|
+
const halfHeight = snapshot.characterSize.height / 2;
|
|
8253
|
+
const floor = snapshot.world.viewport.height - halfHeight - (interaction.floorInset ?? DEFAULT_FLOOR_INSET);
|
|
8254
|
+
let velocityX = this.#throwVelocity.x;
|
|
8255
|
+
let velocityY = this.#throwVelocity.y + (interaction.gravity ?? DEFAULT_GRAVITY) * dt;
|
|
8256
|
+
let x = this.#position.x + velocityX * dt;
|
|
8257
|
+
let y = this.#position.y + velocityY * dt;
|
|
8258
|
+
const right = snapshot.world.viewport.width - halfWidth;
|
|
8259
|
+
if (x < halfWidth) {
|
|
8260
|
+
x = halfWidth;
|
|
8261
|
+
velocityX = Math.abs(velocityX) * bounce;
|
|
8262
|
+
} else if (x > right) {
|
|
8263
|
+
x = right;
|
|
8264
|
+
velocityX = -Math.abs(velocityX) * bounce;
|
|
8265
|
+
}
|
|
8266
|
+
if (y < halfHeight) {
|
|
8267
|
+
y = halfHeight;
|
|
8268
|
+
velocityY = Math.abs(velocityY) * bounce;
|
|
8269
|
+
}
|
|
8270
|
+
const next = { x, y };
|
|
8271
|
+
if (interaction.catchTarget && this.#targets?.contains(
|
|
8272
|
+
interaction.catchTarget,
|
|
8273
|
+
next,
|
|
8274
|
+
interaction.catchMargin ?? 24
|
|
8275
|
+
) && this.#catchCharacter(interaction.catchTarget)) {
|
|
8276
|
+
return;
|
|
8277
|
+
}
|
|
8278
|
+
if (y >= floor) {
|
|
8279
|
+
this.#position = { x, y: floor };
|
|
8280
|
+
this.#landCharacter();
|
|
8281
|
+
return;
|
|
8282
|
+
}
|
|
8283
|
+
this.#position = next;
|
|
8284
|
+
this.#throwVelocity = { x: velocityX * 0.995, y: velocityY };
|
|
8285
|
+
}
|
|
7043
8286
|
#calculatePresentation(snapshot, evaluation) {
|
|
7044
8287
|
const { frame, characterSize, world } = snapshot;
|
|
7045
8288
|
const { request } = evaluation;
|
|
7046
8289
|
const loaded = frame.loaded.content;
|
|
7047
8290
|
if (!this.#reducedMotion)
|
|
7048
8291
|
this.#animationClock += Math.max(0, frame.elapsed);
|
|
8292
|
+
this.#advanceThrow(snapshot);
|
|
7049
8293
|
const requested = request.capability === "locomotion" && request.motion ? loaded.directionalStates?.[directionTo(
|
|
7050
8294
|
{ x: 0, y: 0 },
|
|
7051
8295
|
{ x: request.motion.x, y: request.motion.y }
|
|
7052
8296
|
)] : resolveCapabilityName(request.state, loaded);
|
|
7053
8297
|
const resolved = resolveState(requested, loaded.states);
|
|
7054
8298
|
let lift = 0;
|
|
7055
|
-
if (request.motion) {
|
|
8299
|
+
if (request.motion?.direct) {
|
|
8300
|
+
const distance = request.motion.maxDistance ?? 0;
|
|
8301
|
+
this.#position = clampPosition(
|
|
8302
|
+
{
|
|
8303
|
+
x: this.#position.x + request.motion.x * distance,
|
|
8304
|
+
y: this.#position.y + request.motion.y * distance
|
|
8305
|
+
},
|
|
8306
|
+
world.viewport,
|
|
8307
|
+
characterSize.width,
|
|
8308
|
+
characterSize.height
|
|
8309
|
+
);
|
|
8310
|
+
lift = request.motion.lift ?? 0;
|
|
8311
|
+
this.#locomotionState = "";
|
|
8312
|
+
this.#locomotionElapsed = 0;
|
|
8313
|
+
} else if (request.motion) {
|
|
7056
8314
|
if (this.#locomotionState !== resolved.name) {
|
|
7057
8315
|
this.#locomotionState = resolved.name;
|
|
7058
8316
|
this.#locomotionElapsed = 0;
|
|
@@ -7083,7 +8341,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7083
8341
|
characterSize.width,
|
|
7084
8342
|
characterSize.height
|
|
7085
8343
|
);
|
|
7086
|
-
lift = locomotionSample(loaded.locomotionMotion, nextCycles).lift * characterSize.height;
|
|
8344
|
+
lift = request.motion.lift ?? locomotionSample(loaded.locomotionMotion, nextCycles).lift * characterSize.height;
|
|
7087
8345
|
} else {
|
|
7088
8346
|
this.#locomotionState = "";
|
|
7089
8347
|
this.#locomotionElapsed = 0;
|
|
@@ -7117,9 +8375,15 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7117
8375
|
presentation.lift
|
|
7118
8376
|
);
|
|
7119
8377
|
if (!this.#frameActive(frame)) return;
|
|
8378
|
+
this.#interactionController?.render(
|
|
8379
|
+
this.#position,
|
|
8380
|
+
snapshot.characterSize,
|
|
8381
|
+
presentation.lift
|
|
8382
|
+
);
|
|
8383
|
+
if (!this.#frameActive(frame)) return;
|
|
7120
8384
|
this.#lastTick = frame.now;
|
|
7121
8385
|
this.#schedulePlan(frame);
|
|
7122
|
-
if (this.#frameActive(frame) && (evaluation.request.motion || frame.input.reaction))
|
|
8386
|
+
if (this.#frameActive(frame) && (evaluation.request.motion || frame.input.reaction || this.#throwing || this.#dragging))
|
|
7123
8387
|
this.#wake();
|
|
7124
8388
|
}
|
|
7125
8389
|
#endPage() {
|
|
@@ -7202,6 +8466,24 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7202
8466
|
y: Math.max(height / 2, Math.min(viewport.height - height / 2, point.y))
|
|
7203
8467
|
};
|
|
7204
8468
|
}
|
|
8469
|
+
function characterTargetPoint(target, anchor, character) {
|
|
8470
|
+
const center = {
|
|
8471
|
+
x: target.left + target.width / 2,
|
|
8472
|
+
y: target.top + target.height / 2
|
|
8473
|
+
};
|
|
8474
|
+
switch (anchor) {
|
|
8475
|
+
case "top":
|
|
8476
|
+
return { x: center.x, y: target.top - character.height / 2 };
|
|
8477
|
+
case "right":
|
|
8478
|
+
return { x: target.right + character.width / 2, y: center.y };
|
|
8479
|
+
case "bottom":
|
|
8480
|
+
return { x: center.x, y: target.bottom + character.height / 2 };
|
|
8481
|
+
case "left":
|
|
8482
|
+
return { x: target.left - character.width / 2, y: center.y };
|
|
8483
|
+
default:
|
|
8484
|
+
return center;
|
|
8485
|
+
}
|
|
8486
|
+
}
|
|
7205
8487
|
|
|
7206
8488
|
// packages/runtime/src/web-component.ts
|
|
7207
8489
|
var PEEKLING_ELEMENT_TAG = "peekling-character";
|
|
@@ -7436,7 +8718,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7436
8718
|
}
|
|
7437
8719
|
|
|
7438
8720
|
// packages/runtime/src/browser.ts
|
|
7439
|
-
var browserCssIntegrity = "sha256-
|
|
8721
|
+
var browserCssIntegrity = "sha256-G1Pmoq2z4+o4mTD2uGdP0s6zJFJB7ZZbDgIGlBeFYsM=" ? "sha256-G1Pmoq2z4+o4mTD2uGdP0s6zJFJB7ZZbDgIGlBeFYsM=" : void 0;
|
|
7440
8722
|
var browserScript = globalThis.document?.currentScript;
|
|
7441
8723
|
if (browserScript?.src) {
|
|
7442
8724
|
setBrowserStyleAsset({
|