textmode.js 0.4.0 → 0.6.0-beta.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 (105) hide show
  1. package/dist/textmode.esm.js +2868 -2164
  2. package/dist/textmode.esm.min.js +2863 -2159
  3. package/dist/textmode.umd.js +11 -8
  4. package/dist/textmode.umd.min.js +11 -8
  5. package/dist/types/Textmode.d.ts +13 -22
  6. package/dist/types/index.d.ts +8 -6
  7. package/dist/types/rendering/index.d.ts +3 -3
  8. package/dist/types/rendering/webgl/batching/DrawQueue.d.ts +89 -0
  9. package/dist/types/rendering/webgl/{VAOManager.d.ts → batching/GeometryAttributeCache.d.ts} +4 -4
  10. package/dist/types/rendering/webgl/batching/InstanceAttributeBinder.d.ts +87 -0
  11. package/dist/types/rendering/webgl/{InstanceBatch.d.ts → batching/InstanceBatch.d.ts} +25 -34
  12. package/dist/types/rendering/webgl/batching/InstanceBuffer.d.ts +78 -0
  13. package/dist/types/rendering/webgl/{InstanceData.d.ts → batching/InstanceData.d.ts} +11 -18
  14. package/dist/types/rendering/webgl/batching/InstanceWriter.d.ts +70 -0
  15. package/dist/types/rendering/webgl/{Framebuffer.d.ts → core/Framebuffer.d.ts} +37 -39
  16. package/dist/types/rendering/webgl/core/Renderer.d.ts +64 -0
  17. package/dist/types/rendering/webgl/{Shader.d.ts → core/Shader.d.ts} +2 -23
  18. package/dist/types/rendering/webgl/core/interfaces/IFramebuffer.d.ts +103 -0
  19. package/dist/types/rendering/webgl/core/interfaces/IRenderer.d.ts +210 -0
  20. package/dist/types/rendering/webgl/geometries/{Arc.d.ts → 2d/Arc.d.ts} +5 -4
  21. package/dist/types/rendering/webgl/geometries/{BezierCurve.d.ts → 2d/BezierCurve.d.ts} +5 -4
  22. package/dist/types/rendering/webgl/geometries/{Ellipse.d.ts → 2d/Ellipse.d.ts} +6 -5
  23. package/dist/types/rendering/webgl/geometries/{Line.d.ts → 2d/Line.d.ts} +5 -4
  24. package/dist/types/rendering/webgl/geometries/{Rectangle.d.ts → 2d/Rectangle.d.ts} +5 -4
  25. package/dist/types/rendering/webgl/geometries/{Triangle.d.ts → 2d/Triangle.d.ts} +5 -4
  26. package/dist/types/rendering/webgl/geometries/BaseGeometry.d.ts +30 -26
  27. package/dist/types/rendering/webgl/geometries/immediate/ImmediateQuad.d.ts +33 -0
  28. package/dist/types/rendering/webgl/geometries/index.d.ts +6 -6
  29. package/dist/types/rendering/webgl/geometries/utils/GeometryDescriptors.d.ts +31 -0
  30. package/dist/types/rendering/webgl/geometries/utils/GeometryGenerator.d.ts +16 -0
  31. package/dist/types/rendering/webgl/index.d.ts +15 -14
  32. package/dist/types/rendering/webgl/materials/Material.d.ts +26 -0
  33. package/dist/types/rendering/webgl/materials/MaterialManager.d.ts +63 -0
  34. package/dist/types/rendering/webgl/materials/index.d.ts +2 -0
  35. package/dist/types/rendering/webgl/pipeline/MaterialBatchPipeline.d.ts +63 -0
  36. package/dist/types/rendering/webgl/pipeline/index.d.ts +7 -0
  37. package/dist/types/rendering/webgl/state/RenderState.d.ts +143 -0
  38. package/dist/types/rendering/webgl/types/DrawCommand.d.ts +5 -3
  39. package/dist/types/rendering/webgl/types/GeometryTypes.d.ts +10 -10
  40. package/dist/types/rendering/webgl/types/RenderTypes.d.ts +1 -1
  41. package/dist/types/rendering/webgl/utils/GLUtils.d.ts +45 -0
  42. package/dist/types/rendering/webgl/utils/hash.d.ts +118 -0
  43. package/dist/types/textmode/AnimationController.d.ts +11 -21
  44. package/dist/types/textmode/Canvas.d.ts +10 -2
  45. package/dist/types/textmode/Grid.d.ts +2 -0
  46. package/dist/types/textmode/TextmodeColor.d.ts +57 -0
  47. package/dist/types/textmode/Textmodifier.d.ts +40 -212
  48. package/dist/types/textmode/interfaces/ITextmodifier.d.ts +272 -0
  49. package/dist/types/textmode/interfaces/index.d.ts +1 -0
  50. package/dist/types/textmode/loadables/TextmodeImage.d.ts +21 -0
  51. package/dist/types/textmode/loadables/TextmodeSource.d.ts +130 -0
  52. package/dist/types/textmode/loadables/TextmodeVideo.d.ts +237 -0
  53. package/dist/types/textmode/{font → loadables/font}/CharacterColorMapper.d.ts +1 -1
  54. package/dist/types/textmode/{font → loadables/font}/CharacterExtractor.d.ts +0 -10
  55. package/dist/types/textmode/{font → loadables/font}/TextmodeFont.d.ts +6 -3
  56. package/dist/types/textmode/{font → loadables/font}/TextureAtlas.d.ts +4 -11
  57. package/dist/types/textmode/{font → loadables/font}/typr/types.d.ts +0 -6
  58. package/dist/types/textmode/loadables/index.d.ts +5 -0
  59. package/dist/types/textmode/loading/LoadingPhaseTracker.d.ts +20 -0
  60. package/dist/types/textmode/loading/LoadingScreenManager.d.ts +170 -0
  61. package/dist/types/textmode/loading/LoadingScreenState.d.ts +22 -0
  62. package/dist/types/textmode/loading/LoadingScreenTheme.d.ts +26 -0
  63. package/dist/types/textmode/loading/LoadingScreenTransition.d.ts +17 -0
  64. package/dist/types/textmode/loading/index.d.ts +6 -0
  65. package/dist/types/textmode/loading/templates/SpinnerTemplate.d.ts +2 -0
  66. package/dist/types/textmode/loading/templates/index.d.ts +1 -0
  67. package/dist/types/textmode/loading/types.d.ts +251 -0
  68. package/dist/types/textmode/managers/KeyboardManager.d.ts +2 -3
  69. package/dist/types/textmode/managers/MouseManager.d.ts +1 -1
  70. package/dist/types/textmode/{plugins → managers}/PluginManager.d.ts +12 -15
  71. package/dist/types/textmode/managers/TouchManager.d.ts +0 -2
  72. package/dist/types/textmode/mixins/AnimationMixin.d.ts +2 -122
  73. package/dist/types/textmode/mixins/FontMixin.d.ts +2 -77
  74. package/dist/types/textmode/mixins/KeyboardMixin.d.ts +3 -85
  75. package/dist/types/textmode/mixins/MouseMixin.d.ts +3 -130
  76. package/dist/types/textmode/mixins/RenderingMixin.d.ts +2 -749
  77. package/dist/types/textmode/mixins/TextmodifierMixin.d.ts +2 -44
  78. package/dist/types/textmode/mixins/TouchMixin.d.ts +2 -187
  79. package/dist/types/textmode/mixins/index.d.ts +8 -8
  80. package/dist/types/textmode/mixins/interfaces/IAnimationMixin.d.ts +167 -0
  81. package/dist/types/textmode/mixins/interfaces/IFontMixin.d.ts +46 -0
  82. package/dist/types/textmode/mixins/interfaces/IKeyboardMixin.d.ts +235 -0
  83. package/dist/types/textmode/mixins/interfaces/IMouseMixin.d.ts +457 -0
  84. package/dist/types/textmode/mixins/interfaces/IRenderingMixin.d.ts +1085 -0
  85. package/dist/types/textmode/mixins/interfaces/ITouchMixin.d.ts +186 -0
  86. package/dist/types/textmode/types.d.ts +49 -0
  87. package/dist/types/textmode/utils/cssColor.d.ts +8 -0
  88. package/dist/types/utils/array.d.ts +34 -0
  89. package/dist/types/utils/math.d.ts +69 -0
  90. package/package.json +1 -1
  91. package/dist/types/rendering/webgl/DrawQueue.d.ts +0 -30
  92. package/dist/types/rendering/webgl/RenderPipeline.d.ts +0 -30
  93. package/dist/types/rendering/webgl/RenderState.d.ts +0 -73
  94. package/dist/types/rendering/webgl/Renderer.d.ts +0 -158
  95. package/dist/types/rendering/webgl/ShaderManager.d.ts +0 -66
  96. package/dist/types/rendering/webgl/geometries/NoiseGrid.d.ts +0 -1
  97. package/dist/types/textmode/TextmodeImage.d.ts +0 -161
  98. package/dist/types/textmode/mixins/ShaderMixin.d.ts +0 -1
  99. /package/dist/types/rendering/webgl/{StateCache.d.ts → utils/ViewportCache.d.ts} +0 -0
  100. /package/dist/types/textmode/{font → loadables/font}/MetricsCalculator.d.ts +0 -0
  101. /package/dist/types/textmode/{font → loadables/font}/index.d.ts +0 -0
  102. /package/dist/types/textmode/{font → loadables/font}/types.d.ts +0 -0
  103. /package/dist/types/textmode/{font → loadables/font}/typr/Typr.d.ts +0 -0
  104. /package/dist/types/textmode/{font → loadables/font}/utils/FontTableReader.d.ts +0 -0
  105. /package/dist/types/textmode/{font → loadables/font}/utils/index.d.ts +0 -0
