zx-kit 0.1.0 → 0.2.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.
@@ -0,0 +1,29 @@
1
+ export declare function initAudio(volume?: number): void;
2
+ export declare function resumeAudio(): void;
3
+ export declare function getAudioContext(): AudioContext | null;
4
+ export declare function getMasterGain(): GainNode | null;
5
+ /** A single note in a melody pattern. freq=0 is a rest (silence). */
6
+ export interface Note {
7
+ freq: number;
8
+ dur: number;
9
+ }
10
+ /**
11
+ * Schedule a sequence of notes using the shared AudioContext.
12
+ * Silently exits if audio has not been initialised yet.
13
+ *
14
+ * @example
15
+ * // Intro jingle — three notes with rests
16
+ * playPattern([
17
+ * { freq: 523, dur: 120 }, // C5
18
+ * { freq: 0, dur: 40 }, // rest
19
+ * { freq: 659, dur: 120 }, // E5
20
+ * { freq: 0, dur: 40 }, // rest
21
+ * { freq: 784, dur: 200 }, // G5
22
+ * ])
23
+ *
24
+ * // With a 500ms delay after scene load
25
+ * playPattern([{ freq: 440, dur: 100 }, { freq: 880, dur: 50 }], 500)
26
+ */
27
+ export declare function playPattern(notes: Note[], startDelay?: number): void;
28
+ export declare function beep(freq: number, durationMs: number, startTime: number): void;
29
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAGA,wBAAgB,SAAS,CAAC,MAAM,SAAM,GAAG,IAAI,CAM5C;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AAED,wBAAgB,aAAa,IAAI,QAAQ,GAAG,IAAI,CAE/C;AAED,qEAAqE;AACrE,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,UAAU,SAAI,GAAG,IAAI,CAS/D;AAGD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAc9E"}
package/dist/audio.js ADDED
@@ -0,0 +1,67 @@
1
+ let ctx = null;
2
+ let masterGain = null;
3
+ export function initAudio(volume = 0.3) {
4
+ if (ctx)
5
+ return;
6
+ ctx = new AudioContext();
7
+ masterGain = ctx.createGain();
8
+ masterGain.gain.value = volume;
9
+ masterGain.connect(ctx.destination);
10
+ }
11
+ export function resumeAudio() {
12
+ if (ctx && ctx.state === 'suspended')
13
+ void ctx.resume();
14
+ }
15
+ export function getAudioContext() {
16
+ return ctx;
17
+ }
18
+ export function getMasterGain() {
19
+ return masterGain;
20
+ }
21
+ /**
22
+ * Schedule a sequence of notes using the shared AudioContext.
23
+ * Silently exits if audio has not been initialised yet.
24
+ *
25
+ * @example
26
+ * // Intro jingle — three notes with rests
27
+ * playPattern([
28
+ * { freq: 523, dur: 120 }, // C5
29
+ * { freq: 0, dur: 40 }, // rest
30
+ * { freq: 659, dur: 120 }, // E5
31
+ * { freq: 0, dur: 40 }, // rest
32
+ * { freq: 784, dur: 200 }, // G5
33
+ * ])
34
+ *
35
+ * // With a 500ms delay after scene load
36
+ * playPattern([{ freq: 440, dur: 100 }, { freq: 880, dur: 50 }], 500)
37
+ */
38
+ export function playPattern(notes, startDelay = 0) {
39
+ const audio = getAudioContext();
40
+ if (!audio)
41
+ return;
42
+ resumeAudio();
43
+ let offset = startDelay;
44
+ for (const note of notes) {
45
+ if (note.freq > 0)
46
+ beep(note.freq, note.dur, audio.currentTime + offset / 1000);
47
+ offset += note.dur;
48
+ }
49
+ }
50
+ // Core primitive — schedule a square-wave beep on the shared AudioContext
51
+ export function beep(freq, durationMs, startTime) {
52
+ if (!ctx || !masterGain)
53
+ return;
54
+ const osc = ctx.createOscillator();
55
+ const gain = ctx.createGain();
56
+ osc.type = 'square';
57
+ osc.frequency.value = freq;
58
+ gain.gain.setValueAtTime(0, startTime);
59
+ gain.gain.linearRampToValueAtTime(0.8, startTime + 0.005);
60
+ gain.gain.setValueAtTime(0.8, startTime + durationMs / 1000 - 0.005);
61
+ gain.gain.linearRampToValueAtTime(0, startTime + durationMs / 1000);
62
+ osc.connect(gain);
63
+ gain.connect(masterGain);
64
+ osc.start(startTime);
65
+ osc.stop(startTime + durationMs / 1000 + 0.01);
66
+ }
67
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAwB,IAAI,CAAA;AACnC,IAAI,UAAU,GAAoB,IAAI,CAAA;AAEtC,MAAM,UAAU,SAAS,CAAC,MAAM,GAAG,GAAG;IACpC,IAAI,GAAG;QAAE,OAAM;IACf,GAAG,GAAG,IAAI,YAAY,EAAE,CAAA;IACxB,UAAU,GAAG,GAAG,CAAC,UAAU,EAAE,CAAA;IAC7B,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;IAC9B,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW;QAAE,KAAK,GAAG,CAAC,MAAM,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAA;AACnB,CAAC;AAQD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,UAAU,GAAG,CAAC;IACvD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAA;IAC/B,IAAI,CAAC,KAAK;QAAE,OAAM;IAClB,WAAW,EAAE,CAAA;IACb,IAAI,MAAM,GAAG,UAAU,CAAA;IACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,WAAW,GAAG,MAAM,GAAG,IAAI,CAAC,CAAA;QAC/E,MAAM,IAAI,IAAI,CAAC,GAAG,CAAA;IACpB,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAkB,EAAE,SAAiB;IACtE,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU;QAAE,OAAM;IAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAA;IAClC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,CAAA;IAC7B,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAA;IACnB,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,SAAS,GAAG,KAAK,CAAC,CAAA;IACzD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,GAAG,KAAK,CAAC,CAAA;IACpE,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC,CAAA;IACnE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACjB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACxB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACpB,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC,CAAA;AAChD,CAAC"}
package/dist/font.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare const FONT: Uint8Array<ArrayBuffer>;
2
+ export declare function getCharRow(charCode: number, row: number): number;
3
+ //# sourceMappingURL=font.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font.d.ts","sourceRoot":"","sources":["../src/font.ts"],"names":[],"mappings":"AAoMA,eAAO,MAAM,IAAI,yBAAsB,CAAA;AAEvC,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhE"}
package/dist/font.js ADDED
@@ -0,0 +1,203 @@
1
+ // ZX Spectrum ROM font — characters 32–127, 8 bytes per char (row-major, bit7=leftmost pixel)
2
+ const RAW = [
3
+ // 32 space
4
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5
+ // 33 !
6
+ 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00,
7
+ // 34 "
8
+ 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
9
+ // 35 #
10
+ 0x00, 0x28, 0x7C, 0x28, 0x28, 0x7C, 0x28, 0x00,
11
+ // 36 $
12
+ 0x00, 0x10, 0x3C, 0x50, 0x3C, 0x14, 0x7C, 0x10,
13
+ // 37 %
14
+ 0x00, 0x62, 0x64, 0x08, 0x10, 0x26, 0x46, 0x00,
15
+ // 38 &
16
+ 0x00, 0x10, 0x28, 0x10, 0x2A, 0x44, 0x3A, 0x00,
17
+ // 39 '
18
+ 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
19
+ // 40 (
20
+ 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00,
21
+ // 41 )
22
+ 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00,
23
+ // 42 *
24
+ 0x00, 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, 0x00,
25
+ // 43 +
26
+ 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
27
+ // 44 ,
28
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10,
29
+ // 45 -
30
+ 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
31
+ // 46 .
32
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
33
+ // 47 /
34
+ 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00,
35
+ // 48 0
36
+ 0x00, 0x3C, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00,
37
+ // 49 1
38
+ 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00,
39
+ // 50 2
40
+ 0x00, 0x3C, 0x42, 0x04, 0x18, 0x20, 0x7E, 0x00,
41
+ // 51 3
42
+ 0x00, 0x3C, 0x42, 0x0C, 0x02, 0x42, 0x3C, 0x00,
43
+ // 52 4
44
+ 0x00, 0x08, 0x18, 0x28, 0x48, 0x7E, 0x08, 0x00,
45
+ // 53 5
46
+ 0x00, 0x7E, 0x40, 0x7C, 0x02, 0x42, 0x3C, 0x00,
47
+ // 54 6
48
+ 0x00, 0x3C, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00,
49
+ // 55 7
50
+ 0x00, 0x7E, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00,
51
+ // 56 8
52
+ 0x00, 0x3C, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00,
53
+ // 57 9
54
+ 0x00, 0x3C, 0x42, 0x42, 0x3E, 0x02, 0x3C, 0x00,
55
+ // 58 :
56
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,
57
+ // 59 ;
58
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20,
59
+ // 60 <
60
+ 0x00, 0x04, 0x08, 0x10, 0x08, 0x04, 0x00, 0x00,
61
+ // 61 =
62
+ 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00,
63
+ // 62 >
64
+ 0x00, 0x20, 0x10, 0x08, 0x10, 0x20, 0x00, 0x00,
65
+ // 63 ?
66
+ 0x00, 0x3C, 0x42, 0x04, 0x08, 0x00, 0x08, 0x00,
67
+ // 64 @
68
+ 0x00, 0x3C, 0x4A, 0x56, 0x5C, 0x40, 0x3C, 0x00,
69
+ // 65 A
70
+ 0x00, 0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x00,
71
+ // 66 B
72
+ 0x00, 0x7C, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00,
73
+ // 67 C
74
+ 0x00, 0x3C, 0x42, 0x40, 0x40, 0x42, 0x3C, 0x00,
75
+ // 68 D
76
+ 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00,
77
+ // 69 E
78
+ 0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00,
79
+ // 70 F
80
+ 0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00,
81
+ // 71 G
82
+ 0x00, 0x3C, 0x42, 0x40, 0x4E, 0x42, 0x3C, 0x00,
83
+ // 72 H
84
+ 0x00, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00,
85
+ // 73 I
86
+ 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00,
87
+ // 74 J
88
+ 0x00, 0x02, 0x02, 0x02, 0x02, 0x42, 0x3C, 0x00,
89
+ // 75 K
90
+ 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00,
91
+ // 76 L
92
+ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00,
93
+ // 77 M
94
+ 0x00, 0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x00,
95
+ // 78 N
96
+ 0x00, 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x00,
97
+ // 79 O
98
+ 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00,
99
+ // 80 P
100
+ 0x00, 0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x00,
101
+ // 81 Q
102
+ 0x00, 0x3C, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00,
103
+ // 82 R
104
+ 0x00, 0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x00,
105
+ // 83 S
106
+ 0x00, 0x3C, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00,
107
+ // 84 T
108
+ 0x00, 0x7E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
109
+ // 85 U
110
+ 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00,
111
+ // 86 V
112
+ 0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00,
113
+ // 87 W
114
+ 0x00, 0x42, 0x42, 0x42, 0x5A, 0x66, 0x42, 0x00,
115
+ // 88 X
116
+ 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00,
117
+ // 89 Y
118
+ 0x00, 0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x00,
119
+ // 90 Z
120
+ 0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00,
121
+ // 91 [
122
+ 0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00,
123
+ // 92 backslash
124
+ 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
125
+ // 93 ]
126
+ 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00,
127
+ // 94 ^
128
+ 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
129
+ // 95 _
130
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E,
131
+ // 96 `
132
+ 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
133
+ // 97 a
134
+ 0x00, 0x00, 0x3C, 0x02, 0x3E, 0x42, 0x3E, 0x00,
135
+ // 98 b
136
+ 0x00, 0x20, 0x20, 0x3E, 0x22, 0x22, 0x3E, 0x00,
137
+ // 99 c
138
+ 0x00, 0x00, 0x1E, 0x20, 0x20, 0x20, 0x1E, 0x00,
139
+ // 100 d
140
+ 0x00, 0x02, 0x02, 0x3E, 0x42, 0x42, 0x3E, 0x00,
141
+ // 101 e
142
+ 0x00, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x3C, 0x00,
143
+ // 102 f
144
+ 0x00, 0x0C, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x00,
145
+ // 103 g
146
+ 0x00, 0x00, 0x3E, 0x42, 0x42, 0x3E, 0x02, 0x3C,
147
+ // 104 h
148
+ 0x00, 0x20, 0x20, 0x2C, 0x32, 0x22, 0x22, 0x00,
149
+ // 105 i
150
+ 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x1C, 0x00,
151
+ // 106 j
152
+ 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x44, 0x38,
153
+ // 107 k
154
+ 0x00, 0x20, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00,
155
+ // 108 l
156
+ 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00,
157
+ // 109 m
158
+ 0x00, 0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x00,
159
+ // 110 n
160
+ 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00,
161
+ // 111 o
162
+ 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x00,
163
+ // 112 p
164
+ 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20,
165
+ // 113 q
166
+ 0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02,
167
+ // 114 r
168
+ 0x00, 0x00, 0x2C, 0x30, 0x20, 0x20, 0x20, 0x00,
169
+ // 115 s
170
+ 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00,
171
+ // 116 t
172
+ 0x00, 0x10, 0x7C, 0x10, 0x10, 0x12, 0x0C, 0x00,
173
+ // 117 u
174
+ 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00,
175
+ // 118 v
176
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00,
177
+ // 119 w
178
+ 0x00, 0x00, 0x42, 0x42, 0x49, 0x55, 0x22, 0x00,
179
+ // 120 x
180
+ 0x00, 0x00, 0x42, 0x24, 0x18, 0x24, 0x42, 0x00,
181
+ // 121 y
182
+ 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38,
183
+ // 122 z
184
+ 0x00, 0x00, 0x7E, 0x04, 0x18, 0x20, 0x7E, 0x00,
185
+ // 123 {
186
+ 0x00, 0x0C, 0x10, 0x60, 0x10, 0x10, 0x0C, 0x00,
187
+ // 124 |
188
+ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
189
+ // 125 }
190
+ 0x00, 0x30, 0x08, 0x06, 0x08, 0x08, 0x30, 0x00,
191
+ // 126 ~
192
+ 0x00, 0x00, 0x32, 0x4C, 0x00, 0x00, 0x00, 0x00,
193
+ // 127 solid block (used for lives / filled blocks)
194
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
195
+ ];
196
+ export const FONT = new Uint8Array(RAW);
197
+ export function getCharRow(charCode, row) {
198
+ const idx = charCode - 32;
199
+ if (idx < 0 || idx >= 96)
200
+ return 0;
201
+ return FONT[idx * 8 + row];
202
+ }
203
+ //# sourceMappingURL=font.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font.js","sourceRoot":"","sources":["../src/font.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,MAAM,GAAG,GAAsB;IAC7B,WAAW;IACX,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,eAAe;IACf,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,OAAO;IACP,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,QAAQ;IACR,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;IACvC,mDAAmD;IACnD,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,IAAI;CACxC,CAAA;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;AAEvC,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,GAAW;IACtD,MAAM,GAAG,GAAG,QAAQ,GAAG,EAAE,CAAA;IACzB,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,EAAE;QAAE,OAAO,CAAC,CAAA;IAClC,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAA;AAC5B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './palette.js';
2
+ export * from './font.js';
3
+ export * from './renderer.js';
4
+ export * from './audio.js';
5
+ export * from './input.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './palette.js';
2
+ export * from './font.js';
3
+ export * from './renderer.js';
4
+ export * from './audio.js';
5
+ export * from './input.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,9 @@
1
+ export type Direction = 'up' | 'down' | 'left' | 'right';
2
+ export declare function initInput(repeatDelay?: number, repeatInterval?: number): void;
3
+ export declare function tickMovement(dtMs: number): Direction | null;
4
+ export declare function consumeFlag(): boolean;
5
+ export declare function consumeDebug(): boolean;
6
+ export declare function consumePause(): boolean;
7
+ export declare function consumeAnyKey(): boolean;
8
+ export declare function isHeld(key: string): boolean;
9
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAmBxD,wBAAgB,SAAS,CAAC,WAAW,SAAM,EAAE,cAAc,SAAK,GAAG,IAAI,CAkCtE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAe3D;AAED,wBAAgB,WAAW,IAAI,OAAO,CAA+D;AACrG,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AACrG,wBAAgB,YAAY,IAAI,OAAO,CAA8D;AACrG,wBAAgB,aAAa,IAAI,OAAO,CAA6D;AACrG,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAyB"}
package/dist/input.js ADDED
@@ -0,0 +1,70 @@
1
+ const DIR_KEYS = {
2
+ ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right',
3
+ };
4
+ const held = new Set();
5
+ let pendingFlag = false;
6
+ let pendingDebug = false;
7
+ let pendingPause = false;
8
+ let pendingAnyKey = false;
9
+ let repeatDir = null;
10
+ let repeatTimer = 0;
11
+ let repeatPhase = 'idle';
12
+ let pendingImmediate = null;
13
+ let _repeatDelay = 150;
14
+ let _repeatInterval = 80;
15
+ export function initInput(repeatDelay = 150, repeatInterval = 80) {
16
+ _repeatDelay = repeatDelay;
17
+ _repeatInterval = repeatInterval;
18
+ window.addEventListener('keydown', (e) => {
19
+ if (e.repeat)
20
+ return;
21
+ pendingAnyKey = true;
22
+ held.add(e.key);
23
+ const dir = DIR_KEYS[e.key];
24
+ if (dir) {
25
+ repeatDir = dir;
26
+ repeatPhase = 'delay';
27
+ repeatTimer = _repeatDelay;
28
+ pendingImmediate = dir;
29
+ }
30
+ if (e.key === 'f' || e.key === 'F')
31
+ pendingFlag = true;
32
+ if (e.key === 'p' || e.key === 'P')
33
+ pendingPause = true;
34
+ if (e.ctrlKey && e.shiftKey && (e.key === 'b' || e.key === 'B')) {
35
+ pendingDebug = true;
36
+ e.preventDefault();
37
+ }
38
+ });
39
+ window.addEventListener('keyup', (e) => {
40
+ held.delete(e.key);
41
+ const dir = DIR_KEYS[e.key];
42
+ if (dir && repeatDir === dir) {
43
+ repeatDir = null;
44
+ repeatPhase = 'idle';
45
+ }
46
+ });
47
+ }
48
+ export function tickMovement(dtMs) {
49
+ if (pendingImmediate !== null) {
50
+ const d = pendingImmediate;
51
+ pendingImmediate = null;
52
+ return d;
53
+ }
54
+ if (repeatDir !== null && repeatPhase !== 'idle') {
55
+ repeatTimer -= dtMs;
56
+ if (repeatTimer <= 0) {
57
+ repeatTimer += _repeatInterval;
58
+ if (repeatPhase === 'delay')
59
+ repeatPhase = 'repeat';
60
+ return repeatDir;
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+ export function consumeFlag() { const v = pendingFlag; pendingFlag = false; return v; }
66
+ export function consumeDebug() { const v = pendingDebug; pendingDebug = false; return v; }
67
+ export function consumePause() { const v = pendingPause; pendingPause = false; return v; }
68
+ export function consumeAnyKey() { const v = pendingAnyKey; pendingAnyKey = false; return v; }
69
+ export function isHeld(key) { return held.has(key); }
70
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export declare const SCALE = 4;
2
+ export declare const CELL = 8;
3
+ export declare const C: {
4
+ readonly BLACK: "#000000";
5
+ readonly BLUE: "#0000CD";
6
+ readonly RED: "#CD0000";
7
+ readonly MAGENTA: "#CD00CD";
8
+ readonly GREEN: "#00CD00";
9
+ readonly CYAN: "#00CDCD";
10
+ readonly YELLOW: "#CDCD00";
11
+ readonly WHITE: "#CDCDCD";
12
+ readonly B_BLACK: "#000000";
13
+ readonly B_BLUE: "#0000FF";
14
+ readonly B_RED: "#FF0000";
15
+ readonly B_MAGENTA: "#FF00FF";
16
+ readonly B_GREEN: "#00FF00";
17
+ readonly B_CYAN: "#00FFFF";
18
+ readonly B_YELLOW: "#FFFF00";
19
+ readonly B_WHITE: "#FFFFFF";
20
+ };
21
+ export type SpectrumColor = typeof C[keyof typeof C];
22
+ //# sourceMappingURL=palette.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,IAAI,CAAA;AACtB,eAAO,MAAM,IAAI,IAAI,CAAA;AAGrB,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;CAiBJ,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,CAAA"}
@@ -0,0 +1,22 @@
1
+ export const SCALE = 4;
2
+ export const CELL = 8;
3
+ // ZX Spectrum palette — exactly 15 colours, EXCLUSIVELY these hex values
4
+ export const C = {
5
+ BLACK: '#000000',
6
+ BLUE: '#0000CD',
7
+ RED: '#CD0000',
8
+ MAGENTA: '#CD00CD',
9
+ GREEN: '#00CD00',
10
+ CYAN: '#00CDCD',
11
+ YELLOW: '#CDCD00',
12
+ WHITE: '#CDCDCD',
13
+ B_BLACK: '#000000',
14
+ B_BLUE: '#0000FF',
15
+ B_RED: '#FF0000',
16
+ B_MAGENTA: '#FF00FF',
17
+ B_GREEN: '#00FF00',
18
+ B_CYAN: '#00FFFF',
19
+ B_YELLOW: '#FFFF00',
20
+ B_WHITE: '#FFFFFF',
21
+ };
22
+ //# sourceMappingURL=palette.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.js","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAA;AACtB,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAA;AAErB,yEAAyE;AACzE,MAAM,CAAC,MAAM,CAAC,GAAG;IACf,KAAK,EAAM,SAAS;IACpB,IAAI,EAAO,SAAS;IACpB,GAAG,EAAQ,SAAS;IACpB,OAAO,EAAI,SAAS;IACpB,KAAK,EAAM,SAAS;IACpB,IAAI,EAAO,SAAS;IACpB,MAAM,EAAK,SAAS;IACpB,KAAK,EAAM,SAAS;IACpB,OAAO,EAAI,SAAS;IACpB,MAAM,EAAK,SAAS;IACpB,KAAK,EAAM,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAI,SAAS;IACpB,MAAM,EAAK,SAAS;IACpB,QAAQ,EAAG,SAAS;IACpB,OAAO,EAAI,SAAS;CACZ,CAAA"}
@@ -0,0 +1,16 @@
1
+ export declare function mirrorSprite(src: Uint8Array): Uint8Array;
2
+ export declare function drawSprite(ctx: CanvasRenderingContext2D, sprite: Uint8Array, x: number, y: number, ink: string, paper: string): void;
3
+ export declare function drawChar(ctx: CanvasRenderingContext2D, code: number, x: number, y: number, ink: string, paper?: string): void;
4
+ export declare function drawText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, ink: string, paper?: string): void;
5
+ /**
6
+ * Flash document.body background between `color` and `resetColor`.
7
+ * Fire-and-forget — does not block.
8
+ *
9
+ * @example
10
+ * flashBorder(C.B_RED, 3, 150) // explosion — 3 red flashes
11
+ * flashBorder(C.B_GREEN, 2, 200) // level complete
12
+ * flashBorder(C.B_CYAN, 2, 120, C.BLUE) // reset to blue border
13
+ */
14
+ export declare function flashBorder(color: string, times: number, intervalMs: number, resetColor?: string): void;
15
+ export declare function drawTextCentered(ctx: CanvasRenderingContext2D, text: string, y: number, cols: number, ink: string, paper?: string): void;
16
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAUxD;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,UAAU,EAClB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GACzB,IAAI,CAUN;AAED,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAYN;AAED,wBAAgB,QAAQ,CACtB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAIN;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAgB,GAC3B,IAAI,CAWN;AAGD,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAC1B,IAAI,CAGN"}
@@ -0,0 +1,73 @@
1
+ import { C, CELL } from './palette.js';
2
+ import { getCharRow } from './font.js';
3
+ // Flip an 8×8 sprite horizontally
4
+ export function mirrorSprite(src) {
5
+ const out = new Uint8Array(8);
6
+ for (let r = 0; r < 8; r++) {
7
+ let b = src[r], m = 0;
8
+ for (let i = 0; i < 8; i++) {
9
+ if (b & (1 << i))
10
+ m |= (1 << (7 - i));
11
+ }
12
+ out[r] = m;
13
+ }
14
+ return out;
15
+ }
16
+ export function drawSprite(ctx, sprite, x, y, ink, paper) {
17
+ ctx.fillStyle = paper;
18
+ ctx.fillRect(x, y, CELL, CELL);
19
+ ctx.fillStyle = ink;
20
+ for (let row = 0; row < 8; row++) {
21
+ const byte = sprite[row];
22
+ for (let bit = 0; bit < 8; bit++) {
23
+ if (byte & (0x80 >> bit))
24
+ ctx.fillRect(x + bit, y + row, 1, 1);
25
+ }
26
+ }
27
+ }
28
+ export function drawChar(ctx, code, x, y, ink, paper) {
29
+ if (paper !== undefined) {
30
+ ctx.fillStyle = paper;
31
+ ctx.fillRect(x, y, CELL, CELL);
32
+ }
33
+ ctx.fillStyle = ink;
34
+ for (let row = 0; row < 8; row++) {
35
+ const byte = getCharRow(code, row);
36
+ for (let bit = 0; bit < 8; bit++) {
37
+ if (byte & (0x80 >> bit))
38
+ ctx.fillRect(x + bit, y + row, 1, 1);
39
+ }
40
+ }
41
+ }
42
+ export function drawText(ctx, text, x, y, ink, paper) {
43
+ for (let i = 0; i < text.length; i++) {
44
+ drawChar(ctx, text.charCodeAt(i), x + i * CELL, y, ink, paper);
45
+ }
46
+ }
47
+ /**
48
+ * Flash document.body background between `color` and `resetColor`.
49
+ * Fire-and-forget — does not block.
50
+ *
51
+ * @example
52
+ * flashBorder(C.B_RED, 3, 150) // explosion — 3 red flashes
53
+ * flashBorder(C.B_GREEN, 2, 200) // level complete
54
+ * flashBorder(C.B_CYAN, 2, 120, C.BLUE) // reset to blue border
55
+ */
56
+ export function flashBorder(color, times, intervalMs, resetColor = C.BLACK) {
57
+ let step = 0;
58
+ const totalSteps = times * 2;
59
+ const id = setInterval(() => {
60
+ document.body.style.backgroundColor = step % 2 === 0 ? color : resetColor;
61
+ step++;
62
+ if (step >= totalSteps) {
63
+ clearInterval(id);
64
+ document.body.style.backgroundColor = resetColor;
65
+ }
66
+ }, intervalMs);
67
+ }
68
+ // cols = total character columns of the canvas (e.g. 32 for standard Spectrum)
69
+ export function drawTextCentered(ctx, text, y, cols, ink, paper) {
70
+ const x = Math.floor((cols - text.length) / 2) * CELL;
71
+ drawText(ctx, text, x, y, ink, paper);
72
+ }
73
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,31 @@
1
1
  {
2
2
  "name": "zx-kit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Reusable ZX Spectrum primitives: font, palette, renderer, audio, input",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./src/index.ts"
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "types": "./dist/index.d.ts"
10
+ }
8
11
  },
9
- "keywords": ["zx-spectrum", "retro", "game", "canvas"],
10
- "license": "MIT"
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "zx-spectrum",
23
+ "retro",
24
+ "game",
25
+ "canvas"
26
+ ],
27
+ "license": "MIT",
28
+ "devDependencies": {
29
+ "typescript": "^6.0.3"
30
+ }
11
31
  }
