@emu198x/zx-spectrum 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.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @emu198x/zx-spectrum
2
+
3
+ A cycle-accurate ZX Spectrum 48K for the browser. The same emulator core as the
4
+ native Emu198x application, compiled to WebAssembly — its output is checked
5
+ pixel-for-pixel against the native build on every change.
6
+
7
+ The 48K ROM travels inside the package, so a page needs no firmware of its own.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @emu198x/zx-spectrum
13
+ ```
14
+
15
+ ## Use
16
+
17
+ ```js
18
+ import init, { Spectrum } from '@emu198x/zx-spectrum';
19
+
20
+ await init();
21
+ const spectrum = await Spectrum.createBundled(document.querySelector('canvas'));
22
+
23
+ let last = performance.now();
24
+ function frame(now) {
25
+ spectrum.tick(now - last);
26
+ last = now;
27
+ requestAnimationFrame(frame);
28
+ }
29
+ requestAnimationFrame(frame);
30
+ ```
31
+
32
+ Pass elapsed real time to `tick`, not one frame per callback. The Spectrum runs
33
+ at 50.08 Hz and a display usually refreshes at 60 Hz or more; `tick` converts
34
+ elapsed time into whole machine frames, so the machine runs at its own speed
35
+ rather than the monitor's.
36
+
37
+ The canvas drawing buffer is resized to the machine's picture (352×296) and the
38
+ page controls the displayed size with CSS. Add `image-rendering: pixelated` or
39
+ the browser will blur the pixels.
40
+
41
+ ## API
42
+
43
+ | Method | Purpose |
44
+ |---|---|
45
+ | `Spectrum.createBundled(canvas)` | Build a 48K on the ROM in this package. |
46
+ | `Spectrum.create(canvas, rom)` | Build a 48K on a ROM you supply. |
47
+ | `tick(elapsedMs)` | Run elapsed real time and draw. Returns frames run. |
48
+ | `loadSnapshot(bytes, format)` | Load a `.sna` or `.z80` snapshot. |
49
+ | `load(slot, kind, bytes)` | Load media — for example a tape into `tape-1`. |
50
+ | `keyDown(code)` / `keyUp(code)` | Feed a DOM `KeyboardEvent.code`. |
51
+ | `setAudioEnabled(on)` | Start or stop audio. |
52
+ | `configureAudio(rate, channels, capacity)` | Match the page's `AudioContext`. |
53
+ | `audioDrain()` | Take buffered samples to feed a worklet. |
54
+ | `frameRgba()` / `frameSize()` | The picture, for presenting it yourself. |
55
+ | `mediaSlots()` | Slot names this machine accepts. |
56
+ | `resize(width, height)` | Tell it the canvas changed size. |
57
+
58
+ `createBundled` and `create` are async because the API keeps room for a GPU
59
+ renderer, which needs an adapter.
60
+
61
+ Keys are mapped from `KeyboardEvent.code`, the physical key, so a learner on an
62
+ AZERTY or Dvorak layout presses the key that sits where the Spectrum's does.
63
+ Shift reaches `CapsShift`; Control and Alt reach `SymbolShift`. Cursor keys
64
+ expand to the chord the hardware actually uses — the Spectrum has no cursor
65
+ keys, and `Up` is `CapsShift`+`7`.
66
+
67
+ ## ROM copyright
68
+
69
+ Amstrad have kindly given their permission for the redistribution of their
70
+ copyrighted material but retain that copyright.
71
+
72
+ The permission is Cliff Lawson's, for Amstrad plc, on comp.sys.sinclair,
73
+ 31 August 1999:
74
+ <https://web.archive.org/web/20180828125931/http://www.worldofspectrum.org/permits/amstrad-roms.txt>
75
+
76
+ The ROM image is included unmodified, and no charge is made for it. The
77
+ permission covers the Sinclair 48K and 128K ROMs and Amstrad's +2/+2A/+3
78
+ machines. It does not extend to the ZX80, ZX81, Interface 1 or 2, Timex
79
+ machines, or Spectrum clones.
80
+
81
+ ## Licence
82
+
83
+ The emulator is licensed under the terms in the Emu198x repository. The ROM is
84
+ copyright Amstrad plc and is redistributed under the permission above; it is
85
+ not covered by that licence.
@@ -0,0 +1,202 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * A ZX Spectrum attached to a canvas.
6
+ */
7
+ export class Spectrum {
8
+ private constructor();
9
+ free(): void;
10
+ [Symbol.dispose](): void;
11
+ /**
12
+ * Takes the buffered audio for the page to feed its worklet.
13
+ */
14
+ audioDrain(): Float32Array;
15
+ /**
16
+ * Waits for the boot prompt, types `LOAD ""`, and starts the tape.
17
+ *
18
+ * The way a lesson runs a program a learner just assembled. Loading
19
+ * through the real ROM matters beyond authenticity: the firmware
20
+ * initialises the machine as it goes, so a program can call ROM routines
21
+ * afterwards. A snapshot built by an assembler cannot offer that, because
22
+ * nobody has yet written down what a booted 48K holds in RAM.
23
+ *
24
+ * Drives the ROM keyboard editor rather than patching the ROM or
25
+ * short-circuiting the loader, and is the same code path the native
26
+ * binary's `--autoload-tape` takes — including its two hard-won waits, for
27
+ * the editor prompt to be repainted before it is read, and for the 128K
28
+ * family's loader to be listening before the tape rolls.
29
+ *
30
+ * Returns the number of frames spent waiting for boot. Load a tape first.
31
+ *
32
+ * # Errors
33
+ *
34
+ * Returns a JavaScript error if no tape is loaded, if the machine does
35
+ * not reach a boot prompt within `max_boot_frames`, or if the prompt
36
+ * never becomes ready for keyword entry.
37
+ */
38
+ autoload(max_boot_frames: number): number;
39
+ /**
40
+ * Matches the audio buffer to the page's `AudioContext`.
41
+ */
42
+ configureAudio(sample_rate: number, channels: number, capacity: number): void;
43
+ /**
44
+ * Builds a 48K attached to `canvas`, from ROM bytes the page supplies.
45
+ *
46
+ * Async even though nothing here awaits: restoring the GPU path (#1436)
47
+ * needs an adapter, and acquiring one is async. Shipping this synchronous
48
+ * would make that a breaking change for every consumer.
49
+ *
50
+ * The canvas's drawing buffer is resized to the machine's picture and the
51
+ * page keeps control of the displayed size through CSS. Pair it with
52
+ * `image-rendering: pixelated` or the browser will blur the pixels.
53
+ *
54
+ * # Errors
55
+ *
56
+ * Returns a JavaScript error if the ROM is not a valid 48K image or the
57
+ * canvas has no 2-D context.
58
+ */
59
+ static create(canvas: HTMLCanvasElement, rom: Uint8Array): Promise<Spectrum>;
60
+ /**
61
+ * Builds a 48K on the ROM embedded in this package.
62
+ *
63
+ * The ordinary entry point for a page: the firmware travels with the
64
+ * emulator, so a lesson embed needs no ROM of its own and no file
65
+ * picker in front of the first thing a learner sees.
66
+ *
67
+ * Present only in a build made with the `bundled-rom` feature, which is
68
+ * how the npm package is published. A build without it uses
69
+ * [`create`](Self::create) and supplies its own image.
70
+ *
71
+ * # Errors
72
+ *
73
+ * Returns a JavaScript error if the canvas has no 2-D context.
74
+ */
75
+ static createBundled(canvas: HTMLCanvasElement): Promise<Spectrum>;
76
+ /**
77
+ * The machine's picture as RGBA bytes, for a page that wants to present
78
+ * it itself.
79
+ */
80
+ frameRgba(): Uint8Array;
81
+ /**
82
+ * Width and height of the machine's picture, as `[width, height]`.
83
+ */
84
+ frameSize(): Uint32Array;
85
+ /**
86
+ * Presses a key, from a DOM `KeyboardEvent.code`.
87
+ *
88
+ * Returns `false` when the Spectrum has no such key, so the page can let
89
+ * the browser keep the keystroke instead of swallowing it.
90
+ */
91
+ keyDown(code: string): boolean;
92
+ /**
93
+ * Releases a key, from a DOM `KeyboardEvent.code`.
94
+ */
95
+ keyUp(code: string): boolean;
96
+ /**
97
+ * Loads a program into a media slot from bytes.
98
+ *
99
+ * `kind` is one of `tape`, `disk`, `snapshot`, `cartridge` or `program`.
100
+ *
101
+ * # Errors
102
+ *
103
+ * Returns a JavaScript error for an unknown slot or kind, or if the
104
+ * machine rejects the image.
105
+ */
106
+ load(slot: string, kind: string, bytes: Uint8Array): void;
107
+ /**
108
+ * Loads a portable snapshot — `.sna` or `.z80` — from bytes.
109
+ *
110
+ * This is how a lesson runs the program it ships: the curriculum's
111
+ * capture pipeline builds `.sna` files, and a snapshot is applied to the
112
+ * machine rather than mounted in a slot, so it does not go through
113
+ * [`load`](Self::load).
114
+ *
115
+ * # Errors
116
+ *
117
+ * Returns a JavaScript error for an unknown format or bytes that do not
118
+ * parse.
119
+ */
120
+ loadSnapshot(bytes: Uint8Array, format: string): void;
121
+ /**
122
+ * The machine's media slots, for a page that wants to name one.
123
+ */
124
+ mediaSlots(): string[];
125
+ /**
126
+ * Starts or stops machine audio.
127
+ */
128
+ setAudioEnabled(enabled: boolean): void;
129
+ /**
130
+ * Runs the machine for `elapsed_ms` of real time and draws the result.
131
+ *
132
+ * Returns the number of machine frames that ran, which is often zero: a
133
+ * 60 Hz display driving a 50 Hz machine has nothing to do on roughly one
134
+ * callback in six.
135
+ *
136
+ * While a tape is playing the machine runs ahead of the clock instead,
137
+ * and the count is correspondingly larger. That is not a setting a page
138
+ * has to find: a tape takes as long to load as it did in 1982, and a
139
+ * reader waiting on a lesson has no reason to sit through it.
140
+ *
141
+ * # Errors
142
+ *
143
+ * Returns a JavaScript error if the machine fails or the canvas rejects
144
+ * the frame.
145
+ */
146
+ tick(elapsed_ms: number): number;
147
+ }
148
+
149
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
150
+
151
+ export interface InitOutput {
152
+ readonly memory: WebAssembly.Memory;
153
+ readonly __wbg_spectrum_free: (a: number, b: number) => void;
154
+ readonly spectrum_audioDrain: (a: number) => [number, number];
155
+ readonly spectrum_autoload: (a: number, b: number) => [number, number, number];
156
+ readonly spectrum_configureAudio: (a: number, b: number, c: number, d: number) => void;
157
+ readonly spectrum_create: (a: any, b: number, c: number) => any;
158
+ readonly spectrum_createBundled: (a: any) => any;
159
+ readonly spectrum_frameRgba: (a: number) => [number, number];
160
+ readonly spectrum_frameSize: (a: number) => [number, number];
161
+ readonly spectrum_keyDown: (a: number, b: number, c: number) => number;
162
+ readonly spectrum_keyUp: (a: number, b: number, c: number) => number;
163
+ readonly spectrum_load: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number];
164
+ readonly spectrum_loadSnapshot: (a: number, b: number, c: number, d: number, e: number) => [number, number];
165
+ readonly spectrum_mediaSlots: (a: number) => [number, number];
166
+ readonly spectrum_setAudioEnabled: (a: number, b: number) => void;
167
+ readonly spectrum_tick: (a: number, b: number) => [number, number, number];
168
+ readonly wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___wasm_bindgen_aa0ad12a6f6b153a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_aa0ad12a6f6b153a___JsError___true_: (a: number, b: number, c: any) => [number, number];
169
+ readonly wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
170
+ readonly __wbindgen_exn_store: (a: number) => void;
171
+ readonly __externref_table_alloc: () => number;
172
+ readonly __wbindgen_externrefs: WebAssembly.Table;
173
+ readonly __wbindgen_destroy_closure: (a: number, b: number) => void;
174
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
175
+ readonly __externref_table_dealloc: (a: number) => void;
176
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
177
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
178
+ readonly __externref_drop_slice: (a: number, b: number) => void;
179
+ readonly __wbindgen_start: () => void;
180
+ }
181
+
182
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
183
+
184
+ /**
185
+ * Instantiates the given `module`, which can either be bytes or
186
+ * a precompiled `WebAssembly.Module`.
187
+ *
188
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
189
+ *
190
+ * @returns {InitOutput}
191
+ */
192
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
193
+
194
+ /**
195
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
196
+ * for everything else, calls `WebAssembly.instantiate` directly.
197
+ *
198
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
199
+ *
200
+ * @returns {Promise<InitOutput>}
201
+ */
202
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
@@ -0,0 +1,719 @@
1
+ /* @ts-self-types="./emu198x_spectrum_web.d.ts" */
2
+
3
+ /**
4
+ * A ZX Spectrum attached to a canvas.
5
+ */
6
+ export class Spectrum {
7
+ static __wrap(ptr) {
8
+ const obj = Object.create(Spectrum.prototype);
9
+ obj.__wbg_ptr = ptr;
10
+ SpectrumFinalization.register(obj, obj.__wbg_ptr, obj);
11
+ return obj;
12
+ }
13
+ __destroy_into_raw() {
14
+ const ptr = this.__wbg_ptr;
15
+ this.__wbg_ptr = 0;
16
+ SpectrumFinalization.unregister(this);
17
+ return ptr;
18
+ }
19
+ free() {
20
+ const ptr = this.__destroy_into_raw();
21
+ wasm.__wbg_spectrum_free(ptr, 0);
22
+ }
23
+ /**
24
+ * Takes the buffered audio for the page to feed its worklet.
25
+ * @returns {Float32Array}
26
+ */
27
+ audioDrain() {
28
+ const ret = wasm.spectrum_audioDrain(this.__wbg_ptr);
29
+ var v1 = getArrayF32FromWasm0(ret[0], ret[1]).slice();
30
+ wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
31
+ return v1;
32
+ }
33
+ /**
34
+ * Waits for the boot prompt, types `LOAD ""`, and starts the tape.
35
+ *
36
+ * The way a lesson runs a program a learner just assembled. Loading
37
+ * through the real ROM matters beyond authenticity: the firmware
38
+ * initialises the machine as it goes, so a program can call ROM routines
39
+ * afterwards. A snapshot built by an assembler cannot offer that, because
40
+ * nobody has yet written down what a booted 48K holds in RAM.
41
+ *
42
+ * Drives the ROM keyboard editor rather than patching the ROM or
43
+ * short-circuiting the loader, and is the same code path the native
44
+ * binary's `--autoload-tape` takes — including its two hard-won waits, for
45
+ * the editor prompt to be repainted before it is read, and for the 128K
46
+ * family's loader to be listening before the tape rolls.
47
+ *
48
+ * Returns the number of frames spent waiting for boot. Load a tape first.
49
+ *
50
+ * # Errors
51
+ *
52
+ * Returns a JavaScript error if no tape is loaded, if the machine does
53
+ * not reach a boot prompt within `max_boot_frames`, or if the prompt
54
+ * never becomes ready for keyword entry.
55
+ * @param {number} max_boot_frames
56
+ * @returns {number}
57
+ */
58
+ autoload(max_boot_frames) {
59
+ const ret = wasm.spectrum_autoload(this.__wbg_ptr, max_boot_frames);
60
+ if (ret[2]) {
61
+ throw takeFromExternrefTable0(ret[1]);
62
+ }
63
+ return ret[0] >>> 0;
64
+ }
65
+ /**
66
+ * Matches the audio buffer to the page's `AudioContext`.
67
+ * @param {number} sample_rate
68
+ * @param {number} channels
69
+ * @param {number} capacity
70
+ */
71
+ configureAudio(sample_rate, channels, capacity) {
72
+ wasm.spectrum_configureAudio(this.__wbg_ptr, sample_rate, channels, capacity);
73
+ }
74
+ /**
75
+ * Builds a 48K attached to `canvas`, from ROM bytes the page supplies.
76
+ *
77
+ * Async even though nothing here awaits: restoring the GPU path (#1436)
78
+ * needs an adapter, and acquiring one is async. Shipping this synchronous
79
+ * would make that a breaking change for every consumer.
80
+ *
81
+ * The canvas's drawing buffer is resized to the machine's picture and the
82
+ * page keeps control of the displayed size through CSS. Pair it with
83
+ * `image-rendering: pixelated` or the browser will blur the pixels.
84
+ *
85
+ * # Errors
86
+ *
87
+ * Returns a JavaScript error if the ROM is not a valid 48K image or the
88
+ * canvas has no 2-D context.
89
+ * @param {HTMLCanvasElement} canvas
90
+ * @param {Uint8Array} rom
91
+ * @returns {Promise<Spectrum>}
92
+ */
93
+ static create(canvas, rom) {
94
+ const ptr0 = passArray8ToWasm0(rom, wasm.__wbindgen_malloc);
95
+ const len0 = WASM_VECTOR_LEN;
96
+ const ret = wasm.spectrum_create(canvas, ptr0, len0);
97
+ return ret;
98
+ }
99
+ /**
100
+ * Builds a 48K on the ROM embedded in this package.
101
+ *
102
+ * The ordinary entry point for a page: the firmware travels with the
103
+ * emulator, so a lesson embed needs no ROM of its own and no file
104
+ * picker in front of the first thing a learner sees.
105
+ *
106
+ * Present only in a build made with the `bundled-rom` feature, which is
107
+ * how the npm package is published. A build without it uses
108
+ * [`create`](Self::create) and supplies its own image.
109
+ *
110
+ * # Errors
111
+ *
112
+ * Returns a JavaScript error if the canvas has no 2-D context.
113
+ * @param {HTMLCanvasElement} canvas
114
+ * @returns {Promise<Spectrum>}
115
+ */
116
+ static createBundled(canvas) {
117
+ const ret = wasm.spectrum_createBundled(canvas);
118
+ return ret;
119
+ }
120
+ /**
121
+ * The machine's picture as RGBA bytes, for a page that wants to present
122
+ * it itself.
123
+ * @returns {Uint8Array}
124
+ */
125
+ frameRgba() {
126
+ const ret = wasm.spectrum_frameRgba(this.__wbg_ptr);
127
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
128
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
129
+ return v1;
130
+ }
131
+ /**
132
+ * Width and height of the machine's picture, as `[width, height]`.
133
+ * @returns {Uint32Array}
134
+ */
135
+ frameSize() {
136
+ const ret = wasm.spectrum_frameSize(this.__wbg_ptr);
137
+ var v1 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
138
+ wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
139
+ return v1;
140
+ }
141
+ /**
142
+ * Presses a key, from a DOM `KeyboardEvent.code`.
143
+ *
144
+ * Returns `false` when the Spectrum has no such key, so the page can let
145
+ * the browser keep the keystroke instead of swallowing it.
146
+ * @param {string} code
147
+ * @returns {boolean}
148
+ */
149
+ keyDown(code) {
150
+ const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
151
+ const len0 = WASM_VECTOR_LEN;
152
+ const ret = wasm.spectrum_keyDown(this.__wbg_ptr, ptr0, len0);
153
+ return ret !== 0;
154
+ }
155
+ /**
156
+ * Releases a key, from a DOM `KeyboardEvent.code`.
157
+ * @param {string} code
158
+ * @returns {boolean}
159
+ */
160
+ keyUp(code) {
161
+ const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
162
+ const len0 = WASM_VECTOR_LEN;
163
+ const ret = wasm.spectrum_keyUp(this.__wbg_ptr, ptr0, len0);
164
+ return ret !== 0;
165
+ }
166
+ /**
167
+ * Loads a program into a media slot from bytes.
168
+ *
169
+ * `kind` is one of `tape`, `disk`, `snapshot`, `cartridge` or `program`.
170
+ *
171
+ * # Errors
172
+ *
173
+ * Returns a JavaScript error for an unknown slot or kind, or if the
174
+ * machine rejects the image.
175
+ * @param {string} slot
176
+ * @param {string} kind
177
+ * @param {Uint8Array} bytes
178
+ */
179
+ load(slot, kind, bytes) {
180
+ const ptr0 = passStringToWasm0(slot, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
181
+ const len0 = WASM_VECTOR_LEN;
182
+ const ptr1 = passStringToWasm0(kind, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
183
+ const len1 = WASM_VECTOR_LEN;
184
+ const ptr2 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
185
+ const len2 = WASM_VECTOR_LEN;
186
+ const ret = wasm.spectrum_load(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
187
+ if (ret[1]) {
188
+ throw takeFromExternrefTable0(ret[0]);
189
+ }
190
+ }
191
+ /**
192
+ * Loads a portable snapshot — `.sna` or `.z80` — from bytes.
193
+ *
194
+ * This is how a lesson runs the program it ships: the curriculum's
195
+ * capture pipeline builds `.sna` files, and a snapshot is applied to the
196
+ * machine rather than mounted in a slot, so it does not go through
197
+ * [`load`](Self::load).
198
+ *
199
+ * # Errors
200
+ *
201
+ * Returns a JavaScript error for an unknown format or bytes that do not
202
+ * parse.
203
+ * @param {Uint8Array} bytes
204
+ * @param {string} format
205
+ */
206
+ loadSnapshot(bytes, format) {
207
+ const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc);
208
+ const len0 = WASM_VECTOR_LEN;
209
+ const ptr1 = passStringToWasm0(format, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
210
+ const len1 = WASM_VECTOR_LEN;
211
+ const ret = wasm.spectrum_loadSnapshot(this.__wbg_ptr, ptr0, len0, ptr1, len1);
212
+ if (ret[1]) {
213
+ throw takeFromExternrefTable0(ret[0]);
214
+ }
215
+ }
216
+ /**
217
+ * The machine's media slots, for a page that wants to name one.
218
+ * @returns {string[]}
219
+ */
220
+ mediaSlots() {
221
+ const ret = wasm.spectrum_mediaSlots(this.__wbg_ptr);
222
+ var v1 = getArrayJsValueFromWasm0(ret[0], ret[1]);
223
+ wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
224
+ return v1;
225
+ }
226
+ /**
227
+ * Starts or stops machine audio.
228
+ * @param {boolean} enabled
229
+ */
230
+ setAudioEnabled(enabled) {
231
+ wasm.spectrum_setAudioEnabled(this.__wbg_ptr, enabled);
232
+ }
233
+ /**
234
+ * Runs the machine for `elapsed_ms` of real time and draws the result.
235
+ *
236
+ * Returns the number of machine frames that ran, which is often zero: a
237
+ * 60 Hz display driving a 50 Hz machine has nothing to do on roughly one
238
+ * callback in six.
239
+ *
240
+ * While a tape is playing the machine runs ahead of the clock instead,
241
+ * and the count is correspondingly larger. That is not a setting a page
242
+ * has to find: a tape takes as long to load as it did in 1982, and a
243
+ * reader waiting on a lesson has no reason to sit through it.
244
+ *
245
+ * # Errors
246
+ *
247
+ * Returns a JavaScript error if the machine fails or the canvas rejects
248
+ * the frame.
249
+ * @param {number} elapsed_ms
250
+ * @returns {number}
251
+ */
252
+ tick(elapsed_ms) {
253
+ const ret = wasm.spectrum_tick(this.__wbg_ptr, elapsed_ms);
254
+ if (ret[2]) {
255
+ throw takeFromExternrefTable0(ret[1]);
256
+ }
257
+ return ret[0] >>> 0;
258
+ }
259
+ }
260
+ if (Symbol.dispose) Spectrum.prototype[Symbol.dispose] = Spectrum.prototype.free;
261
+ function __wbg_get_imports() {
262
+ const import0 = {
263
+ __proto__: null,
264
+ __wbg_Error_408e67f47ca7b58b: function(arg0, arg1) {
265
+ const ret = Error(getStringFromWasm0(arg0, arg1));
266
+ return ret;
267
+ },
268
+ __wbg___wbindgen_is_function_5e4570eb24ffa122: function(arg0) {
269
+ const ret = typeof(arg0) === 'function';
270
+ return ret;
271
+ },
272
+ __wbg___wbindgen_is_undefined_6cff064c44e0d823: function(arg0) {
273
+ const ret = arg0 === undefined;
274
+ return ret;
275
+ },
276
+ __wbg___wbindgen_throw_bb96b2010945f0bc: function(arg0, arg1) {
277
+ throw new Error(getStringFromWasm0(arg0, arg1));
278
+ },
279
+ __wbg__wbg_cb_unref_be22cc64ae6946a0: function(arg0) {
280
+ arg0._wbg_cb_unref();
281
+ },
282
+ __wbg_call_35dba3c747ad7521: function() { return handleError(function (arg0, arg1, arg2) {
283
+ const ret = arg0.call(arg1, arg2);
284
+ return ret;
285
+ }, arguments); },
286
+ __wbg_getContext_71c33f14b63da593: function() { return handleError(function (arg0, arg1, arg2) {
287
+ const ret = arg0.getContext(getStringFromWasm0(arg1, arg2));
288
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
289
+ }, arguments); },
290
+ __wbg_height_e56f6fb197710e09: function(arg0) {
291
+ const ret = arg0.height;
292
+ return ret;
293
+ },
294
+ __wbg_instanceof_CanvasRenderingContext2d_d23139c3ef7651a3: function(arg0) {
295
+ let result;
296
+ try {
297
+ result = arg0 instanceof CanvasRenderingContext2D;
298
+ } catch (_) {
299
+ result = false;
300
+ }
301
+ const ret = result;
302
+ return ret;
303
+ },
304
+ __wbg_new_typed_cceaf62d8d95e9f2: function(arg0, arg1) {
305
+ try {
306
+ var state0 = {a: arg0, b: arg1};
307
+ var cb0 = (arg0, arg1) => {
308
+ const a = state0.a;
309
+ state0.a = 0;
310
+ try {
311
+ return wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined_______true_(a, state0.b, arg0, arg1);
312
+ } finally {
313
+ state0.a = a;
314
+ }
315
+ };
316
+ const ret = new Promise(cb0);
317
+ return ret;
318
+ } finally {
319
+ state0.a = 0;
320
+ }
321
+ },
322
+ __wbg_new_with_u8_clamped_array_and_sh_d9a3bf9abac17f51: function() { return handleError(function (arg0, arg1, arg2, arg3) {
323
+ const ret = new ImageData(getClampedArrayU8FromWasm0(arg0, arg1), arg2 >>> 0, arg3 >>> 0);
324
+ return ret;
325
+ }, arguments); },
326
+ __wbg_putImageData_17fd10517d5503a3: function() { return handleError(function (arg0, arg1, arg2, arg3) {
327
+ arg0.putImageData(arg1, arg2, arg3);
328
+ }, arguments); },
329
+ __wbg_queueMicrotask_ac694eae12e92dfb: function(arg0) {
330
+ queueMicrotask(arg0);
331
+ },
332
+ __wbg_queueMicrotask_be5fe34a8f4cad4d: function(arg0) {
333
+ const ret = arg0.queueMicrotask;
334
+ return ret;
335
+ },
336
+ __wbg_resolve_020f95d838c6ef25: function(arg0) {
337
+ const ret = Promise.resolve(arg0);
338
+ return ret;
339
+ },
340
+ __wbg_set_height_d72f2b76484a44de: function(arg0, arg1) {
341
+ arg0.height = arg1 >>> 0;
342
+ },
343
+ __wbg_set_width_36ef6630b22fc519: function(arg0, arg1) {
344
+ arg0.width = arg1 >>> 0;
345
+ },
346
+ __wbg_spectrum_new: function(arg0) {
347
+ const ret = Spectrum.__wrap(arg0);
348
+ return ret;
349
+ },
350
+ __wbg_static_accessor_GLOBAL_THIS_466428f93b4eaa76: function() {
351
+ const ret = typeof globalThis === 'undefined' ? null : globalThis;
352
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
353
+ },
354
+ __wbg_static_accessor_GLOBAL_c7aea38d4de089bc: function() {
355
+ const ret = typeof global === 'undefined' ? null : global;
356
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
357
+ },
358
+ __wbg_static_accessor_SELF_42d4fae05e59267a: function() {
359
+ const ret = typeof self === 'undefined' ? null : self;
360
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
361
+ },
362
+ __wbg_static_accessor_WINDOW_e0db14a0eba6a812: function() {
363
+ const ret = typeof window === 'undefined' ? null : window;
364
+ return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
365
+ },
366
+ __wbg_then_7026b513a94278a8: function(arg0, arg1) {
367
+ const ret = arg0.then(arg1);
368
+ return ret;
369
+ },
370
+ __wbg_width_1952934caca67137: function(arg0) {
371
+ const ret = arg0.width;
372
+ return ret;
373
+ },
374
+ __wbindgen_cast_0000000000000001: function(arg0, arg1) {
375
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 21, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
376
+ const ret = makeMutClosure(arg0, arg1, wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___wasm_bindgen_aa0ad12a6f6b153a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_aa0ad12a6f6b153a___JsError___true_);
377
+ return ret;
378
+ },
379
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
380
+ // Cast intrinsic for `Ref(String) -> Externref`.
381
+ const ret = getStringFromWasm0(arg0, arg1);
382
+ return ret;
383
+ },
384
+ __wbindgen_init_externref_table: function() {
385
+ const table = wasm.__wbindgen_externrefs;
386
+ const offset = table.grow(4);
387
+ table.set(0, undefined);
388
+ table.set(offset + 0, undefined);
389
+ table.set(offset + 1, null);
390
+ table.set(offset + 2, true);
391
+ table.set(offset + 3, false);
392
+ },
393
+ };
394
+ return {
395
+ __proto__: null,
396
+ "./emu198x_spectrum_web_bg.js": import0,
397
+ };
398
+ }
399
+
400
+ function wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___wasm_bindgen_aa0ad12a6f6b153a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_aa0ad12a6f6b153a___JsError___true_(arg0, arg1, arg2) {
401
+ const ret = wasm.wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___wasm_bindgen_aa0ad12a6f6b153a___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_aa0ad12a6f6b153a___JsError___true_(arg0, arg1, arg2);
402
+ if (ret[1]) {
403
+ throw takeFromExternrefTable0(ret[0]);
404
+ }
405
+ }
406
+
407
+ function wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined_______true_(arg0, arg1, arg2, arg3) {
408
+ wasm.wasm_bindgen_aa0ad12a6f6b153a___convert__closures_____invoke___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined___js_sys_33d4c80ea43e39ff___Function_fn_wasm_bindgen_aa0ad12a6f6b153a___JsValue_____wasm_bindgen_aa0ad12a6f6b153a___sys__Undefined_______true_(arg0, arg1, arg2, arg3);
409
+ }
410
+
411
+ const SpectrumFinalization = (typeof FinalizationRegistry === 'undefined')
412
+ ? { register: () => {}, unregister: () => {} }
413
+ : new FinalizationRegistry(ptr => wasm.__wbg_spectrum_free(ptr, 1));
414
+
415
+ function addToExternrefTable0(obj) {
416
+ const idx = wasm.__externref_table_alloc();
417
+ wasm.__wbindgen_externrefs.set(idx, obj);
418
+ return idx;
419
+ }
420
+
421
+ const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined')
422
+ ? { register: () => {}, unregister: () => {} }
423
+ : new FinalizationRegistry(state => wasm.__wbindgen_destroy_closure(state.a, state.b));
424
+
425
+ function getArrayF32FromWasm0(ptr, len) {
426
+ ptr = ptr >>> 0;
427
+ return getFloat32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
428
+ }
429
+
430
+ function getArrayJsValueFromWasm0(ptr, len) {
431
+ ptr = ptr >>> 0;
432
+ const mem = getDataViewMemory0();
433
+ const result = [];
434
+ for (let i = ptr; i < ptr + 4 * len; i += 4) {
435
+ result.push(wasm.__wbindgen_externrefs.get(mem.getUint32(i, true)));
436
+ }
437
+ wasm.__externref_drop_slice(ptr, len);
438
+ return result;
439
+ }
440
+
441
+ function getArrayU32FromWasm0(ptr, len) {
442
+ ptr = ptr >>> 0;
443
+ return getUint32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
444
+ }
445
+
446
+ function getArrayU8FromWasm0(ptr, len) {
447
+ ptr = ptr >>> 0;
448
+ return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
449
+ }
450
+
451
+ function getClampedArrayU8FromWasm0(ptr, len) {
452
+ ptr = ptr >>> 0;
453
+ return getUint8ClampedArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
454
+ }
455
+
456
+ let cachedDataViewMemory0 = null;
457
+ function getDataViewMemory0() {
458
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
459
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
460
+ }
461
+ return cachedDataViewMemory0;
462
+ }
463
+
464
+ let cachedFloat32ArrayMemory0 = null;
465
+ function getFloat32ArrayMemory0() {
466
+ if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) {
467
+ cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer);
468
+ }
469
+ return cachedFloat32ArrayMemory0;
470
+ }
471
+
472
+ function getStringFromWasm0(ptr, len) {
473
+ return decodeText(ptr >>> 0, len);
474
+ }
475
+
476
+ let cachedUint32ArrayMemory0 = null;
477
+ function getUint32ArrayMemory0() {
478
+ if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
479
+ cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
480
+ }
481
+ return cachedUint32ArrayMemory0;
482
+ }
483
+
484
+ let cachedUint8ArrayMemory0 = null;
485
+ function getUint8ArrayMemory0() {
486
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
487
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
488
+ }
489
+ return cachedUint8ArrayMemory0;
490
+ }
491
+
492
+ let cachedUint8ClampedArrayMemory0 = null;
493
+ function getUint8ClampedArrayMemory0() {
494
+ if (cachedUint8ClampedArrayMemory0 === null || cachedUint8ClampedArrayMemory0.byteLength === 0) {
495
+ cachedUint8ClampedArrayMemory0 = new Uint8ClampedArray(wasm.memory.buffer);
496
+ }
497
+ return cachedUint8ClampedArrayMemory0;
498
+ }
499
+
500
+ function handleError(f, args) {
501
+ try {
502
+ return f.apply(this, args);
503
+ } catch (e) {
504
+ const idx = addToExternrefTable0(e);
505
+ wasm.__wbindgen_exn_store(idx);
506
+ }
507
+ }
508
+
509
+ function isLikeNone(x) {
510
+ return x === undefined || x === null;
511
+ }
512
+
513
+ function makeMutClosure(arg0, arg1, f) {
514
+ const state = { a: arg0, b: arg1, cnt: 1 };
515
+ const real = (...args) => {
516
+
517
+ // First up with a closure we increment the internal reference
518
+ // count. This ensures that the Rust closure environment won't
519
+ // be deallocated while we're invoking it.
520
+ state.cnt++;
521
+ const a = state.a;
522
+ state.a = 0;
523
+ try {
524
+ return f(a, state.b, ...args);
525
+ } finally {
526
+ state.a = a;
527
+ real._wbg_cb_unref();
528
+ }
529
+ };
530
+ real._wbg_cb_unref = () => {
531
+ if (--state.cnt === 0) {
532
+ wasm.__wbindgen_destroy_closure(state.a, state.b);
533
+ state.a = 0;
534
+ CLOSURE_DTORS.unregister(state);
535
+ }
536
+ };
537
+ CLOSURE_DTORS.register(real, state, state);
538
+ return real;
539
+ }
540
+
541
+ function passArray8ToWasm0(arg, malloc) {
542
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
543
+ getUint8ArrayMemory0().set(arg, ptr / 1);
544
+ WASM_VECTOR_LEN = arg.length;
545
+ return ptr;
546
+ }
547
+
548
+ function passStringToWasm0(arg, malloc, realloc) {
549
+ if (realloc === undefined) {
550
+ const buf = cachedTextEncoder.encode(arg);
551
+ const ptr = malloc(buf.length, 1) >>> 0;
552
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
553
+ WASM_VECTOR_LEN = buf.length;
554
+ return ptr;
555
+ }
556
+
557
+ let len = arg.length;
558
+ let ptr = malloc(len, 1) >>> 0;
559
+
560
+ const mem = getUint8ArrayMemory0();
561
+
562
+ let offset = 0;
563
+
564
+ for (; offset < len; offset++) {
565
+ const code = arg.charCodeAt(offset);
566
+ if (code > 0x7F) break;
567
+ mem[ptr + offset] = code;
568
+ }
569
+ if (offset !== len) {
570
+ if (offset !== 0) {
571
+ arg = arg.slice(offset);
572
+ }
573
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
574
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
575
+ const ret = cachedTextEncoder.encodeInto(arg, view);
576
+
577
+ offset += ret.written;
578
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
579
+ }
580
+
581
+ WASM_VECTOR_LEN = offset;
582
+ return ptr;
583
+ }
584
+
585
+ function takeFromExternrefTable0(idx) {
586
+ const value = wasm.__wbindgen_externrefs.get(idx);
587
+ wasm.__externref_table_dealloc(idx);
588
+ return value;
589
+ }
590
+
591
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
592
+ cachedTextDecoder.decode();
593
+ const MAX_SAFARI_DECODE_BYTES = 2146435072;
594
+ let numBytesDecoded = 0;
595
+ function decodeText(ptr, len) {
596
+ numBytesDecoded += len;
597
+ if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
598
+ cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
599
+ cachedTextDecoder.decode();
600
+ numBytesDecoded = len;
601
+ }
602
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
603
+ }
604
+
605
+ const cachedTextEncoder = new TextEncoder();
606
+
607
+ if (!('encodeInto' in cachedTextEncoder)) {
608
+ cachedTextEncoder.encodeInto = function (arg, view) {
609
+ const buf = cachedTextEncoder.encode(arg);
610
+ view.set(buf);
611
+ return {
612
+ read: arg.length,
613
+ written: buf.length
614
+ };
615
+ };
616
+ }
617
+
618
+ let WASM_VECTOR_LEN = 0;
619
+
620
+ let wasmModule, wasmInstance, wasm;
621
+ function __wbg_finalize_init(instance, module) {
622
+ wasmInstance = instance;
623
+ wasm = instance.exports;
624
+ wasmModule = module;
625
+ cachedDataViewMemory0 = null;
626
+ cachedFloat32ArrayMemory0 = null;
627
+ cachedUint32ArrayMemory0 = null;
628
+ cachedUint8ArrayMemory0 = null;
629
+ cachedUint8ClampedArrayMemory0 = null;
630
+ wasm.__wbindgen_start();
631
+ return wasm;
632
+ }
633
+
634
+ async function __wbg_load(module, imports) {
635
+ if (typeof Response === 'function' && module instanceof Response) {
636
+ if (!module.ok) {
637
+ throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
638
+ }
639
+
640
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
641
+ try {
642
+ return await WebAssembly.instantiateStreaming(module, imports);
643
+ } catch (e) {
644
+ const validResponse = expectedResponseType(module.type);
645
+
646
+ if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
647
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
648
+
649
+ } else { throw e; }
650
+ }
651
+ }
652
+
653
+ const bytes = await module.arrayBuffer();
654
+ return await WebAssembly.instantiate(bytes, imports);
655
+ } else {
656
+ const instance = await WebAssembly.instantiate(module, imports);
657
+
658
+ if (instance instanceof WebAssembly.Instance) {
659
+ return { instance, module };
660
+ } else {
661
+ return instance;
662
+ }
663
+ }
664
+
665
+ function expectedResponseType(type) {
666
+ switch (type) {
667
+ case 'basic': case 'cors': case 'default': return true;
668
+ }
669
+ return false;
670
+ }
671
+ }
672
+
673
+ function initSync(module) {
674
+ if (wasm !== undefined) return wasm;
675
+
676
+
677
+ if (module !== undefined) {
678
+ if (Object.getPrototypeOf(module) === Object.prototype) {
679
+ ({module} = module)
680
+ } else {
681
+ console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
682
+ }
683
+ }
684
+
685
+ const imports = __wbg_get_imports();
686
+ if (!(module instanceof WebAssembly.Module)) {
687
+ module = new WebAssembly.Module(module);
688
+ }
689
+ const instance = new WebAssembly.Instance(module, imports);
690
+ return __wbg_finalize_init(instance, module);
691
+ }
692
+
693
+ async function __wbg_init(module_or_path) {
694
+ if (wasm !== undefined) return wasm;
695
+
696
+
697
+ if (module_or_path !== undefined) {
698
+ if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
699
+ ({module_or_path} = module_or_path)
700
+ } else {
701
+ console.warn('using deprecated parameters for the initialization function; pass a single object instead')
702
+ }
703
+ }
704
+
705
+ if (module_or_path === undefined) {
706
+ module_or_path = new URL('emu198x_spectrum_web_bg.wasm', import.meta.url);
707
+ }
708
+ const imports = __wbg_get_imports();
709
+
710
+ if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
711
+ module_or_path = fetch(module_or_path);
712
+ }
713
+
714
+ const { instance, module } = await __wbg_load(await module_or_path, imports);
715
+
716
+ return __wbg_finalize_init(instance, module);
717
+ }
718
+
719
+ export { initSync, __wbg_init as default };
Binary file
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@emu198x/zx-spectrum",
3
+ "type": "module",
4
+ "description": "ZX Spectrum in the browser, published to npm as @emu198x/zx-spectrum",
5
+ "version": "0.1.0",
6
+ "license": "SEE LICENSE IN README.md",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/emu198x/emu198x"
10
+ },
11
+ "files": [
12
+ "emu198x_spectrum_web_bg.wasm",
13
+ "emu198x_spectrum_web.js",
14
+ "emu198x_spectrum_web.d.ts",
15
+ "README.md"
16
+ ],
17
+ "main": "emu198x_spectrum_web.js",
18
+ "types": "emu198x_spectrum_web.d.ts",
19
+ "sideEffects": [
20
+ "./snippets/*"
21
+ ]
22
+ }