@simpludify/core 0.1.3 → 0.1.5

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.
@@ -42,15 +42,20 @@ export declare class ActionController<A extends ActionSet> implements LifetimeOw
42
42
  private readonly entries;
43
43
  private readonly sources;
44
44
  private readonly bus;
45
+ private keyboardAllowed;
46
+ private readonly blockedKeys;
45
47
  private pending;
46
48
  private transitions;
47
49
  constructor(actions: A, options: {
48
50
  scene: Scene;
49
51
  input: InputSystem;
50
52
  bindings?: ActionBindings<A>;
53
+ keyboard?: boolean;
51
54
  });
52
55
  get disposed(): boolean;
53
56
  get active(): boolean;
57
+ get keyboardEnabled(): boolean;
58
+ set keyboardEnabled(value: boolean);
54
59
  get sourceCount(): number;
55
60
  onDispose(callback: () => void): () => void;
56
61
  private entry;
@@ -2,8 +2,11 @@ import { type LifetimeOwner } from "../foundation/lifetime.js";
2
2
  /** @internal Shared lifetime for logical and device contributions. */
3
3
  export declare abstract class OwnedInputSource {
4
4
  private dead;
5
+ private accepting;
5
6
  private removeOwner;
6
7
  get disposed(): boolean;
8
+ get enabled(): boolean;
9
+ set enabled(value: boolean);
7
10
  /** @internal */ own(owner: LifetimeOwner): void;
8
11
  protected writable(neutral: boolean): boolean;
9
12
  protected abstract release(remove: boolean): void;
@@ -2,6 +2,12 @@ import { type LifetimeOwner } from "../foundation/lifetime.js";
2
2
  import type { ActionFrame } from "./action-frame.js";
3
3
  import { OwnedInputSource } from "./input-source.js";
4
4
  import { type KeyCode } from "./key-code.js";
5
+ /** Host device adapter. Sampled before all Action frames; reset flushes held device state. */
6
+ export interface InputAdapter {
7
+ sample(): void;
8
+ reset(): void;
9
+ dispose(): void;
10
+ }
5
11
  /** @internal Engine boundary participant, implemented by ActionController. */
6
12
  export interface ActionInputPort {
7
13
  readonly active: boolean;
@@ -24,12 +30,17 @@ export declare class KeyboardSource extends OwnedInputSource {
24
30
  /** Engine-owned routing and update boundary. No raw game-state/alternate movement API. */
25
31
  export declare class InputSystem {
26
32
  private readonly actions;
33
+ private readonly adapters;
27
34
  private readonly keyboards;
28
35
  private dead;
29
36
  private playback;
30
37
  private frames;
38
+ /** @internal Device hosts may reject live gestures during Replay playback. */
39
+ get liveInput(): boolean;
31
40
  get sourceCount(): number;
32
41
  /** @internal */ registerActions(actions: ActionInputPort): () => void;
42
+ /** Host integration boundary; ordinary game input uses ActionSource instead. */
43
+ addAdapter(adapter: InputAdapter): () => void;
33
44
  acceptsKey(code: KeyCode): boolean;
34
45
  private notify;
35
46
  /** @internal Device state is resolved only through Action bindings. */
@@ -4,6 +4,7 @@ import type { ScreenPoint, WorldPoint } from "../graphics/coordinates.js";
4
4
  import type { Scene } from "../scene/scene.js";
5
5
  import type { CanvasNode } from "../ui/canvas-node.js";
6
6
  import type { CanvasUI } from "../ui/canvas-ui.js";
7
+ import type { PointerTarget, PointerTargetProvider } from "./pointer-target.js";
7
8
  /** Snapshot coordinates at DOM delivery. Screen is host CSS units; world includes the current Camera. */
8
9
  export interface PointerInfo {
9
10
  readonly pointerId: number;
@@ -30,6 +31,10 @@ export declare class ScenePointer implements LifetimeOwner {
30
31
  private readonly lifetime;
31
32
  readonly events: EventBus;
32
33
  private readonly removeScene;
34
+ private targets;
35
+ /** @internal Exactly one Scene virtual-input provider shares the existing router. */
36
+ attachTargets(provider: PointerTargetProvider): () => void;
37
+ /** @internal */ pickTarget(data: PointerInfo): PointerTarget | undefined;
33
38
  constructor(scene: Scene);
34
39
  get disposed(): boolean;
35
40
  onDispose(callback: () => void): () => void;
@@ -38,6 +43,7 @@ export declare class ScenePointer implements LifetimeOwner {
38
43
  /** @internal Device-independent routing state; DOM is only an adapter. */
39
44
  export declare class PointerRouting {
40
45
  private readonly released;
46
+ private readonly targetOwners;
41
47
  private readonly controlOwners;
42
48
  private readonly scrollOwners;
43
49
  private readonly suppressed;
@@ -60,6 +66,7 @@ export declare class PointerRouting {
60
66
  deliveries: number;
61
67
  scrollDrags: number;
62
68
  controlDrags: number;
69
+ virtualDrags: number;
63
70
  };
64
71
  setScene(channel: ScenePointer, ui?: CanvasUI): void;
65
72
  private hold;
@@ -86,6 +93,8 @@ export declare class PointerRouting {
86
93
  releaseKeys(node: CanvasNode): void;
87
94
  private prune;
88
95
  release(): void;
96
+ /** @internal Host focus changes interrupt virtual devices without changing Canvas editing rules. */
97
+ releaseVirtual(): void;
89
98
  dispose(): void;
90
99
  reset(): void;
91
100
  }
@@ -0,0 +1,14 @@
1
+ import type { LifetimeOwner } from "../foundation/lifetime.js";
2
+ import type { PointerInfo } from "./pointer-routing.js";
3
+ /** @internal Scene-scoped recipients behind Canvas UI; the existing router owns all IDs. */
4
+ export interface PointerTarget extends LifetimeOwner {
5
+ readonly available: boolean;
6
+ readonly revision: number;
7
+ subscribe(callback: () => void): () => void;
8
+ contains(data: PointerInfo): boolean;
9
+ deliver(type: "down" | "move" | "up" | "cancel", data: PointerInfo): void;
10
+ }
11
+ /** @internal */
12
+ export interface PointerTargetProvider extends LifetimeOwner {
13
+ pick(data: PointerInfo): PointerTarget | undefined;
14
+ }
@@ -0,0 +1,140 @@
1
+ import { type LifetimeOwner } from "../foundation/lifetime.js";
2
+ import type { Point, ScreenPoint } from "../graphics/coordinates.js";
3
+ import type { PointerInfo } from "./pointer-routing.js";
4
+ import type { PointerTarget } from "./pointer-target.js";
5
+ import { type VirtualPosition, type VirtualRegion } from "./virtual-regions.js";
6
+ export declare const VirtualStickMode: {
7
+ readonly Fixed: "fixed";
8
+ readonly Floating: "floating";
9
+ readonly Follow: "follow";
10
+ };
11
+ export type VirtualStickMode = (typeof VirtualStickMode)[keyof typeof VirtualStickMode];
12
+ export interface VirtualControlOptions {
13
+ readonly region: VirtualRegion;
14
+ readonly position?: VirtualPosition;
15
+ /** Host CSS pixels, independent of Camera, DPR and Canvas UI scale. */
16
+ readonly radius?: number;
17
+ /** Radial fraction, 0 <= deadZone < 1; the remaining magnitude is rescaled. */
18
+ readonly deadZone?: number;
19
+ readonly enabled?: boolean;
20
+ readonly visible?: boolean;
21
+ /** Presentation seconds to the one-shot onHold notification. Default 0.5. */
22
+ readonly holdDelay?: number;
23
+ readonly color?: number;
24
+ }
25
+ export interface VirtualStickOptions extends VirtualControlOptions {
26
+ readonly mode?: VirtualStickMode;
27
+ }
28
+ export interface VirtualButtonOptions extends VirtualControlOptions {
29
+ /** Direction is optional; false by default. The Action remains an ordinary Button. */
30
+ readonly direction?: boolean;
31
+ }
32
+ export interface VirtualGesture {
33
+ readonly control: VirtualControl;
34
+ readonly pointerId: number;
35
+ readonly pointerType: string;
36
+ readonly origin: ScreenPoint;
37
+ readonly position: ScreenPoint;
38
+ readonly center: ScreenPoint;
39
+ /** Final direction is retained in end/cancel payloads after the live Action is cleared. */
40
+ readonly direction: Point;
41
+ readonly inside: boolean;
42
+ readonly elapsed: number;
43
+ }
44
+ /** @internal */
45
+ export interface VirtualControlHost {
46
+ available(): boolean;
47
+ center(control: VirtualControl): Point;
48
+ contains(control: VirtualControl, data: PointerInfo): boolean;
49
+ region(control: VirtualControl, value: VirtualRegion): void;
50
+ remove(control: VirtualControl): void;
51
+ }
52
+ /** @internal */
53
+ export interface VirtualBinding extends LifetimeOwner {
54
+ write(direction: Point, pressed: boolean): void;
55
+ clear(): void;
56
+ dispose(): void;
57
+ active(): boolean;
58
+ }
59
+ /** @internal Validate before allocating ActionSources or registering a target. */
60
+ export declare function checkVirtualOptions(options: VirtualStickOptions & VirtualButtonOptions): void;
61
+ /** Portable gesture state. Routing, Action composition and rendering retain their existing owners. */
62
+ export declare abstract class VirtualControl implements PointerTarget {
63
+ readonly kind: "stick" | "button";
64
+ private readonly host;
65
+ private readonly binding;
66
+ private readonly life;
67
+ private readonly events;
68
+ private readonly observers;
69
+ private activation;
70
+ private activeFlag;
71
+ private shown;
72
+ private size;
73
+ private deadZoneValue;
74
+ private version;
75
+ private gesture;
76
+ private vector;
77
+ private dragMode;
78
+ readonly position: VirtualPosition | undefined;
79
+ readonly holdDelay: number;
80
+ readonly color: number;
81
+ readonly directional: boolean;
82
+ protected constructor(kind: "stick" | "button", options: VirtualStickOptions & VirtualButtonOptions, host: VirtualControlHost, binding: VirtualBinding);
83
+ get disposed(): boolean;
84
+ get available(): boolean;
85
+ get revision(): number;
86
+ get enabled(): boolean;
87
+ set enabled(value: boolean);
88
+ get visible(): boolean;
89
+ set visible(value: boolean);
90
+ get radius(): number;
91
+ set radius(value: number);
92
+ get deadZone(): number;
93
+ set deadZone(value: number);
94
+ get region(): VirtualRegion;
95
+ set region(value: VirtualRegion);
96
+ protected get stickMode(): VirtualStickMode;
97
+ protected set stickMode(value: VirtualStickMode);
98
+ get pointerId(): number | undefined;
99
+ get pressed(): boolean;
100
+ get elapsed(): number;
101
+ get direction(): Point;
102
+ get center(): ScreenPoint;
103
+ get knob(): ScreenPoint;
104
+ onDispose(callback: () => void): () => void;
105
+ /** @internal Geometry/availability invalidation, not a per-frame observer. */
106
+ subscribe(callback: () => void): () => void;
107
+ onStart(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
108
+ onChange(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
109
+ onEnd(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
110
+ onCancel(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
111
+ onHold(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
112
+ /** Release/cancel only; the captured physical ID stays suppressed until its release. */
113
+ cancel(): void;
114
+ /** @internal */
115
+ invalidate(): void;
116
+ private alive;
117
+ private interrupt;
118
+ contains(data: PointerInfo): boolean;
119
+ private snapshot;
120
+ private update;
121
+ deliver(type: "down" | "move" | "up" | "cancel", data: PointerInfo): void;
122
+ /** @internal Explicit presentation clock; no browser/OS timer in Core. */
123
+ advance(seconds: number): void;
124
+ private finish;
125
+ dispose(): void;
126
+ }
127
+ export declare class VirtualStick extends VirtualControl {
128
+ /** @internal Use VirtualInput.stick. */
129
+ constructor(options: VirtualStickOptions, host: VirtualControlHost, binding: VirtualBinding);
130
+ get value(): Point;
131
+ get mode(): VirtualStickMode;
132
+ set mode(value: VirtualStickMode);
133
+ }
134
+ export declare class VirtualButton extends VirtualControl {
135
+ /** @internal Use VirtualInput.button. */
136
+ constructor(options: VirtualButtonOptions, host: VirtualControlHost, binding: VirtualBinding);
137
+ get value(): boolean;
138
+ /** Confirmation on normal release, including a drag outside the activation region; never on cancel. */
139
+ onCommit(callback: (event: VirtualGesture) => void, owner?: LifetimeOwner): () => void;
140
+ }
@@ -0,0 +1,49 @@
1
+ import type { Viewport } from "../graphics/coordinates.js";
2
+ import type { ActionController, ActionSet } from "./actions.js";
3
+ import type { InputAdapter, InputSystem } from "./input.js";
4
+ import type { PointerInfo, ScenePointer } from "./pointer-routing.js";
5
+ import type { PointerTargetProvider } from "./pointer-target.js";
6
+ import { VirtualButton, type VirtualButtonOptions, type VirtualControl, VirtualStick, type VirtualStickOptions } from "./virtual-control.js";
7
+ /** Scene-scoped virtual devices; all gameplay values flow through existing ActionSources. */
8
+ export declare class VirtualInput implements InputAdapter, PointerTargetProvider {
9
+ readonly pointer: ScenePointer;
10
+ private readonly input;
11
+ private readonly life;
12
+ private list;
13
+ private regions;
14
+ private anchors;
15
+ private view;
16
+ private active;
17
+ private shown;
18
+ private dirty;
19
+ private readonly host;
20
+ constructor(pointer: ScenePointer, input: InputSystem);
21
+ get disposed(): boolean;
22
+ get controls(): readonly VirtualControl[];
23
+ get viewport(): Viewport;
24
+ get enabled(): boolean;
25
+ set enabled(value: boolean);
26
+ get visible(): boolean;
27
+ set visible(value: boolean);
28
+ onDispose(callback: () => void): () => void;
29
+ private flag;
30
+ private alive;
31
+ private validate;
32
+ private binding;
33
+ stick<A extends ActionSet>(controller: ActionController<A>, action: Extract<A[keyof A], {
34
+ kind: "axis2d";
35
+ }>, options: VirtualStickOptions): VirtualStick;
36
+ button<A extends ActionSet>(controller: ActionController<A>, action: Extract<A[keyof A], {
37
+ kind: "button";
38
+ }>, options: VirtualButtonOptions): VirtualButton;
39
+ private add;
40
+ private resolve;
41
+ private centers;
42
+ /** Resolve after Canvas layout and before routing/rendering. Layout changes cancel active gestures. */
43
+ refresh(viewport?: Viewport): void;
44
+ pick(data: PointerInfo): VirtualControl | undefined;
45
+ sample(): void;
46
+ advance(seconds: number): void;
47
+ reset(): void;
48
+ dispose(): void;
49
+ }
@@ -0,0 +1,68 @@
1
+ import type { Point, ScreenPoint, Viewport } from "../graphics/coordinates.js";
2
+ export type VirtualSpace = "viewport" | "screen";
3
+ export interface VirtualPosition extends Point {
4
+ /** viewport uses fractions of the current Viewport; screen uses host CSS pixels. */
5
+ readonly space?: VirtualSpace;
6
+ }
7
+ export interface VirtualRectRegion extends VirtualPosition {
8
+ readonly kind: "rect";
9
+ readonly width: number;
10
+ readonly height: number;
11
+ }
12
+ export interface VirtualCircleRegion extends VirtualPosition {
13
+ readonly kind: "circle";
14
+ /** In viewport space the radius is a fraction of its smaller dimension. */
15
+ readonly radius: number;
16
+ }
17
+ export interface VirtualCustomRegion {
18
+ readonly kind: "custom";
19
+ /** Conservative host CSS-pixel bounds, including every point accepted by contains. */
20
+ readonly bounds: (viewport: Viewport) => Viewport;
21
+ readonly contains: (point: ScreenPoint, viewport: Viewport) => boolean;
22
+ }
23
+ export type VirtualRegion = VirtualRectRegion | VirtualCircleRegion | VirtualCustomRegion;
24
+ export declare const VirtualRegions: Readonly<{
25
+ /** A shared edge is not an overlap. Use separate rectangles to leave a center gap. */
26
+ Left: Readonly<{
27
+ readonly kind: "rect";
28
+ readonly x: 0;
29
+ readonly y: 0;
30
+ readonly width: 0.5;
31
+ readonly height: 1;
32
+ }>;
33
+ Right: Readonly<{
34
+ readonly kind: "rect";
35
+ readonly x: 0.5;
36
+ readonly y: 0;
37
+ readonly width: 0.5;
38
+ readonly height: 1;
39
+ }>;
40
+ }>;
41
+ /** @internal */
42
+ export type ResolvedVirtualRegion = {
43
+ readonly kind: "rect";
44
+ readonly bounds: Viewport;
45
+ } | {
46
+ readonly kind: "circle";
47
+ readonly bounds: Viewport;
48
+ readonly center: Point;
49
+ readonly radius: number;
50
+ } | {
51
+ readonly kind: "custom";
52
+ readonly bounds: Viewport;
53
+ readonly test: VirtualCustomRegion["contains"];
54
+ };
55
+ /** @internal */
56
+ export declare function virtualFinite(value: number, field: string): number;
57
+ /** @internal */
58
+ export declare function virtualBounds(value: Viewport): Viewport;
59
+ /** @internal */
60
+ export declare function virtualPosition(value: VirtualPosition, viewport: Viewport): Point;
61
+ /** @internal Copy configuration before retaining it. Predicate functions are deliberately live. */
62
+ export declare function checkedVirtualRegion(region: VirtualRegion): VirtualRegion;
63
+ /** @internal */
64
+ export declare function resolveVirtualRegion(region: VirtualRegion, viewport: Viewport): ResolvedVirtualRegion;
65
+ /** @internal Rectangles are half-open; circles exclude their circumference. */
66
+ export declare function virtualContains(region: ResolvedVirtualRegion, point: ScreenPoint, viewport: Viewport): boolean;
67
+ /** @internal Exact built-in intersection; custom bounds are conservatively ambiguous. */
68
+ export declare function virtualOverlap(a: ResolvedVirtualRegion, b: ResolvedVirtualRegion): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simpludify/core",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {