@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 +85 -0
- package/emu198x_spectrum_web.d.ts +202 -0
- package/emu198x_spectrum_web.js +719 -0
- package/emu198x_spectrum_web_bg.wasm +0 -0
- package/package.json +22 -0
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
|
+
}
|