@oidoid/void 0.1.0-1

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 (66) hide show
  1. package/bin/ase +14 -0
  2. package/dist/atlas/aseprite.d.ts +37 -0
  3. package/dist/atlas/aseprite.js +2 -0
  4. package/dist/atlas/aseprite.js.map +1 -0
  5. package/dist/atlas/atlas.d.ts +20 -0
  6. package/dist/atlas/atlas.js +68 -0
  7. package/dist/atlas/atlas.js.map +1 -0
  8. package/dist/audio/synth.d.ts +4 -0
  9. package/dist/audio/synth.js +21 -0
  10. package/dist/audio/synth.js.map +1 -0
  11. package/dist/graphics/bitmap.d.ts +14 -0
  12. package/dist/graphics/bitmap.js +14 -0
  13. package/dist/graphics/bitmap.js.map +1 -0
  14. package/dist/graphics/cam.d.ts +16 -0
  15. package/dist/graphics/cam.js +42 -0
  16. package/dist/graphics/cam.js.map +1 -0
  17. package/dist/graphics/frag.glsl.d.ts +1 -0
  18. package/dist/graphics/frag.glsl.js +15 -0
  19. package/dist/graphics/frag.glsl.js.map +1 -0
  20. package/dist/graphics/frame-listener.d.ts +16 -0
  21. package/dist/graphics/frame-listener.js +83 -0
  22. package/dist/graphics/frame-listener.js.map +1 -0
  23. package/dist/graphics/renderer.d.ts +12 -0
  24. package/dist/graphics/renderer.js +184 -0
  25. package/dist/graphics/renderer.js.map +1 -0
  26. package/dist/graphics/vert.glsl.d.ts +1 -0
  27. package/dist/graphics/vert.glsl.js +46 -0
  28. package/dist/graphics/vert.glsl.js.map +1 -0
  29. package/dist/index.d.ts +32 -0
  30. package/dist/index.js +79 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/input/gamepad-poller.d.ts +8 -0
  33. package/dist/input/gamepad-poller.js +38 -0
  34. package/dist/input/gamepad-poller.js.map +1 -0
  35. package/dist/input/input.d.ts +44 -0
  36. package/dist/input/input.js +175 -0
  37. package/dist/input/input.js.map +1 -0
  38. package/dist/input/keyboard-poller.d.ts +7 -0
  39. package/dist/input/keyboard-poller.js +30 -0
  40. package/dist/input/keyboard-poller.js.map +1 -0
  41. package/dist/input/pointer-poller.d.ts +12 -0
  42. package/dist/input/pointer-poller.js +67 -0
  43. package/dist/input/pointer-poller.js.map +1 -0
  44. package/dist/sprite/sprite.d.ts +51 -0
  45. package/dist/sprite/sprite.js +161 -0
  46. package/dist/sprite/sprite.js.map +1 -0
  47. package/dist/storage/json-storage.d.ts +4 -0
  48. package/dist/storage/json-storage.js +13 -0
  49. package/dist/storage/json-storage.js.map +1 -0
  50. package/dist/test/tsconfig.json +13 -0
  51. package/dist/text/font.d.ts +6 -0
  52. package/dist/text/font.js +18 -0
  53. package/dist/text/font.js.map +1 -0
  54. package/dist/text/text-layout.d.ts +11 -0
  55. package/dist/text/text-layout.js +73 -0
  56. package/dist/text/text-layout.js.map +1 -0
  57. package/dist/tsconfig.json +12 -0
  58. package/dist/types/2d.d.ts +9 -0
  59. package/dist/types/2d.js +2 -0
  60. package/dist/types/2d.js.map +1 -0
  61. package/dist/void.js +60 -0
  62. package/dist/void.js.map +7 -0
  63. package/dist/void.meta.json +294 -0
  64. package/license.text +661 -0
  65. package/package.json +73 -0
  66. package/readme.md +33 -0
