@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.
Files changed (52) hide show
  1. package/README.md +59 -8
  2. package/dist/canvas-renderer.d.ts +17 -0
  3. package/dist/canvas-renderer.d.ts.map +1 -0
  4. package/dist/canvas-renderer.js +192 -0
  5. package/dist/canvas.d.ts +5 -0
  6. package/dist/canvas.d.ts.map +1 -0
  7. package/dist/canvas.js +6 -0
  8. package/dist/configuration-validation.d.ts.map +1 -1
  9. package/dist/configuration-validation.js +176 -1
  10. package/dist/content.d.ts +3 -0
  11. package/dist/content.d.ts.map +1 -1
  12. package/dist/content.js +33 -7
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/input.d.ts.map +1 -1
  16. package/dist/input.js +4 -1
  17. package/dist/interaction.d.ts +37 -0
  18. package/dist/interaction.d.ts.map +1 -0
  19. package/dist/interaction.js +204 -0
  20. package/dist/overrides.d.ts +8 -0
  21. package/dist/overrides.d.ts.map +1 -1
  22. package/dist/overrides.js +18 -16
  23. package/dist/path-sampler.d.ts +9 -0
  24. package/dist/path-sampler.d.ts.map +1 -0
  25. package/dist/path-sampler.js +47 -0
  26. package/dist/peekling.css +1 -1
  27. package/dist/peekling.css.sri +1 -1
  28. package/dist/peekling.js +1365 -86
  29. package/dist/peekling.js.sri +1 -1
  30. package/dist/peekling.min.js +1 -1
  31. package/dist/peekling.min.js.sri +1 -1
  32. package/dist/plan-compiler.d.ts +2 -0
  33. package/dist/plan-compiler.d.ts.map +1 -1
  34. package/dist/plan-compiler.js +71 -14
  35. package/dist/plan.d.ts +27 -1
  36. package/dist/plan.d.ts.map +1 -1
  37. package/dist/plan.js +281 -22
  38. package/dist/registry.js +2 -2
  39. package/dist/renderer.d.ts +18 -1
  40. package/dist/renderer.d.ts.map +1 -1
  41. package/dist/renderer.js +1 -0
  42. package/dist/runtime-validation.d.ts.map +1 -1
  43. package/dist/runtime-validation.js +35 -0
  44. package/dist/runtime.d.ts +49 -3
  45. package/dist/runtime.d.ts.map +1 -1
  46. package/dist/runtime.js +365 -14
  47. package/dist/targets.d.ts +11 -0
  48. package/dist/targets.d.ts.map +1 -0
  49. package/dist/targets.js +106 -0
  50. package/dist/types.d.ts +61 -1
  51. package/dist/types.d.ts.map +1 -1
  52. package/package.json +5 -1
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { hatch, type PeeklingFinishReason, type PeeklingFinishResult, type PeeklingHatchInput, type PeeklingInstance, type PeeklingOptions, type PeeklingPackSelection, type PeeklingPosition, } from "./runtime.js";
1
+ export { hatch, type PeeklingFinishReason, type PeeklingFinishResult, type PeeklingHatchInput, type PeeklingIndicator, type PeeklingInteractionOptions, type PeeklingInstance, type PeeklingOptions, type PeeklingPackSelection, type PeeklingPosition, type PeeklingPressAction, } from "./runtime.js";
2
2
  export { hidePeekling, isPeeklingHidden, showPeekling, type PeeklingHideDuration, } from "./visibility.js";
3
3
  export type { RuntimeStyleAsset } from "./styles.js";
4
4
  export { definePeeklingElement, PEEKLING_ELEMENT_TAG, type PeeklingElement, } from "./web-component.js";
5
- export type { ContentRegion, DiagnosticRecord, DiagnosticSeverity, Direction, EmitResult, HostBindings, HostContent, HostContentItem, HostContentPrimitive, HostContentSurface, HostSurfaceMount, HostSurfaceMountContext, HostSurfaceMountResult, JsonValue, NativeDensity, NativeManifest, NormalizedPack, Plan, PlanBrowserEvent, PlanCapability, PlanChannel, PlanCondition, PlanDisposition, PlanEffect, PlanEventSource, PlanMotionEffect, PlanRule, PlanStateSelection, PlanSurfaceEffect, PlanSurfaceOrdering, OverrideCompletionReason, OverrideHandle, OverrideInput, OverrideLifetime, OverrideResult, OverrideStatus, StateDefinition, SurfaceTheme, } from "./types.js";
5
+ export type { ContentRegion, DiagnosticRecord, DiagnosticSeverity, Direction, EmitResult, HostBindings, HostContent, HostContentItem, HostContentPrimitive, HostContentSurface, HostSurfaceMount, HostSurfaceMountContext, HostSurfaceMountResult, JsonValue, NativeDensity, NativeManifest, NormalizedPack, Plan, PlanBrowserEvent, PlanCapability, PlanChannel, PlanCondition, PlanDisposition, PlanEffect, PlanEventSource, PlanMotionEffect, PeeklingPreset, PlanRule, PlanStateSelection, PlanSurfaceEffect, PlanSurfaceOrdering, OverrideCompletionReason, OverrideHandle, OverrideInput, OverrideLifetime, OverrideResult, OverrideStatus, StateDefinition, SurfaceTheme, TargetAnchor, TargetSnapshot, } from "./types.js";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,SAAS,EACT,aAAa,EACb,cAAc,EACd,cAAc,EACd,IAAI,EACJ,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,SAAS,EACT,aAAa,EACb,cAAc,EACd,cAAc,EACd,IAAI,EACJ,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,KAAK,EACL,aAAa,EACd,MAAM,YAAY,CAAC;AAWpB,qBAAa,cAAc;;IACzB,OAAO,EAAE,KAAK,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,EAAE,CAAM;IACzC,cAAc,EAAE,MAAM,CAAC;IAkBvB,YACE,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QACP,MAAM,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;QACtC,QAAQ,CAAC,EAAE,WAAW,CACpB,MAAM,EACN,IAAI,GAAG;YAAE,YAAY,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAA;SAAE,CACvD,CAAC;QACF,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QACvC,GAAG,EAAE,MAAM,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;KAClB,EAYF;IAED,IAAI,QAAQ,IAAI,aAAa,GAAG,SAAS,CAExC;IAED,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,SAAS,EACnB,MAAM,GAAE,eAA+B,GAErC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAClD;QAAE,QAAQ,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,CAiC5C;IAED,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAQ/C;IAED,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAajC;IAED,OAAO,IAAI,IAAI,CAOd;CAkIF"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,KAAK,EACL,aAAa,EACd,MAAM,YAAY,CAAC;AAWpB,qBAAa,cAAc;;IACzB,OAAO,EAAE,KAAK,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,EAAE,CAAM;IACzC,cAAc,EAAE,MAAM,CAAC;IAkBvB,YACE,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QACP,MAAM,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC;QACtC,QAAQ,CAAC,EAAE,WAAW,CACpB,MAAM,EACN,IAAI,GAAG;YAAE,YAAY,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAA;SAAE,CACvD,CAAC;QACF,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QACvC,GAAG,EAAE,MAAM,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,IAAI,CAAC;KAClB,EAYF;IAED,IAAI,QAAQ,IAAI,aAAa,GAAG,SAAS,CAExC;IAED,eAAe,CACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,SAAS,EACnB,MAAM,GAAE,eAA+B,GAErC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAClD;QAAE,QAAQ,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,CAiC5C;IAED,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAQ/C;IAED,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAajC;IAED,OAAO,IAAI,IAAI,CAOd;CAmIF"}
package/dist/input.js CHANGED
@@ -134,7 +134,10 @@ export class InputCollector {
134
134
  listen(this.#document, "visibilitychange", () => this.captureReaction("document.visibility", { visible: !this.#document.hidden }, "browser"), true);
135
135
  }
136
136
  else if (event === "window.scroll") {
137
- listen(this.#window, "scroll", (input) => this.#captureObserved("window.scroll", input));
137
+ listen(this.#window, "scroll", (input) => {
138
+ this.#clearPointer();
139
+ this.#captureObserved("window.scroll", input);
140
+ });
138
141
  }
139
142
  else if (event === "window.focus") {
140
143
  listen(this.#window, "focus", () => this.captureReaction("window.focus", { focused: true }, "browser"));
@@ -0,0 +1,37 @@
1
+ import { type RuntimeStyleAsset } from "./styles.js";
2
+ import type { Point } from "./types.js";
3
+ export interface CharacterIndicator {
4
+ kind?: "dot" | "count";
5
+ count?: number;
6
+ label: string;
7
+ color?: "transparent" | `#${string}`;
8
+ visible?: boolean;
9
+ }
10
+ export interface CharacterInteractionControllerOptions {
11
+ document: Document;
12
+ styles: RuntimeStyleAsset;
13
+ label: string;
14
+ draggable: boolean;
15
+ /** Present only when the character button controls an owned content surface. */
16
+ expanded?: boolean;
17
+ indicator?: CharacterIndicator;
18
+ onPress(): void;
19
+ onDragStart(): void;
20
+ onDragMove(position: Readonly<Point>, velocity: Readonly<Point>): void;
21
+ onDragEnd(velocity: Readonly<Point>, moved: boolean, pointer: Readonly<Point>): void;
22
+ }
23
+ /** Accessible owned hit target layered above either character renderer. */
24
+ export declare class CharacterInteractionController {
25
+ #private;
26
+ readonly ready: Promise<void>;
27
+ constructor(options: CharacterInteractionControllerOptions);
28
+ render(position: Readonly<Point>, character: Readonly<{
29
+ width: number;
30
+ height: number;
31
+ }>, lift?: number): void;
32
+ setHidden(hidden: boolean): void;
33
+ setExpanded(expanded: boolean): void;
34
+ updateIndicator(indicator?: CharacterIndicator | null): void;
35
+ destroy(): void;
36
+ }
37
+ //# sourceMappingURL=interaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,MAAM,EAAE,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qCAAqC;IACpD,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,OAAO,IAAI,IAAI,CAAC;IAChB,WAAW,IAAI,IAAI,CAAC;IACpB,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IACvE,SAAS,CACP,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,GACvB,IAAI,CAAC;CACT;AAED,2EAA2E;AAC3E,qBAAa,8BAA8B;;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAuB9B,YAAY,OAAO,EAAE,qCAAqC,EAyCzD;IAED,MAAM,CACJ,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,SAAS,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,EACtD,IAAI,SAAI,GACP,IAAI,CAWN;IAED,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAE/B;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,eAAe,CAAC,SAAS,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAuB3D;IAQD,OAAO,IAAI,IAAI,CAKd;CAwGF"}
@@ -0,0 +1,204 @@
1
+ import { runtimeMessage } from "./runtime-diagnostics.js";
2
+ import { connectRuntimeHost, ShadowStyleSheet, } from "./styles.js";
3
+ /** Accessible owned hit target layered above either character renderer. */
4
+ export class CharacterInteractionController {
5
+ ready;
6
+ #document;
7
+ #host;
8
+ #root;
9
+ #button;
10
+ #badge;
11
+ #styles;
12
+ #options;
13
+ #buttonRule;
14
+ #badgeRule;
15
+ #indicator;
16
+ #label;
17
+ #position = { x: 0, y: 0 };
18
+ #pointerId;
19
+ #startPointer = { x: 0, y: 0 };
20
+ #lastPointer = { x: 0, y: 0 };
21
+ #startPosition = { x: 0, y: 0 };
22
+ #velocity = { x: 0, y: 0 };
23
+ #lastTime = 0;
24
+ #moved = false;
25
+ #suppressClick = false;
26
+ #destroyed = false;
27
+ constructor(options) {
28
+ this.#options = options;
29
+ this.#document = options.document;
30
+ this.#label = options.label;
31
+ this.#host = options.document.createElement("div");
32
+ this.#host.setAttribute("data-peekling-interaction", "");
33
+ this.#root = this.#host.attachShadow({ mode: "closed" });
34
+ this.#styles = new ShadowStyleSheet(options.document, this.#root, options.styles);
35
+ this.#button = options.document.createElement("button");
36
+ this.#button.type = "button";
37
+ this.#button.className = "peekling-character-hit";
38
+ this.#button.setAttribute("aria-label", options.label);
39
+ if (options.expanded !== undefined) {
40
+ this.#button.setAttribute("aria-expanded", String(options.expanded));
41
+ }
42
+ this.#button.toggleAttribute("data-peekling-draggable", options.draggable);
43
+ this.#badge = options.document.createElement("span");
44
+ this.#badge.className = "peekling-character-indicator";
45
+ this.#badge.setAttribute("aria-hidden", "true");
46
+ this.#button.append(this.#badge);
47
+ this.#root.append(this.#button);
48
+ this.ready = this.#styles.ready.then(() => {
49
+ if (this.#destroyed)
50
+ return;
51
+ this.#buttonRule = this.#styles.addRule(".peekling-character-hit");
52
+ this.#badgeRule = this.#styles.addRule(".peekling-character-indicator");
53
+ this.#syncIndicatorColor();
54
+ });
55
+ void this.ready.catch(() => { });
56
+ this.#button.addEventListener("click", this.#click);
57
+ if (options.draggable) {
58
+ this.#button.addEventListener("pointerdown", this.#pointerDown);
59
+ this.#button.addEventListener("pointermove", this.#pointerMove);
60
+ this.#button.addEventListener("pointerup", this.#pointerUp);
61
+ this.#button.addEventListener("pointercancel", this.#pointerCancel);
62
+ }
63
+ this.updateIndicator(options.indicator);
64
+ this.#repair();
65
+ }
66
+ render(position, character, lift = 0) {
67
+ if (this.#destroyed)
68
+ return;
69
+ this.#repair();
70
+ this.#position = { x: position.x, y: position.y - lift };
71
+ const rule = this.#buttonRule;
72
+ if (!rule)
73
+ return;
74
+ const left = position.x - character.width / 2;
75
+ const top = position.y - character.height / 2 - lift;
76
+ rule.width = `${character.width}px`;
77
+ rule.height = `${character.height}px`;
78
+ rule.transform = `translate3d(${left}px,${top}px,0)`;
79
+ }
80
+ setHidden(hidden) {
81
+ if (!this.#destroyed)
82
+ this.#host.toggleAttribute("hidden", hidden);
83
+ }
84
+ setExpanded(expanded) {
85
+ if (!this.#destroyed && this.#button.hasAttribute("aria-expanded")) {
86
+ this.#button.setAttribute("aria-expanded", String(expanded));
87
+ }
88
+ }
89
+ updateIndicator(indicator) {
90
+ if (this.#destroyed)
91
+ return;
92
+ this.#indicator = indicator ?? undefined;
93
+ this.#syncIndicatorColor();
94
+ const visible = Boolean(indicator &&
95
+ indicator.visible !== false &&
96
+ (indicator.kind !== "count" || (indicator.count ?? 0) > 0));
97
+ this.#badge.hidden = !visible;
98
+ if (!visible || !indicator) {
99
+ this.#badge.textContent = "";
100
+ this.#button.setAttribute("aria-label", this.#label);
101
+ return;
102
+ }
103
+ const kind = indicator.kind ?? "dot";
104
+ this.#badge.dataset.kind = kind;
105
+ this.#badge.textContent =
106
+ kind === "count" ? String(Math.min(99, indicator.count ?? 0)) : "";
107
+ this.#button.setAttribute("aria-label", `${this.#label}. ${indicator.label}`);
108
+ }
109
+ #syncIndicatorColor() {
110
+ if (this.#badgeRule) {
111
+ this.#badgeRule.backgroundColor = this.#indicator?.color ?? "";
112
+ }
113
+ }
114
+ destroy() {
115
+ if (this.#destroyed)
116
+ return;
117
+ this.#destroyed = true;
118
+ this.#styles.destroy();
119
+ this.#host.remove();
120
+ }
121
+ #click = () => {
122
+ if (this.#suppressClick) {
123
+ this.#suppressClick = false;
124
+ return;
125
+ }
126
+ this.#options.onPress();
127
+ };
128
+ #pointerDown = (event) => {
129
+ if (this.#destroyed ||
130
+ this.#pointerId !== undefined ||
131
+ (!event.isPrimary && event.pointerType !== "mouse") ||
132
+ (event.pointerType === "mouse" && event.button !== 0)) {
133
+ return;
134
+ }
135
+ this.#pointerId = event.pointerId;
136
+ this.#startPointer = { x: event.clientX, y: event.clientY };
137
+ this.#lastPointer = { ...this.#startPointer };
138
+ this.#startPosition = { ...this.#position };
139
+ this.#velocity = { x: 0, y: 0 };
140
+ this.#lastTime = event.timeStamp;
141
+ this.#moved = false;
142
+ try {
143
+ this.#button.setPointerCapture(event.pointerId);
144
+ }
145
+ catch {
146
+ // Pointer capture is an optimization. Owned pointer listeners still work.
147
+ }
148
+ this.#options.onDragStart();
149
+ };
150
+ #pointerMove = (event) => {
151
+ if (event.pointerId !== this.#pointerId)
152
+ return;
153
+ const dx = event.clientX - this.#startPointer.x;
154
+ const dy = event.clientY - this.#startPointer.y;
155
+ if (!this.#moved && Math.hypot(dx, dy) >= 4)
156
+ this.#moved = true;
157
+ const elapsed = Math.max(8, Math.min(100, event.timeStamp - this.#lastTime));
158
+ const sampleX = ((event.clientX - this.#lastPointer.x) * 1_000) / elapsed;
159
+ const sampleY = ((event.clientY - this.#lastPointer.y) * 1_000) / elapsed;
160
+ this.#velocity = {
161
+ x: sampleX * 0.65 + this.#velocity.x * 0.35,
162
+ y: sampleY * 0.65 + this.#velocity.y * 0.35,
163
+ };
164
+ this.#lastPointer = { x: event.clientX, y: event.clientY };
165
+ this.#lastTime = event.timeStamp;
166
+ this.#options.onDragMove({
167
+ x: this.#startPosition.x + dx,
168
+ y: this.#startPosition.y + dy,
169
+ }, this.#velocity);
170
+ };
171
+ #pointerUp = (event) => {
172
+ if (event.pointerId !== this.#pointerId)
173
+ return;
174
+ this.#finishPointer(event, this.#moved, this.#velocity);
175
+ };
176
+ #pointerCancel = (event) => {
177
+ if (event.pointerId !== this.#pointerId)
178
+ return;
179
+ this.#finishPointer(event, this.#moved, { x: 0, y: 0 }, this.#lastPointer);
180
+ };
181
+ #finishPointer(event, moved, velocity, pointer = { x: event.clientX, y: event.clientY }) {
182
+ const pointerId = this.#pointerId;
183
+ this.#pointerId = undefined;
184
+ if (pointerId !== undefined) {
185
+ try {
186
+ this.#button.releasePointerCapture(pointerId);
187
+ }
188
+ catch {
189
+ // Capture may already have been released by the browser.
190
+ }
191
+ }
192
+ this.#suppressClick = moved;
193
+ this.#options.onDragEnd(velocity, moved, pointer);
194
+ }
195
+ #repair() {
196
+ if (this.#destroyed)
197
+ return;
198
+ connectRuntimeHost(this.#host, this.#document, "data-peekling-interaction");
199
+ if (this.#root.host !== this.#host ||
200
+ this.#button.getRootNode() !== this.#root) {
201
+ throw new Error(runtimeMessage("interaction.root", "Peekling interaction root structure was changed"));
202
+ }
203
+ }
204
+ }
@@ -9,6 +9,14 @@ interface OverrideWorld {
9
9
  x: number;
10
10
  y: number;
11
11
  };
12
+ viewport?: {
13
+ width: number;
14
+ height: number;
15
+ };
16
+ characterSize?: {
17
+ width: number;
18
+ height: number;
19
+ };
12
20
  }
13
21
  /** Instance-owned temporary channel controller. It never mutates the Plan. */
14
22
  export declare class OverrideManager {
@@ -1 +1 @@
1
- {"version":3,"file":"overrides.d.ts","sourceRoot":"","sources":["../src/overrides.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,aAAa,EAIb,gBAAgB,EAChB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAiBpB,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC;AAED,8EAA8E;AAC9E,qBAAa,eAAe;;IAO1B,YACE,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,MAAM,EACjB,UAAU,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,EAKjD;IAED,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAyDxC;IAED,MAAM,CAAC,MAAM,GAAE,wBAAqC,GAAG,cAAc,CAIpE;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAK7D;IAED,gFAAgF;IAChF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,eAA+B,GAAG,KAAK,CAWzE;IAED,OAAO,CACL,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,EAC/B,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC7B,eAAe,CAmDjB;IAED,UAAU,IAAI,MAAM,GAAG,SAAS,CAQ/B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1B;IAED,KAAK,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAE5C;CA+CF;AAMD,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,wBAAwB,GAC/B,cAAc,CAOhB"}
1
+ {"version":3,"file":"overrides.d.ts","sourceRoot":"","sources":["../src/overrides.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,aAAa,EAIb,gBAAgB,EAChB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAkBpB,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,QAAQ,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,8EAA8E;AAC9E,qBAAa,eAAe;;IAO1B,YACE,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,MAAM,EACjB,UAAU,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,EAKjD;IAED,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAyDxC;IAED,MAAM,CAAC,MAAM,GAAE,wBAAqC,GAAG,cAAc,CAIpE;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAK7D;IAED,gFAAgF;IAChF,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,eAA+B,GAAG,KAAK,CAWzE;IAED,OAAO,CACL,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,EAC/B,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC7B,eAAe,CA4DjB;IAED,UAAU,IAAI,MAAM,GAAG,SAAS,CAQ/B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1B;IAED,KAAK,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAE5C;CAgDF;AAMD,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,wBAAwB,GAC/B,cAAc,CAOhB"}
package/dist/overrides.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { EVENT_NAME_PATTERN } from "./contracts.js";
2
2
  import { browserCompletionEvent, isContinuousBrowserEvent } from "./events.js";
3
- import { DEFAULT_PERSISTENT_REQUEST_LIMIT, DEFAULT_SPEED } from "./defaults.js";
3
+ import { DEFAULT_PERSISTENT_REQUEST_LIMIT } from "./defaults.js";
4
4
  import { compileOverrideEffect, } from "./plan-compiler.js";
5
5
  import { snapshotOwnData } from "./own-data.js";
6
+ import { evaluateHorizontalPatrol, motionToward, } from "./plan.js";
6
7
  import { runtimeMessage } from "./runtime-diagnostics.js";
7
8
  const OVERRIDE_LIMIT = 8;
8
9
  const MAX_LIFETIME = DEFAULT_PERSISTENT_REQUEST_LIMIT;
@@ -99,22 +100,22 @@ export class OverrideManager {
99
100
  delete output.state;
100
101
  }
101
102
  const motion = item.effect.motion;
102
- if (motion && world.pointer && world.position) {
103
- const dx = world.pointer.x - world.position.x;
104
- const dy = world.pointer.y - world.position.y;
105
- const distance = Math.hypot(dx, dy);
106
- const arrivalRadius = motion.arrivalRadius ?? 0;
107
- if (distance > arrivalRadius) {
108
- output.motion = {
109
- x: dx / distance,
110
- y: dy / distance,
111
- speed: motion.speed ?? DEFAULT_SPEED,
112
- maxDistance: distance - arrivalRadius,
113
- };
114
- }
115
- else {
103
+ if (motion?.type === "horizontal-patrol") {
104
+ const [direction, request] = evaluateHorizontalPatrol(motion, world, item.patrolDirection);
105
+ item.patrolDirection = direction;
106
+ if (request)
107
+ output.motion = request;
108
+ else
109
+ delete output.motion;
110
+ }
111
+ else if (motion?.type === "follow-pointer" &&
112
+ world.pointer &&
113
+ world.position) {
114
+ const request = motionToward(motion, world.position, world.pointer.x, world.pointer.y, motion.arrivalRadius, world);
115
+ if (request)
116
+ output.motion = request;
117
+ else
116
118
  delete output.motion;
117
- }
118
119
  }
119
120
  for (const surface of item.effect.surfaces) {
120
121
  surfaces.set(surface.channel, Object.freeze({
@@ -180,6 +181,7 @@ export class OverrideManager {
180
181
  startedAt: 0,
181
182
  deadline: 0,
182
183
  status: "rejected",
184
+ patrolDirection: true,
183
185
  handle,
184
186
  finish,
185
187
  });
@@ -0,0 +1,9 @@
1
+ import type { Point } from "./types.js";
2
+ /** Bounded browser-native SVG path geometry. Path data is never inserted as HTML. */
3
+ export declare class SvgPathSampler {
4
+ #private;
5
+ constructor(document: Document);
6
+ validate(path: string): boolean;
7
+ sample(path: string, progress: number): Point | undefined;
8
+ }
9
+ //# sourceMappingURL=path-sampler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-sampler.d.ts","sourceRoot":"","sources":["../src/path-sampler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AASxC,qFAAqF;AACrF,qBAAa,cAAc;;IAIzB,YAAY,QAAQ,EAAE,QAAQ,EAE7B;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAaxD;CAqBF"}
@@ -0,0 +1,47 @@
1
+ const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
2
+ /** Bounded browser-native SVG path geometry. Path data is never inserted as HTML. */
3
+ export class SvgPathSampler {
4
+ #document;
5
+ #cache = new Map();
6
+ constructor(document) {
7
+ this.#document = document;
8
+ }
9
+ validate(path) {
10
+ return this.#geometry(path) !== undefined;
11
+ }
12
+ sample(path, progress) {
13
+ const geometry = this.#geometry(path);
14
+ if (!geometry)
15
+ return;
16
+ const bounded = Math.max(0, Math.min(1, progress));
17
+ try {
18
+ const point = geometry.element.getPointAtLength(geometry.length * bounded);
19
+ if (!Number.isFinite(point.x) || !Number.isFinite(point.y))
20
+ return;
21
+ return { x: point.x, y: point.y };
22
+ }
23
+ catch {
24
+ return;
25
+ }
26
+ }
27
+ #geometry(path) {
28
+ const cached = this.#cache.get(path);
29
+ if (cached)
30
+ return cached;
31
+ if (this.#cache.size >= 16)
32
+ return;
33
+ const element = this.#document.createElementNS(SVG_NAMESPACE, "path");
34
+ element.setAttribute("d", path);
35
+ try {
36
+ const length = element.getTotalLength();
37
+ if (!Number.isFinite(length) || length <= 0)
38
+ return;
39
+ const geometry = Object.freeze({ element, length });
40
+ this.#cache.set(path, geometry);
41
+ return geometry;
42
+ }
43
+ catch {
44
+ return;
45
+ }
46
+ }
47
+ }
package/dist/peekling.css CHANGED
@@ -1 +1 @@
1
- :host{all:initial!important;position:fixed!important;inset:0!important;pointer-events:none!important}:host([data-peekling-host][hidden]){display:none!important}:host([data-peekling-host]){z-index:2147483646!important;contain:strict!important;overflow:hidden!important}.sprite{display:block;position:absolute;background-repeat:no-repeat;transform-origin:0 0}:host([data-peekling-content]){z-index:2147483645!important;color:var(--peekling-surface-color, #262626)!important;font:500 14px/1.4 system-ui!important}.surface{position:absolute;box-sizing:border-box;width:min(var(--peekling-surface-width, 320px),calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;padding:var(--peekling-surface-padding, 12px 14px);border:1px solid var(--peekling-surface-border, #d9d9d3);border-radius:var(--peekling-surface-radius, 14px);background:var(--peekling-surface-background, #fafafa);pointer-events:auto}.title{display:block}.surface p{margin:0}.surface a{display:inline-flex;min-width:44px;min-height:44px;align-items:center;justify-content:center;margin-top:6px;color:var(--peekling-surface-link, #174f00)}.surface a:focus-visible{outline:3px solid;outline-offset:3px}:host([data-peekling-controls]){z-index:2147483647!important;color:#262626!important;font:600 14px/1.25 system-ui!important}.peekling-visibility-trigger{position:fixed;right:0;bottom:0;width:64px;height:64px;border:0;background:transparent;opacity:0;pointer-events:none}.peekling-visibility-trigger:focus-visible{opacity:1;outline:3px solid;background:#fafafa}.peekling-visibility-panel{position:fixed;right:16px;bottom:16px;box-sizing:border-box;width:min(272px,calc(100vw - 32px));padding:16px;border:1px solid #d9d9d3;border-radius:18px;background:#fafafa;pointer-events:auto}.peekling-visibility-panel h2{margin:0 0 12px}.peekling-visibility-option{display:block;width:100%;min-height:44px;padding:10px 12px;border:0;background:transparent;color:inherit;font:inherit}.peekling-visibility-option:hover,.peekling-visibility-option:focus-visible{outline:2px solid}
1
+ :host{all:initial!important;position:fixed!important;inset:0!important;pointer-events:none!important}:host([data-peekling-host][hidden]){display:none!important}:host([data-peekling-host]){z-index:2147483646!important;contain:strict!important;overflow:hidden!important}.sprite{display:block;position:absolute;background-repeat:no-repeat;transform-origin:0 0}:host([data-peekling-content]){z-index:2147483645!important;color:var(--peekling-surface-color, #262626)!important;font:500 14px/1.4 system-ui!important}:host([data-peekling-content][hidden]){display:none!important}:host([data-peekling-interaction]){z-index:2147483647!important;contain:strict!important;overflow:hidden!important}:host([data-peekling-interaction][hidden]){display:none!important}.peekling-character-hit{-webkit-appearance:none;appearance:none;position:absolute;margin:0;padding:0;border:0;border-radius:28%;background:transparent;color:#262626;pointer-events:auto;cursor:pointer;transform-origin:0 0;-webkit-tap-highlight-color:transparent;-webkit-backface-visibility:hidden;backface-visibility:hidden}.peekling-character-hit[data-peekling-draggable]{cursor:grab;touch-action:none}.peekling-character-hit[data-peekling-draggable]:active{cursor:grabbing}.peekling-character-hit:focus-visible{outline:3px solid #2f6f1d;outline-offset:3px}.peekling-character-indicator{position:absolute;top:-2px;right:-2px;display:grid;box-sizing:border-box;min-width:16px;height:16px;padding:0 4px;place-items:center;border:2px solid #fafafa;border-radius:999px;background:#ff4d4f;color:#fff;font:700 10px/1 system-ui}.peekling-character-indicator[data-kind=dot]{min-width:12px;width:12px;height:12px;padding:0}.surface{position:absolute;box-sizing:border-box;width:min(var(--peekling-surface-width, 320px),calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;padding:var(--peekling-surface-padding, 12px 14px);border:1px solid var(--peekling-surface-border, #d9d9d3);border-radius:var(--peekling-surface-radius, 14px);background:var(--peekling-surface-background, #fafafa);pointer-events:auto}.surface [hidden]{display:none!important}.title{display:block}.surface p{margin:0}.surface a{display:inline-flex;min-width:44px;min-height:44px;align-items:center;justify-content:center;margin-top:6px;color:var(--peekling-surface-link, #174f00)}.surface a:focus-visible{outline:3px solid;outline-offset:3px}:host([data-peekling-controls]){z-index:2147483647!important;color:#262626!important;font:600 14px/1.25 system-ui!important}.peekling-visibility-trigger{position:fixed;right:0;bottom:0;width:64px;height:64px;border:0;background:transparent;opacity:0;pointer-events:none}.peekling-visibility-trigger:focus-visible{opacity:1;outline:3px solid;background:#fafafa}.peekling-visibility-panel{position:fixed;right:16px;bottom:16px;box-sizing:border-box;width:min(272px,calc(100vw - 32px));padding:16px;border:1px solid #d9d9d3;border-radius:18px;background:#fafafa;pointer-events:auto}.peekling-visibility-panel h2{margin:0 0 12px}.peekling-visibility-option{display:block;width:100%;min-height:44px;padding:10px 12px;border:0;background:transparent;color:inherit;font:inherit}.peekling-visibility-option:hover,.peekling-visibility-option:focus-visible{outline:2px solid}
@@ -1 +1 @@
1
- sha256-w8BENjaJ/B1wtpk3iuh7jT++FlbT5+fx5BBlvePx1qo=
1
+ sha256-r4PIKebZlQTb2JaHfQibQqQxHaKciwlXtTMDEvDTUPY=