textmode.js 0.7.1 → 0.8.0-beta.2

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 (54) hide show
  1. package/dist/textmode.esm.js +2042 -2108
  2. package/dist/textmode.umd.js +16 -16
  3. package/dist/types/Textmode.d.ts +11 -11
  4. package/dist/types/errors/index.d.ts +1 -1
  5. package/dist/types/index.d.ts +11 -3
  6. package/dist/types/rendering/webgl/core/Framebuffer.d.ts +0 -6
  7. package/dist/types/rendering/webgl/core/Renderer.d.ts +7 -6
  8. package/dist/types/rendering/webgl/core/interfaces/IFramebuffer.d.ts +6 -6
  9. package/dist/types/rendering/webgl/core/interfaces/IRenderer.d.ts +3 -3
  10. package/dist/types/rendering/webgl/index.d.ts +2 -2
  11. package/dist/types/rendering/webgl/pipeline/MaterialBatchPipeline.d.ts +1 -1
  12. package/dist/types/textmode/Canvas.d.ts +2 -2
  13. package/dist/types/textmode/Grid.d.ts +32 -3
  14. package/dist/types/textmode/Textmodifier.d.ts +14 -72
  15. package/dist/types/textmode/conversion/ConversionManager.d.ts +73 -0
  16. package/dist/types/textmode/conversion/ConversionRegistry.d.ts +61 -18
  17. package/dist/types/textmode/conversion/index.d.ts +3 -1
  18. package/dist/types/textmode/filters/FilterManager.d.ts +0 -4
  19. package/dist/types/textmode/filters/index.d.ts +1 -1
  20. package/dist/types/textmode/interfaces/ITextmodifier.d.ts +165 -50
  21. package/dist/types/textmode/layers/Layer2DCompositor.d.ts +13 -20
  22. package/dist/types/textmode/layers/LayerManager.d.ts +31 -20
  23. package/dist/types/textmode/layers/TextmodeLayer.d.ts +58 -20
  24. package/dist/types/textmode/layers/interfaces/ILayerManager.d.ts +7 -0
  25. package/dist/types/textmode/layers/interfaces/ITextmodeLayer.d.ts +49 -28
  26. package/dist/types/textmode/layers/types.d.ts +16 -21
  27. package/dist/types/textmode/loadables/ITextmodeSource.d.ts +123 -0
  28. package/dist/types/textmode/loadables/TextmodeImage.d.ts +2 -2
  29. package/dist/types/textmode/loadables/TextmodeSource.d.ts +10 -118
  30. package/dist/types/textmode/loadables/font/CharacterExtractor.d.ts +1 -1
  31. package/dist/types/textmode/loadables/font/TextmodeFont.d.ts +3 -0
  32. package/dist/types/textmode/loadables/font/index.d.ts +2 -2
  33. package/dist/types/textmode/loadables/index.d.ts +0 -2
  34. package/dist/types/textmode/loadables/video/ITextmodeVideo.d.ts +75 -0
  35. package/dist/types/textmode/loadables/video/TextmodeVideo.d.ts +23 -126
  36. package/dist/types/textmode/loading/LoadingPhase.d.ts +26 -0
  37. package/dist/types/textmode/loading/LoadingScreenManager.d.ts +91 -93
  38. package/dist/types/textmode/loading/index.d.ts +3 -2
  39. package/dist/types/textmode/loading/types.d.ts +57 -57
  40. package/dist/types/textmode/managers/MouseManager.d.ts +24 -14
  41. package/dist/types/textmode/managers/TouchManager.d.ts +25 -13
  42. package/dist/types/textmode/mixins/index.d.ts +1 -2
  43. package/dist/types/textmode/mixins/interfaces/IAnimationMixin.d.ts +87 -87
  44. package/dist/types/textmode/mixins/interfaces/IKeyboardMixin.d.ts +128 -128
  45. package/dist/types/textmode/mixins/interfaces/IMouseMixin.d.ts +96 -105
  46. package/dist/types/textmode/mixins/interfaces/IRenderingMixin.d.ts +271 -370
  47. package/dist/types/textmode/mixins/interfaces/ITouchMixin.d.ts +1 -1
  48. package/dist/types/textmode/types.d.ts +2 -6
  49. package/package.json +5 -2
  50. package/dist/types/textmode/layers/filters/index.d.ts +0 -6
  51. package/dist/types/textmode/loadables/video/TextmodeVideoPreloader.d.ts +0 -29
  52. package/dist/types/textmode/loadables/video/types.d.ts +0 -43
  53. package/dist/types/textmode/mixins/FontMixin.d.ts +0 -8
  54. package/dist/types/textmode/mixins/interfaces/IFontMixin.d.ts +0 -46
@@ -1,17 +1,22 @@
1
1
  import type { TextmodeCanvas } from '../Canvas';
2
2
  import type { TextmodeGrid } from '../Grid';
3
3
  /**
4
- * Mouse coordinates in grid space.
4
+ * Mouse coordinates in grid space using center-based coordinates.
5
5
  *
6
- * Unlike the main drawing logic, where `(0,0,0)` is the center cell,
7
- * the mouse coordinates use the top-left cell as `(0,0)`. This means
8
- * you'll need to adjust accordingly when using these coordinates
9
- * for drawing or other grid operations.
6
+ * The coordinate system matches the main drawing/rendering space:
7
+ * - `(0, 0)` is the center cell of the grid
8
+ * - Negative X values are to the left of center
9
+ * - Positive X values are to the right of center
10
+ * - Negative Y values are above center
11
+ * - Positive Y values are below center
12
+ *
13
+ * When the mouse is outside the grid bounds, both `x` and `y` are set to
14
+ * `Number.NEGATIVE_INFINITY` to indicate an invalid/outside position.
10
15
  */
11
16
  export interface MousePosition {
12
- /** Grid X coordinate (column), -1 if mouse is outside grid */
17
+ /** Grid X coordinate (column) in center-based coords. `Number.NEGATIVE_INFINITY` if outside grid. */
13
18
  x: number;
14
- /** Grid Y coordinate (row), -1 if mouse is outside grid */
19
+ /** Grid Y coordinate (row) in center-based coords. `Number.NEGATIVE_INFINITY` if outside grid. */
15
20
  y: number;
16
21
  }
17
22
  /**
@@ -38,6 +43,10 @@ export interface MouseEventData {
38
43
  * Mouse event handler function type
39
44
  */
40
45
  export type MouseEventHandler = (data: MouseEventData) => void;
46
+ /**
47
+ * Grid provider function type - returns the grid to use for coordinate calculations
48
+ */
49
+ export type GridProvider = () => TextmodeGrid | undefined;
41
50
  /**
42
51
  * Manages all mouse interaction for a Textmodifier instance.
43
52
  * Handles event listeners, coordinate conversion, and event dispatching.
@@ -45,7 +54,7 @@ export type MouseEventHandler = (data: MouseEventData) => void;
45
54
  */
