wasm-game-ts 0.1.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.
Files changed (52) hide show
  1. package/README.md +57 -0
  2. package/dist/hash.d.ts +3 -0
  3. package/dist/hash.d.ts.map +1 -0
  4. package/dist/hash.js +15 -0
  5. package/dist/hash.js.map +1 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +7 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/inputs.d.ts +61 -0
  11. package/dist/inputs.d.ts.map +1 -0
  12. package/dist/inputs.js +143 -0
  13. package/dist/inputs.js.map +1 -0
  14. package/dist/keycodes.d.ts +3 -0
  15. package/dist/keycodes.d.ts.map +1 -0
  16. package/dist/keycodes.js +73 -0
  17. package/dist/keycodes.js.map +1 -0
  18. package/dist/package.d.ts +45 -0
  19. package/dist/package.d.ts.map +1 -0
  20. package/dist/package.js +765 -0
  21. package/dist/package.js.map +1 -0
  22. package/dist/types.d.ts +104 -0
  23. package/dist/types.d.ts.map +1 -0
  24. package/dist/types.js +13 -0
  25. package/dist/types.js.map +1 -0
  26. package/dist/wasm-game.d.ts +22 -0
  27. package/dist/wasm-game.d.ts.map +1 -0
  28. package/dist/wasm-game.js +164 -0
  29. package/dist/wasm-game.js.map +1 -0
  30. package/dist/worker/assets/OFL.txt +88 -0
  31. package/dist/worker/assets/PressStart2P-Regular.ttf +0 -0
  32. package/dist/worker/fonts.d.ts +2 -0
  33. package/dist/worker/fonts.d.ts.map +1 -0
  34. package/dist/worker/fonts.js +159 -0
  35. package/dist/worker/fonts.js.map +1 -0
  36. package/dist/worker/renderer.d.ts +34 -0
  37. package/dist/worker/renderer.d.ts.map +1 -0
  38. package/dist/worker/renderer.js +504 -0
  39. package/dist/worker/renderer.js.map +1 -0
  40. package/dist/worker/snapshotter.d.ts +17 -0
  41. package/dist/worker/snapshotter.d.ts.map +1 -0
  42. package/dist/worker/snapshotter.js +190 -0
  43. package/dist/worker/snapshotter.js.map +1 -0
  44. package/dist/worker/wasm-host.d.ts +18 -0
  45. package/dist/worker/wasm-host.d.ts.map +1 -0
  46. package/dist/worker/wasm-host.js +42 -0
  47. package/dist/worker/wasm-host.js.map +1 -0
  48. package/dist/worker/worker.d.ts +2 -0
  49. package/dist/worker/worker.d.ts.map +1 -0
  50. package/dist/worker/worker.js +311 -0
  51. package/dist/worker/worker.js.map +1 -0
  52. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # wasm-game-ts