package/src/audio.ts DELETED
@@ -1,39 +0,0 @@
1
- let ctx: AudioContext | null = null
2
- let masterGain: GainNode | null = null
3
-
4
- export function initAudio(volume = 0.3): void {
5
- if (ctx) return
6
- ctx = new AudioContext()
7
- masterGain = ctx.createGain()
8
- masterGain.gain.value = volume
9
- masterGain.connect(ctx.destination)
10
- }
11
-
12
- export function resumeAudio(): void {
13
- if (ctx && ctx.state === 'suspended') void ctx.resume()
14
- }
15
-
16
- export function getAudioContext(): AudioContext | null {
17
- return ctx
18
- }
19
-
20
- export function getMasterGain(): GainNode | null {
21
- return masterGain
22
- }
23
-
24
- // Core primitive — schedule a square-wave beep on the shared AudioContext
25
- export function beep(freq: number, durationMs: number, startTime: number): void {
26
- if (!ctx || !masterGain) return
27
- const osc = ctx.createOscillator()
28
- const gain = ctx.createGain()
29
- osc.type = 'square'
30
- osc.frequency.value = freq
31
- gain.gain.setValueAtTime(0, startTime)
32
- gain.gain.linearRampToValueAtTime(0.8, startTime + 0.005)
33
- gain.gain.setValueAtTime(0.8, startTime + durationMs / 1000 - 0.005)
34
- gain.gain.linearRampToValueAtTime(0, startTime + durationMs / 1000)
35
- osc.connect(gain)
36
- gain.connect(masterGain)
37
- osc.start(startTime)
38
- osc.stop(startTime + durationMs / 1000 + 0.01)
39
- }
package/src/font.ts DELETED
@@ -1,203 +0,0 @@
1
- // ZX Spectrum ROM font — characters 32–127, 8 bytes per char (row-major, bit7=leftmost pixel)
2
- const RAW: readonly number[] = [
3
- // 32 space
4
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
5
- // 33 !
6
- 0x00,0x10,0x10,0x10,0x10,0x00,0x10,0x00,
7
- // 34 "
8
- 0x00,0x28,0x28,0x00,0x00,0x00,0x00,0x00,
9
- // 35 #
10
- 0x00,0x28,0x7C,0x28,0x28,0x7C,0x28,0x00,
11
- // 36 $
12
- 0x00,0x10,0x3C,0x50,0x3C,0x14,0x7C,0x10,
13
- // 37 %
14
- 0x00,0x62,0x64,0x08,0x10,0x26,0x46,0x00,
15
- // 38 &
16
- 0x00,0x10,0x28,0x10,0x2A,0x44,0x3A,0x00,
17
- // 39 '
18
- 0x00,0x08,0x08,0x00,0x00,0x00,0x00,0x00,
19
- // 40 (
20
- 0x00,0x04,0x08,0x08,0x08,0x08,0x04,0x00,
21
- // 41 )
22
- 0x00,0x20,0x10,0x10,0x10,0x10,0x20,0x00,
23
- // 42 *
24
- 0x00,0x00,0x14,0x08,0x3E,0x08,0x14,0x00,
25
- // 43 +
26
- 0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,
27
- // 44 ,
28
- 0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
29
- // 45 -
30
- 0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
31
- // 46 .
32
- 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
33
- // 47 /
34
- 0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x00,
35
- // 48 0
36
- 0x00,0x3C,0x46,0x4A,0x52,0x62,0x3C,0x00,
37
- // 49 1
38
- 0x00,0x08,0x18,0x08,0x08,0x08,0x1C,0x00,
39
- // 50 2
40
- 0x00,0x3C,0x42,0x04,0x18,0x20,0x7E,0x00,
41
- // 51 3
42
- 0x00,0x3C,0x42,0x0C,0x02,0x42,0x3C,0x00,
43
- // 52 4
44
- 0x00,0x08,0x18,0x28,0x48,0x7E,0x08,0x00,
45
- // 53 5
46
- 0x00,0x7E,0x40,0x7C,0x02,0x42,0x3C,0x00,
47
- // 54 6
48
- 0x00,0x3C,0x40,0x7C,0x42,0x42,0x3C,0x00,
49
- // 55 7
50
- 0x00,0x7E,0x02,0x04,0x08,0x10,0x10,0x00,
51
- // 56 8
52
- 0x00,0x3C,0x42,0x3C,0x42,0x42,0x3C,0x00,
53
- // 57 9
54
- 0x00,0x3C,0x42,0x42,0x3E,0x02,0x3C,0x00,
55
- // 58 :
56
- 0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,
57
- // 59 ;
58
- 0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x20,
59
- // 60 <
60
- 0x00,0x04,0x08,0x10,0x08,0x04,0x00,0x00,
61
- // 61 =
62
- 0x00,0x00,0x00,0x7C,0x00,0x7C,0x00,0x00,
63
- // 62 >
64
- 0x00,0x20,0x10,0x08,0x10,0x20,0x00,0x00,
65
- // 63 ?
66
- 0x00,0x3C,0x42,0x04,0x08,0x00,0x08,0x00,
67
- // 64 @
68
- 0x00,0x3C,0x4A,0x56,0x5C,0x40,0x3C,0x00,
69
- // 65 A
70
- 0x00,0x18,0x24,0x42,0x7E,0x42,0x42,0x00,
71
- // 66 B
72
- 0x00,0x7C,0x42,0x7C,0x42,0x42,0x7C,0x00,
73
- // 67 C
74
- 0x00,0x3C,0x42,0x40,0x40,0x42,0x3C,0x00,
75
- // 68 D
76
- 0x00,0x78,0x44,0x42,0x42,0x44,0x78,0x00,
77
- // 69 E
78
- 0x00,0x7E,0x40,0x7C,0x40,0x40,0x7E,0x00,
79
- // 70 F
80
- 0x00,0x7E,0x40,0x7C,0x40,0x40,0x40,0x00,
81
- // 71 G
82
- 0x00,0x3C,0x42,0x40,0x4E,0x42,0x3C,0x00,
83
- // 72 H
84
- 0x00,0x42,0x42,0x7E,0x42,0x42,0x42,0x00,
85
- // 73 I
86
- 0x00,0x3E,0x08,0x08,0x08,0x08,0x3E,0x00,
87
- // 74 J
88
- 0x00,0x02,0x02,0x02,0x02,0x42,0x3C,0x00,
89
- // 75 K
90
- 0x00,0x44,0x48,0x70,0x48,0x44,0x42,0x00,
91
- // 76 L
92
- 0x00,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,
93
- // 77 M
94
- 0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x00,
95
- // 78 N
96
- 0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x00,
97
- // 79 O
98
- 0x00,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,
99
- // 80 P
100
- 0x00,0x7C,0x42,0x42,0x7C,0x40,0x40,0x00,
101
- // 81 Q
102
- 0x00,0x3C,0x42,0x42,0x4A,0x44,0x3A,0x00,
103
- // 82 R
104
- 0x00,0x7C,0x42,0x42,0x7C,0x48,0x44,0x00,
105
- // 83 S
106
- 0x00,0x3C,0x40,0x3C,0x02,0x42,0x3C,0x00,
107
- // 84 T
108
- 0x00,0x7E,0x08,0x08,0x08,0x08,0x08,0x00,
109
- // 85 U
110
- 0x00,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,
111
- // 86 V
112
- 0x00,0x42,0x42,0x42,0x42,0x24,0x18,0x00,
113
- // 87 W
114
- 0x00,0x42,0x42,0x42,0x5A,0x66,0x42,0x00,
115
- // 88 X
116
- 0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00,
117
- // 89 Y
118
- 0x00,0x42,0x42,0x24,0x18,0x08,0x08,0x00,
119
- // 90 Z
120
- 0x00,0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,
121
- // 91 [
122
- 0x00,0x1C,0x10,0x10,0x10,0x10,0x1C,0x00,
123
- // 92 backslash
124
- 0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x00,
125
- // 93 ]
126
- 0x00,0x38,0x08,0x08,0x08,0x08,0x38,0x00,
127
- // 94 ^
128
- 0x00,0x08,0x14,0x22,0x00,0x00,0x00,0x00,
129
- // 95 _
130
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,
131
- // 96 `
132
- 0x00,0x10,0x08,0x00,0x00,0x00,0x00,0x00,
133
- // 97 a
134
- 0x00,0x00,0x3C,0x02,0x3E,0x42,0x3E,0x00,
135
- // 98 b
136
- 0x00,0x20,0x20,0x3E,0x22,0x22,0x3E,0x00,
137
- // 99 c
138
- 0x00,0x00,0x1E,0x20,0x20,0x20,0x1E,0x00,
139
- // 100 d
140
- 0x00,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,
141
- // 101 e
142
- 0x00,0x00,0x3C,0x42,0x7E,0x40,0x3C,0x00,
143
- // 102 f
144
- 0x00,0x0C,0x10,0x3C,0x10,0x10,0x10,0x00,
145
- // 103 g
146
- 0x00,0x00,0x3E,0x42,0x42,0x3E,0x02,0x3C,
147
- // 104 h
148
- 0x00,0x20,0x20,0x2C,0x32,0x22,0x22,0x00,
149
- // 105 i
150
- 0x00,0x08,0x00,0x18,0x08,0x08,0x1C,0x00,
151
- // 106 j
152
- 0x00,0x04,0x00,0x0C,0x04,0x04,0x44,0x38,
153
- // 107 k
154
- 0x00,0x20,0x28,0x30,0x28,0x24,0x22,0x00,
155
- // 108 l
156
- 0x00,0x18,0x08,0x08,0x08,0x08,0x1C,0x00,
157
- // 109 m
158
- 0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x00,
159
- // 110 n
160
- 0x00,0x00,0x2C,0x32,0x22,0x22,0x22,0x00,
161
- // 111 o
162
- 0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x00,
163
- // 112 p
164
- 0x00,0x00,0x3C,0x22,0x22,0x3C,0x20,0x20,
165
- // 113 q
166
- 0x00,0x00,0x1E,0x22,0x22,0x1E,0x02,0x02,
167
- // 114 r
168
- 0x00,0x00,0x2C,0x30,0x20,0x20,0x20,0x00,
169
- // 115 s
170
- 0x00,0x00,0x1E,0x20,0x1C,0x02,0x3C,0x00,
171
- // 116 t
172
- 0x00,0x10,0x7C,0x10,0x10,0x12,0x0C,0x00,
173
- // 117 u
174
- 0x00,0x00,0x22,0x22,0x22,0x26,0x1A,0x00,
175
- // 118 v
176
- 0x00,0x00,0x42,0x42,0x42,0x24,0x18,0x00,
177
- // 119 w
178
- 0x00,0x00,0x42,0x42,0x49,0x55,0x22,0x00,
179
- // 120 x
180
- 0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,
181
- // 121 y
182
- 0x00,0x00,0x44,0x44,0x44,0x3C,0x04,0x38,
183
- // 122 z
184
- 0x00,0x00,0x7E,0x04,0x18,0x20,0x7E,0x00,
185
- // 123 {
186
- 0x00,0x0C,0x10,0x60,0x10,0x10,0x0C,0x00,
187
- // 124 |
188
- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00,
189
- // 125 }
190
- 0x00,0x30,0x08,0x06,0x08,0x08,0x30,0x00,
191
- // 126 ~
192
- 0x00,0x00,0x32,0x4C,0x00,0x00,0x00,0x00,
193
- // 127 solid block (used for lives / filled blocks)
194
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
195
- ]
196
-
197
- export const FONT = new Uint8Array(RAW)
198
-
199
- export function getCharRow(charCode: number, row: number): number {
200
- const idx = charCode - 32
201
- if (idx < 0 || idx >= 96) return 0
202
- return FONT[idx * 8 + row]
203
- }
package/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from './palette.ts'
2
- export * from './font.ts'
3
- export * from './renderer.ts'
4
- export * from './audio.ts'
5
- export * from './input.ts'
package/src/input.ts DELETED
@@ -1,77 +0,0 @@
1
- export type Direction = 'up' | 'down' | 'left' | 'right'
2
-
3
- const DIR_KEYS: Record<string, Direction> = {
4
- ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right',
5
- }
6
-
7
- const held = new Set<string>()
8
- let pendingFlag = false
9
- let pendingDebug = false
10
- let pendingPause = false
11
- let pendingAnyKey = false
12
-
13
- let repeatDir: Direction | null = null
14
- let repeatTimer = 0
15
- let repeatPhase: 'delay' | 'repeat' | 'idle' = 'idle'
16
- let pendingImmediate: Direction | null = null
17
- let _repeatDelay = 150
18
- let _repeatInterval = 80
19
-
20
- export function initInput(repeatDelay = 150, repeatInterval = 80): void {
21
- _repeatDelay = repeatDelay
22
- _repeatInterval = repeatInterval
23
-
24
- window.addEventListener('keydown', (e: KeyboardEvent) => {
25
- if (e.repeat) return
26
- pendingAnyKey = true
27
- held.add(e.key)
28
-
29
- const dir = DIR_KEYS[e.key]
30
- if (dir) {
31
- repeatDir = dir
32
- repeatPhase = 'delay'
33
- repeatTimer = _repeatDelay
34
- pendingImmediate = dir
35
- }
36
-
37
- if (e.key === 'f' || e.key === 'F') pendingFlag = true
38
- if (e.key === 'p' || e.key === 'P') pendingPause = true
39
-
40
- if (e.ctrlKey && e.shiftKey && (e.key === 'b' || e.key === 'B')) {
41
- pendingDebug = true
42
- e.preventDefault()
43
- }
44
- })
45
-
46
- window.addEventListener('keyup', (e: KeyboardEvent) => {
47
- held.delete(e.key)
48
- const dir = DIR_KEYS[e.key]
49
- if (dir && repeatDir === dir) {
50
- repeatDir = null
51
- repeatPhase = 'idle'
52
- }
53
- })
54
- }
55
-
56
- export function tickMovement(dtMs: number): Direction | null {
57
- if (pendingImmediate !== null) {
58
- const d = pendingImmediate
59
- pendingImmediate = null
60
- return d
61
- }
62
- if (repeatDir !== null && repeatPhase !== 'idle') {
63
- repeatTimer -= dtMs
64
- if (repeatTimer <= 0) {
65
- repeatTimer += _repeatInterval
66
- if (repeatPhase === 'delay') repeatPhase = 'repeat'
67
- return repeatDir
68
- }
69
- }
70
- return null
71
- }
72
-
73
- export function consumeFlag(): boolean { const v = pendingFlag; pendingFlag = false; return v }
74
- export function consumeDebug(): boolean { const v = pendingDebug; pendingDebug = false; return v }
75
- export function consumePause(): boolean { const v = pendingPause; pendingPause = false; return v }
76
- export function consumeAnyKey(): boolean { const v = pendingAnyKey; pendingAnyKey = false; return v }
77
- export function isHeld(key: string): boolean { return held.has(key) }
package/src/palette.ts DELETED
@@ -1,24 +0,0 @@
1
- export const SCALE = 4
2
- export const CELL = 8
3
-
4
- // ZX Spectrum palette — exactly 15 colours, EXCLUSIVELY these hex values
5
- export const C = {
6
- BLACK: '#000000',
7
- BLUE: '#0000CD',
8
- RED: '#CD0000',
9
- MAGENTA: '#CD00CD',
10
- GREEN: '#00CD00',
11
- CYAN: '#00CDCD',
12
- YELLOW: '#CDCD00',
13
- WHITE: '#CDCDCD',
14
- B_BLACK: '#000000',
15
- B_BLUE: '#0000FF',
16
- B_RED: '#FF0000',
17
- B_MAGENTA: '#FF00FF',
18
- B_GREEN: '#00FF00',
19
- B_CYAN: '#00FFFF',
20
- B_YELLOW: '#FFFF00',
21
- B_WHITE: '#FFFFFF',
22
- } as const
23
-
24
- export type SpectrumColor = typeof C[keyof typeof C]
package/src/renderer.ts DELETED
@@ -1,74 +0,0 @@
1
- import { CELL } from './palette.ts'
2
- import { getCharRow } from './font.ts'
3
-
4
- // Flip an 8×8 sprite horizontally
5
- export function mirrorSprite(src: Uint8Array): Uint8Array {
6
- const out = new Uint8Array(8)
7
- for (let r = 0; r < 8; r++) {
8
- let b = src[r], m = 0
9
- for (let i = 0; i < 8; i++) {
10
- if (b & (1 << i)) m |= (1 << (7 - i))
11
- }
12
- out[r] = m
13
- }
14
- return out
15
- }
16
-
17
- export function drawSprite(
18
- ctx: CanvasRenderingContext2D,
19
- sprite: Uint8Array,
20
- x: number, y: number,
21
- ink: string, paper: string,
22
- ): void {
23
- ctx.fillStyle = paper
24
- ctx.fillRect(x, y, CELL, CELL)
25
- ctx.fillStyle = ink
26
- for (let row = 0; row < 8; row++) {
27
- const byte = sprite[row]
28
- for (let bit = 0; bit < 8; bit++) {
29
- if (byte & (0x80 >> bit)) ctx.fillRect(x + bit, y + row, 1, 1)
30
- }
31
- }
32
- }
33
-
34
- export function drawChar(
35
- ctx: CanvasRenderingContext2D,
36
- code: number,
37
- x: number, y: number,
38
- ink: string, paper?: string,
39
- ): void {
40
- if (paper !== undefined) {
41
- ctx.fillStyle = paper
42
- ctx.fillRect(x, y, CELL, CELL)
43
- }
44
- ctx.fillStyle = ink
45
- for (let row = 0; row < 8; row++) {
46
- const byte = getCharRow(code, row)
47
- for (let bit = 0; bit < 8; bit++) {
48
- if (byte & (0x80 >> bit)) ctx.fillRect(x + bit, y + row, 1, 1)
49
- }
50
- }
51
- }
52
-
53
- export function drawText(
54
- ctx: CanvasRenderingContext2D,
55
- text: string,
56
- x: number, y: number,
57
- ink: string, paper?: string,
58
- ): void {
59
- for (let i = 0; i < text.length; i++) {
60
- drawChar(ctx, text.charCodeAt(i), x + i * CELL, y, ink, paper)
61
- }
62
- }
63
-
64
- // cols = total character columns of the canvas (e.g. 32 for standard Spectrum)
65
- export function drawTextCentered(
66
- ctx: CanvasRenderingContext2D,
67
- text: string,
68
- y: number,
69
- cols: number,
70
- ink: string, paper?: string,
71
- ): void {
72
- const x = Math.floor((cols - text.length) / 2) * CELL
73
- drawText(ctx, text, x, y, ink, paper)
74
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2023",
4
- "module": "esnext",
5
- "lib": ["ES2023", "DOM"],
6
- "moduleResolution": "bundler",
7
- "allowImportingTsExtensions": true,
8
- "verbatimModuleSyntax": true,
9
- "moduleDetection": "force",
10
- "noEmit": true,
11
- "strict": true,
12
- "noUnusedLocals": true,
13
- "noUnusedParameters": true
14
- },
15
- "include": ["src"]
16
- }