46
55
  export declare class MouseManager {
47
56
  private _canvas;
48
- private _grid;
57
+ private _getGrid;
49
58
  private _mousePosition;
50
59
  private _previousMousePosition;
51
60
  private _lastClientCoordinates;
@@ -62,7 +71,12 @@ export declare class MouseManager {
62
71
  private _mouseReleasedCallback?;
63
72
  private _mouseMovedCallback?;
64
73
  private _mouseScrolledCallback?;
65
- constructor(canvas: TextmodeCanvas);
74
+ /**
75
+ * Create a new MouseManager.
76
+ * @param canvas The canvas to track mouse events on.
77
+ * @param getGrid A function that returns the grid to use for coordinate calculations.
78
+ */
79
+ constructor(canvas: TextmodeCanvas, getGrid: GridProvider);
66
80
  /**
67
81
  * Temporarily suppress mouse event callbacks for a duration in milliseconds.
68
82
  * Used to prevent synthetic mouse events from touch interactions from firing twice.
@@ -77,10 +91,6 @@ export declare class MouseManager {
77
91
  * Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
78
92
  */
79
93
  $setCursor(cursor?: string): void;
80
- /**
81
- * Update the grid reference (useful when grid changes after font loading)
82
- */
83
- $initialize(grid: TextmodeGrid): void;
84
94
  /**
85
95
  * Setup mouse event listeners on the canvas.
86
96
  */
@@ -147,7 +157,7 @@ export declare class MouseManager {
147
157
  private _handleMouseScrolled;
148
158
  /**
149
159
  * Update mouse position based on mouse event.
150
- * Converts pixel coordinates to grid coordinates.
160
+ * Converts pixel coordinates to center-based grid coordinates.
151
161
  */
152
162
  private _updateMousePosition;
153
163
  }
@@ -1,15 +1,24 @@
1
1
  import type { TextmodeCanvas } from '../Canvas';
2
- import type { TextmodeGrid } from '../Grid';
3
- import type { MouseManager } from './MouseManager';
2
+ import type { MouseManager, GridProvider } from './MouseManager';
4
3
  /**
5
- * Touch position expressed both in grid and client coordinates
4
+ * Touch position expressed both in grid and client coordinates.
5
+ *
6
+ * The grid coordinate system uses center-based coordinates matching the rendering space:
7
+ * - `(0, 0)` is the center cell of the grid
8
+ * - Negative X values are to the left of center
9
+ * - Positive X values are to the right of center
10
+ * - Negative Y values are above center
11
+ * - Positive Y values are below center
12
+ *
13
+ * When the touch is outside the grid bounds, `x` and `y` are set to
14
+ * `Number.NEGATIVE_INFINITY` to indicate an invalid/outside position.
6
15
  */
7
16
  export interface TouchPosition {
8
17
  /** Identifier provided by the browser for a touch point */
9
18
  id: number;
10
- /** Grid X coordinate (column), -1 if touch is outside grid */
19
+ /** Grid X coordinate (column) in center-based coords. `Number.NEGATIVE_INFINITY` if outside grid. */
11
20
  x: number;
12
- /** Grid Y coordinate (row), -1 if touch is outside grid */
21
+ /** Grid Y coordinate (row) in center-based coords. `Number.NEGATIVE_INFINITY` if outside grid. */
13
22
  y: number;
14
23
  /** Client X coordinate in CSS pixels */
15
24
  clientX: number;
@@ -27,10 +36,9 @@ export interface TouchPosition {
27
36
  /**
28
37
  * Touch event data.
29
38
  *
30
- * Unlike the main drawing logic, where `(0,0,0)` is the center cell,
31
- * the mouse coordinates use the top-left cell as `(0,0)`. This means
32
- * you'll need to adjust accordingly when using these coordinates
33
- * for drawing or other grid operations.
39
+ * The coordinate system uses center-based coordinates matching the main rendering space:
40
+ * - `(0, 0)` is the center cell of the grid
41
+ * - Coordinates can be used directly with `translate()` and other drawing functions
34
42
  */
35
43
  export interface TouchEventData {
36
44
  /** The touch point that triggered this event */
@@ -153,7 +161,7 @@ export type TouchRotateHandler = (data: TouchRotateEventData) => void;
153
161
  export declare class TouchManager {
154
162
  private readonly _canvas;
155
163
  private readonly _mouseManager?;
156
- private _grid;
164
+ private readonly _getGrid;
157
165
  private _activeTouches;
158
166
  private _previousTouches;
159
167
  private _touchInfo;
@@ -187,9 +195,13 @@ export declare class TouchManager {
187
195
  private readonly _mouseSuppressionDuration;
188
196
  private _lastTapTime;
189
197
  private _lastTapPosition;
190
- constructor(canvas: TextmodeCanvas, mouseManager?: MouseManager);
191
- /** Initialise the manager with the active grid */
192
- $initialize(grid: TextmodeGrid): void;
198
+ /**
199
+ * Create a new TouchManager.
200
+ * @param canvas The canvas to track touch events on.
201
+ * @param getGrid A function that returns the grid to use for coordinate calculations.
202
+ * @param mouseManager Optional mouse manager for suppressing mouse events during touch.
203
+ */
204
+ constructor(canvas: TextmodeCanvas, getGrid: GridProvider, mouseManager?: MouseManager);
193
205
  /** Install touch listeners onto the canvas */
194
206
  $setupListeners(): void;
195
207
  /** Remove all touch listeners */
@@ -1,10 +1,9 @@
1
1
  export { type Constructor, type Mixin, $applyMixins } from './TextmodifierMixin';
2
2
  export { RenderingMixin } from './RenderingMixin';
3
- export { FontMixin } from './FontMixin';
4
3
  export { AnimationMixin } from './AnimationMixin';
5
4
  export { MouseMixin } from './MouseMixin';
6
5
  export { TouchMixin } from './TouchMixin';
7
6
  export { KeyboardMixin } from './KeyboardMixin';
8
7
  export type { MousePosition, MouseEventData, MouseEventHandler } from '../managers/MouseManager';
9
8
  export type { KeyboardEventData, KeyboardEventHandler, KeyState } from '../managers/KeyboardManager';
10
- export type { TouchEventData, TouchLongPressEventData, TouchPinchEventData, TouchPosition, TouchRotateEventData, TouchSwipeEventData, TouchTapEventData } from '../managers/TouchManager';
9
+ export type { TouchEventData, TouchLongPressEventData, TouchPinchEventData, TouchPosition, TouchRotateEventData, TouchSwipeEventData, TouchTapEventData, } from '../managers/TouchManager';
@@ -30,57 +30,57 @@ export interface IAnimationMixin {
30
30
  * it to be resumed later with {@link loop}. This is useful for temporarily pausing
31
31
  * animation while maintaining the ability to continue it.
32
32
  *
33
- * @example
34
- * ```javascript
35
- * const t = textmode.create({ width: 800, height: 600 });
36
- *
37
- * // Toggle loop on SPACE
38
- * t.keyPressed((data) => {
39
- * if (data.key === ' ') {
40
- * if (t.isLooping()) {
41
- * t.noLoop();
42
- * } else {
43
- * t.loop();
44
- * }
45
- * }
46
- * });
47
- *
48
- * t.draw(() => {
49
- * t.background(0);
50
- * t.char('A');
51
- * t.charColor(255, 255, 255);
52
- * t.rotateZ(t.frameCount * 2);
53
- * t.rect(16, 16);
54
- * });
55
- * ```
33
+ * @example
34
+ * ```javascript
35
+ * const t = textmode.create({ width: 800, height: 600 });
36
+ *
37
+ * // Toggle loop on SPACE
38
+ * t.keyPressed((data) => {
39
+ * if (data.key === ' ') {
40
+ * if (t.isLooping()) {
41
+ * t.noLoop();
42
+ * } else {
43
+ * t.loop();
44
+ * }
45
+ * }
46
+ * });
47
+ *
48
+ * t.draw(() => {
49
+ * t.background(0);
50
+ * t.char('A');
51
+ * t.charColor(255, 255, 255);
52
+ * t.rotateZ(t.frameCount * 2);
53
+ * t.rect(16, 16);
54
+ * });
55
+ * ```
56
56
  */
57
57
  noLoop(): void;
58
58
  /**
59
59
  * Resume the rendering loop if it was stopped by {@link noLoop}.
60
60
  *
61
- * @example
62
- * ```javascript
63
- * const t = textmode.create({ width: 800, height: 600 });
64
- *
65
- * // Toggle loop on SPACE
66
- * t.keyPressed((data) => {
67
- * if (data.key === ' ') {
68
- * if (t.isLooping()) {
69
- * t.noLoop();
70
- * } else {
71
- * t.loop();
72
- * }
73
- * }
74
- * });
75
- *
76
- * t.draw(() => {
77
- * t.background(0);
78
- * t.char('A');
79
- * t.charColor(255, 255, 255);
80
- * t.rotateZ(t.frameCount * 2);
81
- * t.rect(16, 16);
82
- * });
83
- * ```
61
+ * @example
62
+ * ```javascript
63
+ * const t = textmode.create({ width: 800, height: 600 });
64
+ *
65
+ * // Toggle loop on SPACE
66
+ * t.keyPressed((data) => {
67
+ * if (data.key === ' ') {
68
+ * if (t.isLooping()) {
69
+ * t.noLoop();
70
+ * } else {
71
+ * t.loop();
72
+ * }
73
+ * }
74
+ * });
75
+ *
76
+ * t.draw(() => {
77
+ * t.background(0);
78
+ * t.char('A');
79
+ * t.charColor(255, 255, 255);
80
+ * t.rotateZ(t.frameCount * 2);
81
+ * t.rect(16, 16);
82
+ * });
83
+ * ```
84
84
  */
85
85
  loop(): void;
86
86
  /**
@@ -93,47 +93,47 @@ export interface IAnimationMixin {
93
93
  *
94
94
  * @example
95
95
  * ```javascript
96
- * // Press SPACE to manually trigger single frames while loop is paused.
97
- *
98
- * const t = textmode.create({ width: 800, height: 600 });
99
- *
100
- * let rotation = 0;
101
- *
102
- * t.keyPressed((data) => {
103
- * if (data.key === ' ') {
104
- * rotation += 15; // Increment rotation
105
- * t.redraw(); // Manually trigger one frame
106
- * }
107
- * });
108
- *
109
- * t.draw(() => {
110
- * if(t.frameCount === 1) {
111
- * t.noLoop();
112
- * }
113
- *
114
- * t.background(0);
115
- *
116
- * t.push();
117
- * t.char('A');
118
- * t.charColor(100, 200, 255);
119
- * t.rotateZ(rotation);
120
- * t.rect(13, 13);
121
- * t.pop();
122
- *
123
- * // Show instruction text
124
- * t.push();
125
- * t.translate(-5, -10);
126
- * t.charColor(150);
127
- * const msg = 'PRESS SPACE';
128
- * [...msg].forEach((char, i) => {
129
- * t.push();
130
- * t.translate(i, 0);
131
- * t.char(char);
132
- * t.point();
133
- * t.pop();
134
- * });
135
- * t.pop();
136
- * });
96
+ * // Press SPACE to manually trigger single frames while loop is paused.
97
+ *
98
+ * const t = textmode.create({ width: 800, height: 600 });
99
+ *
100
+ * let rotation = 0;
101
+ *
102
+ * t.keyPressed((data) => {
103
+ * if (data.key === ' ') {
104
+ * rotation += 15; // Increment rotation
105
+ * t.redraw(); // Manually trigger one frame
106
+ * }
107
+ * });
108
+ *
109
+ * t.draw(() => {
110
+ * if(t.frameCount === 1) {
111
+ * t.noLoop();
112
+ * }
113
+ *
114
+ * t.background(0);
115
+ *
116
+ * t.push();
117
+ * t.char('A');
118
+ * t.charColor(100, 200, 255);
119
+ * t.rotateZ(rotation);
120
+ * t.rect(13, 13);
121
+ * t.pop();
122
+ *
123
+ * // Show instruction text
124
+ * t.push();
125
+ * t.translate(-5, -10);
126
+ * t.charColor(150);
127
+ * const msg = 'PRESS SPACE';
128
+ * [...msg].forEach((char, i) => {
129
+ * t.push();
130
+ * t.translate(i, 0);
131
+ * t.char(char);
132
+ * t.point();
133
+ * t.pop();
134
+ * });
135
+ * t.pop();
136
+ * });
137
137
  * ```
138
138
  */
139
139
  redraw(n?: number): void;
@@ -1,4 +1,4 @@
1
- import type { KeyboardEventHandler } from "../../managers/KeyboardManager";
1
+ import type { KeyboardEventHandler } from '../../managers/KeyboardManager';
2
2
  /**
3
3
  * Capabilities provided by the KeyboardMixin
4
4
  */
@@ -10,36 +10,36 @@ export interface IKeyboardMixin {
10
10
  * @returns true if the key is currently pressed, false otherwise
11
11
  *
12
12
  * @example
13
- * ```javascript
14
- * const t = textmode.create({ width: 800, height: 600 });
15
- *
16
- * let playerX = 0;
17
- * let playerY = 0;
18
- *
19
- * t.draw(() => {
20
- * t.background(0);
21
- *
22
- * // Check for arrow keys to move a character
23
- * if (t.isKeyPressed('ArrowUp')) {
24
- * playerY -= 1;
25
- * }
26
- * if (t.isKeyPressed('ArrowDown')) {
27
- * playerY += 1;
28
- * }
29
- * if (t.isKeyPressed('ArrowLeft')) {
30
- * playerX -= 1;
31
- * }
32
- * if (t.isKeyPressed('ArrowRight')) {
33
- * playerX += 1;
34
- * }
35
- *
36
- * // Draw player character
37
- * t.char('@');
38
- * t.charColor(255, 255, 0);
39
- * t.translate(playerX, playerY);
40
- * t.point();
41
- * });
42
- * ```
13
+ * ```javascript
14
+ * const t = textmode.create({ width: 800, height: 600 });
15
+ *
16
+ * let playerX = 0;
17
+ * let playerY = 0;
18
+ *
19
+ * t.draw(() => {
20
+ * t.background(0);
21
+ *
22
+ * // Check for arrow keys to move a character
23
+ * if (t.isKeyPressed('ArrowUp')) {
24
+ * playerY -= 1;
25
+ * }
26
+ * if (t.isKeyPressed('ArrowDown')) {
27
+ * playerY += 1;
28
+ * }
29
+ * if (t.isKeyPressed('ArrowLeft')) {
30
+ * playerX -= 1;
31
+ * }
32
+ * if (t.isKeyPressed('ArrowRight')) {
33
+ * playerX += 1;
34
+ * }
35
+ *
36
+ * // Draw player character
37
+ * t.char('@');
38
+ * t.charColor(255, 255, 0);
39
+ * t.translate(playerX, playerY);
40
+ * t.point();
41
+ * });
42
+ * ```
43
43
  */
44
44
  isKeyPressed(key: string): boolean;
45
45
  /**
@@ -47,34 +47,34 @@ export interface IKeyboardMixin {
47
47
  *
48
48
  * @param callback The function to call when a key is pressed
49
49
  *
50
- * @example
51
- * ```javascript
52
- * const t = textmode.create({ width: 800, height: 600 });
53
- *
54
- * let lastKey = '?';
55
- * let pulse = 0;
56
- *
57
- * // Update some visual state when a key is pressed
58
- * t.keyPressed((data) => {
59
- * lastKey = data.key;
60
- * pulse = 6; // make the next frames brighter
61
- * });
62
- *
63
- * t.draw(() => {
64
- * t.background(0);
65
- *
66
- * // Fade brightness back down each frame
67
- * const glow = Math.max(0, pulse--);
68
- * const brightness = 120 + glow * 20;
69
- * t.charColor(brightness, brightness, 0);
70
- *
71
- * // Show the last pressed key at the center of the grid
72
- * t.push();
73
- * t.char(lastKey.length ? lastKey[0] : '?');
74
- * t.point();
75
- * t.pop();
76
- * });
77
- * ```
50
+ * @example
51
+ * ```javascript
52
+ * const t = textmode.create({ width: 800, height: 600 });
53
+ *
54
+ * let lastKey = '?';
55
+ * let pulse = 0;
56
+ *
57
+ * // Update some visual state when a key is pressed
58
+ * t.keyPressed((data) => {
59
+ * lastKey = data.key;
60
+ * pulse = 6; // make the next frames brighter
61
+ * });
62
+ *
63
+ * t.draw(() => {
64
+ * t.background(0);
65
+ *
66
+ * // Fade brightness back down each frame
67
+ * const glow = Math.max(0, pulse--);
68
+ * const brightness = 120 + glow * 20;
69
+ * t.charColor(brightness, brightness, 0);
70
+ *
71
+ * // Show the last pressed key at the center of the grid
72
+ * t.push();
73
+ * t.char(lastKey.length ? lastKey[0] : '?');
74
+ * t.point();
75
+ * t.pop();
76
+ * });
77
+ * ```
78
78
  */
79
79
  keyPressed(callback: KeyboardEventHandler): void;
80
80
  /**
@@ -82,31 +82,31 @@ export interface IKeyboardMixin {
82
82
  *
83
83
  * @param callback The function to call when a key is released
84
84
  *
85
- * @example
86
- * ```javascript
87
- * const t = textmode.create({ width: 800, height: 600 });
88
- *
89
- * let lastRelease = '?';
90
- * let fade = 0;
91
- *
92
- * // Capture the most recent key release and trigger a pulse
93
- * t.keyReleased((data) => {
94
- * lastRelease = data.key;
95
- * fade = 10;
96
- * });
97
- *
98
- * t.draw(() => {
99
- * t.background(0);
100
- *
101
- * // Dim the glow over time
102
- * const glow = Math.max(0, fade--);
103
- * const color = 80 + glow * 17;
104
- * t.charColor(color, color, 255);
105
- *
106
- * t.char(lastRelease.length ? lastRelease[0] : '?');
107
- * t.point();
108
- * });
109
- * ```
85
+ * @example
86
+ * ```javascript
87
+ * const t = textmode.create({ width: 800, height: 600 });
88
+ *
89
+ * let lastRelease = '?';
90
+ * let fade = 0;
91
+ *
92
+ * // Capture the most recent key release and trigger a pulse
93
+ * t.keyReleased((data) => {
94
+ * lastRelease = data.key;
95
+ * fade = 10;
96
+ * });
97
+ *
98
+ * t.draw(() => {
99
+ * t.background(0);
100
+ *
101
+ * // Dim the glow over time
102
+ * const glow = Math.max(0, fade--);
103
+ * const color = 80 + glow * 17;
104
+ * t.charColor(color, color, 255);
105
+ *
106
+ * t.char(lastRelease.length ? lastRelease[0] : '?');
107
+ * t.point();
108
+ * });
109
+ * ```
110
110
  */
111
111
  keyReleased(callback: KeyboardEventHandler): void;
112
112
  /**
@@ -161,25 +161,25 @@ export interface IKeyboardMixin {
161
161
  * Returns an array of key strings that are currently being held down.
162
162
  *
163
163
  * @example
164
- * ```javascript
165
- * const t = textmode.create({ width: 800, height: 600 });
166
- *
167
- * t.draw(() => {
168
- * t.background(0);
169
- *
170
- * const pressed = t.pressedKeys;
171
- *
172
- * // Display all currently pressed keys
173
- * pressed.forEach((key, index) => {
174
- * t.push();
175
- * t.char(key[0] || '?'); // Show first character of key name
176
- * t.charColor(255, 200, 100);
177
- * t.translate(index, 0);
178
- * t.point();
179
- * t.pop();
180
- * });
181
- * });
182
- * ```
164
+ * ```javascript
165
+ * const t = textmode.create({ width: 800, height: 600 });
166
+ *
167
+ * t.draw(() => {
168
+ * t.background(0);
169
+ *
170
+ * const pressed = t.pressedKeys;
171
+ *
172
+ * // Display all currently pressed keys
173
+ * pressed.forEach((key, index) => {
174
+ * t.push();
175
+ * t.char(key[0] || '?'); // Show first character of key name
176
+ * t.charColor(255, 200, 100);
177
+ * t.translate(index, 0);
178
+ * t.point();
179
+ * t.pop();
180
+ * });
181
+ * });
182
+ * ```
183
183
  */
184
184
  get pressedKeys(): string[];
185
185
  /**
@@ -187,31 +187,31 @@ export interface IKeyboardMixin {
187
187
  *
188
188
  * Returns an object with boolean properties for each modifier key.
189
189
  *
190
- * @example
191
- * ```javascript
192
- * const t = textmode.create({ width: 800, height: 600 });
193
- *
194
- * t.draw(() => {
195
- * t.background(0);
196
- * const mods = t.modifierState;
197
- *
198
- * // Change behavior based on modifier keys
199
- * if (mods.shift) {
200
- * // Draw in caps or with different behavior
201
- * t.char('S');
202
- * t.charColor(255, 255, 0);
203
- * t.point();
204
- * }
205
- *
206
- * if (mods.ctrl) {
207
- * // Control key is pressed
208
- * t.translate(2, 0);
209
- * t.char('C');
210
- * t.charColor(0, 255, 255);
211
- * t.point();
212
- * }
213
- * });
214
- * ```
190
+ * @example
191
+ * ```javascript
192
+ * const t = textmode.create({ width: 800, height: 600 });
193
+ *
194
+ * t.draw(() => {
195
+ * t.background(0);
196
+ * const mods = t.modifierState;
197
+ *
198
+ * // Change behavior based on modifier keys
199
+ * if (mods.shift) {
200
+ * // Draw in caps or with different behavior
201
+ * t.char('S');
202
+ * t.charColor(255, 255, 0);
203
+ * t.point();
204
+ * }
205
+ *
206
+ * if (mods.ctrl) {
207
+ * // Control key is pressed
208
+ * t.translate(2, 0);
209
+ * t.char('C');
210
+ * t.charColor(0, 255, 255);
211
+ * t.point();
212
+ * }
213
+ * });
214
+ * ```
215
215
  */
216
216
  get modifierState(): {
217
217
  /**