like2d 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +66 -0
  2. package/dist/audio.d.ts +52 -0
  3. package/dist/audio.d.ts.map +1 -0
  4. package/dist/audio.js +250 -0
  5. package/dist/events.d.ts +36 -0
  6. package/dist/events.d.ts.map +1 -0
  7. package/dist/events.js +1 -0
  8. package/dist/gamecontrollerdb.txt +2219 -0
  9. package/dist/gamepad-button-map.d.ts +5 -0
  10. package/dist/gamepad-button-map.d.ts.map +1 -0
  11. package/dist/gamepad-button-map.js +56 -0
  12. package/dist/gamepad-db.d.ts +49 -0
  13. package/dist/gamepad-db.d.ts.map +1 -0
  14. package/dist/gamepad-db.js +192 -0
  15. package/dist/gamepad-mapping.d.ts +31 -0
  16. package/dist/gamepad-mapping.d.ts.map +1 -0
  17. package/dist/gamepad-mapping.js +191 -0
  18. package/dist/gamepad.d.ts +56 -0
  19. package/dist/gamepad.d.ts.map +1 -0
  20. package/dist/gamepad.js +216 -0
  21. package/dist/graphics.d.ts +80 -0
  22. package/dist/graphics.d.ts.map +1 -0
  23. package/dist/graphics.js +388 -0
  24. package/dist/index.d.ts +45 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +250 -0
  27. package/dist/input-state.d.ts +14 -0
  28. package/dist/input-state.d.ts.map +1 -0
  29. package/dist/input-state.js +50 -0
  30. package/dist/input.d.ts +36 -0
  31. package/dist/input.d.ts.map +1 -0
  32. package/dist/input.js +127 -0
  33. package/dist/keyboard.d.ts +9 -0
  34. package/dist/keyboard.d.ts.map +1 -0
  35. package/dist/keyboard.js +33 -0
  36. package/dist/mouse.d.ts +20 -0
  37. package/dist/mouse.d.ts.map +1 -0
  38. package/dist/mouse.js +84 -0
  39. package/dist/rect.d.ts +27 -0
  40. package/dist/rect.d.ts.map +1 -0
  41. package/dist/rect.js +132 -0
  42. package/dist/scene.d.ts +10 -0
  43. package/dist/scene.d.ts.map +1 -0
  44. package/dist/scene.js +1 -0
  45. package/dist/timer.d.ts +19 -0
  46. package/dist/timer.d.ts.map +1 -0
  47. package/dist/timer.js +86 -0
  48. package/dist/vector2.d.ts +32 -0
  49. package/dist/vector2.d.ts.map +1 -0
  50. package/dist/vector2.js +105 -0
  51. package/package.json +64 -0
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # LÏKE2D Framework Library
2
+
3
+ You've reached the more detailed docs for this framework.
4
+ For now, the source code is the best API docs we have.
5
+
6
+ ## Features of LIKE
7
+
8
+ **Stateless Canvas API**
9
+
10
+ JS canvas has state to keep track of like color and line width.
11
+ LIKE abstracts that away so it's easy to reason about.
12
+
13
+ **Fire-and-forget asset loading**
14
+
15
+ Loading sound and images in Vanilla JS is clunky and can interrupt your game loop.
16
+ LIKE has synchronous asset handles and abstracts away the clunkiness.
17
+
18
+ **Zero boilerplate, physical game input**
19
+
20
+ LIKE does the input boilerplate for you.
21
+ - Keeping track of what's held/pressed.
22
+ - Controller mapping by physical location. Not every A is in the same spot.
23
+ - Mapping inputs into actions for easy remapping.
24
+
25
+ **Declarative event system**
26
+
27
+ Don't bother juggling stateful listeners.
28
+ LIKE keeps event handling simple by running it all through a single callback.
29
+
30
+ **Build it how you want it**
31
+
32
+ It's not an engine, it's a framework.
33
+ For new developers, this means making simple games easily: no engine, no problem!
34
+ For others, get to work faster making your own specialized tooling, engine, and more,
35
+ all without banging your head on browser APIs.
36
+
37
+ ## Getting started
38
+
39
+ TODO: fill this in.
40
+
41
+ Then run:
42
+ ```bash
43
+ pnpm install
44
+ pnpm run dev
45
+ ```
46
+
47
+ ## For LOVE developers
48
+
49
+ LIKE is not compatible with LOVE.
50
+
51
+ To summarize the differences:
52
+ - We don't keep track of color etc. as state (via setColor, etc.), so it gets passed in each draw call.
53
+ - We use objects for optional arguments, and avoid function overloading.
54
+ - We make use of tuples for passing around colors, coordinates, and rects.
55
+ - In LOVE, Callbacks such as `love.keypressed` needed to be wrapped in order to make Scenes. This pattern is part of LIKE.
56
+ - 2d Canvas so, no shaders.
57
+ - No built-in physics.
58
+
59
+ ## Full Disclosure about AI
60
+
61
+ Yes, this framework was created with the help of heavily supervised AI.
62
+
63
+ Virtually every design decision was made by me, and I have micro-managed the code output.
64
+
65
+ Over time, I will rewrite parts of it by hand as desired. Possibly the whole thing.
66
+
@@ -0,0 +1,52 @@
1
+ export interface SourceOptions {
2
+ volume?: number;
3
+ pitch?: number;
4
+ looping?: boolean;
5
+ }
6
+ export declare class Source {
7
+ private audio;
8
+ private _volume;
9
+ private _pitch;
10
+ private _looping;
11
+ private path;
12
+ private isLoaded;
13
+ private loadPromise;
14
+ private globalVolume;
15
+ constructor(path: string, options?: SourceOptions);
16
+ _setGlobalVolume(vol: number): void;
17
+ ready(): Promise<void>;
18
+ private updatePlaybackRate;
19
+ play(): boolean;
20
+ stop(): void;
21
+ pause(): void;
22
+ resume(): boolean;
23
+ seek(position: number): void;
24
+ tell(): number;
25
+ getDuration(): number;
26
+ isPlaying(): boolean;
27
+ isPaused(): boolean;
28
+ isStopped(): boolean;
29
+ isReady(): boolean;
30
+ setVolume(volume: number): void;
31
+ getVolume(): number;
32
+ setPitch(pitch: number): void;
33
+ getPitch(): number;
34
+ setLooping(looping: boolean): void;
35
+ isLooping(): boolean;
36
+ clone(): Source;
37
+ }
38
+ export declare class Audio {
39
+ private sources;
40
+ private globalVolume;
41
+ newSource(path: string, options?: SourceOptions): Source;
42
+ play(source: Source): boolean;
43
+ stop(source?: Source): void;
44
+ pause(source?: Source): void;
45
+ resume(source?: Source): void;
46
+ setVolume(volume: number): void;
47
+ getVolume(): number;
48
+ getActiveSourceCount(): number;
49
+ getActiveSources(): Source[];
50
+ }
51
+ export declare const audio: Audio;
52
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,YAAY,CAAa;gBAErB,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IA6BrD,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,OAAO,CAAC,kBAAkB;IAI1B,IAAI,IAAI,OAAO;IAoBf,IAAI,IAAI,IAAI;IAKZ,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,OAAO;IAOjB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI5B,IAAI,IAAI,MAAM;IAId,WAAW,IAAI,MAAM;IAIrB,SAAS,IAAI,OAAO;IAIpB,QAAQ,IAAI,OAAO;IAInB,SAAS,IAAI,OAAO;IAIpB,OAAO,IAAI,OAAO;IAIlB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/B,SAAS,IAAI,MAAM;IAInB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,QAAQ,IAAI,MAAM;IAIlB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKlC,SAAS,IAAI,OAAO;IAIpB,KAAK,IAAI,MAAM;CAShB;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,YAAY,CAAa;IAEjC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM;IAOxD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI7B,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ3B,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAY5B,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAY7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,SAAS,IAAI,MAAM;IAInB,oBAAoB,IAAI,MAAM;IAU9B,gBAAgB,IAAI,MAAM,EAAE;CAS7B;AAED,eAAO,MAAM,KAAK,OAAc,CAAC"}
package/dist/audio.js ADDED
@@ -0,0 +1,250 @@
1
+ export class Source {
2
+ constructor(path, options = {}) {
3
+ Object.defineProperty(this, "audio", {
4
+ enumerable: true,
5
+ configurable: true,
6
+ writable: true,
7
+ value: void 0
8
+ });
9
+ Object.defineProperty(this, "_volume", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: 1
14
+ });
15
+ Object.defineProperty(this, "_pitch", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: 1
20
+ });
21
+ Object.defineProperty(this, "_looping", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: false
26
+ });
27
+ Object.defineProperty(this, "path", {
28
+ enumerable: true,
29
+ configurable: true,
30
+ writable: true,
31
+ value: void 0
32
+ });
33
+ Object.defineProperty(this, "isLoaded", {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: false
38
+ });
39
+ Object.defineProperty(this, "loadPromise", {
40
+ enumerable: true,
41
+ configurable: true,
42
+ writable: true,
43
+ value: void 0
44
+ });
45
+ Object.defineProperty(this, "globalVolume", {
46
+ enumerable: true,
47
+ configurable: true,
48
+ writable: true,
49
+ value: 1
50
+ });
51
+ this.path = path;
52
+ this.audio = document.createElement('audio');
53
+ this.audio.src = path;
54
+ this._volume = options.volume ?? 1;
55
+ this._pitch = options.pitch ?? 1;
56
+ this._looping = options.looping ?? false;
57
+ this.audio.volume = this._volume;
58
+ this.audio.loop = this._looping;
59
+ this.updatePlaybackRate();
60
+ this.loadPromise = new Promise((resolve, reject) => {
61
+ this.audio.oncanplaythrough = () => {
62
+ this.isLoaded = true;
63
+ resolve();
64
+ };
65
+ this.audio.onerror = () => {
66
+ reject(new Error(`Failed to load audio: ${path}`));
67
+ };
68
+ if (this.audio.readyState >= 4) {
69
+ this.isLoaded = true;
70
+ resolve();
71
+ }
72
+ });
73
+ }
74
+ _setGlobalVolume(vol) {
75
+ this.globalVolume = vol;
76
+ this.audio.volume = this._volume * this.globalVolume;
77
+ }
78
+ ready() {
79
+ return this.loadPromise;
80
+ }
81
+ updatePlaybackRate() {
82
+ this.audio.playbackRate = this._pitch;
83
+ }
84
+ play() {
85
+ if (!this.isLoaded) {
86
+ // Silently return false - asset not loaded yet
87
+ return false;
88
+ }
89
+ // Only reset to beginning if stopped (not paused)
90
+ if (this.isStopped() || this.audio.ended) {
91
+ this.audio.currentTime = 0;
92
+ }
93
+ const playPromise = this.audio.play();
94
+ if (playPromise) {
95
+ playPromise.catch(err => {
96
+ console.warn(`Failed to play audio "${this.path}":`, err.message);
97
+ });
98
+ }
99
+ return true;
100
+ }
101
+ stop() {
102
+ this.audio.pause();
103
+ this.audio.currentTime = 0;
104
+ }
105
+ pause() {
106
+ this.audio.pause();
107
+ }
108
+ resume() {
109
+ if (this.audio.paused) {
110
+ return this.play();
111
+ }
112
+ return false;
113
+ }
114
+ seek(position) {
115
+ this.audio.currentTime = position;
116
+ }
117
+ tell() {
118
+ return this.audio.currentTime;
119
+ }
120
+ getDuration() {
121
+ return this.audio.duration || 0;
122
+ }
123
+ isPlaying() {
124
+ return !this.audio.paused && !this.audio.ended;
125
+ }
126
+ isPaused() {
127
+ return this.audio.paused && this.audio.currentTime > 0;
128
+ }
129
+ isStopped() {
130
+ return this.audio.paused && this.audio.currentTime === 0;
131
+ }
132
+ isReady() {
133
+ return this.isLoaded;
134
+ }
135
+ setVolume(volume) {
136
+ this._volume = Math.max(0, Math.min(1, volume));
137
+ this.audio.volume = this._volume * this.globalVolume;
138
+ }
139
+ getVolume() {
140
+ return this._volume;
141
+ }
142
+ setPitch(pitch) {
143
+ this._pitch = Math.max(0.125, Math.min(8, pitch));
144
+ this.updatePlaybackRate();
145
+ }
146
+ getPitch() {
147
+ return this._pitch;
148
+ }
149
+ setLooping(looping) {
150
+ this._looping = looping;
151
+ this.audio.loop = looping;
152
+ }
153
+ isLooping() {
154
+ return this._looping;
155
+ }
156
+ clone() {
157
+ const clone = new Source(this.path, {
158
+ volume: this._volume,
159
+ pitch: this._pitch,
160
+ looping: this._looping
161
+ });
162
+ clone._setGlobalVolume(this.globalVolume);
163
+ return clone;
164
+ }
165
+ }
166
+ export class Audio {
167
+ constructor() {
168
+ Object.defineProperty(this, "sources", {
169
+ enumerable: true,
170
+ configurable: true,
171
+ writable: true,
172
+ value: new Set()
173
+ });
174
+ Object.defineProperty(this, "globalVolume", {
175
+ enumerable: true,
176
+ configurable: true,
177
+ writable: true,
178
+ value: 1
179
+ });
180
+ }
181
+ newSource(path, options) {
182
+ const source = new Source(path, options);
183
+ source._setGlobalVolume(this.globalVolume);
184
+ this.sources.add(source);
185
+ return source;
186
+ }
187
+ play(source) {
188
+ return source.play();
189
+ }
190
+ stop(source) {
191
+ if (source) {
192
+ source.stop();
193
+ }
194
+ else {
195
+ this.sources.forEach(s => s.stop());
196
+ }
197
+ }
198
+ pause(source) {
199
+ if (source) {
200
+ source.pause();
201
+ }
202
+ else {
203
+ this.sources.forEach(s => {
204
+ if (s.isPlaying()) {
205
+ s.pause();
206
+ }
207
+ });
208
+ }
209
+ }
210
+ resume(source) {
211
+ if (source) {
212
+ source.resume();
213
+ }
214
+ else {
215
+ this.sources.forEach(s => {
216
+ if (s.isPaused()) {
217
+ s.resume();
218
+ }
219
+ });
220
+ }
221
+ }
222
+ setVolume(volume) {
223
+ this.globalVolume = Math.max(0, Math.min(1, volume));
224
+ this.sources.forEach(source => {
225
+ source._setGlobalVolume(this.globalVolume);
226
+ });
227
+ }
228
+ getVolume() {
229
+ return this.globalVolume;
230
+ }
231
+ getActiveSourceCount() {
232
+ let count = 0;
233
+ this.sources.forEach(source => {
234
+ if (source.isPlaying()) {
235
+ count++;
236
+ }
237
+ });
238
+ return count;
239
+ }
240
+ getActiveSources() {
241
+ const active = [];
242
+ this.sources.forEach(source => {
243
+ if (source.isPlaying()) {
244
+ active.push(source);
245
+ }
246
+ });
247
+ return active;
248
+ }
249
+ }
250
+ export const audio = new Audio();
@@ -0,0 +1,36 @@
1
+ export type Event = {
2
+ type: 'keypressed';
3
+ scancode: string;
4
+ keycode: string;
5
+ } | {
6
+ type: 'keyreleased';
7
+ scancode: string;
8
+ keycode: string;
9
+ } | {
10
+ type: 'mousepressed';
11
+ x: number;
12
+ y: number;
13
+ button: number;
14
+ } | {
15
+ type: 'mousereleased';
16
+ x: number;
17
+ y: number;
18
+ button: number;
19
+ } | {
20
+ type: 'actionpressed';
21
+ action: string;
22
+ } | {
23
+ type: 'actionreleased';
24
+ action: string;
25
+ } | {
26
+ type: 'gamepadpressed';
27
+ gamepadIndex: number;
28
+ buttonIndex: number;
29
+ buttonName: string;
30
+ } | {
31
+ type: 'gamepadreleased';
32
+ gamepadIndex: number;
33
+ buttonIndex: number;
34
+ buttonName: string;
35
+ };
36
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC"}
package/dist/events.js ADDED
@@ -0,0 +1 @@
1
+ export {};