@yali-engine/input 0.0.0-stage → 0.4.0

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/dist/dom.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { Input } from './input.ts';
2
+ /** What `attachDom` listens on. */
3
+ export interface DomSource {
4
+ /** Pointer and wheel events (the canvas). */
5
+ readonly target: EventTarget;
6
+ /** Key events and blur (default: `window` when there is one, else `target`). */
7
+ readonly keys?: EventTarget;
8
+ /** Stop the page scrolling on wheel over the target (default true). */
9
+ readonly preventWheel?: boolean;
10
+ }
11
+ /**
12
+ * Feeds DOM pointer, wheel and key events into `input`, and releases every key on blur so
13
+ * none stays stuck down. Returns the detach function and the listener count (for the
14
+ * dispose leak check).
15
+ */
16
+ export declare function attachDom(input: Input, source: DomSource): {
17
+ detach(): void;
18
+ listeners(): number;
19
+ };
package/dist/dom.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Feeds DOM pointer, wheel and key events into `input`, and releases every key on blur so
3
+ * none stays stuck down. Returns the detach function and the listener count (for the
4
+ * dispose leak check).
5
+ */
6
+ export function attachDom(input, source) {
7
+ const keys = source.keys ?? (typeof window !== 'undefined' ? window : source.target);
8
+ const off = [];
9
+ const listen = (t, type, fn, opts) => {
10
+ const h = fn;
11
+ t.addEventListener(type, h, opts);
12
+ off.push(() => t.removeEventListener(type, h, opts));
13
+ };
14
+ // Movement: a mouse's movementX/Y (pointer lock needs it); for touch and pen, the change
15
+ // in position. Chrome on Android reports touch movementX in other units (a 10 CSS px move
16
+ // came as -4 at devicePixelRatio 2.625, rounded), so a drag turned 2.6x slower there.
17
+ let lastId = -1;
18
+ let lastX = 0;
19
+ let lastY = 0;
20
+ const pointer = (kind) => (e) => {
21
+ if (kind === 'pointerdown')
22
+ source.target.setPointerCapture?.(e.pointerId);
23
+ let mx = e.movementX;
24
+ let my = e.movementY;
25
+ if (e.pointerType !== 'mouse') {
26
+ const same = kind !== 'pointerdown' && e.pointerId === lastId;
27
+ mx = same ? e.offsetX - lastX : 0;
28
+ my = same ? e.offsetY - lastY : 0;
29
+ lastId = e.pointerId;
30
+ lastX = e.offsetX;
31
+ lastY = e.offsetY;
32
+ }
33
+ input.push({ kind, x: e.offsetX, y: e.offsetY, movementX: mx, movementY: my, buttons: e.buttons, pointerId: e.pointerId });
34
+ };
35
+ listen(source.target, 'pointerdown', pointer('pointerdown'));
36
+ listen(source.target, 'pointermove', pointer('pointermove'));
37
+ listen(source.target, 'pointerup', pointer('pointerup'));
38
+ listen(source.target, 'wheel', (e) => {
39
+ if (source.preventWheel ?? true)
40
+ e.preventDefault();
41
+ input.push({ kind: 'wheel', deltaX: e.deltaX, deltaY: e.deltaY });
42
+ }, { passive: false });
43
+ listen(keys, 'keydown', (e) => {
44
+ if (!e.repeat)
45
+ input.push({ kind: 'keydown', code: e.code });
46
+ });
47
+ listen(keys, 'keyup', (e) => input.push({ kind: 'keyup', code: e.code }));
48
+ listen(keys, 'blur', () => input.releaseAll());
49
+ return {
50
+ detach() {
51
+ for (const f of off.splice(0))
52
+ f();
53
+ },
54
+ listeners: () => off.length,
55
+ };
56
+ }
57
+ //# sourceMappingURL=dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `@yali-engine/input`: keyboard, pointer and wheel as per-frame state, fed by the DOM or by
3
+ * forwarded events (worker render mode), with frame-exact recording and replay for the
4
+ * headless deterministic mode (DESIGN.md §19, ADR-0040).
5
+ *
6
+ * @example
7
+ * import { inputPlugin, type Input } from '@yali-engine/input';
8
+ * const app = App.create({ core, plugins: [inputPlugin({ dom: { target: canvas } })] });
9
+ * const input = app.resource<Input>('input');
10
+ * if (input.pressed('Space')) jump();
11
+ */
12
+ export { attachDom, type DomSource } from './dom.ts';
13
+ export { Input, type InputEvent, type InputRecording, KINDS, type PointerState } from './input.ts';
14
+ export { inputPlugin, type InputPluginOptions } from './plugin.ts';
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@yali-engine/input`: keyboard, pointer and wheel as per-frame state, fed by the DOM or by
3
+ * forwarded events (worker render mode), with frame-exact recording and replay for the
4
+ * headless deterministic mode (DESIGN.md §19, ADR-0040).
5
+ *
6
+ * @example
7
+ * import { inputPlugin, type Input } from '@yali-engine/input';
8
+ * const app = App.create({ core, plugins: [inputPlugin({ dom: { target: canvas } })] });
9
+ * const input = app.resource<Input>('input');
10
+ * if (input.pressed('Space')) jump();
11
+ */
12
+ export { attachDom } from "./dom.js";
13
+ export { Input, KINDS } from "./input.js";
14
+ export { inputPlugin } from "./plugin.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAkB,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,KAAK,EAAwC,KAAK,EAAqB,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * One input event as plain data: what a DOM listener sees, what the page forwards to a
3
+ * render worker (it matches `@yali-engine/render`'s `ForwardedInput`), and what a recording holds.
4
+ * Keys are identified by `code` (the physical key, `KeyW`), so layouts do not matter.
5
+ */
6
+ export type InputEvent = {
7
+ readonly kind: 'pointerdown' | 'pointermove' | 'pointerup';
8
+ readonly x: number;
9
+ readonly y: number;
10
+ readonly movementX: number;
11
+ readonly movementY: number;
12
+ readonly buttons: number;
13
+ readonly pointerId?: number;
14
+ } | {
15
+ readonly kind: 'wheel';
16
+ readonly deltaX: number;
17
+ readonly deltaY: number;
18
+ } | {
19
+ readonly kind: 'keydown' | 'keyup';
20
+ readonly code: string;
21
+ readonly key?: string;
22
+ };
23
+ /**
24
+ * A recording: every event applied, keyed by the frame it was applied in (counted from the
25
+ * recording's first frame). Plain JSON. Replaying it on a fixed clock reproduces a run.
26
+ */
27
+ export interface InputRecording {
28
+ readonly version: 1;
29
+ /** Frames the recording spans; replay ends after this many. */
30
+ readonly frames: number;
31
+ /** Key codes, indexed by the key events below. */
32
+ readonly codes: readonly string[];
33
+ /** Flattened `[frame, kind, a, b, c, d, e]` per event (see `KINDS`). */
34
+ readonly events: readonly number[];
35
+ }
36
+ /** Event kinds in recording order: a recording's kind field indexes this. */
37
+ export declare const KINDS: readonly ["pointerdown", "pointermove", "pointerup", "wheel", "keydown", "keyup"];
38
+ /** Pointer state for the current frame. Fields update in place; nothing is allocated. */
39
+ export interface PointerState {
40
+ /** Position in CSS pixels, relative to the input target. */
41
+ x: number;
42
+ y: number;
43
+ /** Movement during this frame. */
44
+ dx: number;
45
+ dy: number;
46
+ /** Wheel delta during this frame. */
47
+ wheelX: number;
48
+ wheelY: number;
49
+ /** Buttons held now (PointerEvent.buttons: 1 primary, 2 secondary, 4 middle). */
50
+ buttons: number;
51
+ /** Buttons that went down / up during this frame. */
52
+ pressed: number;
53
+ released: number;
54
+ }
55
+ /**
56
+ * Input as per-frame state (DESIGN.md §19). Events are queued as they arrive and applied
57
+ * all at once in the frame's `Input` stage, so every system in a frame sees the same state
58
+ * and a frame's input does not depend on when, within it, a DOM event landed.
59
+ *
60
+ * Recording keeps the events with the frame they were applied in; replay applies them in
61
+ * the same frames and ignores live input meanwhile. With a fixed clock and a seed
62
+ * (ADR-0030), that reproduces a run exactly. The queue is a preallocated ring: pushing
63
+ * and applying allocate nothing (recording grows its arrays).
64
+ *
65
+ * @example
66
+ * const input = app.resource<Input>('input');
67
+ * if (input.down('KeyW')) speed += 1;
68
+ * if (input.pointer.buttons & 1) camera.yaw -= input.pointer.dx * 0.005;
69
+ */
70
+ export declare class Input {
71
+ #private;
72
+ readonly pointer: PointerState;
73
+ /** Events lost because the queue was full (it holds `capacity` until the next frame). */
74
+ dropped: number;
75
+ constructor(options?: {
76
+ capacity?: number;
77
+ });
78
+ /** Whether `code` is held this frame. */
79
+ down(code: string): boolean;
80
+ /** Whether `code` went down during this frame. */
81
+ pressed(code: string): boolean;
82
+ /** Whether `code` went up during this frame. */
83
+ released(code: string): boolean;
84
+ /** Queues an event for the next `Input` stage. */
85
+ push(e: InputEvent): void;
86
+ /** Queues a key-up for every held key (on blur, so no key stays stuck down). */
87
+ releaseAll(): void;
88
+ /** Starts recording from the next frame. */
89
+ record(): void;
90
+ /** Stops recording and returns it (an empty recording if none was running). */
91
+ stopRecording(): InputRecording;
92
+ /** Whether a recording is running. */
93
+ get recording(): boolean;
94
+ /** Replays `rec` from the next frame; live input is ignored until it ends. */
95
+ replay(rec: InputRecording): void;
96
+ /** Whether a replay is running (it ends by itself after the recording's last frame). */
97
+ get replaying(): boolean;
98
+ /**
99
+ * Applies the frame's input: called once per frame by `inputPlugin` in the `Input` stage
100
+ * (or by hand in tests). Clears per-frame state, then applies the queued events, or the
101
+ * replay's events for this frame.
102
+ */
103
+ frame(): void;
104
+ }
package/dist/input.js ADDED
@@ -0,0 +1,239 @@
1
+ import { YaliError } from '@yali-engine/core';
2
+ /** Event kinds in recording order: a recording's kind field indexes this. */
3
+ export const KINDS = ['pointerdown', 'pointermove', 'pointerup', 'wheel', 'keydown', 'keyup'];
4
+ const PDOWN = 0;
5
+ const PMOVE = 1;
6
+ const PUP = 2;
7
+ const WHEEL = 3;
8
+ const KDOWN = 4;
9
+ const KUP = 5;
10
+ /** Fields per event in the queue and in a recording (after the frame): kind + 5 values. */
11
+ const FIELDS = 6;
12
+ const MAX_CODES = 512;
13
+ /**
14
+ * Input as per-frame state (DESIGN.md §19). Events are queued as they arrive and applied
15
+ * all at once in the frame's `Input` stage, so every system in a frame sees the same state
16
+ * and a frame's input does not depend on when, within it, a DOM event landed.
17
+ *
18
+ * Recording keeps the events with the frame they were applied in; replay applies them in
19
+ * the same frames and ignores live input meanwhile. With a fixed clock and a seed
20
+ * (ADR-0030), that reproduces a run exactly. The queue is a preallocated ring: pushing
21
+ * and applying allocate nothing (recording grows its arrays).
22
+ *
23
+ * @example
24
+ * const input = app.resource<Input>('input');
25
+ * if (input.down('KeyW')) speed += 1;
26
+ * if (input.pointer.buttons & 1) camera.yaw -= input.pointer.dx * 0.005;
27
+ */
28
+ export class Input {
29
+ pointer = { x: 0, y: 0, dx: 0, dy: 0, wheelX: 0, wheelY: 0, buttons: 0, pressed: 0, released: 0 };
30
+ #queue;
31
+ #head = 0;
32
+ #count = 0;
33
+ /** Events lost because the queue was full (it holds `capacity` until the next frame). */
34
+ dropped = 0;
35
+ #codes = new Map();
36
+ #codeNames = [];
37
+ #down = new Uint8Array(MAX_CODES);
38
+ #pressed = new Uint8Array(MAX_CODES);
39
+ #released = new Uint8Array(MAX_CODES);
40
+ #frame = 0;
41
+ #recording = null;
42
+ #replay = null;
43
+ #replayPending = null;
44
+ #recordPending = false;
45
+ constructor(options = {}) {
46
+ this.#queue = new Float64Array((options.capacity ?? 1024) * FIELDS);
47
+ }
48
+ /** Whether `code` is held this frame. */
49
+ down(code) {
50
+ const id = this.#codes.get(code);
51
+ return id !== undefined && this.#down[id] === 1;
52
+ }
53
+ /** Whether `code` went down during this frame. */
54
+ pressed(code) {
55
+ const id = this.#codes.get(code);
56
+ return id !== undefined && this.#pressed[id] === 1;
57
+ }
58
+ /** Whether `code` went up during this frame. */
59
+ released(code) {
60
+ const id = this.#codes.get(code);
61
+ return id !== undefined && this.#released[id] === 1;
62
+ }
63
+ /** Queues an event for the next `Input` stage. */
64
+ push(e) {
65
+ switch (e.kind) {
66
+ case 'pointerdown':
67
+ case 'pointermove':
68
+ case 'pointerup':
69
+ this.#enqueue(e.kind === 'pointerdown' ? PDOWN : e.kind === 'pointerup' ? PUP : PMOVE, e.x, e.y, e.movementX, e.movementY, e.buttons);
70
+ break;
71
+ case 'wheel':
72
+ this.#enqueue(WHEEL, e.deltaX, e.deltaY, 0, 0, 0);
73
+ break;
74
+ case 'keydown':
75
+ case 'keyup':
76
+ this.#enqueue(e.kind === 'keydown' ? KDOWN : KUP, this.#intern(e.code), 0, 0, 0, 0);
77
+ break;
78
+ default:
79
+ throw new YaliError('INPUT_KIND', `Unknown input event kind ${e.kind}.`, `Use one of ${KINDS.join(', ')}.`);
80
+ }
81
+ }
82
+ /** Queues a key-up for every held key (on blur, so no key stays stuck down). */
83
+ releaseAll() {
84
+ for (let id = 0; id < this.#codeNames.length; id++)
85
+ if (this.#down[id])
86
+ this.#enqueue(KUP, id, 0, 0, 0, 0);
87
+ if (this.pointer.buttons)
88
+ this.#enqueue(PUP, this.pointer.x, this.pointer.y, 0, 0, 0);
89
+ }
90
+ /** Starts recording from the next frame. */
91
+ record() {
92
+ this.#recordPending = true;
93
+ }
94
+ /** Stops recording and returns it (an empty recording if none was running). */
95
+ stopRecording() {
96
+ const r = this.#recording;
97
+ this.#recording = null;
98
+ this.#recordPending = false;
99
+ if (!r)
100
+ return { version: 1, frames: 0, codes: [], events: [] };
101
+ return { version: 1, frames: this.#frame - r.start, codes: r.names, events: r.events };
102
+ }
103
+ /** Whether a recording is running. */
104
+ get recording() {
105
+ return this.#recording !== null || this.#recordPending;
106
+ }
107
+ /** Replays `rec` from the next frame; live input is ignored until it ends. */
108
+ replay(rec) {
109
+ if (rec?.version !== 1 || !Array.isArray(rec.events) || !Array.isArray(rec.codes) || rec.events.length % (FIELDS + 1) !== 0) {
110
+ throw new YaliError('INPUT_RECORDING', 'This is not a version 1 input recording.', 'Pass what Input.stopRecording() returned (plain JSON is fine).');
111
+ }
112
+ this.#replayPending = rec;
113
+ }
114
+ /** Whether a replay is running (it ends by itself after the recording's last frame). */
115
+ get replaying() {
116
+ return this.#replay !== null || this.#replayPending !== null;
117
+ }
118
+ /**
119
+ * Applies the frame's input: called once per frame by `inputPlugin` in the `Input` stage
120
+ * (or by hand in tests). Clears per-frame state, then applies the queued events, or the
121
+ * replay's events for this frame.
122
+ */
123
+ frame() {
124
+ this.#pressed.fill(0);
125
+ this.#released.fill(0);
126
+ const p = this.pointer;
127
+ p.dx = p.dy = p.wheelX = p.wheelY = p.pressed = p.released = 0;
128
+ if (this.#replayPending) {
129
+ const rec = this.#replayPending;
130
+ this.#replayPending = null;
131
+ const remap = new Int32Array(rec.codes.length);
132
+ for (let i = 0; i < rec.codes.length; i++)
133
+ remap[i] = this.#intern(rec.codes[i]);
134
+ this.#replay = { rec, start: this.#frame, cursor: 0, remap };
135
+ }
136
+ if (this.#recordPending && !this.#recording) {
137
+ this.#recordPending = false;
138
+ this.#recording = { start: this.#frame, events: [], codes: new Map(), names: [] };
139
+ }
140
+ const q = this.#queue;
141
+ const cap = q.length / FIELDS;
142
+ if (this.#replay) {
143
+ this.#count = 0; // live input is ignored during a replay
144
+ const r = this.#replay;
145
+ const ev = r.rec.events;
146
+ const at = this.#frame - r.start;
147
+ while (r.cursor < ev.length && ev[r.cursor] === at) {
148
+ const k = ev[r.cursor + 1];
149
+ const a = k === KDOWN || k === KUP ? r.remap[ev[r.cursor + 2]] : ev[r.cursor + 2];
150
+ this.#apply(k, a, ev[r.cursor + 3], ev[r.cursor + 4], ev[r.cursor + 5], ev[r.cursor + 6]);
151
+ r.cursor += FIELDS + 1;
152
+ }
153
+ if (at + 1 >= r.rec.frames)
154
+ this.#replay = null;
155
+ }
156
+ else {
157
+ for (; this.#count > 0; this.#count--) {
158
+ const o = this.#head * FIELDS;
159
+ this.#apply(q[o], q[o + 1], q[o + 2], q[o + 3], q[o + 4], q[o + 5]);
160
+ this.#head = (this.#head + 1) % cap;
161
+ }
162
+ }
163
+ this.#frame++;
164
+ }
165
+ #apply(kind, a, b, c, d, e) {
166
+ const p = this.pointer;
167
+ if (kind === KDOWN || kind === KUP) {
168
+ if (kind === KDOWN) {
169
+ if (this.#down[a])
170
+ return; // auto-repeat
171
+ this.#down[a] = 1;
172
+ this.#pressed[a] = 1;
173
+ }
174
+ else {
175
+ if (!this.#down[a])
176
+ return;
177
+ this.#down[a] = 0;
178
+ this.#released[a] = 1;
179
+ }
180
+ }
181
+ else if (kind === WHEEL) {
182
+ p.wheelX += a;
183
+ p.wheelY += b;
184
+ }
185
+ else {
186
+ p.x = a;
187
+ p.y = b;
188
+ p.dx += c;
189
+ p.dy += d;
190
+ const was = p.buttons;
191
+ p.buttons = e;
192
+ p.pressed |= p.buttons & ~was;
193
+ p.released |= was & ~p.buttons;
194
+ }
195
+ const r = this.#recording;
196
+ if (r) {
197
+ let ka = a;
198
+ if (kind === KDOWN || kind === KUP) {
199
+ let local = r.codes.get(a);
200
+ if (local === undefined) {
201
+ local = r.names.length;
202
+ r.codes.set(a, local);
203
+ r.names.push(this.#codeNames[a]);
204
+ }
205
+ ka = local;
206
+ }
207
+ r.events.push(this.#frame - r.start, kind, ka, b, c, d, e);
208
+ }
209
+ }
210
+ #enqueue(kind, a, b, c, d, e) {
211
+ const q = this.#queue;
212
+ const cap = q.length / FIELDS;
213
+ if (this.#count === cap) {
214
+ this.dropped++;
215
+ return;
216
+ }
217
+ const o = ((this.#head + this.#count) % cap) * FIELDS;
218
+ q[o] = kind;
219
+ q[o + 1] = a;
220
+ q[o + 2] = b;
221
+ q[o + 3] = c;
222
+ q[o + 4] = d;
223
+ q[o + 5] = e;
224
+ this.#count++;
225
+ }
226
+ #intern(code) {
227
+ let id = this.#codes.get(code);
228
+ if (id === undefined) {
229
+ if (this.#codeNames.length >= MAX_CODES) {
230
+ throw new YaliError('INPUT_TOO_MANY_KEYS', `More than ${MAX_CODES} distinct key codes.`, 'Key codes are KeyboardEvent.code values; pass those, not free text.');
231
+ }
232
+ id = this.#codeNames.length;
233
+ this.#codes.set(code, id);
234
+ this.#codeNames.push(code);
235
+ }
236
+ return id;
237
+ }
238
+ }
239
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { YaliPlugin } from '@yali-engine/core';
2
+ import { type DomSource } from './dom.ts';
3
+ /** Options for `inputPlugin`. */
4
+ export interface InputPluginOptions {
5
+ /**
6
+ * Where DOM events come from (the canvas). Leave it out where there is no DOM (worker
7
+ * render mode, headless): push events with `input.push` instead.
8
+ */
9
+ readonly dom?: DomSource;
10
+ /** Queue capacity in events between two frames (default 1024). */
11
+ readonly capacity?: number;
12
+ }
13
+ /**
14
+ * `@yali-engine/input` as a plugin: provides the `input` resource and applies the queued events
15
+ * at the start of every frame (the `Input` stage). Registers three agent tools:
16
+ * `input.record`, `input.stop_recording` (returns the recording) and `input.replay`.
17
+ *
18
+ * @example
19
+ * App.create({ core, plugins: [inputPlugin({ dom: { target: canvas } }), game] });
20
+ * // in a system: app.resource<Input>('input').pressed('Space')
21
+ */
22
+ export declare function inputPlugin(options?: InputPluginOptions): YaliPlugin;
package/dist/plugin.js ADDED
@@ -0,0 +1,52 @@
1
+ import { attachDom } from "./dom.js";
2
+ import { Input } from "./input.js";
3
+ /**
4
+ * `@yali-engine/input` as a plugin: provides the `input` resource and applies the queued events
5
+ * at the start of every frame (the `Input` stage). Registers three agent tools:
6
+ * `input.record`, `input.stop_recording` (returns the recording) and `input.replay`.
7
+ *
8
+ * @example
9
+ * App.create({ core, plugins: [inputPlugin({ dom: { target: canvas } }), game] });
10
+ * // in a system: app.resource<Input>('input').pressed('Space')
11
+ */
12
+ export function inputPlugin(options = {}) {
13
+ return {
14
+ name: '@yali-engine/input',
15
+ version: '0.4.0',
16
+ build(b) {
17
+ const input = new Input({ capacity: options.capacity });
18
+ b.provide('input', input);
19
+ b.system({ name: 'input.frame', stage: 'Input', run: () => input.frame() });
20
+ if (options.dom) {
21
+ const dom = attachDom(input, options.dom);
22
+ b.leaks(() => ({ listeners: dom.listeners() }));
23
+ b.onDispose(() => dom.detach());
24
+ }
25
+ b.tool({
26
+ name: 'input.record',
27
+ description: 'Starts recording input from the next frame (frame-exact; see input.stop_recording).',
28
+ input: { type: 'object', properties: {} },
29
+ run: () => {
30
+ input.record();
31
+ return { recording: true };
32
+ },
33
+ });
34
+ b.tool({
35
+ name: 'input.stop_recording',
36
+ description: 'Stops recording and returns the recording as JSON, for input.replay.',
37
+ input: { type: 'object', properties: {} },
38
+ run: () => input.stopRecording(),
39
+ });
40
+ b.tool({
41
+ name: 'input.replay',
42
+ description: 'Replays a recording from the next frame; live input is ignored until it ends.',
43
+ input: { type: 'object', properties: { recording: { type: 'object', description: 'What input.stop_recording returned.' } }, required: ['recording'] },
44
+ run: (args) => {
45
+ input.replay(args.recording);
46
+ return { replaying: true, frames: args.recording.frames };
47
+ },
48
+ });
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAkB,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,KAAK,EAAuB,MAAM,YAAY,CAAC;AAaxD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,UAA8B,EAAE;IAC1D,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;QAChB,KAAK,CAAC,CAAC;YACL,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACxD,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC5E,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChB,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC1C,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;gBAChD,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAClC,CAAC;YACD,CAAC,CAAC,IAAI,CAAC;gBACL,IAAI,EAAE,cAAc;gBACpB,WAAW,EAAE,qFAAqF;gBAClG,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;gBACzC,GAAG,EAAE,GAAG,EAAE;oBACR,KAAK,CAAC,MAAM,EAAE,CAAC;oBACf,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;gBAC7B,CAAC;aACF,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC;gBACL,IAAI,EAAE,sBAAsB;gBAC5B,WAAW,EAAE,sEAAsE;gBACnF,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;gBACzC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE;aACjC,CAAC,CAAC;YACH,CAAC,CAAC,IAAI,CAAC;gBACL,IAAI,EAAE,cAAc;gBACpB,WAAW,EAAE,+EAA+E;gBAC5F,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qCAAqC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE;gBACrJ,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;oBACZ,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAA2B,CAAC,CAAC;oBAC/C,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAG,IAAI,CAAC,SAA4B,CAAC,MAAM,EAAE,CAAC;gBAChF,CAAC;aACF,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,27 @@
1
1
  {
2
2
  "name": "@yali-engine/input",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.4.0",
4
+ "description": "Yali input: keyboard, pointer and wheel as per-frame state, from the DOM or forwarded events, with frame-exact recording and replay.",
5
+ "license": "MIT OR Apache-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@yali-engine/core": "0.4.0"
22
+ },
23
+ "scripts": {
24
+ "typecheck": "tsc -p tsconfig.json",
25
+ "test": "node --experimental-strip-types --no-warnings --test \"test/*.test.ts\""
26
+ }
6
27
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.