@@ -0,0 +1,235 @@
1
+ import type { KeyboardEventHandler } from "../../managers/KeyboardManager";
2
+ /**
3
+ * Capabilities provided by the KeyboardMixin
4
+ */
5
+ export interface IKeyboardMixin {
6
+ /**
7
+ * Check if a specific key is currently being pressed.
8
+ *
9
+ * @param key The key to check (e.g., 'a', 'Enter', 'ArrowLeft')
10
+ * @returns true if the key is currently pressed, false otherwise
11
+ *
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
+ * ```
43
+ */
44
+ isKeyPressed(key: string): boolean;
45
+ /**
46
+ * Set a callback function that will be called when a key is pressed down.
47
+ *
48
+ * @param callback The function to call when a key is pressed
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.translate(t.grid.cols / 2, t.grid.rows / 2);
74
+ * t.char(lastKey.length ? lastKey[0] : '?');
75
+ * t.point();
76
+ * t.pop();
77
+ * });
78
+ * ```
79
+ */
80
+ keyPressed(callback: KeyboardEventHandler): void;
81
+ /**
82
+ * Set a callback function that will be called when a key is released.
83
+ *
84
+ * @param callback The function to call when a key is released
85
+ *
86
+ * @example
87
+ * ```javascript
88
+ * const t = textmode.create({ width: 800, height: 600 });
89
+ *
90
+ * let lastRelease = '?';
91
+ * let fade = 0;
92
+ *
93
+ * // Capture the most recent key release and trigger a pulse
94
+ * t.keyReleased((data) => {
95
+ * lastRelease = data.key;
96
+ * fade = 10;
97
+ * });
98
+ *
99
+ * t.draw(() => {
100
+ * t.background(0);
101
+ *
102
+ * // Dim the glow over time
103
+ * const glow = Math.max(0, fade--);
104
+ * const color = 80 + glow * 17;
105
+ * t.charColor(color, color, 255);
106
+ *
107
+ * t.char(lastRelease.length ? lastRelease[0] : '?');
108
+ * t.point();
109
+ * });
110
+ * ```
111
+ */
112
+ keyReleased(callback: KeyboardEventHandler): void;
113
+ /**
114
+ * Get the last key that was pressed.
115
+ *
116
+ * Returns the key string of the last pressed key, or null if no key has been pressed.
117
+ *
118
+ * @example
119
+ * ```javascript
120
+ * const t = textmode.create({ width: 800, height: 600 });
121
+ *
122
+ * t.draw(() => {
123
+ * t.background(0);
124
+ *
125
+ * const lastKey = t.lastKeyPressed;
126
+ * if (lastKey) {
127
+ * // Display the last pressed key
128
+ * t.char(lastKey);
129
+ * t.charColor(255, 255, 255);
130
+ * t.point();
131
+ * }
132
+ * });
133
+ * ```
134
+ */
135
+ get lastKeyPressed(): string | null;
136
+ /**
137
+ * Get the last key that was released.
138
+ *
139
+ * Returns the key string of the last released key, or null if no key has been released.
140
+ *
141
+ * @example
142
+ * ```javascript
143
+ * const t = textmode.create({ width: 800, height: 600 });
144
+ *
145
+ * t.draw(() => {
146
+ * t.background(0);
147
+ *
148
+ * const lastKey = t.lastKeyReleased;
149
+ * if (lastKey) {
150
+ * // Display the last released key
151
+ * t.char(lastKey);
152
+ * t.charColor(128, 128, 128);
153
+ * t.point();
154
+ * }
155
+ * });
156
+ * ```
157
+ */
158
+ get lastKeyReleased(): string | null;
159
+ /**
160
+ * Get all currently pressed keys.
161
+ *
162
+ * Returns an array of key strings that are currently being held down.
163
+ *
164
+ * @example
165
+ * ```javascript
166
+ * const t = textmode.create({ width: 800, height: 600 });
167
+ *
168
+ * t.draw(() => {
169
+ * t.background(0);
170
+ *
171
+ * const pressed = t.pressedKeys;
172
+ *
173
+ * // Display all currently pressed keys
174
+ * pressed.forEach((key, index) => {
175
+ * t.push();
176
+ * t.char(key[0] || '?'); // Show first character of key name
177
+ * t.charColor(255, 200, 100);
178
+ * t.translate(index, 0);
179
+ * t.point();
180
+ * t.pop();
181
+ * });
182
+ * });
183
+ * ```
184
+ */
185
+ get pressedKeys(): string[];
186
+ /**
187
+ * Get current modifier key states.
188
+ *
189
+ * Returns an object with boolean properties for each modifier key.
190
+ *
191
+ * @example
192
+ * ```javascript
193
+ * const t = textmode.create({ width: 800, height: 600 });
194
+ *
195
+ * t.draw(() => {
196
+ * t.background(0);
197
+ * const mods = t.modifierState;
198
+ *
199
+ * // Change behavior based on modifier keys
200
+ * if (mods.shift) {
201
+ * // Draw in caps or with different behavior
202
+ * t.char('S');
203
+ * t.charColor(255, 255, 0);
204
+ * t.point();
205
+ * }
206
+ *
207
+ * if (mods.ctrl) {
208
+ * // Control key is pressed
209
+ * t.translate(2, 0);
210
+ * t.char('C');
211
+ * t.charColor(0, 255, 255);
212
+ * t.point();
213
+ * }
214
+ * });
215
+ * ```
216
+ */
217
+ get modifierState(): {
218
+ /**
219
+ * Whether the Ctrl key is currently pressed
220
+ */
221
+ ctrl: boolean;
222
+ /**
223
+ * Whether the Shift key is currently pressed
224
+ */
225
+ shift: boolean;
226
+ /**
227
+ * Whether the Alt key is currently pressed
228
+ */
229
+ alt: boolean;
230
+ /**
231
+ * Whether the Meta key *(Command on Mac, Windows key on Windows)* is currently pressed
232
+ */
233
+ meta: boolean;
234
+ };
235
+ }
@@ -0,0 +1,457 @@
1
+ import type { MouseEventHandler, MousePosition } from "../../managers/MouseManager";
2
+ /**
3
+ * Capabilities provided by the MouseMixin
4
+ */
5
+ export interface IMouseMixin {
6
+ /**
7
+ * Set a callback function that will be called when the mouse is clicked.
8
+ *
9
+ * @param callback The function to call when the mouse is clicked
10
+ *
11
+ * @example
12
+ * ```javascript
13
+ * // Click to spawn ripples.
14
+ *
15
+ * const t = textmode.create({ width: 800, height: 600 });
16
+ *
17
+ * // Store ripples as { x, y } in center-based coordinates
18
+ * const ripples = [];
19
+ *
20
+ * // Create a ripple at the clicked grid cell
21
+ * t.mouseClicked((data) => {
22
+ * // Convert top-left grid coords to center-based coords (matching draw-time origin)
23
+ * const centerX = Math.round(data.position.x - (t.grid.cols - 1) / 2);
24
+ * const centerY = Math.round(data.position.y - (t.grid.rows - 1) / 2);
25
+ *
26
+ * ripples.push({ x: centerX, y: centerY, age: 0, maxAge: 20 });
27
+ * });
28
+ *
29
+ * t.draw(() => {
30
+ * t.background(0);
31
+ *
32
+ * // Update and draw ripples (iterate backwards when removing)
33
+ * for (let i = ripples.length - 1; i >= 0; i--) {
34
+ * const r = ripples[i];
35
+ * r.age++;
36
+ * const life = r.age / r.maxAge; // 0..1
37
+ * const radius = 1 + life * 7; // expands from ~1 to ~8
38
+ * const intensity = Math.round(255 * (1 - life)); // fades out
39
+ *
40
+ * // Keep cells dark so characters stand out
41
+ * t.charColor(intensity, intensity, 255);
42
+ * t.cellColor(0);
43
+ *
44
+ * t.push();
45
+ * // position already in center-based coordinates
46
+ * t.translate(r.x, r.y);
47
+ *
48
+ * // Draw a ring by sampling points around the circle
49
+ * for (let a = 0; a < Math.PI * 2; a += Math.PI / 8) {
50
+ * const ox = Math.round(Math.cos(a) * radius);
51
+ * const oy = Math.round(Math.sin(a) * radius);
52
+ * t.push();
53
+ * t.translate(ox, oy);
54
+ * t.char('*');
55
+ * t.point();
56
+ * t.pop();
57
+ * }
58
+ *
59
+ * t.pop();
60
+ *
61
+ * // Remove finished ripples
62
+ * if (r.age > r.maxAge) {
63
+ * ripples.splice(i, 1);
64
+ * }
65
+ * }
66
+ *
67
+ * // Show crosshair for the current mouse cell. Convert t.mouse (top-left origin)
68
+ * // to the center-based coordinates used for drawing just like above.
69
+ * if (t.mouse.x !== -1 && t.mouse.y !== -1) {
70
+ * const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
71
+ * const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
72
+ * t.push();
73
+ * t.charColor(180);
74
+ * t.translate(cx, cy);
75
+ * t.char('+');
76
+ * t.point();
77
+ * t.pop();
78
+ * }
79
+ * });
80
+ * ```
81
+ */
82
+ mouseClicked(callback: MouseEventHandler): void;
83
+ /**
84
+ * Set a callback function that will be called when the mouse is pressed down.
85
+ *
86
+ * @param callback The function to call when the mouse is pressed
87
+ *
88
+ * @example
89
+ * ```javascript
90
+ * // Hold mouse to spray particles that fall with gravity.
91
+ *
92
+ * const t = textmode.create({ width: 800, height: 600 });
93
+ *
94
+ * const particles = [];
95
+ * let pressing = false;
96
+ *
97
+ * t.mousePressed((data) => {
98
+ * if (data.position.x === -1 || data.position.y === -1) return;
99
+ * pressing = true;
100
+ * });
101
+ *
102
+ * t.mouseReleased(() => {
103
+ * pressing = false;
104
+ * });
105
+ *
106
+ * t.draw(() => {
107
+ * t.background(0);
108
+ *
109
+ * // Spawn particles while pressing
110
+ * if (pressing && t.mouse.x !== -1) {
111
+ * const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
112
+ * const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
113
+ *
114
+ * for (let i = 0; i < 3; i++) {
115
+ * particles.push({
116
+ * x: cx,
117
+ * y: cy,
118
+ * vx: (Math.random() - 0.5) * 0.8,
119
+ * vy: Math.random() * -0.5 - 0.2,
120
+ * age: 0,
121
+ * maxAge: 30 + Math.random() * 20
122
+ * });
123
+ * }
124
+ * }
125
+ *
126
+ * // Update and draw particles
127
+ * for (let i = particles.length - 1; i >= 0; i--) {
128
+ * const p = particles[i];
129
+ * p.age++;
130
+ * p.vy += 0.08; // gravity
131
+ * p.x += p.vx;
132
+ * p.y += p.vy;
133
+ *
134
+ * if (p.age >= p.maxAge) {
135
+ * particles.splice(i, 1);
136
+ * continue;
137
+ * }
138
+ *
139
+ * const life = 1 - (p.age / p.maxAge);
140
+ * const brightness = Math.round(255 * life);
141
+ *
142
+ * t.push();
143
+ * t.charColor(brightness, brightness * 0.7, 100);
144
+ * t.translate(Math.round(p.x), Math.round(p.y));
145
+ * t.char(life > 0.5 ? 'o' : '.');
146
+ * t.point();
147
+ * t.pop();
148
+ * }
149
+ * });
150
+ * ```
151
+ */
152
+ mousePressed(callback: MouseEventHandler): void;
153
+ /**
154
+ * Set a callback function that will be called when the mouse is released.
155
+ *
156
+ * @param callback The function to call when the mouse is released
157
+ *
158
+ * @example
159
+ * ```javascript
160
+ * // Drag to draw lines that fade over time.
161
+ *
162
+ * const t = textmode.create({ width: 800, height: 600 });
163
+ *
164
+ * const lines = [];
165
+ * let dragStart = null;
166
+ *
167
+ * t.mousePressed((data) => {
168
+ * if (data.position.x === -1 || data.position.y === -1) return;
169
+ * const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
170
+ * const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
171
+ * dragStart = { x: cx, y: cy };
172
+ * });
173
+ *
174
+ * t.mouseReleased((data) => {
175
+ * if (!dragStart || data.position.x === -1) return;
176
+ * const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
177
+ * const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
178
+ *
179
+ * // Calculate line center and local endpoints
180
+ * const centerX = (dragStart.x + cx) / 2;
181
+ * const centerY = (dragStart.y + cy) / 2;
182
+ * const dx = cx - dragStart.x;
183
+ * const dy = cy - dragStart.y;
184
+ *
185
+ * lines.push({
186
+ * cx: centerX, cy: centerY,
187
+ * dx: dx, dy: dy,
188
+ * age: 0, maxAge: 30
189
+ * });
190
+ * dragStart = null;
191
+ * });
192
+ *
193
+ * t.draw(() => {
194
+ * t.background(0);
195
+ *
196
+ * // Draw stored lines with fade
197
+ * for (let i = lines.length - 1; i >= 0; i--) {
198
+ * const ln = lines[i];
199
+ * ln.age++;
200
+ *
201
+ * if (ln.age >= ln.maxAge) {
202
+ * lines.splice(i, 1);
203
+ * continue;
204
+ * }
205
+ *
206
+ * const life = 1 - (ln.age / ln.maxAge);
207
+ * const brightness = Math.round(150 * life);
208
+ *
209
+ * t.push();
210
+ * t.charColor(brightness, brightness, 255);
211
+ * t.char('-');
212
+ * t.lineWeight(2);
213
+ * t.translate(ln.cx, ln.cy);
214
+ * t.line(-ln.dx / 2, -ln.dy / 2, ln.dx / 2, ln.dy / 2);
215
+ * t.pop();
216
+ * }
217
+ *
218
+ * // Draw current drag line
219
+ * if (dragStart && t.mouse.x !== -1) {
220
+ * const cx = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
221
+ * const cy = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
222
+ * const centerX = (dragStart.x + cx) / 2;
223
+ * const centerY = (dragStart.y + cy) / 2;
224
+ * const dx = cx - dragStart.x;
225
+ * const dy = cy - dragStart.y;
226
+ *
227
+ * t.push();
228
+ * t.charColor(255, 200, 0);
229
+ * t.char('o');
230
+ * t.lineWeight(2);
231
+ * t.translate(centerX, centerY);
232
+ * t.line(-dx / 2, -dy / 2, dx / 2, dy / 2);
233
+ * t.pop();
234
+ * }
235
+ * });
236
+ * ```
237
+ */
238
+ mouseReleased(callback: MouseEventHandler): void;
239
+ /**
240
+ * Set a callback function that will be called when the mouse moves.
241
+ *
242
+ * @param callback The function to call when the mouse moves
243
+ *
244
+ * @example
245
+ * ```javascript
246
+ * // Trail of particles following the mouse.
247
+ *
248
+ * const t = textmode.create({ width: 800, height: 600 });
249
+ *
250
+ * const trail = [];
251
+ * const maxTrail = 120;
252
+ * let lastMouse = null;
253
+ *
254
+ * t.mouseMoved((data) => {
255
+ * if (data.position.x === -1 || data.position.y === -1) return;
256
+ *
257
+ * // Convert to center-based coords
258
+ * const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
259
+ * const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
260
+ *
261
+ * // Spawn multiple particles based on movement speed
262
+ * const dx = lastMouse ? cx - lastMouse.x : 0;
263
+ * const dy = lastMouse ? cy - lastMouse.y : 0;
264
+ * const speed = Math.sqrt(dx * dx + dy * dy);
265
+ * const count = Math.max(1, Math.ceil(speed * 1.5));
266
+ *
267
+ * for (let i = 0; i < count; i++) {
268
+ * trail.push({
269
+ * x: cx,
270
+ * y: cy,
271
+ * age: 0,
272
+ * maxAge: 15 + Math.random() * 10
273
+ * });
274
+ * }
275
+ *
276
+ * lastMouse = { x: cx, y: cy };
277
+ * if (trail.length > maxTrail) trail.splice(0, trail.length - maxTrail);
278
+ * });
279
+ *
280
+ * t.draw(() => {
281
+ * t.background(0);
282
+ *
283
+ * // Draw and age particles
284
+ * for (let i = trail.length - 1; i >= 0; i--) {
285
+ * const p = trail[i];
286
+ * p.age++;
287
+ *
288
+ * if (p.age >= p.maxAge) {
289
+ * trail.splice(i, 1);
290
+ * continue;
291
+ * }
292
+ *
293
+ * const life = 1 - (p.age / p.maxAge);
294
+ * const brightness = Math.round(255 * life);
295
+ * const chars = ['.', '*', 'o', '@'];
296
+ * const idx = Math.floor(life * chars.length);
297
+ *
298
+ * t.push();
299
+ * t.charColor(brightness, brightness * 0.6, 255);
300
+ * t.translate(p.x, p.y);
301
+ * t.char(chars[Math.min(idx, chars.length - 1)]);
302
+ * t.point();
303
+ * t.pop();
304
+ * }
305
+ * });
306
+ * ```
307
+ */
308
+ mouseMoved(callback: MouseEventHandler): void;
309
+ /**
310
+ * Set a callback function that will be called when the mouse wheel is scrolled.
311
+ *
312
+ * @param callback The function to call when the mouse wheel is scrolled
313
+ *
314
+ * @example
315
+ * ```javascript
316
+ * // Scroll to create expanding rings.
317
+ *
318
+ * const t = textmode.create({ width: 800, height: 600 });
319
+ *
320
+ * const rings = [];
321
+ *
322
+ * t.mouseScrolled((data) => {
323
+ * if (data.position.x === -1 || data.position.y === -1) return;
324
+ *
325
+ * const cx = Math.round(data.position.x - (t.grid.cols - 1) / 2);
326
+ * const cy = Math.round(data.position.y - (t.grid.rows - 1) / 2);
327
+ *
328
+ * // Use scroll delta to determine ring intensity and direction
329
+ * const scrollSpeed = 2;
330
+ * const intensity = Math.min(scrollSpeed * 30, 255);
331
+ * const scrollDown = (data.delta?.y || 0) > 0;
332
+ *
333
+ * rings.push({
334
+ * x: cx,
335
+ * y: cy,
336
+ * radius: 1,
337
+ * maxRadius: 5 + scrollSpeed * 0.5,
338
+ * color: intensity,
339
+ * scrollDown: scrollDown,
340
+ * age: 0,
341
+ * maxAge: 20
342
+ * });
343
+ * });
344
+ *
345
+ * t.draw(() => {
346
+ * t.background(0);
347
+ *
348
+ * // Update and draw rings
349
+ * for (let i = rings.length - 1; i >= 0; i--) {
350
+ * const r = rings[i];
351
+ * r.age++;
352
+ * r.radius += (r.maxRadius - r.radius) * 0.15;
353
+ *
354
+ * if (r.age >= r.maxAge) {
355
+ * rings.splice(i, 1);
356
+ * continue;
357
+ * }
358
+ *
359
+ * const life = 1 - (r.age / r.maxAge);
360
+ * const brightness = Math.round(r.color * life);
361
+ *
362
+ * t.push();
363
+ * // Blue for scroll down, orange for scroll up
364
+ * if (r.scrollDown) {
365
+ * t.charColor(brightness * 0.5, brightness * 0.8, 255);
366
+ * } else {
367
+ * t.charColor(255, brightness * 0.6, brightness * 0.3);
368
+ * }
369
+ * t.translate(r.x, r.y);
370
+ *
371
+ * // Draw ring
372
+ * for (let a = 0; a < Math.PI * 2; a += Math.PI / 6) {
373
+ * const ox = Math.round(Math.cos(a) * r.radius);
374
+ * const oy = Math.round(Math.sin(a) * r.radius);
375
+ * t.push();
376
+ * t.translate(ox, oy);
377
+ * t.char('o');
378
+ * t.point();
379
+ * t.pop();
380
+ * }
381
+ * t.pop();
382
+ * }
383
+ * });
384
+ * ```
385
+ */
386
+ mouseScrolled(callback: MouseEventHandler): void;
387
+ /**
388
+ * Get the current mouse position in grid coordinates.
389
+ *
390
+ * Returns the mouse position as grid cell coordinates *(column, row)*.
391
+ *
392
+ * If the mouse is outside the grid or the instance is not ready,
393
+ * it returns `{ x: -1, y: -1 }`.
394
+ *
395
+ * @example
396
+ * ```javascript
397
+ * const t = textmode.create({ width: 800, height: 600 });
398
+ *
399
+ * t.draw(() => {
400
+ * t.background(0);
401
+ *
402
+ * // Convert mouse position from top-left origin to center-based origin
403
+ * const centerX = Math.round(t.mouse.x - (t.grid.cols - 1) / 2);
404
+ * const centerY = Math.round(t.mouse.y - (t.grid.rows - 1) / 2);
405
+ *
406
+ * t.translate(centerX, centerY);
407
+ * t.char('*');
408
+ * t.charColor(255, 0, 0);
409
+ * t.cellColor(100);
410
+ * t.point();
411
+ * });
412
+ * ```
413
+ */
414
+ get mouse(): MousePosition;
415
+ /**
416
+ * Set the mouse cursor for the textmode canvas.
417
+ *
418
+ * Provide any valid CSS cursor value (e.g. 'default', 'pointer', 'crosshair', 'move', 'text', 'grab', 'grabbing',
419
+ * 'none', 'zoom-in', 'zoom-out', 'ns-resize', 'ew-resize', 'nwse-resize', 'nesw-resize', etc.),
420
+ * or a CSS `url(...)` cursor. Call with no argument or an empty string to reset to default.
421
+ *
422
+ * See MDN for all options: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
423
+ *
424
+ * @example
425
+ * ```javascript
426
+ * const t = textmode.create({ width: 800, height: 600 });
427
+ * const target = { width: 30, height: 15 };
428
+ *
429
+ * t.draw(() => {
430
+ * t.background(0);
431
+ * t.charColor(255); // keep char visible
432
+ * t.char('*');
433
+ * t.rect(target.width, target.height);
434
+ *
435
+ * // Rectangle is centered at (0, 0) which is grid center
436
+ * // Calculate bounds relative to grid center
437
+ * const centerX = t.grid.cols / 2;
438
+ * const centerY = t.grid.rows / 2;
439
+ *
440
+ * const halfRectWidth = target.width / 2;
441
+ * const halfRectHeight = target.height / 2;
442
+ *
443
+ * const rectLeft = centerX - halfRectWidth;
444
+ * const rectRight = centerX + halfRectWidth;
445
+ * const rectTop = centerY - halfRectHeight;
446
+ * const rectBottom = centerY + halfRectHeight;
447
+ *
448
+ * const hovering =
449
+ * t.mouse.x >= rectLeft && t.mouse.x < rectRight &&
450
+ * t.mouse.y >= rectTop && t.mouse.y < rectBottom;
451
+ *
452
+ * t.cursor(hovering ? 'pointer' : 'default');
453
+ * });
454
+ * ```
455
+ */
456
+ cursor(cursor?: string): void;
457
+ }