@@ -0,0 +1,46 @@
1
+ export const vertGLSL = `#version 300 es
2
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2
3
+ uniform lowp usampler2D uCels;
4
+ uniform mediump ivec4 uCam;
5
+ uniform highp uint uFrame;
6
+
7
+ layout (location=0) in lowp ivec2 iUV;
8
+ layout (location=1) in highp uint iXY;
9
+ layout (location=2) in highp uint iWH;
10
+ layout (location=3) in highp uint iIFFZZ;
11
+
12
+ flat out highp ivec4 vTexXYWH;
13
+ out highp vec2 vDstWH;
14
+
15
+ const mediump int maxY = 0x1000;
16
+ const lowp int maxZ = 8;
17
+ const mediump int maxDepth = maxY * maxZ;
18
+
19
+ void main() {
20
+ mediump int x = int(iXY) >> 19;
21
+ mediump int y = int(iXY << 16) >> 19;
22
+ lowp int z = int(iIFFZZ & 0x7u);
23
+ bool zend = bool(iIFFZZ & 0x8u);
24
+ bool flipX = bool(iIFFZZ & 0x20u);
25
+ bool flipY = bool(iIFFZZ & 0x10u);
26
+ mediump int id = int((iIFFZZ >> 6) & 0x7ff0u);
27
+ lowp int cel = int((iIFFZZ >> 6) & 0xfu);
28
+ mediump int w = int((iWH >> 12) & 0xfffu);
29
+ mediump int h = int(iWH & 0xfffu);
30
+
31
+ lowp int frame = ((int(uFrame) - cel) / 4) & 0xf;
32
+ mediump uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);
33
+
34
+ // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel
35
+ highp float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);
36
+
37
+ highp ivec2 targetWH = ivec2(iUV) * ivec2(w, h);
38
+ highp ivec2 origWH = ivec2(iUV) * ivec2(texXYWH.zw);
39
+
40
+ highp vec2 end = vec2(x + targetWH.x, y + targetWH.y);
41
+ highp vec2 clip = ((-2. * vec2(uCam.xy) + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);
42
+ gl_Position = vec4(clip, depth, 1);
43
+ vTexXYWH = ivec4(texXYWH);
44
+ vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));
45
+ }`;
46
+ //# sourceMappingURL=vert.glsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vert.glsl.js","sourceRoot":"","sources":["../../src/graphics/vert.glsl.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CtB,CAAA"}
@@ -0,0 +1,32 @@
1
+ import type { AnimTag } from './atlas/aseprite.js';
2
+ import type { Atlas } from './atlas/atlas.js';
3
+ import { Synth } from './audio/synth.js';
4
+ import { type Bitmap } from './graphics/bitmap.js';
5
+ import { Cam } from './graphics/cam.js';
6
+ import { Input, type StandardButton } from './input/input.js';
7
+ import { Sprite } from './sprite/sprite.js';
8
+ import { JSONStorage } from './storage/json-storage.js';
9
+ export type { Font } from 'mem-font';
10
+ export type { AnimTag } from './atlas/aseprite.js';
11
+ export type { Atlas } from './atlas/atlas.js';
12
+ export { Sprite } from './sprite/sprite.js';
13
+ export type { SpriteJSON } from './sprite/sprite.js';
14
+ export { fontCharToTag } from './text/font.js';
15
+ export { layoutText, type TextLayout } from './text/text-layout.js';
16
+ export type { Box, WH, XY } from './types/2d.js';
17
+ export declare class Void<Tag extends AnimTag = AnimTag, Button extends string = StandardButton> {
18
+ #private;
19
+ static new<Tag extends AnimTag = AnimTag, Button extends string = StandardButton>(): Promise<Void<Tag, Button>>;
20
+ readonly atlas: Atlas<Tag>;
21
+ readonly cam: Cam;
22
+ readonly ctrl: Input<Button>;
23
+ readonly kv: JSONStorage;
24
+ readonly synth: Synth;
25
+ constructor(spritesheet: HTMLImageElement);
26
+ set background(rgba: number);
27
+ blit(bmp: Readonly<Bitmap>): void;
28
+ get frame(): number;
29
+ render(loop?: () => void): void;
30
+ sprite(tag: Tag): Sprite<Tag>;
31
+ stop(): void;
32
+ }
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ import { Synth } from './audio/synth.js';
2
+ import { BitmapBuffer } from './graphics/bitmap.js';
3
+ import { Cam } from './graphics/cam.js';
4
+ import { FrameListener } from './graphics/frame-listener.js';
5
+ import { Renderer } from './graphics/renderer.js';
6
+ import { Input } from './input/input.js';
7
+ import { Sprite } from './sprite/sprite.js';
8
+ import { JSONStorage } from './storage/json-storage.js';
9
+ export { Sprite } from './sprite/sprite.js';
10
+ export { fontCharToTag } from './text/font.js';
11
+ export { layoutText } from './text/text-layout.js';
12
+ export class Void {
13
+ static async new() {
14
+ return new Void(await loadImage(atlasURI));
15
+ }
16
+ atlas = atlas;
17
+ cam = new Cam();
18
+ ctrl;
19
+ kv = new JSONStorage();
20
+ synth = new Synth();
21
+ #bitmaps = new BitmapBuffer(1_000_000);
22
+ #framer;
23
+ #renderer;
24
+ constructor(spritesheet) {
25
+ const meta = document.createElement('meta');
26
+ meta.name = 'viewport';
27
+ // Don't wait for double-tap scaling on mobile.
28
+ meta.content = 'maximum-scale=1, minimum-scale=1, user-scalable=no';
29
+ document.head.appendChild(meta);
30
+ document.body.style.margin = '0';
31
+ document.body.style.width = '100vw';
32
+ document.body.style.height = '100vh';
33
+ document.body.style.overflow = 'hidden';
34
+ const canvas = document.createElement('canvas');
35
+ canvas.style.cursor = 'none';
36
+ canvas.style.display = 'block'; // No line height spacing.
37
+ canvas.style.imageRendering = 'pixelated';
38
+ // Update on each pointermove *touch* Event like *mouse* Events.
39
+ canvas.style.touchAction = 'none';
40
+ document.body.append(canvas);
41
+ this.ctrl = new Input(this.cam, canvas);
42
+ this.#renderer = new Renderer(atlas, canvas, spritesheet);
43
+ this.#framer = new FrameListener(canvas, this.ctrl, this.#renderer);
44
+ this.#framer.register('add');
45
+ this.background = 0x000000ff;
46
+ }
47
+ set background(rgba) {
48
+ document.body.style.background = `#${rgba.toString(16).padStart(8, '0')}`;
49
+ this.#renderer.clearColor(rgba);
50
+ }
51
+ blit(bmp) {
52
+ this.#bitmaps.push(bmp);
53
+ }
54
+ get frame() {
55
+ return this.#framer.frame;
56
+ }
57
+ render(loop) {
58
+ this.cam.resize();
59
+ this.#framer.render(this.cam, this.#bitmaps, loop);
60
+ this.#bitmaps.size = 0;
61
+ }
62
+ sprite(tag) {
63
+ return new Sprite(this.atlas, tag);
64
+ }
65
+ stop() {
66
+ this.#framer.cancel();
67
+ this.#framer.register('remove');
68
+ this.ctrl.register('remove');
69
+ }
70
+ }
71
+ function loadImage(src) {
72
+ return new Promise((resolve, reject) => {
73
+ const img = new Image();
74
+ img.onload = () => resolve(img);
75
+ img.onerror = () => reject(img);
76
+ img.src = src;
77
+ });
78
+ }
79
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare class GamepadPoller {
2
+ #private;
3
+ get bits(): number;
4
+ mapAxis(axis: number, lessBit: number, moreBit: number): void;
5
+ mapButton(button: number, bit: number): void;
6
+ poll(): void;
7
+ reset(): void;
8
+ }
@@ -0,0 +1,38 @@
1
+ export class GamepadPoller {
2
+ #bits = 0;
3
+ #bitByAxis = {};
4
+ #bitByButton = {};
5
+ get bits() {
6
+ return this.#bits;
7
+ }
8
+ mapAxis(axis, lessBit, moreBit) {
9
+ this.#bitByAxis[axis] = [lessBit, moreBit];
10
+ }
11
+ mapButton(button, bit) {
12
+ this.#bitByButton[button] = bit;
13
+ }
14
+ poll() {
15
+ if (!isSecureContext)
16
+ return;
17
+ this.#bits = 0;
18
+ for (const pad of navigator.getGamepads()) {
19
+ for (const [index, axis] of pad?.axes.entries() ?? []) {
20
+ const bits = this.#bitByAxis[index];
21
+ if (bits == null)
22
+ continue;
23
+ const bit = axis < 0 ? bits[0] : axis === 0 ? 0 : bits[1];
24
+ this.#bits |= Math.abs(axis) >= 0.5 ? bit : 0;
25
+ }
26
+ for (const [index, button] of pad?.buttons.entries() ?? []) {
27
+ const bit = this.#bitByButton[index];
28
+ if (bit == null)
29
+ continue;
30
+ this.#bits |= button.pressed ? bit : 0;
31
+ }
32
+ }
33
+ }
34
+ reset() {
35
+ this.#bits = 0;
36
+ }
37
+ }
38
+ //# sourceMappingURL=gamepad-poller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gamepad-poller.js","sourceRoot":"","sources":["../../src/input/gamepad-poller.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,aAAa;IACxB,KAAK,GAAG,CAAC,CAAA;IACA,UAAU,GAAmD,EAAE,CAAA;IAC/D,YAAY,GAA4B,EAAE,CAAA;IAEnD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,OAAe,EAAE,OAAe;QACpD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC5C,CAAC;IAED,SAAS,CAAC,MAAc,EAAE,GAAW;QACnC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,GAAG,CAAA;IACjC,CAAC;IAED,IAAI;QACF,IAAI,CAAC,eAAe;YAAE,OAAM;QAC5B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;QACd,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;YAC1C,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;gBACtD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;gBACnC,IAAI,IAAI,IAAI,IAAI;oBAAE,SAAQ;gBAC1B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACzD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/C,CAAC;YACD,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;gBAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;gBACpC,IAAI,GAAG,IAAI,IAAI;oBAAE,SAAQ;gBACzB,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YACxC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;IAChB,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ import { Cam } from '../graphics/cam.js';
2
+ import type { XY } from '../types/2d.js';
3
+ export type StandardButton = 'L' | 'R' | 'U' | 'D' | // Dpad.
4
+ 'C' | 'B' | 'A' | // Primary, secondary, tertiary.
5
+ 'S';
6
+ export declare class Input<Button extends string = StandardButton> {
7
+ #private;
8
+ handled: boolean;
9
+ /** The maximum duration in milliseconds permitted between combo inputs. */
10
+ maxInterval: number;
11
+ /** The minimum duration in milliseconds for an input to be considered held. */
12
+ minHeld: number;
13
+ constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement);
14
+ /**
15
+ * Combos are interpreted exactly both in buttons pressed per tick (eg, up
16
+ * will not match up and down the way `isOn('Up')` will) and sequence (order
17
+ * and length). Combos only test button on state.
18
+ */
19
+ isCombo(...combo: readonly (readonly Button[])[]): boolean;
20
+ /** Like isOnCombo() but test if the last button set is triggered. */
21
+ isComboStart(...combo: readonly (readonly Button[])[]): boolean;
22
+ /** True if held on or off. */
23
+ isHeld(): boolean;
24
+ isOffStart(...buttons: readonly Button[]): boolean;
25
+ /**
26
+ * Test if all buttons are on. True if the buttons are pressed regardless of
27
+ * whether other buttons are pressed. Eg, `isOn('Up')` will return true when
28
+ * up is pressed or when up and down are pressed.
29
+ */
30
+ isOn(...buttons: readonly Button[]): boolean;
31
+ isOnStart(...buttons: readonly Button[]): boolean;
32
+ /** True if triggered on or off. */
33
+ isStart(...buttons: readonly Button[]): boolean;
34
+ mapAxis(less: Button, more: Button, ...axes: readonly number[]): void;
35
+ mapButton(button: Button, ...indices: readonly number[]): void;
36
+ mapClick(button: Button, ...clicks: readonly number[]): void;
37
+ mapStandard(): void;
38
+ mapKey(button: Button, ...keys: readonly string[]): void;
39
+ get point(): Readonly<XY> | undefined;
40
+ get pointType(): 'mouse' | 'touch' | 'pen' | undefined;
41
+ poll(tick: number): void;
42
+ register(op: 'add' | 'remove'): void;
43
+ reset(): void;
44
+ }
@@ -0,0 +1,175 @@
1
+ import { Cam } from '../graphics/cam.js';
2
+ import { GamepadPoller } from './gamepad-poller.js';
3
+ import { KeyboardPoller } from './keyboard-poller.js';
4
+ import { PointerPoller } from './pointer-poller.js';
5
+ export class Input {
6
+ handled = false;
7
+ /** The maximum duration in milliseconds permitted between combo inputs. */
8
+ maxInterval = 300;
9
+ /** The minimum duration in milliseconds for an input to be considered held. */
10
+ minHeld = 300;
11
+ /** The time in milliseconds since the input changed. */
12
+ #duration = 0;
13
+ /** Prior button state, possibly 0, but not necessarily a combo member. */
14
+ #prevBits = 0;
15
+ /**
16
+ * A sequence of nonzero buttons ordered from oldest (first) to latest (last).
17
+ * Combos are terminated only by expiration.
18
+ */
19
+ #combo = [];
20
+ /** Logical button to bit. */
21
+ #bitByButton = {};
22
+ #gamepad = new GamepadPoller();
23
+ #keyboard = new KeyboardPoller();
24
+ #pointer;
25
+ #pollBits = 0;
26
+ #pollTick = 0;
27
+ constructor(cam, canvas) {
28
+ this.#pointer = new PointerPoller(cam, canvas);
29
+ }
30
+ /**
31
+ * Combos are interpreted exactly both in buttons pressed per tick (eg, up
32
+ * will not match up and down the way `isOn('Up')` will) and sequence (order
33
+ * and length). Combos only test button on state.
34
+ */
35
+ isCombo(...combo) {
36
+ if (combo.length !== this.#combo.length)
37
+ return false;
38
+ for (const [i, buttons] of combo.entries()) {
39
+ const bits = this.#buttonsToBits(buttons);
40
+ if (this.#combo[i] !== bits)
41
+ return false;
42
+ }
43
+ // #combo is a historical record of buttons. Whenever buttons changes, a new
44
+ // entry is pushed. Make sure the current entry is the current state and
45
+ // that the last entry's buttons haven't been released.
46
+ return this.#combo[combo.length - 1] === this.#bits;
47
+ }
48
+ /** Like isOnCombo() but test if the last button set is triggered. */
49
+ isComboStart(...combo) {
50
+ return (this.isCombo(...combo) &&
51
+ !!combo.at(-1)?.every(button => this.isOnStart(button)));
52
+ }
53
+ /** True if held on or off. */
54
+ isHeld() {
55
+ return this.#duration >= this.minHeld;
56
+ }
57
+ isOffStart(...buttons) {
58
+ return !this.isOn(...buttons) && this.isStart(...buttons);
59
+ }
60
+ /**
61
+ * Test if all buttons are on. True if the buttons are pressed regardless of
62
+ * whether other buttons are pressed. Eg, `isOn('Up')` will return true when
63
+ * up is pressed or when up and down are pressed.
64
+ */
65
+ isOn(...buttons) {
66
+ const bits = this.#buttonsToBits(buttons);
67
+ return (this.#bits & bits) === bits;
68
+ }
69
+ isOnStart(...buttons) {
70
+ return this.isOn(...buttons) && this.isStart(...buttons);
71
+ }
72
+ /** True if triggered on or off. */
73
+ isStart(...buttons) {
74
+ const bits = this.#buttonsToBits(buttons);
75
+ return (this.#bits & bits) !== (this.#prevBits & bits);
76
+ }
77
+ mapAxis(less, more, ...axes) {
78
+ for (const axis of axes) {
79
+ this.#gamepad.mapAxis(axis, this.#map(less), this.#map(more));
80
+ }
81
+ }
82
+ mapButton(button, ...indices) {
83
+ for (const index of indices) {
84
+ this.#gamepad.mapButton(index, this.#map(button));
85
+ }
86
+ }
87
+ mapClick(button, ...clicks) {
88
+ for (const click of clicks)
89
+ this.#pointer.map(click, this.#map(button));
90
+ }
91
+ mapStandard() {
92
+ this.mapKey('L', 'ArrowLeft', 'a');
93
+ this.mapKey('R', 'ArrowRight', 'd');
94
+ this.mapKey('U', 'ArrowUp', 'w');
95
+ this.mapKey('D', 'ArrowDown', 's');
96
+ this.mapKey('C', 'z');
97
+ this.mapKey('B', 'x');
98
+ this.mapKey('A', 'c');
99
+ this.mapKey('S', 'Enter', 'Escape');
100
+ // https://w3c.github.io/gamepad/#remapping
101
+ this.mapAxis('L', 'R', 0, 2);
102
+ this.mapAxis('U', 'D', 1, 3);
103
+ this.mapButton('L', 14);
104
+ this.mapButton('R', 15);
105
+ this.mapButton('U', 12);
106
+ this.mapButton('D', 13);
107
+ this.mapButton('A', 0);
108
+ this.mapButton('S', 9);
109
+ this.mapClick('A', 1);
110
+ }
111
+ mapKey(button, ...keys) {
112
+ for (const key of keys)
113
+ this.#keyboard.map(key, this.#map(button));
114
+ }
115
+ get point() {
116
+ return this.#pointer.xy;
117
+ }
118
+ get pointType() {
119
+ return this.#pointer.type;
120
+ }
121
+ poll(tick) {
122
+ this.handled = false;
123
+ this.#duration += this.#pollTick;
124
+ this.#prevBits = this.#pollBits;
125
+ this.#gamepad.poll();
126
+ if (this.#duration > this.maxInterval &&
127
+ (this.#bits === 0 || this.#bits !== this.#prevBits)) {
128
+ // Expired.
129
+ this.#duration = 0;
130
+ this.#combo.length = 0;
131
+ }
132
+ else if (this.#bits !== this.#prevBits) {
133
+ // Some button state has changed and at least one button is still pressed.
134
+ this.#duration = 0;
135
+ if (this.#bits !== 0)
136
+ this.#combo.push(this.#bits);
137
+ }
138
+ else if (this.#bits !== 0 && this.#bits === this.#prevBits) {
139
+ // Held. Update combo with the latest buttons.
140
+ this.#combo.pop();
141
+ this.#combo.push(this.#bits);
142
+ }
143
+ this.#pollTick = tick;
144
+ this.#pollBits = this.#bits;
145
+ }
146
+ register(op) {
147
+ this.#keyboard.register(op);
148
+ this.#pointer.register(op);
149
+ }
150
+ reset() {
151
+ this.handled = false;
152
+ this.#gamepad.reset();
153
+ this.#keyboard.reset();
154
+ this.#pointer.reset();
155
+ }
156
+ /**
157
+ * The current state and prospective combo member. A zero value can never be a
158
+ * combo member but is necessary to persist in previous to distinguish the off
159
+ * state between repeated button presses like up, up.
160
+ */
161
+ get #bits() {
162
+ return this.#gamepad.bits | this.#keyboard.bits | this.#pointer.bits;
163
+ }
164
+ #buttonsToBits(buttons) {
165
+ let bits = 0;
166
+ for (const button of buttons)
167
+ bits |= this.#bitByButton[button] ?? 0;
168
+ return bits;
169
+ }
170
+ #map(button) {
171
+ return (this.#bitByButton[button] ??=
172
+ 1 << Object.keys(this.#bitByButton).length);
173
+ }
174
+ }
175
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/input/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare class KeyboardPoller {
2
+ #private;
3
+ get bits(): number;
4
+ map(key: string, bit: number): void;
5
+ register(op: 'add' | 'remove'): void;
6
+ reset: () => void;
7
+ }
@@ -0,0 +1,30 @@
1
+ export class KeyboardPoller {
2
+ #bits = 0;
3
+ #bitByKey = {};
4
+ get bits() {
5
+ return this.#bits;
6
+ }
7
+ map(key, bit) {
8
+ this.#bitByKey[key] = bit;
9
+ }
10
+ register(op) {
11
+ const fn = `${op}EventListener`;
12
+ // keyup is not received if window loses focus.
13
+ globalThis[fn]('blur', this.reset, { capture: true, passive: true });
14
+ for (const type of ['keydown', 'keyup']) {
15
+ const callback = this.#onKey;
16
+ globalThis[fn](type, callback, { capture: true, passive: true });
17
+ }
18
+ }
19
+ reset = () => {
20
+ this.#bits = 0;
21
+ };
22
+ #onKey = (ev) => {
23
+ const on = ev.type === 'keydown';
24
+ const bit = this.#bitByKey[ev.key];
25
+ if (bit == null)
26
+ return;
27
+ this.#bits = on ? this.#bits | bit : this.#bits & ~bit;
28
+ };
29
+ }
30
+ //# sourceMappingURL=keyboard-poller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-poller.js","sourceRoot":"","sources":["../../src/input/keyboard-poller.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,cAAc;IACzB,KAAK,GAAG,CAAC,CAAA;IACA,SAAS,GAA4B,EAAE,CAAA;IAEhD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,GAAW;QAC1B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;IAC3B,CAAC;IAED,QAAQ,CAAC,EAAoB;QAC3B,MAAM,EAAE,GAAU,GAAG,EAAE,eAAe,CAAA;QACtC,+CAA+C;QAC/C,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAA;QAClE,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAuC,IAAI,CAAC,MAAM,CAAA;YAChE,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC,CAAA;QAChE,CAAC;IACH,CAAC;IAED,KAAK,GAAG,GAAS,EAAE;QACjB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;IAChB,CAAC,CAAA;IAED,MAAM,GAAG,CAAC,EAAiB,EAAQ,EAAE;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,SAAS,CAAA;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,GAAG,IAAI,IAAI;YAAE,OAAM;QACvB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,CAAA;IACxD,CAAC,CAAA;CACF"}
@@ -0,0 +1,12 @@
1
+ import { Cam } from '../graphics/cam.js';
2
+ import type { XY } from '../types/2d.js';
3
+ export declare class PointerPoller {
4
+ #private;
5
+ constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement);
6
+ get bits(): number;
7
+ map(button: number, bit: number): void;
8
+ get type(): 'mouse' | 'touch' | 'pen' | undefined;
9
+ register(op: 'add' | 'remove'): void;
10
+ reset: () => void;
11
+ get xy(): Readonly<XY> | undefined;
12
+ }
@@ -0,0 +1,67 @@
1
+ import { Cam } from '../graphics/cam.js';
2
+ export class PointerPoller {
3
+ #bitByButton = {};
4
+ #bits = 0;
5
+ #cam;
6
+ #canvas;
7
+ #clientXY = { x: 0, y: 0 };
8
+ #type;
9
+ #xy;
10
+ constructor(cam, canvas) {
11
+ this.#cam = cam;
12
+ this.#canvas = canvas;
13
+ }
14
+ get bits() {
15
+ return this.#bits;
16
+ }
17
+ map(button, bit) {
18
+ this.#bitByButton[button] = bit;
19
+ }
20
+ get type() {
21
+ return this.#type;
22
+ }
23
+ register(op) {
24
+ const fn = `${op}EventListener`;
25
+ this.#canvas[fn]('pointercancel', this.reset, {
26
+ capture: true,
27
+ passive: true
28
+ });
29
+ for (const type of ['pointerdown', 'pointermove', 'pointerup']) {
30
+ this.#canvas[fn](type, this.#onPointEvent, { capture: true, passive: type !== 'pointerdown' });
31
+ }
32
+ this.#canvas[fn]('contextmenu', this.#onContextMenuEvent, { capture: true });
33
+ }
34
+ reset = () => {
35
+ this.#bits = 0;
36
+ this.#type = undefined;
37
+ this.#xy = undefined;
38
+ };
39
+ get xy() {
40
+ return this.#xy;
41
+ }
42
+ #onContextMenuEvent = (ev) => ev.preventDefault();
43
+ #onPointEvent = (ev) => {
44
+ // Ignore non-primary inputs to avoid flickering between distant points.
45
+ if (!ev.isPrimary)
46
+ return;
47
+ if (ev.type === 'pointerdown')
48
+ this.#canvas.setPointerCapture(ev.pointerId);
49
+ ({ clientX: this.#clientXY.x, clientY: this.#clientXY.y } = ev);
50
+ this.#bits = this.#evButtonsToBits(ev.buttons);
51
+ this.#type = ['mouse', 'touch', 'pen'].find(type => type === ev.pointerType);
52
+ this.#xy = this.#cam.toLevelXY(this.#clientXY);
53
+ const passive = ev.type !== 'pointerdown';
54
+ if (!passive)
55
+ ev.preventDefault();
56
+ };
57
+ #evButtonsToBits(buttons) {
58
+ let bits = 0;
59
+ for (let button = 1; button <= buttons; button <<= 1) {
60
+ if ((button & buttons) !== button)
61
+ continue;
62
+ bits |= this.#bitByButton[button] ?? 0;
63
+ }
64
+ return bits;
65
+ }
66
+ }
67
+ //# sourceMappingURL=pointer-poller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer-poller.js","sourceRoot":"","sources":["../../src/input/pointer-poller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { AnimTag } from '../atlas/aseprite.js';
2
+ import type { Atlas } from '../atlas/atlas.js';
3
+ import type { Bitmap } from '../graphics/bitmap.js';
4
+ import type { Box, WH, XY } from '../types/2d.js';
5
+ export type SpriteJSON = {
6
+ cel?: number;
7
+ flip?: string;
8
+ tag: string;
9
+ x?: number;
10
+ y?: number;
11
+ z?: number;
12
+ w?: number;
13
+ h?: number;
14
+ zend?: boolean;
15
+ };
16
+ export declare class Sprite<T extends AnimTag = AnimTag> implements Bitmap, Box {
17
+ #private;
18
+ static parse<T extends AnimTag = AnimTag>(atlas: Atlas<T>, json: Readonly<SpriteJSON>): Sprite<T>;
19
+ readonly hitbox: Box;
20
+ _iffzz: number;
21
+ _xy: number;
22
+ _wh: number;
23
+ constructor(atlas: Atlas<T>, tag: T);
24
+ above(sprite: Readonly<Sprite>): boolean;
25
+ get cel(): number;
26
+ /** Set to frame number to start at the beginning. */
27
+ set cel(cel: number);
28
+ get flipX(): boolean;
29
+ set flipX(flip: boolean);
30
+ get flipY(): boolean;
31
+ set flipY(flip: boolean);
32
+ get h(): number;
33
+ set h(h: number);
34
+ hits(box: Readonly<XY & Partial<WH>>): boolean;
35
+ overlaps(box: Readonly<XY & Partial<WH>>): boolean;
36
+ get tag(): T;
37
+ set tag(tag: T);
38
+ toString(): string;
39
+ get w(): number;
40
+ set w(w: number);
41
+ get x(): number;
42
+ set x(x: number);
43
+ set xy(xy: Readonly<XY>);
44
+ get y(): number;
45
+ set y(y: number);
46
+ get z(): number;
47
+ /** Greater is further. */
48
+ set z(z: number);
49
+ get zend(): boolean;
50
+ set zend(end: boolean);
51
+ }