@peekling/runtime 0.1.0 → 0.1.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/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 +204 -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 +1365 -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.2 | 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,208 @@
|
|
|
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, this.#moved, { x: 0, y: 0 }, this.#lastPointer);
|
|
1732
|
+
};
|
|
1733
|
+
#finishPointer(event, moved, velocity, pointer = { x: event.clientX, y: event.clientY }) {
|
|
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, pointer);
|
|
1744
|
+
}
|
|
1745
|
+
#repair() {
|
|
1746
|
+
if (this.#destroyed) return;
|
|
1747
|
+
connectRuntimeHost(this.#host, this.#document, "data-peekling-interaction");
|
|
1748
|
+
if (this.#root.host !== this.#host || this.#button.getRootNode() !== this.#root) {
|
|
1749
|
+
throw new Error(
|
|
1750
|
+
runtimeMessage(
|
|
1751
|
+
"interaction.root",
|
|
1752
|
+
"Peekling interaction root structure was changed"
|
|
1753
|
+
)
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1534
1759
|
// packages/runtime/src/direction.ts
|
|
1535
1760
|
var OCTANTS = ["E", "SE", "S", "SW", "W", "NW", "N", "NE"];
|
|
1536
1761
|
function directionTo(from, to) {
|
|
@@ -2949,8 +3174,8 @@
|
|
|
2949
3174
|
}
|
|
2950
3175
|
|
|
2951
3176
|
// 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 ? "
|
|
3177
|
+
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";
|
|
3178
|
+
var PEEK_REFERENCE_SHA256 = true ? "9a2e2a41e85f7c4b8d3487a3655db40872675bd9c0780e139a946eabdf71d75f" : "9a2e2a41e85f7c4b8d3487a3655db40872675bd9c0780e139a946eabdf71d75f";
|
|
2954
3179
|
var REGISTRY = {
|
|
2955
3180
|
peek: Object.freeze({
|
|
2956
3181
|
url: PEEK_REFERENCE_URL,
|
|
@@ -3840,7 +4065,7 @@
|
|
|
3840
4065
|
);
|
|
3841
4066
|
}
|
|
3842
4067
|
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
|
|
4068
|
+
const motion = input.motion === void 0 ? void 0 : compileMotion(input.motion, `${path}.motion`, context);
|
|
3844
4069
|
const surfaces = input.surfaces === void 0 ? [] : input.surfaces;
|
|
3845
4070
|
if (!Array.isArray(surfaces) || surfaces.length > SURFACE_LIMIT) {
|
|
3846
4071
|
fail(
|
|
@@ -4010,19 +4235,81 @@
|
|
|
4010
4235
|
}
|
|
4011
4236
|
return freeze({ kind: "capability", name: input.capability });
|
|
4012
4237
|
}
|
|
4013
|
-
function compileMotion(input, path) {
|
|
4238
|
+
function compileMotion(input, path, context) {
|
|
4014
4239
|
object(input, path);
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4240
|
+
switch (input.type) {
|
|
4241
|
+
case "follow-pointer":
|
|
4242
|
+
closed3(input, ["type", "speed", "arrivalRadius"], path);
|
|
4243
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4244
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4245
|
+
break;
|
|
4246
|
+
case "horizontal-patrol":
|
|
4247
|
+
closed3(input, ["type", "speed", "edgeInset"], path);
|
|
4248
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4249
|
+
bounded(input.edgeInset, `${path}.edgeInset`, 0, 1e3);
|
|
4250
|
+
break;
|
|
4251
|
+
case "viewport-traverse":
|
|
4252
|
+
closed3(input, ["type", "speed", "edgeInset", "clockwise"], path);
|
|
4253
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4254
|
+
bounded(input.edgeInset, `${path}.edgeInset`, 0, 1e3);
|
|
4255
|
+
if (input.clockwise !== void 0 && typeof input.clockwise !== "boolean") {
|
|
4256
|
+
fail("invalid-motion", `${path}.clockwise`, "must be boolean");
|
|
4257
|
+
}
|
|
4258
|
+
break;
|
|
4259
|
+
case "move-to":
|
|
4260
|
+
closed3(input, ["type", "x", "y", "speed", "arrivalRadius"], path);
|
|
4261
|
+
bounded(input.x, `${path}.x`, -1e5, 1e5);
|
|
4262
|
+
bounded(input.y, `${path}.y`, -1e5, 1e5);
|
|
4263
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4264
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4265
|
+
break;
|
|
4266
|
+
case "move-to-target":
|
|
4267
|
+
closed3(
|
|
4268
|
+
input,
|
|
4269
|
+
["type", "target", "anchor", "speed", "arrivalRadius"],
|
|
4270
|
+
path
|
|
4271
|
+
);
|
|
4272
|
+
id(input.target, `${path}.target`, "Target");
|
|
4273
|
+
if (context.targets && !context.targets.has(input.target)) {
|
|
4274
|
+
fail(
|
|
4275
|
+
"unknown-target",
|
|
4276
|
+
`${path}.target`,
|
|
4277
|
+
`references unknown target ${input.target}`
|
|
4278
|
+
);
|
|
4279
|
+
}
|
|
4280
|
+
if (input.anchor !== void 0 && !["center", "top", "right", "bottom", "left"].includes(input.anchor)) {
|
|
4281
|
+
fail("invalid-motion", `${path}.anchor`, "is not supported");
|
|
4282
|
+
}
|
|
4283
|
+
bounded(input.speed, `${path}.speed`, 1, 1e3);
|
|
4284
|
+
bounded(input.arrivalRadius, `${path}.arrivalRadius`, 0, 1e3);
|
|
4285
|
+
break;
|
|
4286
|
+
case "jump-to":
|
|
4287
|
+
closed3(input, ["type", "x", "y", "duration", "height"], path);
|
|
4288
|
+
bounded(input.x, `${path}.x`, -1e5, 1e5);
|
|
4289
|
+
bounded(input.y, `${path}.y`, -1e5, 1e5);
|
|
4290
|
+
bounded(input.duration, `${path}.duration`, 100, 1e4);
|
|
4291
|
+
bounded(input.height, `${path}.height`, 0, 2e3);
|
|
4292
|
+
break;
|
|
4293
|
+
case "svg-path": {
|
|
4294
|
+
closed3(input, ["type", "path", "duration", "loop", "relative"], path);
|
|
4295
|
+
if (typeof input.path !== "string" || input.path.length < 1 || input.path.length > 4096 || /[\0\r\n]/.test(input.path)) {
|
|
4296
|
+
fail("invalid-path", `${path}.path`, "must be bounded SVG path data");
|
|
4297
|
+
}
|
|
4298
|
+
if (context.validatePath && !context.validatePath(input.path)) {
|
|
4299
|
+
fail("invalid-path", `${path}.path`, "must be valid SVG path data");
|
|
4300
|
+
}
|
|
4301
|
+
bounded(input.duration, `${path}.duration`, 100, 6e4);
|
|
4302
|
+
for (const field of ["loop", "relative"]) {
|
|
4303
|
+
if (input[field] !== void 0 && typeof input[field] !== "boolean") {
|
|
4304
|
+
fail("invalid-motion", `${path}.${field}`, "must be boolean");
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
break;
|
|
4308
|
+
}
|
|
4309
|
+
default:
|
|
4310
|
+
fail("invalid-motion", `${path}.type`, "is not a supported motion type");
|
|
4018
4311
|
}
|
|
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
|
-
});
|
|
4312
|
+
return freeze({ ...input });
|
|
4026
4313
|
}
|
|
4027
4314
|
function compileSurface(input, path, context, allowPayload) {
|
|
4028
4315
|
object(input, path);
|
|
@@ -4363,7 +4650,25 @@
|
|
|
4363
4650
|
thresholds: [...thresholds].sort((left, right) => left - right)
|
|
4364
4651
|
};
|
|
4365
4652
|
}
|
|
4366
|
-
function
|
|
4653
|
+
function createPresetPlan(preset, locomotion) {
|
|
4654
|
+
const state = locomotion ? { capability: "locomotion" } : { state: "idle" };
|
|
4655
|
+
if (preset === "still") {
|
|
4656
|
+
return {
|
|
4657
|
+
baseline: {
|
|
4658
|
+
channels: ["state"],
|
|
4659
|
+
state: { state: "idle" }
|
|
4660
|
+
}
|
|
4661
|
+
};
|
|
4662
|
+
}
|
|
4663
|
+
if (preset === "bottom-patrol" || preset === "viewport-roam") {
|
|
4664
|
+
return {
|
|
4665
|
+
baseline: {
|
|
4666
|
+
channels: ["motion", "state"],
|
|
4667
|
+
state,
|
|
4668
|
+
motion: preset === "bottom-patrol" ? { type: "horizontal-patrol", speed: DEFAULT_SPEED } : { type: "viewport-traverse", speed: DEFAULT_SPEED }
|
|
4669
|
+
}
|
|
4670
|
+
};
|
|
4671
|
+
}
|
|
4367
4672
|
return {
|
|
4368
4673
|
baseline: {
|
|
4369
4674
|
channels: ["state"],
|
|
@@ -4389,6 +4694,12 @@
|
|
|
4389
4694
|
#eventState = createPlanEventState();
|
|
4390
4695
|
#activeChannels = /* @__PURE__ */ new Map();
|
|
4391
4696
|
#activeSurfaces = /* @__PURE__ */ new Map();
|
|
4697
|
+
#patrolDirections = /* @__PURE__ */ new WeakMap();
|
|
4698
|
+
#traversePhases = /* @__PURE__ */ new WeakMap();
|
|
4699
|
+
#jumpOwner;
|
|
4700
|
+
#jumpState;
|
|
4701
|
+
#pathOwner;
|
|
4702
|
+
#pathState;
|
|
4392
4703
|
#activeInterrupts = [];
|
|
4393
4704
|
#surfaceVersion = 0;
|
|
4394
4705
|
#lastEventStatus;
|
|
@@ -4476,24 +4787,81 @@
|
|
|
4476
4787
|
if (state?.kind === "capability") {
|
|
4477
4788
|
output.capability = state.name;
|
|
4478
4789
|
}
|
|
4479
|
-
const
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
const
|
|
4485
|
-
if (
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4790
|
+
const motionOwner = channels.get("motion");
|
|
4791
|
+
const motion = motionOwner?.motion;
|
|
4792
|
+
const settleCapability = () => {
|
|
4793
|
+
if (output.capability !== "locomotion") return;
|
|
4794
|
+
delete output.capability;
|
|
4795
|
+
const baseline = this.#baselineState();
|
|
4796
|
+
if (!output.state && baseline) output.state = baseline;
|
|
4797
|
+
};
|
|
4798
|
+
if (motion?.type !== "jump-to") {
|
|
4799
|
+
this.#jumpOwner = void 0;
|
|
4800
|
+
this.#jumpState = void 0;
|
|
4801
|
+
}
|
|
4802
|
+
if (motion?.type !== "svg-path") {
|
|
4803
|
+
this.#pathOwner = void 0;
|
|
4804
|
+
this.#pathState = void 0;
|
|
4805
|
+
}
|
|
4806
|
+
if (motion?.type === "horizontal-patrol" && world.characterSize) {
|
|
4807
|
+
const [direction, request] = evaluateHorizontalPatrol(
|
|
4808
|
+
motion,
|
|
4809
|
+
world,
|
|
4810
|
+
this.#patrolDirections.get(motionOwner) ?? true
|
|
4811
|
+
);
|
|
4812
|
+
this.#patrolDirections.set(motionOwner, direction);
|
|
4813
|
+
if (request) output.motion = request;
|
|
4814
|
+
} else if (motion?.type === "viewport-traverse" && world.characterSize) {
|
|
4815
|
+
const [phase, request] = evaluateViewportTraverse(
|
|
4816
|
+
motion,
|
|
4817
|
+
world,
|
|
4818
|
+
this.#traversePhases.get(motionOwner)
|
|
4819
|
+
);
|
|
4820
|
+
this.#traversePhases.set(motionOwner, phase);
|
|
4821
|
+
if (request) output.motion = request;
|
|
4822
|
+
} else if (motion?.type === "follow-pointer") {
|
|
4823
|
+
const request = world.pointer ? motionToward(
|
|
4824
|
+
motion,
|
|
4825
|
+
world.position,
|
|
4826
|
+
world.pointer.x,
|
|
4827
|
+
world.pointer.y,
|
|
4828
|
+
motion.arrivalRadius,
|
|
4829
|
+
world
|
|
4830
|
+
) : void 0;
|
|
4831
|
+
if (request) output.motion = request;
|
|
4832
|
+
else settleCapability();
|
|
4833
|
+
} else if (motion?.type === "move-to") {
|
|
4834
|
+
const request = motionToward(
|
|
4835
|
+
motion,
|
|
4836
|
+
world.position,
|
|
4837
|
+
motion.x,
|
|
4838
|
+
motion.y,
|
|
4839
|
+
motion.arrivalRadius,
|
|
4840
|
+
world
|
|
4841
|
+
);
|
|
4842
|
+
if (request) output.motion = request;
|
|
4843
|
+
else settleCapability();
|
|
4844
|
+
} else if (motion?.type === "move-to-target") {
|
|
4845
|
+
const target = world.targets?.[motion.target];
|
|
4846
|
+
const point = target && world.characterSize ? targetPoint(target, motion.anchor, world.characterSize) : void 0;
|
|
4847
|
+
const request = point ? motionToward(
|
|
4848
|
+
motion,
|
|
4849
|
+
world.position,
|
|
4850
|
+
point.x,
|
|
4851
|
+
point.y,
|
|
4852
|
+
motion.arrivalRadius,
|
|
4853
|
+
world
|
|
4854
|
+
) : void 0;
|
|
4855
|
+
if (request) output.motion = { ...request, trackTarget: true };
|
|
4856
|
+
else settleCapability();
|
|
4857
|
+
} else if (motion?.type === "jump-to") {
|
|
4858
|
+
const request = this.#evaluateJump(motionOwner, motion, world);
|
|
4859
|
+
if (request) output.motion = request;
|
|
4860
|
+
else settleCapability();
|
|
4861
|
+
} else if (motion?.type === "svg-path") {
|
|
4862
|
+
const request = this.#evaluatePath(motionOwner, motion, world);
|
|
4863
|
+
if (request) output.motion = request;
|
|
4864
|
+
else settleCapability();
|
|
4497
4865
|
}
|
|
4498
4866
|
const selected = /* @__PURE__ */ new Map();
|
|
4499
4867
|
for (const surface of this.#plan.baseline.surfaces) {
|
|
@@ -4532,6 +4900,12 @@
|
|
|
4532
4900
|
this.#activeChannels.clear();
|
|
4533
4901
|
this.#activeSurfaces.clear();
|
|
4534
4902
|
this.#activeInterrupts = [];
|
|
4903
|
+
this.#patrolDirections = /* @__PURE__ */ new WeakMap();
|
|
4904
|
+
this.#traversePhases = /* @__PURE__ */ new WeakMap();
|
|
4905
|
+
this.#jumpOwner = void 0;
|
|
4906
|
+
this.#jumpState = void 0;
|
|
4907
|
+
this.#pathOwner = void 0;
|
|
4908
|
+
this.#pathState = void 0;
|
|
4535
4909
|
this.#eventState.ordering.clear();
|
|
4536
4910
|
this.#eventState.sessions.clear();
|
|
4537
4911
|
this.#lastEventStatus = void 0;
|
|
@@ -4557,17 +4931,75 @@
|
|
|
4557
4931
|
const state = this.#plan.baseline.state;
|
|
4558
4932
|
return state?.kind === "state" ? state.name : void 0;
|
|
4559
4933
|
}
|
|
4934
|
+
#evaluateJump(owner, effect, world) {
|
|
4935
|
+
if (this.#jumpOwner !== owner || !this.#jumpState) {
|
|
4936
|
+
this.#jumpOwner = owner;
|
|
4937
|
+
this.#jumpState = {
|
|
4938
|
+
startedAt: world.now,
|
|
4939
|
+
from: { ...world.position }
|
|
4940
|
+
};
|
|
4941
|
+
}
|
|
4942
|
+
const duration = effect.duration ?? 800;
|
|
4943
|
+
const progress = Math.max(
|
|
4944
|
+
0,
|
|
4945
|
+
Math.min(1, (world.now - this.#jumpState.startedAt) / duration)
|
|
4946
|
+
);
|
|
4947
|
+
const target = boundedPoint(effect, world);
|
|
4948
|
+
const desired = {
|
|
4949
|
+
x: this.#jumpState.from.x + (target.x - this.#jumpState.from.x) * progress,
|
|
4950
|
+
y: this.#jumpState.from.y + (target.y - this.#jumpState.from.y) * progress
|
|
4951
|
+
};
|
|
4952
|
+
const lift = progress === 0 || progress === 1 ? 0 : Math.sin(Math.PI * progress) * (effect.height ?? world.characterSize?.height ?? 32);
|
|
4953
|
+
const request = directMotion(world.position, desired, lift);
|
|
4954
|
+
if (progress < 1 || request.maxDistance) return request;
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
#evaluatePath(owner, effect, world) {
|
|
4958
|
+
const sample = world.samplePath;
|
|
4959
|
+
if (!sample) return;
|
|
4960
|
+
const first = sample(effect.path, 0);
|
|
4961
|
+
if (!first) return;
|
|
4962
|
+
if (this.#pathOwner !== owner || !this.#pathState) {
|
|
4963
|
+
this.#pathOwner = owner;
|
|
4964
|
+
this.#pathState = {
|
|
4965
|
+
startedAt: world.now,
|
|
4966
|
+
offset: effect.relative === false ? { x: 0, y: 0 } : {
|
|
4967
|
+
x: world.position.x - first.x,
|
|
4968
|
+
y: world.position.y - first.y
|
|
4969
|
+
}
|
|
4970
|
+
};
|
|
4971
|
+
}
|
|
4972
|
+
const duration = effect.duration ?? 4e3;
|
|
4973
|
+
const elapsed = Math.max(0, world.now - this.#pathState.startedAt);
|
|
4974
|
+
const complete = effect.loop !== true && elapsed >= duration;
|
|
4975
|
+
const progress = effect.loop ? elapsed % duration / duration : Math.min(1, elapsed / duration);
|
|
4976
|
+
const point = sample(effect.path, progress);
|
|
4977
|
+
if (!point) return;
|
|
4978
|
+
const desired = {
|
|
4979
|
+
x: point.x + this.#pathState.offset.x,
|
|
4980
|
+
y: point.y + this.#pathState.offset.y
|
|
4981
|
+
};
|
|
4982
|
+
const request = directMotion(world.position, boundedPoint(desired, world));
|
|
4983
|
+
if (!complete || request.maxDistance) return request;
|
|
4984
|
+
return;
|
|
4985
|
+
}
|
|
4560
4986
|
#isContinuous(rule, world) {
|
|
4561
4987
|
const condition = rule.when;
|
|
4562
4988
|
if (condition.source !== "browser") return false;
|
|
4563
4989
|
if (condition.event === "pointer.move") {
|
|
4564
4990
|
if (!world.pointer) return false;
|
|
4565
4991
|
const motion = rule.effect.motion;
|
|
4566
|
-
if (!motion) return true;
|
|
4567
|
-
return
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4992
|
+
if (!motion || motion.type !== "follow-pointer") return true;
|
|
4993
|
+
return Boolean(
|
|
4994
|
+
motionToward(
|
|
4995
|
+
motion,
|
|
4996
|
+
world.position,
|
|
4997
|
+
world.pointer.x,
|
|
4998
|
+
world.pointer.y,
|
|
4999
|
+
motion.arrivalRadius,
|
|
5000
|
+
world
|
|
5001
|
+
)
|
|
5002
|
+
);
|
|
4571
5003
|
}
|
|
4572
5004
|
if (condition.event !== "section.visibility") return false;
|
|
4573
5005
|
const section = world.sections?.[condition.selector];
|
|
@@ -4610,6 +5042,128 @@
|
|
|
4610
5042
|
function completionSource(name) {
|
|
4611
5043
|
return browserCompletionEvent(name) ? "browser" : "application";
|
|
4612
5044
|
}
|
|
5045
|
+
function evaluateHorizontalPatrol(effect, world, direction) {
|
|
5046
|
+
const halfWidth = world.characterSize.width / 2;
|
|
5047
|
+
const inset = effect.edgeInset ?? 0;
|
|
5048
|
+
const left = Math.min(world.viewport.width / 2, halfWidth + inset);
|
|
5049
|
+
const right = world.viewport.width - left;
|
|
5050
|
+
const halfHeight = world.characterSize.height / 2;
|
|
5051
|
+
const y = Math.max(halfHeight, world.viewport.height - halfHeight);
|
|
5052
|
+
let request = motionToward(
|
|
5053
|
+
effect,
|
|
5054
|
+
world.position,
|
|
5055
|
+
direction ? right : left,
|
|
5056
|
+
y
|
|
5057
|
+
);
|
|
5058
|
+
if (!request) {
|
|
5059
|
+
direction = !direction;
|
|
5060
|
+
request = motionToward(effect, world.position, direction ? right : left, y);
|
|
5061
|
+
}
|
|
5062
|
+
return [direction, request];
|
|
5063
|
+
}
|
|
5064
|
+
function evaluateViewportTraverse(effect, world, phase) {
|
|
5065
|
+
const inset = effect.edgeInset ?? 0;
|
|
5066
|
+
const halfWidth = world.characterSize.width / 2;
|
|
5067
|
+
const halfHeight = world.characterSize.height / 2;
|
|
5068
|
+
const left = Math.min(world.viewport.width / 2, halfWidth + inset);
|
|
5069
|
+
const right = Math.max(left, world.viewport.width - left);
|
|
5070
|
+
const top = Math.min(world.viewport.height / 2, halfHeight + inset);
|
|
5071
|
+
const bottom = Math.max(top, world.viewport.height - halfHeight - inset);
|
|
5072
|
+
const points = [
|
|
5073
|
+
{ x: left, y: bottom },
|
|
5074
|
+
{ x: right, y: bottom },
|
|
5075
|
+
{ x: right, y: top },
|
|
5076
|
+
{ x: left, y: top }
|
|
5077
|
+
];
|
|
5078
|
+
if (phase === void 0) {
|
|
5079
|
+
phase = points.reduce(
|
|
5080
|
+
(nearest, point, index) => Math.hypot(point.x - world.position.x, point.y - world.position.y) < Math.hypot(
|
|
5081
|
+
points[nearest].x - world.position.x,
|
|
5082
|
+
points[nearest].y - world.position.y
|
|
5083
|
+
) ? index : nearest,
|
|
5084
|
+
0
|
|
5085
|
+
);
|
|
5086
|
+
}
|
|
5087
|
+
let target = points[phase];
|
|
5088
|
+
let request = motionToward(effect, world.position, target.x, target.y);
|
|
5089
|
+
if (!request) {
|
|
5090
|
+
const direction = effect.clockwise === false ? -1 : 1;
|
|
5091
|
+
phase = (phase + direction + points.length) % points.length;
|
|
5092
|
+
target = points[phase];
|
|
5093
|
+
request = motionToward(effect, world.position, target.x, target.y);
|
|
5094
|
+
}
|
|
5095
|
+
return [phase, request];
|
|
5096
|
+
}
|
|
5097
|
+
function targetPoint(target, anchor = "center", character) {
|
|
5098
|
+
const center = {
|
|
5099
|
+
x: target.left + target.width / 2,
|
|
5100
|
+
y: target.top + target.height / 2
|
|
5101
|
+
};
|
|
5102
|
+
switch (anchor) {
|
|
5103
|
+
case "top":
|
|
5104
|
+
return { x: center.x, y: target.top - character.height / 2 };
|
|
5105
|
+
case "right":
|
|
5106
|
+
return { x: target.right + character.width / 2, y: center.y };
|
|
5107
|
+
case "bottom":
|
|
5108
|
+
return { x: center.x, y: target.bottom + character.height / 2 };
|
|
5109
|
+
case "left":
|
|
5110
|
+
return { x: target.left - character.width / 2, y: center.y };
|
|
5111
|
+
default:
|
|
5112
|
+
return center;
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5115
|
+
function boundedPoint(point, world) {
|
|
5116
|
+
const size = world.characterSize;
|
|
5117
|
+
if (!size) return { x: point.x, y: point.y };
|
|
5118
|
+
return {
|
|
5119
|
+
x: Math.max(
|
|
5120
|
+
size.width / 2,
|
|
5121
|
+
Math.min(world.viewport.width - size.width / 2, point.x)
|
|
5122
|
+
),
|
|
5123
|
+
y: Math.max(
|
|
5124
|
+
size.height / 2,
|
|
5125
|
+
Math.min(world.viewport.height - size.height / 2, point.y)
|
|
5126
|
+
)
|
|
5127
|
+
};
|
|
5128
|
+
}
|
|
5129
|
+
function directMotion(position, target, lift = 0) {
|
|
5130
|
+
const dx = target.x - position.x;
|
|
5131
|
+
const dy = target.y - position.y;
|
|
5132
|
+
const distance = Math.hypot(dx, dy);
|
|
5133
|
+
return {
|
|
5134
|
+
x: distance ? dx / distance : 0,
|
|
5135
|
+
y: distance ? dy / distance : 0,
|
|
5136
|
+
speed: 0,
|
|
5137
|
+
maxDistance: distance,
|
|
5138
|
+
lift,
|
|
5139
|
+
direct: true
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5142
|
+
function motionToward(effect, position, x, y, arrivalRadius = 0, bounds) {
|
|
5143
|
+
const size = bounds?.characterSize;
|
|
5144
|
+
const viewport = bounds?.viewport;
|
|
5145
|
+
if (size && viewport) {
|
|
5146
|
+
const pointerX = x;
|
|
5147
|
+
const pointerY = y;
|
|
5148
|
+
x = Math.max(size.width / 2, Math.min(viewport.width - size.width / 2, x));
|
|
5149
|
+
y = Math.max(
|
|
5150
|
+
size.height / 2,
|
|
5151
|
+
Math.min(viewport.height - size.height / 2, y)
|
|
5152
|
+
);
|
|
5153
|
+
if (x !== pointerX || y !== pointerY) arrivalRadius = 0;
|
|
5154
|
+
}
|
|
5155
|
+
const dx = x - position.x;
|
|
5156
|
+
const dy = y - position.y;
|
|
5157
|
+
const distance = Math.hypot(dx, dy);
|
|
5158
|
+
const maxDistance = distance - arrivalRadius;
|
|
5159
|
+
if (maxDistance <= 4) return;
|
|
5160
|
+
return {
|
|
5161
|
+
x: dx / distance,
|
|
5162
|
+
y: dy / distance,
|
|
5163
|
+
speed: effect.speed ?? DEFAULT_SPEED,
|
|
5164
|
+
maxDistance
|
|
5165
|
+
};
|
|
5166
|
+
}
|
|
4613
5167
|
|
|
4614
5168
|
// packages/runtime/src/configuration-validation.ts
|
|
4615
5169
|
var collectConfigurationFaults = !compactRuntimeDiagnostics;
|
|
@@ -4621,6 +5175,10 @@
|
|
|
4621
5175
|
"atlasUrl",
|
|
4622
5176
|
"styles",
|
|
4623
5177
|
"plan",
|
|
5178
|
+
"preset",
|
|
5179
|
+
"targets",
|
|
5180
|
+
"interaction",
|
|
5181
|
+
"indicator",
|
|
4624
5182
|
"content",
|
|
4625
5183
|
"bindings",
|
|
4626
5184
|
"theme",
|
|
@@ -4652,6 +5210,14 @@
|
|
|
4652
5210
|
if (options.format !== void 0 && options.format !== 1) {
|
|
4653
5211
|
reportConfigurationFault("unsupported-format", "$.format", fault);
|
|
4654
5212
|
}
|
|
5213
|
+
if (options.plan !== void 0 && options.preset !== void 0) {
|
|
5214
|
+
reportConfigurationFault("incompatible-behavior", "$.preset", fault);
|
|
5215
|
+
}
|
|
5216
|
+
if (options.preset !== void 0 && !["companion", "still", "bottom-patrol", "viewport-roam"].includes(
|
|
5217
|
+
options.preset
|
|
5218
|
+
)) {
|
|
5219
|
+
reportConfigurationFault("invalid-preset", "$.preset", fault);
|
|
5220
|
+
}
|
|
4655
5221
|
if (options.character !== void 0) {
|
|
4656
5222
|
if (typeof options.character !== "string" || !NAME_PATTERN.test(options.character)) {
|
|
4657
5223
|
reportConfigurationFault("invalid-character", "$.character", fault);
|
|
@@ -4737,6 +5303,12 @@
|
|
|
4737
5303
|
if (collectConfigurationFaults) content = {};
|
|
4738
5304
|
}
|
|
4739
5305
|
validateBindings(options.bindings, content, fault);
|
|
5306
|
+
validateTargets(options.targets, fault);
|
|
5307
|
+
validateInteraction(options.interaction, options.targets, fault);
|
|
5308
|
+
validateIndicator(options.indicator, fault);
|
|
5309
|
+
if (options.interaction === false && options.indicator !== void 0) {
|
|
5310
|
+
reportConfigurationFault("incompatible-indicator", "$.indicator", fault);
|
|
5311
|
+
}
|
|
4740
5312
|
validateTheme(options.theme, fault);
|
|
4741
5313
|
validateDiagnostics(options.diagnostics, fault);
|
|
4742
5314
|
validateAccessibility(options.accessibility, fault);
|
|
@@ -4747,6 +5319,201 @@
|
|
|
4747
5319
|
}
|
|
4748
5320
|
return content;
|
|
4749
5321
|
}
|
|
5322
|
+
function validateInteraction(interaction, targets, fault) {
|
|
5323
|
+
if (interaction === void 0 || interaction === false) return;
|
|
5324
|
+
const checked = shape(
|
|
5325
|
+
interaction,
|
|
5326
|
+
"invalid-interaction",
|
|
5327
|
+
"$.interaction",
|
|
5328
|
+
[
|
|
5329
|
+
"press",
|
|
5330
|
+
"pressEvent",
|
|
5331
|
+
"drag",
|
|
5332
|
+
"throw",
|
|
5333
|
+
"dragState",
|
|
5334
|
+
"riseState",
|
|
5335
|
+
"fallState",
|
|
5336
|
+
"landState",
|
|
5337
|
+
"gravity",
|
|
5338
|
+
"maxThrowSpeed",
|
|
5339
|
+
"bounce",
|
|
5340
|
+
"floorInset",
|
|
5341
|
+
"label",
|
|
5342
|
+
"contentInitiallyHidden",
|
|
5343
|
+
"clearIndicatorOnPress",
|
|
5344
|
+
"catchTarget",
|
|
5345
|
+
"catchAnchor",
|
|
5346
|
+
"catchMargin",
|
|
5347
|
+
"catchEvent"
|
|
5348
|
+
],
|
|
5349
|
+
fault
|
|
5350
|
+
);
|
|
5351
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5352
|
+
const value = checked;
|
|
5353
|
+
if (value.press !== void 0 && ![
|
|
5354
|
+
"toggle-content",
|
|
5355
|
+
"show-content",
|
|
5356
|
+
"hide-content",
|
|
5357
|
+
"emit",
|
|
5358
|
+
"none"
|
|
5359
|
+
].includes(value.press)) {
|
|
5360
|
+
reportConfigurationFault(
|
|
5361
|
+
"invalid-interaction",
|
|
5362
|
+
"$.interaction.press",
|
|
5363
|
+
fault
|
|
5364
|
+
);
|
|
5365
|
+
}
|
|
5366
|
+
if (value.pressEvent !== void 0 && (typeof value.pressEvent !== "string" || !EVENT_NAME_PATTERN.test(value.pressEvent))) {
|
|
5367
|
+
reportConfigurationFault(
|
|
5368
|
+
"invalid-interaction-event",
|
|
5369
|
+
"$.interaction.pressEvent",
|
|
5370
|
+
fault
|
|
5371
|
+
);
|
|
5372
|
+
}
|
|
5373
|
+
if (value.press === "emit" && value.pressEvent === void 0) {
|
|
5374
|
+
reportConfigurationFault(
|
|
5375
|
+
"missing-interaction-event",
|
|
5376
|
+
"$.interaction.pressEvent",
|
|
5377
|
+
fault
|
|
5378
|
+
);
|
|
5379
|
+
}
|
|
5380
|
+
if (value.pressEvent !== void 0 && value.press !== void 0 && value.press !== "emit") {
|
|
5381
|
+
reportConfigurationFault(
|
|
5382
|
+
"incompatible-interaction-event",
|
|
5383
|
+
"$.interaction.pressEvent",
|
|
5384
|
+
fault
|
|
5385
|
+
);
|
|
5386
|
+
}
|
|
5387
|
+
for (const field of [
|
|
5388
|
+
"drag",
|
|
5389
|
+
"throw",
|
|
5390
|
+
"contentInitiallyHidden",
|
|
5391
|
+
"clearIndicatorOnPress"
|
|
5392
|
+
]) {
|
|
5393
|
+
if (value[field] !== void 0 && typeof value[field] !== "boolean") {
|
|
5394
|
+
reportConfigurationFault(
|
|
5395
|
+
"invalid-interaction",
|
|
5396
|
+
`$.interaction.${field}`,
|
|
5397
|
+
fault
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
for (const field of [
|
|
5402
|
+
"dragState",
|
|
5403
|
+
"riseState",
|
|
5404
|
+
"fallState",
|
|
5405
|
+
"landState"
|
|
5406
|
+
]) {
|
|
5407
|
+
if (value[field] !== void 0 && (typeof value[field] !== "string" || !STATE_NAME_PATTERN.test(value[field]))) {
|
|
5408
|
+
reportConfigurationFault(
|
|
5409
|
+
"invalid-interaction-state",
|
|
5410
|
+
`$.interaction.${field}`,
|
|
5411
|
+
fault
|
|
5412
|
+
);
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
for (const [field, minimum, maximum] of [
|
|
5416
|
+
["gravity", 0, 1e4],
|
|
5417
|
+
["maxThrowSpeed", 0, 1e4],
|
|
5418
|
+
["bounce", 0, 1],
|
|
5419
|
+
["floorInset", 0, 1e3],
|
|
5420
|
+
["catchMargin", 0, 1e3]
|
|
5421
|
+
]) {
|
|
5422
|
+
const item = value[field];
|
|
5423
|
+
if (item !== void 0 && (typeof item !== "number" || !Number.isFinite(item) || item < minimum || item > maximum)) {
|
|
5424
|
+
reportConfigurationFault(
|
|
5425
|
+
"invalid-interaction-range",
|
|
5426
|
+
`$.interaction.${field}`,
|
|
5427
|
+
fault
|
|
5428
|
+
);
|
|
5429
|
+
}
|
|
5430
|
+
}
|
|
5431
|
+
if (value.label !== void 0 && !text2(value.label, 120)) {
|
|
5432
|
+
reportConfigurationFault(
|
|
5433
|
+
"invalid-interaction-label",
|
|
5434
|
+
"$.interaction.label",
|
|
5435
|
+
fault
|
|
5436
|
+
);
|
|
5437
|
+
}
|
|
5438
|
+
if (value.catchTarget !== void 0 && (typeof value.catchTarget !== "string" || !NAME_PATTERN.test(value.catchTarget) || !Object.hasOwn(targets ?? {}, value.catchTarget))) {
|
|
5439
|
+
reportConfigurationFault(
|
|
5440
|
+
"invalid-catch-target",
|
|
5441
|
+
"$.interaction.catchTarget",
|
|
5442
|
+
fault
|
|
5443
|
+
);
|
|
5444
|
+
}
|
|
5445
|
+
if (value.catchAnchor !== void 0 && !["center", "top", "right", "bottom", "left"].includes(
|
|
5446
|
+
value.catchAnchor
|
|
5447
|
+
)) {
|
|
5448
|
+
reportConfigurationFault(
|
|
5449
|
+
"invalid-catch-anchor",
|
|
5450
|
+
"$.interaction.catchAnchor",
|
|
5451
|
+
fault
|
|
5452
|
+
);
|
|
5453
|
+
}
|
|
5454
|
+
if (value.catchEvent !== void 0 && (typeof value.catchEvent !== "string" || !EVENT_NAME_PATTERN.test(value.catchEvent))) {
|
|
5455
|
+
reportConfigurationFault(
|
|
5456
|
+
"invalid-interaction-event",
|
|
5457
|
+
"$.interaction.catchEvent",
|
|
5458
|
+
fault
|
|
5459
|
+
);
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
function validateIndicator(indicator, fault) {
|
|
5463
|
+
if (indicator === void 0) return;
|
|
5464
|
+
const checked = shape(
|
|
5465
|
+
indicator,
|
|
5466
|
+
"invalid-indicator",
|
|
5467
|
+
"$.indicator",
|
|
5468
|
+
["kind", "count", "label", "color", "visible"],
|
|
5469
|
+
fault
|
|
5470
|
+
);
|
|
5471
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5472
|
+
const value = checked;
|
|
5473
|
+
if (value.kind !== void 0 && value.kind !== "dot" && value.kind !== "count") {
|
|
5474
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.kind", fault);
|
|
5475
|
+
}
|
|
5476
|
+
if (!text2(value.label, 120)) {
|
|
5477
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.label", fault);
|
|
5478
|
+
}
|
|
5479
|
+
if (value.count !== void 0 && (typeof value.count !== "number" || !Number.isInteger(value.count) || value.count < 0 || value.count > 999)) {
|
|
5480
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.count", fault);
|
|
5481
|
+
}
|
|
5482
|
+
if (value.color !== void 0 && !isSurfaceColor(value.color)) {
|
|
5483
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.color", fault);
|
|
5484
|
+
}
|
|
5485
|
+
if (value.visible !== void 0 && typeof value.visible !== "boolean") {
|
|
5486
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.visible", fault);
|
|
5487
|
+
}
|
|
5488
|
+
}
|
|
5489
|
+
function validateTargets(targets, fault) {
|
|
5490
|
+
if (targets === void 0) return;
|
|
5491
|
+
const checked = shape(
|
|
5492
|
+
targets,
|
|
5493
|
+
"invalid-targets",
|
|
5494
|
+
"$.targets",
|
|
5495
|
+
void 0,
|
|
5496
|
+
fault
|
|
5497
|
+
);
|
|
5498
|
+
if (collectConfigurationFaults && !checked) return;
|
|
5499
|
+
const entries = Object.entries(checked);
|
|
5500
|
+
if (entries.length > 16) {
|
|
5501
|
+
reportConfigurationFault("target-limit", "$.targets", fault);
|
|
5502
|
+
}
|
|
5503
|
+
for (const [id2, selector2] of entries) {
|
|
5504
|
+
if (!NAME_PATTERN.test(id2)) {
|
|
5505
|
+
reportConfigurationFault("invalid-target", `$.targets.${id2}`, fault, id2);
|
|
5506
|
+
}
|
|
5507
|
+
if (typeof selector2 !== "string" || selector2.length < 1 || selector2.length > 256 || /[\0\r\n]/.test(selector2)) {
|
|
5508
|
+
reportConfigurationFault(
|
|
5509
|
+
"invalid-target-selector",
|
|
5510
|
+
`$.targets.${id2}`,
|
|
5511
|
+
fault,
|
|
5512
|
+
id2
|
|
5513
|
+
);
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
4750
5517
|
function validRuntimeName(value) {
|
|
4751
5518
|
return value === void 0 || typeof value === "boolean" || text2(value, 80);
|
|
4752
5519
|
}
|
|
@@ -4975,7 +5742,8 @@
|
|
|
4975
5742
|
if (options.plan !== void 0) {
|
|
4976
5743
|
try {
|
|
4977
5744
|
compilePlan(options.plan, {
|
|
4978
|
-
contentIds: new Set(Object.keys(content))
|
|
5745
|
+
contentIds: new Set(Object.keys(content)),
|
|
5746
|
+
targets: new Set(Object.keys(options.targets ?? {}))
|
|
4979
5747
|
});
|
|
4980
5748
|
} catch (cause) {
|
|
4981
5749
|
fail2(
|
|
@@ -5056,6 +5824,40 @@
|
|
|
5056
5824
|
return `${detail ?? field} must be a function`;
|
|
5057
5825
|
case "invalid-plan":
|
|
5058
5826
|
return detail ?? "Plan is invalid";
|
|
5827
|
+
case "incompatible-behavior":
|
|
5828
|
+
return "Choose preset or plan, not both";
|
|
5829
|
+
case "invalid-preset":
|
|
5830
|
+
return "preset must be companion, still, bottom-patrol, or viewport-roam";
|
|
5831
|
+
case "invalid-targets":
|
|
5832
|
+
return "targets must be an object of target IDs and CSS selectors";
|
|
5833
|
+
case "target-limit":
|
|
5834
|
+
return "targets supports at most 16 entries";
|
|
5835
|
+
case "invalid-target":
|
|
5836
|
+
return "target IDs must be bounded lowercase IDs";
|
|
5837
|
+
case "invalid-target-selector":
|
|
5838
|
+
return "target selectors must be bounded CSS selector text";
|
|
5839
|
+
case "invalid-interaction":
|
|
5840
|
+
return "interaction contains an unsupported value";
|
|
5841
|
+
case "invalid-interaction-event":
|
|
5842
|
+
return "interaction events must be bounded application Event names";
|
|
5843
|
+
case "missing-interaction-event":
|
|
5844
|
+
return "pressEvent is required when press is emit";
|
|
5845
|
+
case "incompatible-interaction-event":
|
|
5846
|
+
return "pressEvent can be used only with the emit press action";
|
|
5847
|
+
case "invalid-interaction-state":
|
|
5848
|
+
return "interaction states must be valid Pack State names";
|
|
5849
|
+
case "invalid-interaction-range":
|
|
5850
|
+
return "interaction physics value is outside its supported range";
|
|
5851
|
+
case "invalid-interaction-label":
|
|
5852
|
+
return "interaction label must be short plain text";
|
|
5853
|
+
case "invalid-catch-target":
|
|
5854
|
+
return "catchTarget must reference a configured target";
|
|
5855
|
+
case "invalid-catch-anchor":
|
|
5856
|
+
return "catchAnchor is not supported";
|
|
5857
|
+
case "invalid-indicator":
|
|
5858
|
+
return "indicator must include a label and valid dot or count settings";
|
|
5859
|
+
case "incompatible-indicator":
|
|
5860
|
+
return "indicator requires character interaction";
|
|
5059
5861
|
default:
|
|
5060
5862
|
return detail ?? code;
|
|
5061
5863
|
}
|
|
@@ -5168,21 +5970,26 @@
|
|
|
5168
5970
|
delete output.state;
|
|
5169
5971
|
}
|
|
5170
5972
|
const motion = item.effect.motion;
|
|
5171
|
-
if (motion
|
|
5172
|
-
const
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5973
|
+
if (motion?.type === "horizontal-patrol") {
|
|
5974
|
+
const [direction, request] = evaluateHorizontalPatrol(
|
|
5975
|
+
motion,
|
|
5976
|
+
world,
|
|
5977
|
+
item.patrolDirection
|
|
5978
|
+
);
|
|
5979
|
+
item.patrolDirection = direction;
|
|
5980
|
+
if (request) output.motion = request;
|
|
5981
|
+
else delete output.motion;
|
|
5982
|
+
} else if (motion?.type === "follow-pointer" && world.pointer && world.position) {
|
|
5983
|
+
const request = motionToward(
|
|
5984
|
+
motion,
|
|
5985
|
+
world.position,
|
|
5986
|
+
world.pointer.x,
|
|
5987
|
+
world.pointer.y,
|
|
5988
|
+
motion.arrivalRadius,
|
|
5989
|
+
world
|
|
5990
|
+
);
|
|
5991
|
+
if (request) output.motion = request;
|
|
5992
|
+
else delete output.motion;
|
|
5186
5993
|
}
|
|
5187
5994
|
for (const surface of item.effect.surfaces) {
|
|
5188
5995
|
surfaces.set(
|
|
@@ -5249,6 +6056,7 @@
|
|
|
5249
6056
|
startedAt: 0,
|
|
5250
6057
|
deadline: 0,
|
|
5251
6058
|
status: "rejected",
|
|
6059
|
+
patrolDirection: true,
|
|
5252
6060
|
handle,
|
|
5253
6061
|
finish
|
|
5254
6062
|
});
|
|
@@ -5556,6 +6364,13 @@
|
|
|
5556
6364
|
this.host.setAttribute("aria-hidden", "true");
|
|
5557
6365
|
}
|
|
5558
6366
|
};
|
|
6367
|
+
var createAtlasRenderer = (options) => new AtlasRenderer(
|
|
6368
|
+
options.document,
|
|
6369
|
+
options.pack,
|
|
6370
|
+
options.atlasUrl,
|
|
6371
|
+
options.scale,
|
|
6372
|
+
options.styles
|
|
6373
|
+
);
|
|
5559
6374
|
|
|
5560
6375
|
// packages/runtime/src/resolver.ts
|
|
5561
6376
|
var ALIASES = {
|
|
@@ -5799,6 +6614,142 @@
|
|
|
5799
6614
|
}
|
|
5800
6615
|
}
|
|
5801
6616
|
|
|
6617
|
+
// packages/runtime/src/path-sampler.ts
|
|
6618
|
+
var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
6619
|
+
var SvgPathSampler = class {
|
|
6620
|
+
#document;
|
|
6621
|
+
#cache = /* @__PURE__ */ new Map();
|
|
6622
|
+
constructor(document) {
|
|
6623
|
+
this.#document = document;
|
|
6624
|
+
}
|
|
6625
|
+
validate(path) {
|
|
6626
|
+
return this.#geometry(path) !== void 0;
|
|
6627
|
+
}
|
|
6628
|
+
sample(path, progress) {
|
|
6629
|
+
const geometry = this.#geometry(path);
|
|
6630
|
+
if (!geometry) return;
|
|
6631
|
+
const bounded2 = Math.max(0, Math.min(1, progress));
|
|
6632
|
+
try {
|
|
6633
|
+
const point = geometry.element.getPointAtLength(
|
|
6634
|
+
geometry.length * bounded2
|
|
6635
|
+
);
|
|
6636
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return;
|
|
6637
|
+
return { x: point.x, y: point.y };
|
|
6638
|
+
} catch {
|
|
6639
|
+
return;
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6642
|
+
#geometry(path) {
|
|
6643
|
+
const cached = this.#cache.get(path);
|
|
6644
|
+
if (cached) return cached;
|
|
6645
|
+
if (this.#cache.size >= 16) return;
|
|
6646
|
+
const element = this.#document.createElementNS(
|
|
6647
|
+
SVG_NAMESPACE,
|
|
6648
|
+
"path"
|
|
6649
|
+
);
|
|
6650
|
+
element.setAttribute("d", path);
|
|
6651
|
+
try {
|
|
6652
|
+
const length = element.getTotalLength();
|
|
6653
|
+
if (!Number.isFinite(length) || length <= 0) return;
|
|
6654
|
+
const geometry = Object.freeze({ element, length });
|
|
6655
|
+
this.#cache.set(path, geometry);
|
|
6656
|
+
return geometry;
|
|
6657
|
+
} catch {
|
|
6658
|
+
return;
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
};
|
|
6662
|
+
|
|
6663
|
+
// packages/runtime/src/targets.ts
|
|
6664
|
+
var TargetTracker = class {
|
|
6665
|
+
#document;
|
|
6666
|
+
#window;
|
|
6667
|
+
#selectors;
|
|
6668
|
+
#elements = /* @__PURE__ */ new Map();
|
|
6669
|
+
#wake;
|
|
6670
|
+
#resizeObserver;
|
|
6671
|
+
#mutationObserver;
|
|
6672
|
+
#snapshot = Object.freeze({});
|
|
6673
|
+
#dirty = true;
|
|
6674
|
+
#destroyed = false;
|
|
6675
|
+
constructor(document, window, selectors, wake) {
|
|
6676
|
+
this.#document = document;
|
|
6677
|
+
this.#window = window;
|
|
6678
|
+
this.#selectors = selectors;
|
|
6679
|
+
this.#wake = wake;
|
|
6680
|
+
const browserWindow = window;
|
|
6681
|
+
this.#resizeObserver = browserWindow.ResizeObserver ? new browserWindow.ResizeObserver(() => this.refresh()) : void 0;
|
|
6682
|
+
this.#mutationObserver = browserWindow.MutationObserver ? new browserWindow.MutationObserver(() => this.refresh()) : void 0;
|
|
6683
|
+
this.#mutationObserver?.observe(document.documentElement, {
|
|
6684
|
+
attributes: true,
|
|
6685
|
+
attributeFilter: ["class", "id"],
|
|
6686
|
+
childList: true,
|
|
6687
|
+
subtree: true
|
|
6688
|
+
});
|
|
6689
|
+
window.addEventListener("resize", this.#markDirty, { passive: true });
|
|
6690
|
+
window.addEventListener("scroll", this.#markDirty, {
|
|
6691
|
+
capture: true,
|
|
6692
|
+
passive: true
|
|
6693
|
+
});
|
|
6694
|
+
}
|
|
6695
|
+
snapshot(force = false) {
|
|
6696
|
+
if (this.#destroyed) return Object.freeze({});
|
|
6697
|
+
if (force) this.#dirty = true;
|
|
6698
|
+
if (!this.#dirty) return this.#snapshot;
|
|
6699
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
6700
|
+
for (const [id2, selector2] of Object.entries(this.#selectors)) {
|
|
6701
|
+
let element = this.#elements.get(id2);
|
|
6702
|
+
if (!element?.isConnected) {
|
|
6703
|
+
if (element) this.#resizeObserver?.unobserve(element);
|
|
6704
|
+
element = this.#document.querySelector(selector2);
|
|
6705
|
+
if (element) {
|
|
6706
|
+
this.#elements.set(id2, element);
|
|
6707
|
+
this.#resizeObserver?.observe(element);
|
|
6708
|
+
} else {
|
|
6709
|
+
this.#elements.delete(id2);
|
|
6710
|
+
}
|
|
6711
|
+
}
|
|
6712
|
+
if (!element) continue;
|
|
6713
|
+
const rect = element.getBoundingClientRect();
|
|
6714
|
+
if (!Number.isFinite(rect.left) || !Number.isFinite(rect.top) || !Number.isFinite(rect.width) || !Number.isFinite(rect.height)) {
|
|
6715
|
+
continue;
|
|
6716
|
+
}
|
|
6717
|
+
output[id2] = Object.freeze({
|
|
6718
|
+
left: rect.left,
|
|
6719
|
+
top: rect.top,
|
|
6720
|
+
right: rect.right,
|
|
6721
|
+
bottom: rect.bottom,
|
|
6722
|
+
width: rect.width,
|
|
6723
|
+
height: rect.height
|
|
6724
|
+
});
|
|
6725
|
+
}
|
|
6726
|
+
this.#snapshot = Object.freeze(output);
|
|
6727
|
+
this.#dirty = false;
|
|
6728
|
+
return this.#snapshot;
|
|
6729
|
+
}
|
|
6730
|
+
contains(id2, point, margin = 0) {
|
|
6731
|
+
const target = this.snapshot(true)[id2];
|
|
6732
|
+
return Boolean(
|
|
6733
|
+
target && point.x >= target.left - margin && point.x <= target.right + margin && point.y >= target.top - margin && point.y <= target.bottom + margin
|
|
6734
|
+
);
|
|
6735
|
+
}
|
|
6736
|
+
refresh = () => {
|
|
6737
|
+
if (this.#destroyed) return;
|
|
6738
|
+
this.#dirty = true;
|
|
6739
|
+
this.#wake();
|
|
6740
|
+
};
|
|
6741
|
+
destroy() {
|
|
6742
|
+
if (this.#destroyed) return;
|
|
6743
|
+
this.#destroyed = true;
|
|
6744
|
+
this.#resizeObserver?.disconnect();
|
|
6745
|
+
this.#mutationObserver?.disconnect();
|
|
6746
|
+
this.#window.removeEventListener("resize", this.#markDirty);
|
|
6747
|
+
this.#window.removeEventListener("scroll", this.#markDirty, true);
|
|
6748
|
+
this.#elements.clear();
|
|
6749
|
+
}
|
|
6750
|
+
#markDirty = () => this.refresh();
|
|
6751
|
+
};
|
|
6752
|
+
|
|
5802
6753
|
// packages/runtime/src/visibility.ts
|
|
5803
6754
|
var PREFERENCE_KEY = "peekling:site-preference";
|
|
5804
6755
|
var SESSION_KEY = "peekling:hidden-session";
|
|
@@ -6157,6 +7108,10 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6157
7108
|
var SUSPEND_PAGE = 2;
|
|
6158
7109
|
var SUSPEND_SITE = 4;
|
|
6159
7110
|
var MAX_TIMER_DELAY = 2147483647;
|
|
7111
|
+
var DEFAULT_GRAVITY = 1800;
|
|
7112
|
+
var DEFAULT_THROW_SPEED = 1800;
|
|
7113
|
+
var DEFAULT_BOUNCE = 0.35;
|
|
7114
|
+
var DEFAULT_FLOOR_INSET = 8;
|
|
6160
7115
|
var EMPTY_CONTENT_SELECTIONS = Object.freeze([]);
|
|
6161
7116
|
function browserSelectorIsValid(document, selector2) {
|
|
6162
7117
|
try {
|
|
@@ -6220,10 +7175,21 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6220
7175
|
}
|
|
6221
7176
|
return input;
|
|
6222
7177
|
}
|
|
7178
|
+
function checkedIndicator(input) {
|
|
7179
|
+
if (input === null) return;
|
|
7180
|
+
const value = snapshotConfiguration(input);
|
|
7181
|
+
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") {
|
|
7182
|
+
throw new TypeError(
|
|
7183
|
+
runtimeMessage("indicator.invalid", "Indicator is invalid")
|
|
7184
|
+
);
|
|
7185
|
+
}
|
|
7186
|
+
return value;
|
|
7187
|
+
}
|
|
6223
7188
|
var PeeklingRuntime = class _PeeklingRuntime {
|
|
6224
|
-
static hatch(input) {
|
|
7189
|
+
static hatch(input, rendererFactory = createAtlasRenderer) {
|
|
6225
7190
|
return new _PeeklingRuntime(
|
|
6226
|
-
hatchOptions(input)
|
|
7191
|
+
hatchOptions(input),
|
|
7192
|
+
rendererFactory
|
|
6227
7193
|
);
|
|
6228
7194
|
}
|
|
6229
7195
|
/** Package-internal presentation update used only by the Web Component. */
|
|
@@ -6259,7 +7225,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6259
7225
|
#loaded;
|
|
6260
7226
|
#renderer;
|
|
6261
7227
|
#contentRenderer;
|
|
7228
|
+
#interactionController;
|
|
6262
7229
|
#sections;
|
|
7230
|
+
#targets;
|
|
6263
7231
|
#input;
|
|
6264
7232
|
#raf = 0;
|
|
6265
7233
|
#planTimer = 0;
|
|
@@ -6295,10 +7263,18 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6295
7263
|
#instanceId;
|
|
6296
7264
|
#diagnostics;
|
|
6297
7265
|
#styles;
|
|
7266
|
+
#rendererFactory;
|
|
6298
7267
|
#rejectedOverrideId = 0;
|
|
6299
7268
|
#reportedNotReadyEvent = false;
|
|
6300
7269
|
#reportedNotReadyOverride = false;
|
|
6301
|
-
|
|
7270
|
+
#trackTargets = false;
|
|
7271
|
+
#pathSampler;
|
|
7272
|
+
#indicator;
|
|
7273
|
+
#dragging = false;
|
|
7274
|
+
#throwing = false;
|
|
7275
|
+
#throwVelocity = { x: 0, y: 0 };
|
|
7276
|
+
#landUntil = 0;
|
|
7277
|
+
constructor(options = {}, rendererFactory = createAtlasRenderer) {
|
|
6302
7278
|
options = snapshotConfiguration(options);
|
|
6303
7279
|
const document = options.document ?? globalThis.document;
|
|
6304
7280
|
const window = options.window ?? globalThis.window;
|
|
@@ -6308,7 +7284,10 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6308
7284
|
);
|
|
6309
7285
|
this.#document = document;
|
|
6310
7286
|
this.#window = window;
|
|
7287
|
+
this.#pathSampler = new SvgPathSampler(document);
|
|
6311
7288
|
this.#options = options;
|
|
7289
|
+
this.#indicator = options.indicator;
|
|
7290
|
+
this.#rendererFactory = rendererFactory;
|
|
6312
7291
|
this.#now = window.performance?.now?.bind(window.performance) ?? Date.now;
|
|
6313
7292
|
this.#instanceId = `instance:${Math.floor(this.#now())}:${Math.random().toString(36).slice(2, 8)}`;
|
|
6314
7293
|
this.#diagnostics = new DiagnosticChannel({
|
|
@@ -6433,6 +7412,28 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6433
7412
|
this.#setSuspended(SUSPEND_HOST, false);
|
|
6434
7413
|
this.#notice("lifecycle.resumed", "info", "lifecycle");
|
|
6435
7414
|
}
|
|
7415
|
+
refreshTargets() {
|
|
7416
|
+
this.#targets?.refresh();
|
|
7417
|
+
}
|
|
7418
|
+
setIndicator(indicator) {
|
|
7419
|
+
if (this.#destroyed) return;
|
|
7420
|
+
this.#indicator = checkedIndicator(indicator);
|
|
7421
|
+
this.#interactionController?.updateIndicator(this.#indicator);
|
|
7422
|
+
}
|
|
7423
|
+
setContentVisible(visible) {
|
|
7424
|
+
if (this.#destroyed || !this.#contentRenderer) return false;
|
|
7425
|
+
const expanded = this.#contentRenderer.setUserHidden(!visible);
|
|
7426
|
+
this.#interactionController?.setExpanded(expanded);
|
|
7427
|
+
this.#wake();
|
|
7428
|
+
return expanded;
|
|
7429
|
+
}
|
|
7430
|
+
toggleContent() {
|
|
7431
|
+
if (this.#destroyed || !this.#contentRenderer) return false;
|
|
7432
|
+
const expanded = this.#contentRenderer.toggleUserHidden();
|
|
7433
|
+
this.#interactionController?.setExpanded(expanded);
|
|
7434
|
+
this.#wake();
|
|
7435
|
+
return expanded;
|
|
7436
|
+
}
|
|
6436
7437
|
destroy() {
|
|
6437
7438
|
this.#destroy("destroyed");
|
|
6438
7439
|
}
|
|
@@ -6446,7 +7447,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6446
7447
|
this.#input?.destroy();
|
|
6447
7448
|
this.#plan?.reset();
|
|
6448
7449
|
this.#sections?.destroy();
|
|
7450
|
+
this.#targets?.destroy();
|
|
6449
7451
|
this.#contentRenderer?.destroy();
|
|
7452
|
+
this.#interactionController?.destroy();
|
|
6450
7453
|
this.#renderer?.destroy();
|
|
6451
7454
|
this.#unregisterVisibility?.();
|
|
6452
7455
|
this.#unregisterVisibility = void 0;
|
|
@@ -6476,10 +7479,20 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6476
7479
|
async #initialize() {
|
|
6477
7480
|
try {
|
|
6478
7481
|
const validateSelector = (selector2) => browserSelectorIsValid(this.#document, selector2);
|
|
7482
|
+
const targetIds = new Set(Object.keys(this.#options.targets ?? {}));
|
|
7483
|
+
for (const selector2 of Object.values(this.#options.targets ?? {})) {
|
|
7484
|
+
if (!validateSelector(selector2)) {
|
|
7485
|
+
throw new TypeError(
|
|
7486
|
+
runtimeMessage("target.selector", "Target selector is invalid")
|
|
7487
|
+
);
|
|
7488
|
+
}
|
|
7489
|
+
}
|
|
6479
7490
|
if (this.#options.plan !== void 0) {
|
|
6480
7491
|
compilePlan(this.#options.plan, {
|
|
6481
7492
|
contentIds: new Set(Object.keys(this.#content)),
|
|
6482
|
-
|
|
7493
|
+
targets: targetIds,
|
|
7494
|
+
validateSelector,
|
|
7495
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6483
7496
|
});
|
|
6484
7497
|
}
|
|
6485
7498
|
const browserWindow = this.#window;
|
|
@@ -6547,12 +7560,14 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6547
7560
|
locomotion ? ["locomotion"] : []
|
|
6548
7561
|
);
|
|
6549
7562
|
const compiled = compilePlan(
|
|
6550
|
-
this.#options.plan ??
|
|
7563
|
+
this.#options.plan ?? createPresetPlan(this.#options.preset ?? "companion", locomotion),
|
|
6551
7564
|
{
|
|
6552
7565
|
states: new Set(Object.keys(loaded.content.states)),
|
|
6553
7566
|
capabilities,
|
|
6554
7567
|
contentIds: new Set(Object.keys(this.#content)),
|
|
6555
|
-
|
|
7568
|
+
targets: targetIds,
|
|
7569
|
+
validateSelector,
|
|
7570
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6556
7571
|
}
|
|
6557
7572
|
);
|
|
6558
7573
|
this.#plan = new PlanRuntime(compiled);
|
|
@@ -6560,7 +7575,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6560
7575
|
{
|
|
6561
7576
|
states: new Set(Object.keys(loaded.content.states)),
|
|
6562
7577
|
capabilities,
|
|
6563
|
-
contentIds: new Set(Object.keys(this.#content))
|
|
7578
|
+
contentIds: new Set(Object.keys(this.#content)),
|
|
7579
|
+
targets: targetIds,
|
|
7580
|
+
validatePath: (path) => this.#pathSampler.validate(path)
|
|
6564
7581
|
},
|
|
6565
7582
|
this.#now,
|
|
6566
7583
|
(message) => this.#diagnose(message, "override.rejected", "warning", "override")
|
|
@@ -6588,21 +7605,45 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6588
7605
|
(loaded.content.atlas.logicalWidth ?? loaded.content.atlas.cellWidth) * scale,
|
|
6589
7606
|
(loaded.content.atlas.logicalHeight ?? loaded.content.atlas.cellHeight) * scale
|
|
6590
7607
|
);
|
|
6591
|
-
this.#renderer =
|
|
6592
|
-
this.#document,
|
|
6593
|
-
loaded.content,
|
|
6594
|
-
loaded.atlasObjectUrl,
|
|
7608
|
+
this.#renderer = this.#rendererFactory({
|
|
7609
|
+
document: this.#document,
|
|
7610
|
+
pack: loaded.content,
|
|
7611
|
+
atlasUrl: loaded.atlasObjectUrl,
|
|
6595
7612
|
scale,
|
|
6596
|
-
this.#styles
|
|
6597
|
-
);
|
|
7613
|
+
styles: this.#styles
|
|
7614
|
+
});
|
|
6598
7615
|
if (Object.keys(this.#content).length || this.#displayName !== void 0) {
|
|
6599
7616
|
this.#ensureContentRenderer();
|
|
6600
7617
|
}
|
|
7618
|
+
if (this.#options.interaction !== false) {
|
|
7619
|
+
const interaction = this.#options.interaction ?? {};
|
|
7620
|
+
const pressAction = interaction.press ?? (interaction.pressEvent ? "emit" : "toggle-content");
|
|
7621
|
+
const controlsContent = Boolean(this.#contentRenderer) && (pressAction === "toggle-content" || pressAction === "show-content" || pressAction === "hide-content");
|
|
7622
|
+
if (interaction.contentInitiallyHidden) {
|
|
7623
|
+
this.#contentRenderer?.setUserHidden(true);
|
|
7624
|
+
}
|
|
7625
|
+
this.#interactionController = new CharacterInteractionController({
|
|
7626
|
+
document: this.#document,
|
|
7627
|
+
styles: this.#styles,
|
|
7628
|
+
label: interaction.label ?? `Interact with ${loaded.content.displayName || "Peekling"}`,
|
|
7629
|
+
draggable: interaction.drag !== false,
|
|
7630
|
+
...controlsContent ? { expanded: !interaction.contentInitiallyHidden } : {},
|
|
7631
|
+
...this.#indicator ? { indicator: this.#indicator } : {},
|
|
7632
|
+
onPress: () => this.#handleCharacterPress(),
|
|
7633
|
+
onDragStart: () => this.#startCharacterDrag(),
|
|
7634
|
+
onDragMove: (position, velocity) => this.#moveCharacterDrag(position, velocity),
|
|
7635
|
+
onDragEnd: (velocity, moved, pointer) => this.#endCharacterDrag(velocity, moved, pointer)
|
|
7636
|
+
});
|
|
7637
|
+
if (interaction.contentInitiallyHidden) {
|
|
7638
|
+
this.#interactionController.setExpanded(false);
|
|
7639
|
+
}
|
|
7640
|
+
}
|
|
6601
7641
|
try {
|
|
6602
7642
|
await Promise.all([
|
|
6603
7643
|
this.#visibilityReady,
|
|
6604
7644
|
this.#renderer.ready,
|
|
6605
|
-
this.#contentRenderer?.ready
|
|
7645
|
+
this.#contentRenderer?.ready,
|
|
7646
|
+
this.#interactionController?.ready
|
|
6606
7647
|
]);
|
|
6607
7648
|
} catch (cause) {
|
|
6608
7649
|
this.#diagnoseStyleFailure(cause);
|
|
@@ -6610,6 +7651,14 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6610
7651
|
}
|
|
6611
7652
|
const requirements = compiledPlanSectionRequirements(compiled);
|
|
6612
7653
|
this.#createInput();
|
|
7654
|
+
if (targetIds.size) {
|
|
7655
|
+
this.#targets = new TargetTracker(
|
|
7656
|
+
this.#document,
|
|
7657
|
+
this.#window,
|
|
7658
|
+
this.#options.targets,
|
|
7659
|
+
() => this.#wake()
|
|
7660
|
+
);
|
|
7661
|
+
}
|
|
6613
7662
|
if (requirements.selectors.length) {
|
|
6614
7663
|
this.#sections = new SectionTracker(
|
|
6615
7664
|
this.#document,
|
|
@@ -6621,6 +7670,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6621
7670
|
);
|
|
6622
7671
|
}
|
|
6623
7672
|
this.#renderer.setHidden(this.#siteHidden);
|
|
7673
|
+
this.#interactionController?.setHidden(this.#siteHidden);
|
|
6624
7674
|
if (this.#suspensions) {
|
|
6625
7675
|
this.#input?.setSuspended(true);
|
|
6626
7676
|
this.#sections?.setSuspended(true);
|
|
@@ -6684,6 +7734,129 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6684
7734
|
});
|
|
6685
7735
|
return this.#contentRenderer;
|
|
6686
7736
|
}
|
|
7737
|
+
#handleCharacterPress() {
|
|
7738
|
+
if (this.#destroyed) return;
|
|
7739
|
+
const interaction = this.#options.interaction || {};
|
|
7740
|
+
if (interaction.clearIndicatorOnPress === true && this.#indicator) {
|
|
7741
|
+
this.setIndicator(null);
|
|
7742
|
+
}
|
|
7743
|
+
const action = interaction.press ?? (interaction.pressEvent ? "emit" : "toggle-content");
|
|
7744
|
+
if (action === "emit") {
|
|
7745
|
+
if (interaction.pressEvent) this.emit(interaction.pressEvent);
|
|
7746
|
+
return;
|
|
7747
|
+
}
|
|
7748
|
+
if (action === "none") return;
|
|
7749
|
+
if (action === "show-content") this.setContentVisible(true);
|
|
7750
|
+
else if (action === "hide-content") this.setContentVisible(false);
|
|
7751
|
+
else this.toggleContent();
|
|
7752
|
+
}
|
|
7753
|
+
#startCharacterDrag() {
|
|
7754
|
+
if (this.#destroyed || this.#siteHidden) return;
|
|
7755
|
+
this.#dragging = true;
|
|
7756
|
+
this.#throwing = false;
|
|
7757
|
+
this.#landUntil = 0;
|
|
7758
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7759
|
+
this.#wake();
|
|
7760
|
+
}
|
|
7761
|
+
#moveCharacterDrag(position, velocity) {
|
|
7762
|
+
if (!this.#dragging || this.#destroyed) return;
|
|
7763
|
+
const size = this.#characterSize();
|
|
7764
|
+
this.#position = size ? clampPosition(
|
|
7765
|
+
position,
|
|
7766
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7767
|
+
size.width,
|
|
7768
|
+
size.height
|
|
7769
|
+
) : { ...position };
|
|
7770
|
+
this.#throwVelocity = { ...velocity };
|
|
7771
|
+
this.#wake();
|
|
7772
|
+
}
|
|
7773
|
+
#endCharacterDrag(velocity, moved, pointer) {
|
|
7774
|
+
if (!this.#dragging || this.#destroyed) return;
|
|
7775
|
+
this.#dragging = false;
|
|
7776
|
+
if (!moved) {
|
|
7777
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7778
|
+
this.#wake();
|
|
7779
|
+
return;
|
|
7780
|
+
}
|
|
7781
|
+
const interaction = this.#options.interaction || {};
|
|
7782
|
+
if (interaction.catchTarget && this.#targets?.contains(
|
|
7783
|
+
interaction.catchTarget,
|
|
7784
|
+
pointer,
|
|
7785
|
+
interaction.catchMargin ?? 24
|
|
7786
|
+
) && this.#catchCharacter(interaction.catchTarget)) {
|
|
7787
|
+
return;
|
|
7788
|
+
}
|
|
7789
|
+
if (this.#reducedMotion) {
|
|
7790
|
+
this.#landCharacter();
|
|
7791
|
+
return;
|
|
7792
|
+
}
|
|
7793
|
+
if (interaction.throw === false) {
|
|
7794
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7795
|
+
this.#wake();
|
|
7796
|
+
return;
|
|
7797
|
+
}
|
|
7798
|
+
const maximum = interaction.maxThrowSpeed ?? DEFAULT_THROW_SPEED;
|
|
7799
|
+
const magnitude = Math.hypot(velocity.x, velocity.y);
|
|
7800
|
+
const factor = magnitude > maximum && magnitude ? maximum / magnitude : 1;
|
|
7801
|
+
this.#throwVelocity = {
|
|
7802
|
+
x: velocity.x * factor,
|
|
7803
|
+
y: velocity.y * factor
|
|
7804
|
+
};
|
|
7805
|
+
this.#throwing = true;
|
|
7806
|
+
this.#wake();
|
|
7807
|
+
}
|
|
7808
|
+
#characterSize() {
|
|
7809
|
+
const loaded = this.#loaded?.content;
|
|
7810
|
+
if (!loaded) return;
|
|
7811
|
+
const scale = this.#options.scale ?? loaded.defaultScale;
|
|
7812
|
+
return {
|
|
7813
|
+
width: (loaded.atlas.logicalWidth ?? loaded.atlas.cellWidth) * scale,
|
|
7814
|
+
height: (loaded.atlas.logicalHeight ?? loaded.atlas.cellHeight) * scale
|
|
7815
|
+
};
|
|
7816
|
+
}
|
|
7817
|
+
#landCharacter() {
|
|
7818
|
+
const size = this.#characterSize();
|
|
7819
|
+
if (size) {
|
|
7820
|
+
const floorInset = (this.#options.interaction || {}).floorInset ?? DEFAULT_FLOOR_INSET;
|
|
7821
|
+
this.#position = clampPosition(
|
|
7822
|
+
{
|
|
7823
|
+
x: this.#position.x,
|
|
7824
|
+
y: this.#window.innerHeight - size.height / 2 - floorInset
|
|
7825
|
+
},
|
|
7826
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7827
|
+
size.width,
|
|
7828
|
+
size.height
|
|
7829
|
+
);
|
|
7830
|
+
}
|
|
7831
|
+
this.#dragging = false;
|
|
7832
|
+
this.#throwing = false;
|
|
7833
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7834
|
+
this.#landUntil = this.#now() + 360;
|
|
7835
|
+
this.#wake();
|
|
7836
|
+
}
|
|
7837
|
+
#catchCharacter(targetId) {
|
|
7838
|
+
const target = this.#targets?.snapshot(true)[targetId];
|
|
7839
|
+
const size = this.#characterSize();
|
|
7840
|
+
if (!target || !size) return false;
|
|
7841
|
+
const interaction = this.#options.interaction || {};
|
|
7842
|
+
const point = characterTargetPoint(
|
|
7843
|
+
target,
|
|
7844
|
+
interaction.catchAnchor ?? "center",
|
|
7845
|
+
size
|
|
7846
|
+
);
|
|
7847
|
+
this.#position = clampPosition(
|
|
7848
|
+
point,
|
|
7849
|
+
{ width: this.#window.innerWidth, height: this.#window.innerHeight },
|
|
7850
|
+
size.width,
|
|
7851
|
+
size.height
|
|
7852
|
+
);
|
|
7853
|
+
this.#throwing = false;
|
|
7854
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
7855
|
+
this.#landUntil = this.#now() + 360;
|
|
7856
|
+
if (interaction.catchEvent) this.emit(interaction.catchEvent);
|
|
7857
|
+
this.#wake();
|
|
7858
|
+
return true;
|
|
7859
|
+
}
|
|
6687
7860
|
#diagnose(message, code = "runtime.notice", severity = "warning", phase = "internal", eventId, metadata, cause) {
|
|
6688
7861
|
this.#diagnostics.emit({
|
|
6689
7862
|
code,
|
|
@@ -6770,6 +7943,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6770
7943
|
if (hidden === this.#siteHidden) return;
|
|
6771
7944
|
this.#siteHidden = hidden;
|
|
6772
7945
|
this.#renderer?.setHidden(hidden);
|
|
7946
|
+
this.#interactionController?.setHidden(hidden);
|
|
6773
7947
|
if (this.#destroyed) return;
|
|
6774
7948
|
if (hidden && this.#contentRenderer) {
|
|
6775
7949
|
this.#contentRenderer.renderSurfaces(
|
|
@@ -6785,6 +7959,9 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6785
7959
|
if (this.#destroyed) return;
|
|
6786
7960
|
}
|
|
6787
7961
|
if (hidden) {
|
|
7962
|
+
this.#dragging = false;
|
|
7963
|
+
this.#throwing = false;
|
|
7964
|
+
this.#throwVelocity = { x: 0, y: 0 };
|
|
6788
7965
|
this.#overrides?.clear("dismissed");
|
|
6789
7966
|
this.#setSuspended(SUSPEND_SITE, true);
|
|
6790
7967
|
this.#notice("lifecycle.dismissed", "info", "lifecycle");
|
|
@@ -6880,8 +8057,13 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6880
8057
|
const loaded = this.#loaded;
|
|
6881
8058
|
this.#densityUpgrade = loaded.upgrade(required).then((changed) => {
|
|
6882
8059
|
if (changed && !this.#destroyed && this.#loaded === loaded) {
|
|
6883
|
-
this.#renderer
|
|
6884
|
-
|
|
8060
|
+
const renderer = this.#renderer;
|
|
8061
|
+
if (!renderer) return;
|
|
8062
|
+
return Promise.resolve(
|
|
8063
|
+
renderer.swapAtlas(loaded.content, loaded.atlasObjectUrl)
|
|
8064
|
+
).then(() => {
|
|
8065
|
+
if (!this.#destroyed && this.#loaded === loaded) this.#wake();
|
|
8066
|
+
});
|
|
6885
8067
|
}
|
|
6886
8068
|
}).catch((error) => {
|
|
6887
8069
|
if (!this.#destroyed)
|
|
@@ -6953,10 +8135,13 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6953
8135
|
pointer: input.pointer,
|
|
6954
8136
|
position: this.#position,
|
|
6955
8137
|
viewport,
|
|
8138
|
+
characterSize,
|
|
6956
8139
|
lastActivityAt: input.lastActivityAt,
|
|
6957
8140
|
reducedMotion: this.#reducedMotion,
|
|
6958
8141
|
pageVisible: !this.#document.hidden,
|
|
6959
8142
|
sections,
|
|
8143
|
+
targets: this.#targets?.snapshot(this.#trackTargets),
|
|
8144
|
+
samplePath: (path, progress) => this.#pathSampler.sample(path, progress),
|
|
6960
8145
|
reaction
|
|
6961
8146
|
};
|
|
6962
8147
|
return {
|
|
@@ -6977,11 +8162,26 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
6977
8162
|
overrides.observeEvent(reaction.name, reaction.source);
|
|
6978
8163
|
}
|
|
6979
8164
|
const request = overrides.compose(ordinary, world);
|
|
8165
|
+
this.#trackTargets = request.motion?.trackTarget === true;
|
|
6980
8166
|
if (this.#reducedMotion) {
|
|
6981
8167
|
delete request.motion;
|
|
6982
8168
|
if (request.capability === "locomotion") delete request.capability;
|
|
6983
8169
|
if (!request.state) request.state = "idle";
|
|
6984
8170
|
}
|
|
8171
|
+
const interaction = this.#options.interaction || {};
|
|
8172
|
+
if (this.#dragging) {
|
|
8173
|
+
delete request.motion;
|
|
8174
|
+
delete request.capability;
|
|
8175
|
+
request.state = interaction.dragState ?? "scroll:fly";
|
|
8176
|
+
} else if (this.#throwing) {
|
|
8177
|
+
delete request.motion;
|
|
8178
|
+
delete request.capability;
|
|
8179
|
+
request.state = this.#throwVelocity.y < 0 ? interaction.riseState ?? "scroll:fly" : interaction.fallState ?? "scroll:fall";
|
|
8180
|
+
} else if (this.#landUntil > world.now) {
|
|
8181
|
+
delete request.motion;
|
|
8182
|
+
delete request.capability;
|
|
8183
|
+
request.state = interaction.landState ?? "success";
|
|
8184
|
+
}
|
|
6985
8185
|
const diagnostics = [];
|
|
6986
8186
|
if (reaction) {
|
|
6987
8187
|
this.#seenReaction = reaction.id;
|
|
@@ -7040,19 +8240,74 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7040
8240
|
}
|
|
7041
8241
|
return this.#frameActive(frame);
|
|
7042
8242
|
}
|
|
8243
|
+
#advanceThrow(snapshot) {
|
|
8244
|
+
if (!this.#throwing) return;
|
|
8245
|
+
const interaction = this.#options.interaction || {};
|
|
8246
|
+
const dt = snapshot.frame.stepMs / 1e3;
|
|
8247
|
+
const bounce = interaction.bounce ?? DEFAULT_BOUNCE;
|
|
8248
|
+
const halfWidth = snapshot.characterSize.width / 2;
|
|
8249
|
+
const halfHeight = snapshot.characterSize.height / 2;
|
|
8250
|
+
const floor = snapshot.world.viewport.height - halfHeight - (interaction.floorInset ?? DEFAULT_FLOOR_INSET);
|
|
8251
|
+
let velocityX = this.#throwVelocity.x;
|
|
8252
|
+
let velocityY = this.#throwVelocity.y + (interaction.gravity ?? DEFAULT_GRAVITY) * dt;
|
|
8253
|
+
let x = this.#position.x + velocityX * dt;
|
|
8254
|
+
let y = this.#position.y + velocityY * dt;
|
|
8255
|
+
const right = snapshot.world.viewport.width - halfWidth;
|
|
8256
|
+
if (x < halfWidth) {
|
|
8257
|
+
x = halfWidth;
|
|
8258
|
+
velocityX = Math.abs(velocityX) * bounce;
|
|
8259
|
+
} else if (x > right) {
|
|
8260
|
+
x = right;
|
|
8261
|
+
velocityX = -Math.abs(velocityX) * bounce;
|
|
8262
|
+
}
|
|
8263
|
+
if (y < halfHeight) {
|
|
8264
|
+
y = halfHeight;
|
|
8265
|
+
velocityY = Math.abs(velocityY) * bounce;
|
|
8266
|
+
}
|
|
8267
|
+
const next = { x, y };
|
|
8268
|
+
if (interaction.catchTarget && this.#targets?.contains(
|
|
8269
|
+
interaction.catchTarget,
|
|
8270
|
+
next,
|
|
8271
|
+
interaction.catchMargin ?? 24
|
|
8272
|
+
) && this.#catchCharacter(interaction.catchTarget)) {
|
|
8273
|
+
return;
|
|
8274
|
+
}
|
|
8275
|
+
if (y >= floor) {
|
|
8276
|
+
this.#position = { x, y: floor };
|
|
8277
|
+
this.#landCharacter();
|
|
8278
|
+
return;
|
|
8279
|
+
}
|
|
8280
|
+
this.#position = next;
|
|
8281
|
+
this.#throwVelocity = { x: velocityX * 0.995, y: velocityY };
|
|
8282
|
+
}
|
|
7043
8283
|
#calculatePresentation(snapshot, evaluation) {
|
|
7044
8284
|
const { frame, characterSize, world } = snapshot;
|
|
7045
8285
|
const { request } = evaluation;
|
|
7046
8286
|
const loaded = frame.loaded.content;
|
|
7047
8287
|
if (!this.#reducedMotion)
|
|
7048
8288
|
this.#animationClock += Math.max(0, frame.elapsed);
|
|
8289
|
+
this.#advanceThrow(snapshot);
|
|
7049
8290
|
const requested = request.capability === "locomotion" && request.motion ? loaded.directionalStates?.[directionTo(
|
|
7050
8291
|
{ x: 0, y: 0 },
|
|
7051
8292
|
{ x: request.motion.x, y: request.motion.y }
|
|
7052
8293
|
)] : resolveCapabilityName(request.state, loaded);
|
|
7053
8294
|
const resolved = resolveState(requested, loaded.states);
|
|
7054
8295
|
let lift = 0;
|
|
7055
|
-
if (request.motion) {
|
|
8296
|
+
if (request.motion?.direct) {
|
|
8297
|
+
const distance = request.motion.maxDistance ?? 0;
|
|
8298
|
+
this.#position = clampPosition(
|
|
8299
|
+
{
|
|
8300
|
+
x: this.#position.x + request.motion.x * distance,
|
|
8301
|
+
y: this.#position.y + request.motion.y * distance
|
|
8302
|
+
},
|
|
8303
|
+
world.viewport,
|
|
8304
|
+
characterSize.width,
|
|
8305
|
+
characterSize.height
|
|
8306
|
+
);
|
|
8307
|
+
lift = request.motion.lift ?? 0;
|
|
8308
|
+
this.#locomotionState = "";
|
|
8309
|
+
this.#locomotionElapsed = 0;
|
|
8310
|
+
} else if (request.motion) {
|
|
7056
8311
|
if (this.#locomotionState !== resolved.name) {
|
|
7057
8312
|
this.#locomotionState = resolved.name;
|
|
7058
8313
|
this.#locomotionElapsed = 0;
|
|
@@ -7083,7 +8338,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7083
8338
|
characterSize.width,
|
|
7084
8339
|
characterSize.height
|
|
7085
8340
|
);
|
|
7086
|
-
lift = locomotionSample(loaded.locomotionMotion, nextCycles).lift * characterSize.height;
|
|
8341
|
+
lift = request.motion.lift ?? locomotionSample(loaded.locomotionMotion, nextCycles).lift * characterSize.height;
|
|
7087
8342
|
} else {
|
|
7088
8343
|
this.#locomotionState = "";
|
|
7089
8344
|
this.#locomotionElapsed = 0;
|
|
@@ -7117,9 +8372,15 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7117
8372
|
presentation.lift
|
|
7118
8373
|
);
|
|
7119
8374
|
if (!this.#frameActive(frame)) return;
|
|
8375
|
+
this.#interactionController?.render(
|
|
8376
|
+
this.#position,
|
|
8377
|
+
snapshot.characterSize,
|
|
8378
|
+
presentation.lift
|
|
8379
|
+
);
|
|
8380
|
+
if (!this.#frameActive(frame)) return;
|
|
7120
8381
|
this.#lastTick = frame.now;
|
|
7121
8382
|
this.#schedulePlan(frame);
|
|
7122
|
-
if (this.#frameActive(frame) && (evaluation.request.motion || frame.input.reaction))
|
|
8383
|
+
if (this.#frameActive(frame) && (evaluation.request.motion || frame.input.reaction || this.#throwing || this.#dragging))
|
|
7123
8384
|
this.#wake();
|
|
7124
8385
|
}
|
|
7125
8386
|
#endPage() {
|
|
@@ -7202,6 +8463,24 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7202
8463
|
y: Math.max(height / 2, Math.min(viewport.height - height / 2, point.y))
|
|
7203
8464
|
};
|
|
7204
8465
|
}
|
|
8466
|
+
function characterTargetPoint(target, anchor, character) {
|
|
8467
|
+
const center = {
|
|
8468
|
+
x: target.left + target.width / 2,
|
|
8469
|
+
y: target.top + target.height / 2
|
|
8470
|
+
};
|
|
8471
|
+
switch (anchor) {
|
|
8472
|
+
case "top":
|
|
8473
|
+
return { x: center.x, y: target.top - character.height / 2 };
|
|
8474
|
+
case "right":
|
|
8475
|
+
return { x: target.right + character.width / 2, y: center.y };
|
|
8476
|
+
case "bottom":
|
|
8477
|
+
return { x: center.x, y: target.bottom + character.height / 2 };
|
|
8478
|
+
case "left":
|
|
8479
|
+
return { x: target.left - character.width / 2, y: center.y };
|
|
8480
|
+
default:
|
|
8481
|
+
return center;
|
|
8482
|
+
}
|
|
8483
|
+
}
|
|
7205
8484
|
|
|
7206
8485
|
// packages/runtime/src/web-component.ts
|
|
7207
8486
|
var PEEKLING_ELEMENT_TAG = "peekling-character";
|
|
@@ -7436,7 +8715,7 @@ ${styles.integrity ?? ""}` === this.#styleKey) return;
|
|
|
7436
8715
|
}
|
|
7437
8716
|
|
|
7438
8717
|
// packages/runtime/src/browser.ts
|
|
7439
|
-
var browserCssIntegrity = "sha256-
|
|
8718
|
+
var browserCssIntegrity = "sha256-r4PIKebZlQTb2JaHfQibQqQxHaKciwlXtTMDEvDTUPY=" ? "sha256-r4PIKebZlQTb2JaHfQibQqQxHaKciwlXtTMDEvDTUPY=" : void 0;
|
|
7440
8719
|
var browserScript = globalThis.document?.currentScript;
|
|
7441
8720
|
if (browserScript?.src) {
|
|
7442
8721
|
setBrowserStyleAsset({
|