2
+
3
+ Browser-first TypeScript framework for running a deterministic WASM game runtime in a WebWorker and rendering via OffscreenCanvas.
4
+
5
+ ## What it expects from the WASM module
6
+
7
+ Exports (WASM -> host):
8
+ - `init(random_seed: i32, module_hash: i32) -> i32` (HostState* offset)
9
+ - `update_start(input_bytes: i32) -> i32` (returns ptr for host to write inputs)
10
+ - `update_end(render_for_player: i32) -> void` (process + produce render/audio/debug buffers)
11
+
12
+ Imports (host -> WASM):
13
+ - `env.get_file_bytes(id: i32, ptr: *mut u8) -> usize`
14
+
15
+ ## Render command buffer
16
+
17
+ The worker renders a binary command buffer written by WASM. Command ids and layouts are defined in:
18
+ `src/worker/renderer.ts`
19
+
20
+ Rust should match these ids and field layouts exactly.
21
+
22
+ ## Local demo
23
+
24
+ 1) Build dist:
25
+ ```bash
26
+ npm install
27
+ npm run build
28
+ ```
29
+
30
+ Run the dev server:
31
+ ```bash
32
+ npm run dev
33
+ ```
34
+
35
+ Open:
36
+
37
+ http://localhost:5173/demo/index.html
38
+
39
+ Click "Pick Package Folder" and select a folder containing:
40
+
41
+ - your .wasm (built from your Rust code)
42
+ - any assets you want (manifest is generated automatically by the folder picker)
43
+
44
+ The demo will start the game and stream keyboard/mouse input for player_id=1.
45
+
46
+ ---
47
+
48
+ ### Commands to run
49
+
50
+ From `wasm-game-ts/`:
51
+
52
+ ```bash
53
+ npm install
54
+ npm run build
55
+ npm run dev
56
+ # open http://localhost:5173/demo/index.html
57
+ ```
package/dist/hash.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare function fnv1a32(bytes: Uint8Array): number;
2
+ export declare function u64Hex(x: bigint): string;
3
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AACA,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAOjD;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIxC"}
package/dist/hash.js ADDED
@@ -0,0 +1,15 @@
1
+ // Deterministic FNV-1a 32-bit (module_hash input to wasm init).
2
+ export function fnv1a32(bytes) {
3
+ let h = 0x811c9dc5; // offset basis
4
+ for (let i = 0; i < bytes.length; i++) {
5
+ h ^= bytes[i];
6
+ h = Math.imul(h, 0x01000193); // prime
7
+ }
8
+ return h | 0;
9
+ }
10
+ export function u64Hex(x) {
11
+ // Always 16 hex digits (64-bit)
12
+ const s = x.toString(16).padStart(16, '0');
13
+ return `0x${s}`;
14
+ }
15
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,UAAU,OAAO,CAAC,KAAiB;IACvC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC,eAAe;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;QACd,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ;IACxC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,gCAAgC;IAChC,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './hash.js';
3
+ export * from './keycodes.js';
4
+ export * from './inputs.js';
5
+ export * from './package.js';
6
+ export * from './wasm-game.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './hash.js';
3
+ export * from './keycodes.js';
4
+ export * from './inputs.js';
5
+ export * from './package.js';
6
+ export * from './wasm-game.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,61 @@
1
+ export declare enum InputType {
2
+ ButtonUp = 0,
3
+ ButtonDown = 1,
4
+ MouseMove = 2,
5
+ MouseWheel = 3,
6
+ Heartbeat = 4
7
+ }
8
+ export type InputEvent = {
9
+ type: InputType.ButtonUp;
10
+ button: number;
11
+ } | {
12
+ type: InputType.ButtonDown;
13
+ button: number;
14
+ } | {
15
+ type: InputType.MouseMove;
16
+ x: number;
17
+ y: number;
18
+ } | {
19
+ type: InputType.MouseWheel;
20
+ x: number;
21
+ y: number;
22
+ } | {
23
+ type: InputType.Heartbeat;
24
+ };
25
+ declare class ByteWriter {
26
+ private readonly buf;
27
+ private readonly view;
28
+ private off;
29
+ constructor(byteLength: number);
30
+ u8(v: number): void;
31
+ i32(v: number): void;
32
+ f32(v: number): void;
33
+ finish(): Uint8Array;
34
+ }
35
+ export declare class PlayerInput {
36
+ readonly playerId: number;
37
+ private _events;
38
+ constructor(playerId: number);
39
+ get events(): readonly InputEvent[];
40
+ keydown(key: number): void;
41
+ keyup(key: number): void;
42
+ mousemove(mouseX: number, mouseY: number): void;
43
+ mousebuttondown(button: number): void;
44
+ mousebuttonup(button: number): void;
45
+ mousewheel(dx: number, dy: number): void;
46
+ heartbeat(): void;
47
+ clear(): void;
48
+ clone(): PlayerInput;
49
+ toJson(): string;
50
+ static FromJson(str: string): PlayerInput;
51
+ byteLength(): number;
52
+ writeTo(w: ByteWriter): void;
53
+ }
54
+ export declare class FrameInput {
55
+ private _players;
56
+ add(playerInput: PlayerInput): void;
57
+ clear(): void;
58
+ toBytes(): Uint8Array;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=inputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,QAAQ,IAAI;IACZ,UAAU,IAAI;IACd,SAAS,IAAI;IACb,UAAU,IAAI;IACd,SAAS,IAAI;CACd;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAA;CAAE,CAAC;AAElC,cAAM,UAAU;IACd,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAW;IAChC,OAAO,CAAC,GAAG,CAAK;gBAEJ,UAAU,EAAE,MAAM;IAK9B,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKnB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKpB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAKpB,MAAM,IAAI,UAAU;CAIrB;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,OAAO,CAAoB;gBAEvB,QAAQ,EAAE,MAAM;IAI5B,IAAI,MAAM,IAAI,SAAS,UAAU,EAAE,CAElC;IAED,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI1B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/C,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIrC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAInC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxC,SAAS,IAAI,IAAI;IAIjB,KAAK,IAAI,IAAI;IAIb,KAAK,IAAI,WAAW;IAOpB,MAAM,IAAI,MAAM;IAIhB,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW;IAQzC,UAAU,IAAI,MAAM;IAiBpB,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI;CAe7B;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAqB;IAErC,GAAG,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IASnC,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,UAAU;CAQtB"}
package/dist/inputs.js ADDED
@@ -0,0 +1,143 @@
1
+ export var InputType;
2
+ (function (InputType) {
3
+ InputType[InputType["ButtonUp"] = 0] = "ButtonUp";
4
+ InputType[InputType["ButtonDown"] = 1] = "ButtonDown";
5
+ InputType[InputType["MouseMove"] = 2] = "MouseMove";
6
+ InputType[InputType["MouseWheel"] = 3] = "MouseWheel";
7
+ InputType[InputType["Heartbeat"] = 4] = "Heartbeat";
8
+ })(InputType || (InputType = {}));
9
+ class ByteWriter {
10
+ constructor(byteLength) {
11
+ this.off = 0;
12
+ this.buf = new ArrayBuffer(byteLength);
13
+ this.view = new DataView(this.buf);
14
+ }
15
+ u8(v) {
16
+ this.view.setUint8(this.off, v & 0xff);
17
+ this.off += 1;
18
+ }
19
+ i32(v) {
20
+ this.view.setInt32(this.off, v | 0, true);
21
+ this.off += 4;
22
+ }
23
+ f32(v) {
24
+ this.view.setFloat32(this.off, Number(v), true);
25
+ this.off += 4;
26
+ }
27
+ finish() {
28
+ // off should equal allocated size, but we return the used slice regardless.
29
+ return new Uint8Array(this.buf, 0, this.off);
30
+ }
31
+ }
32
+ export class PlayerInput {
33
+ constructor(playerId) {
34
+ this._events = [];
35
+ this.playerId = playerId | 0;
36
+ }
37
+ get events() {
38
+ return this._events;
39
+ }
40
+ keydown(key) {
41
+ this._events.push({ type: InputType.ButtonDown, button: key | 0 });
42
+ }
43
+ keyup(key) {
44
+ this._events.push({ type: InputType.ButtonUp, button: key | 0 });
45
+ }
46
+ mousemove(mouseX, mouseY) {
47
+ this._events.push({ type: InputType.MouseMove, x: Number(mouseX), y: Number(mouseY) });
48
+ }
49
+ mousebuttondown(button) {
50
+ this._events.push({ type: InputType.ButtonDown, button: button | 0 });
51
+ }
52
+ mousebuttonup(button) {
53
+ this._events.push({ type: InputType.ButtonUp, button: button | 0 });
54
+ }
55
+ mousewheel(dx, dy) {
56
+ this._events.push({ type: InputType.MouseWheel, x: Number(dx), y: Number(dy) });
57
+ }
58
+ heartbeat() {
59
+ this._events.push({ type: InputType.Heartbeat });
60
+ }
61
+ clear() {
62
+ this._events.length = 0;
63
+ }
64
+ clone() {
65
+ const p = new PlayerInput(this.playerId);
66
+ // deep-ish copy; events are tiny POJOs
67
+ p._events = this._events.map((e) => ({ ...e }));
68
+ return p;
69
+ }
70
+ toJson() {
71
+ return JSON.stringify({ playerId: this.playerId, events: this._events });
72
+ }
73
+ static FromJson(str) {
74
+ const obj = JSON.parse(str);
75
+ const p = new PlayerInput(obj.playerId | 0);
76
+ // Basic validation/coercion
77
+ p._events = Array.isArray(obj.events) ? obj.events.map((e) => ({ ...e })) : [];
78
+ return p;
79
+ }
80
+ byteLength() {
81
+ // Encoding is exactly as your Rust spec:
82
+ // input_type: u8
83
+ // player_id : i32
84
+ // + payload:
85
+ // button up/down: i32 button
86
+ // mouse move/wheel: f32 x, f32 y
87
+ // heartbeat: nothing
88
+ let n = 0;
89
+ for (const e of this._events) {
90
+ if (e.type === InputType.ButtonUp || e.type === InputType.ButtonDown)
91
+ n += 1 + 4 + 4;
92
+ else if (e.type === InputType.MouseMove || e.type === InputType.MouseWheel)
93
+ n += 1 + 4 + 4 + 4;
94
+ else
95
+ n += 1 + 4;
96
+ }
97
+ return n;
98
+ }
99
+ writeTo(w) {
100
+ for (const e of this._events) {
101
+ w.u8(e.type);
102
+ w.i32(this.playerId);
103
+ if (e.type === InputType.ButtonUp || e.type === InputType.ButtonDown) {
104
+ w.i32(e.button | 0);
105
+ }
106
+ else if (e.type === InputType.MouseMove || e.type === InputType.MouseWheel) {
107
+ const mm = e;
108
+ w.f32(mm.x);
109
+ w.f32(mm.y);
110
+ }
111
+ else {
112
+ // Heartbeat: no extra payload
113
+ }
114
+ }
115
+ }
116
+ }
117
+ export class FrameInput {
118
+ constructor() {
119
+ this._players = [];
120
+ }
121
+ add(playerInput) {
122
+ // By copy, not by reference.
123
+ const cloned = playerInput.clone();
124
+ // Heartbeat default: if the player has no other events this frame,
125
+ // we add a heartbeat so "presence" is deterministic.
126
+ if (cloned.events.length === 0)
127
+ cloned.heartbeat();
128
+ this._players.push(cloned);
129
+ }
130
+ clear() {
131
+ this._players.length = 0;
132
+ }
133
+ toBytes() {
134
+ let total = 0;
135
+ for (const p of this._players)
136
+ total += p.byteLength();
137
+ const w = new ByteWriter(total);
138
+ for (const p of this._players)
139
+ p.writeTo(w);
140
+ return w.finish();
141
+ }
142
+ }
143
+ //# sourceMappingURL=inputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.js","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function keycodeFromKeyboardEvent(ev: KeyboardEvent): number;
2
+ export declare function mouseButtonFromPointerEvent(ev: MouseEvent | PointerEvent): number;
3
+ //# sourceMappingURL=keycodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keycodes.d.ts","sourceRoot":"","sources":["../src/keycodes.ts"],"names":[],"mappings":"AAGA,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,CAmElE;AAED,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAOjF"}
@@ -0,0 +1,73 @@
1
+ // Browser -> "X11 keysym-ish" mapping used by your Rust KeyCode enum.
2
+ // For a first pass we support the common codes used by WASD + arrows etc.
3
+ export function keycodeFromKeyboardEvent(ev) {
4
+ const code = ev.code;
5
+ // Letters: KeyA..KeyZ -> ASCII 'A'..'Z' (0x0041..)
6
+ if (code.startsWith('Key') && code.length === 4) {
7
+ const c = code.charCodeAt(3); // 'A'..'Z'
8
+ return c | 0;
9
+ }
10
+ // Digits: Digit0..Digit9 -> ASCII '0'..'9' (0x0030..)
11
+ if (code.startsWith('Digit') && code.length === 6) {
12
+ const d = code.charCodeAt(5); // '0'..'9'
13
+ return d | 0;
14
+ }
15
+ switch (code) {
16
+ case 'Space': return 0x0020;
17
+ case 'Comma': return 0x002c;
18
+ case 'Period': return 0x002e;
19
+ case 'Minus': return 0x002d;
20
+ case 'Equal': return 0x003d;
21
+ case 'Slash': return 0x002f;
22
+ case 'Semicolon': return 0x003b;
23
+ case 'Quote': return 0x0027;
24
+ case 'Backquote': return 0x0060;
25
+ case 'BracketLeft': return 0x005b;
26
+ case 'BracketRight': return 0x005d;
27
+ case 'Backslash': return 0x005c;
28
+ case 'Escape': return 0xff1b;
29
+ case 'Enter': return 0xff0d;
30
+ case 'Tab': return 0xff09;
31
+ case 'Backspace': return 0xff08;
32
+ case 'Insert': return 0xff63;
33
+ case 'Delete': return 0xffff;
34
+ case 'ArrowRight': return 0xff53;
35
+ case 'ArrowLeft': return 0xff51;
36
+ case 'ArrowDown': return 0xff54;
37
+ case 'ArrowUp': return 0xff52;
38
+ case 'PageUp': return 0xff55;
39
+ case 'PageDown': return 0xff56;
40
+ case 'Home': return 0xff50;
41
+ case 'End': return 0xff57;
42
+ case 'ShiftLeft': return 0xffe1;
43
+ case 'ShiftRight': return 0xffe2;
44
+ case 'ControlLeft': return 0xffe3;
45
+ case 'ControlRight': return 0xffe4;
46
+ case 'AltLeft': return 0xffe9;
47
+ case 'AltRight': return 0xffea;
48
+ case 'MetaLeft': return 0xffeb;
49
+ case 'MetaRight': return 0xffec;
50
+ case 'ContextMenu': return 0xff67;
51
+ }
52
+ // Fallback: attempt to map single-character keys (rarely used)
53
+ if (ev.key && ev.key.length === 1) {
54
+ const ch = ev.key.toUpperCase();
55
+ const cc = ch.charCodeAt(0);
56
+ if (cc >= 0x20 && cc <= 0x7e)
57
+ return cc;
58
+ }
59
+ // Unknown
60
+ return 0x01ff;
61
+ }
62
+ export function mouseButtonFromPointerEvent(ev) {
63
+ // DOM: 0 left, 1 middle, 2 right
64
+ const b = ev.button | 0;
65
+ if (b === 0)
66
+ return 0;
67
+ if (b === 1)
68
+ return 1;
69
+ if (b === 2)
70
+ return 2;
71
+ return 3;
72
+ }
73
+ //# sourceMappingURL=keycodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keycodes.js","sourceRoot":"","sources":["../src/keycodes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { PackageFileMeta, SerializedPackage } from './types.js';
2
+ export interface PackageFile {
3
+ id: number;
4
+ path: string;
5
+ bytes: Uint8Array;
6
+ meta: PackageFileMeta;
7
+ }
8
+ export interface WorkerPayloadOptions {
9
+ transfer?: boolean;
10
+ wasmIdOverride?: number;
11
+ }
12
+ export declare class ImmutablePackage {
13
+ readonly files: readonly PackageFile[];
14
+ readonly wasmId: number;
15
+ private readonly byId;
16
+ private readonly byPath;
17
+ private constructor();
18
+ /** True if we can pick a folder in this browser (either API or webkitdirectory). */
19
+ static supportsFolderPicker(): boolean;
20
+ /** Safari/Brave-friendly folder picker: <input type="file" webkitdirectory multiple> */
21
+ private static pickFolderViaWebkitInput;
22
+ /**
23
+ * Build a package from a FileList (e.g. returned by webkitdirectory picker).
24
+ * This is also handy if you ever add an explicit <input webkitdirectory> in the demo HTML.
25
+ */
26
+ static fromFileList(fileList: FileList, options?: {
27
+ wasmPath?: string;
28
+ }): Promise<ImmutablePackage>;
29
+ listWasmFiles(): PackageFile[];
30
+ getById(id: number): PackageFile | undefined;
31
+ getByPath(path: string): PackageFile | undefined;
32
+ getBytesById(id: number): Uint8Array | null;
33
+ toWorkerPayload(opts?: WorkerPayloadOptions): {
34
+ pkg: SerializedPackage;
35
+ transferables: Transferable[];
36
+ };
37
+ static fromDirectoryPicker(options?: {
38
+ wasmPath?: string;
39
+ }): Promise<ImmutablePackage>;
40
+ static fromWasmFilePicker(): Promise<ImmutablePackage>;
41
+ static fromDirectoryHandle(dir: FileSystemDirectoryHandle, options?: {
42
+ wasmPath?: string;
43
+ }): Promise<ImmutablePackage>;
44
+ }
45
+ //# sourceMappingURL=package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../src/package.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAyB,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAkTD,qBAAa,gBAAgB;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAElD,OAAO;IAQP,oFAAoF;IACpF,MAAM,CAAC,oBAAoB,IAAI,OAAO;IAYtC,wFAAwF;IACxF,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAyFvC;;;OAGG;WACU,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmK7G,aAAa,IAAI,WAAW,EAAE;IAI9B,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI5C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIhD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAK3C,eAAe,CAAC,IAAI,GAAE,oBAAyB,GAAG;QAAE,GAAG,EAAE,iBAAiB,CAAC;QAAC,aAAa,EAAE,YAAY,EAAE,CAAA;KAAE;WAmB9F,mBAAmB,CAAC,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;WAoCnF,kBAAkB,IAAI,OAAO,CAAC,gBAAgB,CAAC;WA4D/C,mBAAmB,CAAC,GAAG,EAAE,yBAAyB,EAAE,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAiJjI"}