textmode.js 0.8.1 → 0.9.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 (32) hide show
  1. package/dist/textmode.esm.js +2841 -2345
  2. package/dist/textmode.umd.js +18 -16
  3. package/dist/types/exports/conversion.d.ts +1 -0
  4. package/dist/types/exports/filters.d.ts +1 -0
  5. package/dist/types/exports/input.d.ts +1 -0
  6. package/dist/types/exports/layering.d.ts +1 -0
  7. package/dist/types/exports/loadables.d.ts +1 -0
  8. package/dist/types/exports/loading.d.ts +1 -0
  9. package/dist/types/exports/plugins.d.ts +1 -0
  10. package/dist/types/index.d.ts +35 -1
  11. package/dist/types/rendering/webgl/core/Framebuffer.d.ts +1 -1
  12. package/dist/types/rendering/webgl/core/Shader.d.ts +17 -3
  13. package/dist/types/rendering/webgl/core/interfaces/IFramebuffer.d.ts +1 -8
  14. package/dist/types/textmode/AnimationController.d.ts +29 -0
  15. package/dist/types/textmode/Grid.d.ts +2 -0
  16. package/dist/types/textmode/Textmodifier.d.ts +8 -15
  17. package/dist/types/textmode/interfaces/ITextmodifier.d.ts +3 -11
  18. package/dist/types/textmode/layers/Camera3D.d.ts +205 -0
  19. package/dist/types/textmode/layers/Layer3DCompositor.d.ts +152 -0
  20. package/dist/types/textmode/layers/LayerManager.d.ts +70 -25
  21. package/dist/types/textmode/layers/TextmodeLayer.d.ts +12 -52
  22. package/dist/types/textmode/layers/index.d.ts +4 -0
  23. package/dist/types/textmode/layers/interfaces/ILayerManager.d.ts +52 -0
  24. package/dist/types/textmode/layers/interfaces/ITextmodeLayer.d.ts +49 -2
  25. package/dist/types/textmode/managers/PluginManager.d.ts +155 -7
  26. package/dist/types/textmode/mixins/interfaces/IAnimationMixin.d.ts +133 -0
  27. package/dist/types/textmode/mixins/interfaces/IRenderingMixin.d.ts +80 -0
  28. package/dist/types/textmode/types.d.ts +4 -3
  29. package/dist/types/utils/TextmodeCollection.d.ts +262 -0
  30. package/dist/types/utils/mat3.d.ts +149 -0
  31. package/dist/types/utils/math.d.ts +26 -0
  32. package/package.json +36 -1
@@ -1,16 +1,19 @@
1
1
  import type { GLFramebuffer } from '../../rendering';
2
2
  import type { Textmodifier } from '../Textmodifier';
3
3
  import { TextmodeLayer } from './TextmodeLayer';
4
+ import { Camera3D } from './Camera3D';
4
5
  import type { TextmodeLayerOptions } from './types';
5
6
  import type { ILayerManager } from './interfaces/ILayerManager';
6
7
  import type { TextmodeOptions } from '../types';
7
8
  import type { TextmodeGrid } from '../Grid';
9
+ import { type FilterName, type BuiltInFilterName, type BuiltInFilterParams, TextmodeFilterManager } from '../filters';
8
10
  /**
9
11
  * Manages all user-defined layers within a Textmodifier in addition to the base layer.
10
12
  *
11
- * This manager is responsible for:
13
+ * Responsibilities:
12
14
  * - Managing the collection of user layers (add, remove, move, swap)
13
15
  * - Coordinating layer rendering and compositing
16
+ * - Owning the global post-processing pipeline (global filters + present to screen)
14
17
  *
15
18
  * The instance of this class can be accessed via {@link Textmodifier.layers}.
16
19
  *
@@ -19,13 +22,20 @@ import type { TextmodeGrid } from '../Grid';
19
22
  export declare class LayerManager implements ILayerManager {
20
23
  private readonly _textmodifier;
21
24
  private readonly _renderer;
22
- private readonly _conversionShader;
23
25
  private readonly _compositor2D;
24
- private _pendingLayers;
25
- private _layers;
26
+ private readonly _compositor3D;
27
+ private readonly _filterManager;
28
+ private readonly _textmodeConversionShader;
29
+ private readonly _presentShader;
30
+ private readonly _camera3D;
31
+ private readonly _layers;
26
32
  private readonly _baseLayer;
27
33
  private _isReady;
34
+ private _renderMode;
28
35
  private readonly _gridDimensionChangeCallbacks;
36
+ private _globalFilterQueue;
37
+ private _preFilterFramebuffer;
38
+ private _postFilterFramebuffer;
29
39
  /**
30
40
  * Create a new LayerManager.
31
41
  * @param textmodifier The Textmodifier instance this manager belongs to.
@@ -33,42 +43,89 @@ export declare class LayerManager implements ILayerManager {
33
43
  */
34
44
  constructor(textmodifier: Textmodifier, opts: TextmodeOptions);
35
45
  /**
36
- * Initialize all pending layers and the compositor.
46
+ * Initialize all pending layers, compositor, and global post-processing resources.
37
47
  * @ignore
38
48
  */
39
49
  $initialize(): Promise<void>;
50
+ /**
51
+ * Queue a global filter to be applied after all layers are composited.
52
+ * Intended to be called by Textmodifier.filter().
53
+ */
54
+ $queueGlobalFilter<T extends BuiltInFilterName>(name: T, params?: BuiltInFilterParams[T]): void;
55
+ $queueGlobalFilter(name: FilterName, params?: unknown): void;
56
+ /**
57
+ * Clear any queued global filters for the current frame.
58
+ * @ignore
59
+ */
60
+ $clearGlobalFilterQueue(): void;
40
61
  add(options?: TextmodeLayerOptions): TextmodeLayer;
41
62
  remove(layer: TextmodeLayer): void;
42
63
  move(layer: TextmodeLayer, newIndex: number): void;
43
64
  swap(layerA: TextmodeLayer, layerB: TextmodeLayer): void;
65
+ mode(mode?: '2d' | '3d'): '2d' | '3d';
66
+ rotation(x?: number, y?: number, z?: number): [number, number, number] | void;
67
+ translation(x?: number, y?: number, z?: number): [number, number, number] | void;
68
+ zoom(zoom?: number): number | void;
69
+ /**
70
+ * Remove and dispose all user layers (keeps base layer intact).
71
+ */
44
72
  clear(): void;
45
73
  /**
46
- * Render all layers (base and user) and composite them to the target framebuffer.
74
+ * Render all layers (base and user) and composite them to the provided target framebuffer.
75
+ * This performs ONLY layer rendering + compositing (no global filters, no present).
76
+ *
47
77
  * @param targetFramebuffer The framebuffer to render the final composited result to.
48
- * @param backgroundColor The background color as RGBA values (0-1 range).
49
78
  * @ignore
50
79
  */
51
- $renderAndComposite(targetFramebuffer: GLFramebuffer, fallbackBaseDraw: () => void): void;
80
+ $renderAndComposite(targetFramebuffer: GLFramebuffer): void;
52
81
  /**
53
- * Render all user layers to their respective framebuffers.
82
+ * Render, composite, apply global filters, present to screen, run post-draw hooks.
83
+ * This replaces the removed "Pass 3/4 + post hooks" section from Textmodifier.$render().
84
+ *
85
+ * @param fallbackBaseDraw Fallback draw callback for the base layer if it has no own draw callback.
86
+ * @ignore
54
87
  */
55
- private _renderUserLayers;
88
+ $renderAndPresent(): void;
56
89
  /**
57
- * Composite all layers onto the target framebuffer.
90
+ * Composite base + user layers onto the target framebuffer.
58
91
  */
59
92
  private _compositeLayers;
60
93
  /**
61
- * Resize all layers and the compositor to match the current grid dimensions.
94
+ * Composite base + user layers in 3D mode using voxel raymarching.
95
+ * In 3D mode, MRT framebuffers are stacked vertically and rendered through the 3D shader.
96
+ */
97
+ private _compositeLayers3D;
98
+ /**
99
+ * Resize all layers, compositor, and global post-processing buffers.
62
100
  * @ignore
63
101
  */
64
102
  $resize(): void;
65
103
  /**
66
- * Dispose of the layer manager, all layers, and the compositor.
104
+ * Dispose of the layer manager, all layers, compositor, and global post-processing resources.
67
105
  * @ignore
68
106
  */
69
107
  $dispose(): void;
70
108
  get all(): readonly TextmodeLayer[];
71
109
  get base(): TextmodeLayer;
110
+ get filters(): TextmodeFilterManager;
111
+ /**
112
+ * Get the 3D camera used for voxel rendering.
113
+ *
114
+ * The camera provides fine-grained control over rotation, translation, and zoom
115
+ * in 3D mode. For simple use cases, you can use the `rotation()`, `translation()`,
116
+ * and `zoom()` methods directly on the layer manager instead.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * // Direct camera access for advanced control
121
+ * const camera = t.layers.camera;
122
+ * camera.rotateY(camera.rotateY() + 1);
123
+ *
124
+ * // Reset camera to defaults
125
+ * t.layers.camera.reset();
126
+ * ```
127
+ */
128
+ get camera(): Camera3D;
72
129
  /**
73
130
  * Get the grid of the topmost visible layer.
74
131
  * Returns the topmost user layer's grid if any are visible, otherwise returns the base layer's grid.
@@ -91,16 +148,4 @@ export declare class LayerManager implements ILayerManager {
91
148
  * Initialize a single layer with required dependencies.
92
149
  */
93
150
  private _initializeLayer;
94
- /**
95
- * Remove a layer from a collection and dispose it.
96
- */
97
- private _removeFromCollection;
98
- /**
99
- * Move a layer to a new index within a collection.
100
- */
101
- private _moveInCollection;
102
- /**
103
- * Swap two layers within a collection.
104
- */
105
- private _swapInCollection;
106
151
  }
@@ -14,6 +14,10 @@ import type { ITextmodeLayer } from './interfaces/ITextmodeLayer';
14
14
  *
15
15
  * You can draw on each layer by providing a draw callback function,
16
16
  * like you would with the base layer's {@link Textmodifier.draw} method.
17
+ *
18
+ * Plugins can extend TextmodeLayer with additional methods using the plugin API's
19
+ * `extendLayer` function. For example, the `textmode-synth` plugin adds a `.synth()`
20
+ * method for hydra-like procedural generation.
17
21
  */
18
22
  export declare class TextmodeLayer implements ITextmodeLayer {
19
23
  /** @ignore */
@@ -40,8 +44,8 @@ export declare class TextmodeLayer implements ITextmodeLayer {
40
44
  private _rawAsciiFramebuffer?;
41
45
  private _pingPongBuffers?;
42
46
  private _drawCallback;
43
- private _hasRenderableContent;
44
47
  private _filterQueue;
48
+ private _pluginState;
45
49
  /**
46
50
  * Create a new TextmodeLayer with the given options.
47
51
  * @param options Layer configuration options.
@@ -54,18 +58,6 @@ export declare class TextmodeLayer implements ITextmodeLayer {
54
58
  * @ignore
55
59
  */
56
60
  $attachDependencies(deps: LayerDependencies): Promise<void>;
57
- /**
58
- * Return true when this layer has a user-provided draw callback.
59
- * @ignore
60
- */
61
- $hasDraw(): boolean;
62
- /**
63
- * Run the layer's draw callback in the calling context. This does NOT
64
- * manage framebuffer binding; the caller must ensure the correct
65
- * framebuffer is bound before invoking this.
66
- * @ignore
67
- */
68
- $runDraw(textmodifier: Textmodifier): void;
69
61
  draw(callback: () => void): void;
70
62
  show(): void;
71
63
  hide(): void;
@@ -78,35 +70,20 @@ export declare class TextmodeLayer implements ITextmodeLayer {
78
70
  rotateZ(z?: number): number | void;
79
71
  filter<T extends BuiltInFilterName>(name: T, params?: BuiltInFilterParams[T]): void;
80
72
  filter(name: FilterName, params?: unknown): void;
81
- /** Get or set the font size for this layer's font. */
82
- fontSize(size?: number): number | void;
83
- /**
84
- * Load a font into this layer from a URL/path or reuse an existing {@link TextmodeFont} instance.
85
- * Creates a new font instance for this layer and loads the font data when a string source is provided.
86
- *
87
- * @param fontSource The URL or path to the font file.
88
- * @returns The loaded TextmodeFont instance.
89
- *
90
- * @example
91
- * ```js
92
- * const layer = t.layers.add();
93
- *
94
- * t.setup(async () => {
95
- * // Load a custom font for this layer
96
- * await layer.loadFont('./fonts/custom.ttf');
97
- * });
98
- * ```
99
- */
73
+ setPluginState<T>(pluginName: string, state: T): void;
74
+ getPluginState<T>(pluginName: string): T | undefined;
75
+ hasPluginState(pluginName: string): boolean;
76
+ deletePluginState(pluginName: string): boolean;
77
+ fontSize(size?: number): void;
100
78
  loadFont(fontSource: string | TextmodeFont): Promise<TextmodeFont>;
101
79
  /**
102
80
  * Render the layer's content into its ASCII framebuffer.
103
81
  * @param textmodifier The Textmodifier instance.
104
82
  * @param conversionShader The shader used for conversion.
83
+ * @param mode The rendering mode, either '2d' or '3d'.
105
84
  * @ignore
106
85
  */
107
- $render(textmodifier: Textmodifier, conversionShader: GLShader, options?: {
108
- fallbackDraw?: () => void;
109
- }): void;
86
+ $render(textmodifier: Textmodifier, conversionShader: GLShader, mode: '2d' | '3d'): void;
110
87
  /**
111
88
  * Resize the layer's framebuffers to match the given grid dimensions.
112
89
  * @param grid The TextmodeGrid instance.
@@ -118,29 +95,12 @@ export declare class TextmodeLayer implements ITextmodeLayer {
118
95
  * @ignore
119
96
  */
120
97
  $dispose(): void;
121
- /**
122
- * Get the texture containing the rendered textmode output for this layer.
123
- */
124
98
  get texture(): WebGLTexture | undefined;
125
- /**
126
- * Get the grid associated with this layer.
127
- */
128
99
  get grid(): TextmodeGrid | undefined;
129
100
  get font(): TextmodeFont;
130
101
  get width(): number;
131
102
  get height(): number;
132
- /**
133
- * Return true when this layer has renderable content.
134
- * @ignore
135
- */
136
- get $hasRenderableContent(): boolean;
137
- /**
138
- * Get the framebuffer used for drawing operations on this layer.
139
- */
140
103
  get drawFramebuffer(): GLFramebuffer | undefined;
141
- /**
142
- * Get the framebuffer containing the rendered textmode output for this layer.
143
- */
144
104
  get asciiFramebuffer(): GLFramebuffer | undefined;
145
105
  private _syncGridToFont;
146
106
  }
@@ -1,4 +1,8 @@
1
1
  export { TextmodeLayer } from './TextmodeLayer';
2
2
  export { LayerManager as TextmodeLayerManager } from './LayerManager';
3
3
  export { Layer2DCompositor as LayerCompositor } from './Layer2DCompositor';
4
+ export { Layer3DCompositor } from './Layer3DCompositor';
5
+ export { Camera3D } from './Camera3D';
4
6
  export type { TextmodeLayerOptions, TextmodeLayerBlendMode } from './types';
7
+ export type { Layer3DOptions, Composite3DParams } from './Layer3DCompositor';
8
+ export type { Camera3DOptions, Camera3DShaderUniforms } from './Camera3D';
@@ -1,6 +1,7 @@
1
1
  import type { TextmodeLayer } from '../TextmodeLayer';
2
2
  import type { TextmodeLayerOptions } from '../types';
3
3
  import type { TextmodeGrid } from '../../Grid';
4
+ import type { Camera3D } from '../Camera3D';
4
5
  export interface ILayerManager {
5
6
  /**
6
7
  * Get all user layers as a readonly array.
@@ -11,6 +12,24 @@ export interface ILayerManager {
11
12
  * This layer represents the main drawing content before any user layers are composited.
12
13
  */
13
14
  readonly base: TextmodeLayer;
15
+ /**
16
+ * The 3D camera used for voxel rendering.
17
+ *
18
+ * The camera provides fine-grained control over rotation, translation, and zoom
19
+ * in 3D mode. For simple use cases, you can use the `rotation()`, `translation()`,
20
+ * and `zoom()` methods directly on the layer manager instead.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // Direct camera access for advanced control
25
+ * const camera = t.layers.camera;
26
+ * camera.rotateY(camera.rotateY() + 1);
27
+ *
28
+ * // Reset camera to defaults
29
+ * t.layers.camera.reset();
30
+ * ```
31
+ */
32
+ readonly camera: Camera3D;
14
33
  /**
15
34
  * Add a new layer to the manager.
16
35
  * @param options Layer configuration options.
@@ -41,6 +60,39 @@ export interface ILayerManager {
41
60
  * and layers need to be recreated from scratch.
42
61
  */
43
62
  clear(): void;
63
+ /**
64
+ * Set or get the rendering mode.
65
+ * - '2d': Traditional 2D layer compositing with ASCII conversion per layer.
66
+ * - '3d': 3D voxel rendering with raymarching through stacked layer data.
67
+ * @param mode The rendering mode to set.
68
+ * @returns Current mode if no argument provided.
69
+ */
70
+ mode(mode?: '2d' | '3d'): '2d' | '3d';
71
+ /**
72
+ * Set or get the 3D rotation angles (in degrees) for voxel rendering.
73
+ * Only applies when renderMode is '3d'.
74
+ * @param x Rotation around X axis in degrees.
75
+ * @param y Rotation around Y axis in degrees.
76
+ * @param z Rotation around Z axis in degrees.
77
+ * @returns Current rotation if no arguments provided.
78
+ */
79
+ rotation(x?: number, y?: number, z?: number): [number, number, number] | void;
80
+ /**
81
+ * Set or get the 3D translation offset for voxel rendering.
82
+ * Only applies when renderMode is '3d'.
83
+ * @param x Translation along X axis.
84
+ * @param y Translation along Y axis.
85
+ * @param z Translation along Z axis.
86
+ * @returns Current translation if no arguments provided.
87
+ */
88
+ translation(x?: number, y?: number, z?: number): [number, number, number] | void;
89
+ /**
90
+ * Set or get the 3D zoom level for voxel rendering.
91
+ * Only applies when renderMode is '3d'.
92
+ * @param zoom Zoom factor (1 = no zoom, >1 = zoom in, <1 = zoom out).
93
+ * @returns Current zoom if no argument provided.
94
+ */
95
+ zoom(zoom?: number): number | void;
44
96
  /**
45
97
  * Get the grid of the topmost visible layer.
46
98
  * Returns the topmost user layer's grid if any are visible, otherwise returns the base layer's grid.
@@ -2,6 +2,7 @@ import type { GLFramebuffer } from '../../../rendering';
2
2
  import type { TextmodeFont } from '../../loadables/font';
3
3
  import type { TextmodeLayerBlendMode } from '../types';
4
4
  import type { FilterName, BuiltInFilterName, BuiltInFilterParams } from '../../filters';
5
+ import type { TextmodeGrid } from '../../Grid';
5
6
  /**
6
7
  * A single layer within a multi-layered textmode rendering context.
7
8
  *
@@ -12,6 +13,10 @@ import type { FilterName, BuiltInFilterName, BuiltInFilterParams } from '../../f
12
13
  * You can draw on each layer by providing a draw callback function,
13
14
  * like you would with the base layer's {@link Textmodifier.draw} method.
14
15
  *
16
+ * Plugins can extend TextmodeLayer with additional methods using the plugin API's
17
+ * `extendLayer` function. For example, the `textmode-synth` plugin adds a `.synth()`
18
+ * method for hydra-like procedural generation.
19
+ *
15
20
  * You can also apply a sequence of post-processing filters to each layer's
16
21
  * rendered output using the {@link ITextmodeLayer.filter} method.
17
22
  *
@@ -24,6 +29,10 @@ export interface ITextmodeLayer {
24
29
  * If the layer is not yet initialized, returns undefined.
25
30
  */
26
31
  readonly texture: WebGLTexture | undefined;
32
+ /**
33
+ * Get the grid associated with this layer.
34
+ */
35
+ readonly grid: TextmodeGrid | undefined;
27
36
  /**
28
37
  * Returns the width of the final ASCII framebuffer in pixels.
29
38
  * If the layer is not yet initialized, returns 0.
@@ -39,7 +48,13 @@ export interface ITextmodeLayer {
39
48
  * If the layer is not yet initialized, returns undefined.
40
49
  */
41
50
  readonly drawFramebuffer: GLFramebuffer | undefined;
42
- /** The font used by this layer. */
51
+ /**
52
+ * Get the framebuffer containing the rendered textmode output for this layer.
53
+ */
54
+ readonly asciiFramebuffer: GLFramebuffer | undefined;
55
+ /**
56
+ * The font used by this layer.
57
+ */
43
58
  readonly font: TextmodeFont;
44
59
  /**
45
60
  * Define this layer's draw callback. The callback is executed each frame
@@ -121,10 +136,41 @@ export interface ITextmodeLayer {
121
136
  * ```
122
137
  */
123
138
  draw(callback: () => void): void;
139
+ /**
140
+ * Store plugin-specific state on this layer.
141
+ * Plugins can use this to attach their own data to layer instances.
142
+ *
143
+ * @param pluginName Unique identifier for the plugin.
144
+ * @param state The state object to store.
145
+ * @ignore
146
+ */
147
+ setPluginState<T>(pluginName: string, state: T): void;
148
+ /**
149
+ * Retrieve plugin-specific state stored on this layer.
150
+ *
151
+ * @param pluginName Unique identifier for the plugin.
152
+ * @returns The stored state object, or undefined if not set.
153
+ * @ignore
154
+ */
155
+ getPluginState<T>(pluginName: string): T | undefined;
156
+ /** Check if plugin-specific state exists on this layer.
157
+ *
158
+ * @param pluginName Unique identifier for the plugin.
159
+ * @returns True if state exists, false otherwise.
160
+ * @ignore
161
+ */
162
+ hasPluginState(pluginName: string): boolean;
163
+ /** Delete plugin-specific state from this layer.
164
+ *
165
+ * @param pluginName Unique identifier for the plugin.
166
+ * @ignore
167
+ */
168
+ deletePluginState(pluginName: string): void;
124
169
  /** Get or set the font size for this layer. */
125
170
  fontSize(size?: number): number | void;
126
171
  /**
127
- * Load a font from the given source into this layer.
172
+ * Load a font into this layer from a URL/path or reuse an existing {@link TextmodeFont} instance.
173
+ * Creates a new font instance for this layer and loads the font data when a string source is provided.
128
174
  *
129
175
  * @param fontSource The URL or path to the font file.
130
176
  * @returns The loaded TextmodeFont instance.
@@ -134,6 +180,7 @@ export interface ITextmodeLayer {
134
180
  * const layer = t.layers.add();
135
181
  *
136
182
  * t.setup(async () => {
183
+ * // Load a custom font for this layer
137
184
  * await layer.loadFont('./fonts/custom.ttf');
138
185
  * });
139
186
  * ```
@@ -4,32 +4,118 @@ import type { GLFramebuffer } from '../../rendering';
4
4
  import type { TextmodeFont } from '../loadables/font';
5
5
  import type { TextmodeGrid } from '../Grid';
6
6
  import type { TextmodeCanvas } from '../Canvas';
7
+ import type { TextmodeLayer } from '../layers/TextmodeLayer';
8
+ import type { TextmodeLayerManager } from '../layers';
9
+ /**
10
+ * Callback type for simple plugin hooks without parameters.
11
+ */
7
12
  export type TextmodePluginHook = () => void;
13
+ /**
14
+ * Callback type for setup lifecycle hooks.
15
+ * Can be synchronous or return a Promise for async operations.
16
+ */
17
+ export type SetupLifecycleHook = () => void | Promise<void>;
18
+ /**
19
+ * Callback type for layer lifecycle events.
20
+ */
21
+ export type LayerLifecycleHook = (layer: TextmodeLayer) => void;
22
+ /**
23
+ * Callback type for layer render hooks.
24
+ */
25
+ export type LayerRenderHook = (layer: TextmodeLayer) => void;
8
26
  /**
9
27
  * An extended API provided to plugins when they are installed on a {@link Textmodifier} instance.
10
28
  */
11
29
  export interface TextmodePluginAPI {
12
30
  /** The WebGL renderer used by the Textmodifier instance. */
13
31
  renderer: GLRenderer;
14
- /** The font used by the Textmodifier instance. */
32
+ /** The font used by the Textmodifier instance (from base layer). */
15
33
  font: TextmodeFont;
16
- /** The grid used by the Textmodifier instance. */
34
+ /** The grid used by the Textmodifier instance (from base layer). */
17
35
  grid: TextmodeGrid;
18
36
  /** The canvas used by the Textmodifier instance. */
19
37
  canvas: TextmodeCanvas;
20
- /** The framebuffer the user draws to with 3 render targets. */
38
+ /** The framebuffer the user draws to with 3 render targets (from base layer). */
21
39
  drawFramebuffer: GLFramebuffer;
22
- /** The framebuffer containing the ASCII representation.<br/>
23
- * This framebuffer only has a single render target. */
40
+ /**
41
+ * The framebuffer containing the ASCII representation (from base layer).<br/>
42
+ * This framebuffer only has a single render target.
43
+ */
24
44
  asciiFramebuffer: GLFramebuffer;
45
+ /** The layer manager for accessing and managing all layers. */
46
+ layerManager: TextmodeLayerManager;
25
47
  /**
26
- * Register a callback to be invoked before each draw cycle. Happens just before the draw framebuffer is being bound.
48
+ * Register a callback to be invoked before each draw cycle.
49
+ * Happens just before any framebuffer
50
+ * @returns A function to unregister the hook.
27
51
  */
28
52
  registerPreDrawHook(callback: () => void): () => void;
29
53
  /**
30
- * Register a callback to be invoked after each draw cycle. Happens outside of the draw framebuffer being bound after the final result is drawn to the screen.
54
+ * Register a callback to be invoked after each draw cycle.
55
+ * Happens outside of the draw framebuffer being bound after the final result is drawn to the screen.
56
+ * @returns A function to unregister the hook.
31
57
  */
32
58
  registerPostDrawHook(callback: () => void): () => void;
59
+ /**
60
+ * Register a callback to be invoked when a layer is about to be disposed.
61
+ * @param callback The callback to invoke with the layer being disposed.
62
+ * @returns A function to unregister the hook.
63
+ */
64
+ registerLayerDisposedHook(callback: LayerLifecycleHook): () => void;
65
+ /**
66
+ * Register a callback to be invoked before each layer's render cycle.
67
+ * This happens after the layer's visibility check but before any drawing operations.
68
+ * Useful for rendering content to the layer's framebuffer before user draw callbacks.
69
+ * @param callback The callback to invoke with the layer and render context.
70
+ * @returns A function to unregister the hook.
71
+ */
72
+ registerLayerPreRenderHook(callback: LayerRenderHook): () => void;
73
+ /**
74
+ * Register a callback to be invoked after each layer's render cycle.
75
+ * This happens after the user draw callback but before ASCII conversion.
76
+ * @param callback The callback to invoke with the layer and render context.
77
+ * @returns A function to unregister the hook.
78
+ */
79
+ registerLayerPostRenderHook(callback: LayerRenderHook): () => void;
80
+ /**
81
+ * Register a callback to be invoked before the user's setup callback runs.
82
+ * This happens after the Textmodifier and all layers are fully initialized,
83
+ * but before user code in `setup()` executes.
84
+ * Useful for plugins that need to prepare resources or state before user setup.
85
+ * @param callback The callback to invoke before setup.
86
+ * @returns A function to unregister the hook.
87
+ */
88
+ registerPreSetupHook(callback: () => void | Promise<void>): () => void;
89
+ /**
90
+ * Register a callback to be invoked after the user's setup callback completes.
91
+ * This happens after user code in `setup()` has finished executing,
92
+ * but before the loading screen finishes and the main render loop begins.
93
+ * Useful for plugins that need to finalize initialization after user setup.
94
+ * @param callback The callback to invoke after setup.
95
+ * @returns A function to unregister the hook.
96
+ */
97
+ registerPostSetupHook(callback: () => void | Promise<void>): () => void;
98
+ /**
99
+ * Extend TextmodeLayer instances with a new method.
100
+ * The method will be available on all existing and future layer instances.
101
+ *
102
+ * @param methodName The name of the method to add.
103
+ * @param implementation The implementation function. `this` will be bound to the TextmodeLayer instance.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * api.extendLayer('synth', function(source: SynthSource) {
108
+ * // `this` is the TextmodeLayer instance
109
+ * this.setPluginState('synth', { source, compiled: compile(source) });
110
+ * });
111
+ * ```
112
+ */
113
+ extendLayer<TArgs extends unknown[], TReturn>(methodName: string, implementation: (this: TextmodeLayer, ...args: TArgs) => TReturn): void;
114
+ /**
115
+ * Remove a method extension from TextmodeLayer.
116
+ * @param methodName The name of the method to remove.
117
+ */
118
+ removeLayerExtension(methodName: string): void;
33
119
  }
34
120
  /**
35
121
  * A plugin interface for extending the functionality of a {@link Textmodifier} instance.
@@ -59,20 +145,82 @@ export interface TextmodePlugin {
59
145
  */
60
146
  uninstall?(textmodifier: Textmodifier, api: TextmodePluginAPI): void | Promise<void>;
61
147
  }
148
+ /**
149
+ * Manager for handling TextmodePlugin installation, uninstallation, and hook execution.
150
+ * @ignore
151
+ */
62
152
  export declare class TextmodePluginManager {
63
153
  private readonly _textmodifier;
64
154
  private readonly _plugins;
65
155
  private readonly _installationOrder;
66
156
  private readonly _preDrawHooks;
67
157
  private readonly _postDrawHooks;
158
+ private readonly _layerDisposedHooks;
159
+ private readonly _layerPreRenderHooks;
160
+ private readonly _layerPostRenderHooks;
161
+ private readonly _preSetupHooks;
162
+ private readonly _postSetupHooks;
163
+ private readonly _layerExtensions;
68
164
  constructor(textmodifier: Textmodifier);
165
+ /**
166
+ * Install plugins synchronously.
167
+ * This is called from the constructor to ensure layer method extensions
168
+ * are available immediately after textmode.create() returns.
169
+ *
170
+ * Plugin install() methods should be synchronous or return void.
171
+ * Any async operations in install() will be started but not awaited.
172
+ *
173
+ * @ignore
174
+ */
175
+ $installManySync(plugins: TextmodePlugin[]): void;
69
176
  $installMany(plugins: TextmodePlugin[]): Promise<void>;
70
177
  $unuse(pluginName: string): Promise<void>;
71
178
  $runPreDrawHooks(): void;
72
179
  $runPostDrawHooks(): void;
180
+ /**
181
+ * Notify plugins that a layer is about to be disposed.
182
+ * Called by LayerManager/TextmodeLayer before disposal.
183
+ * @ignore
184
+ */
185
+ $notifyLayerDisposed(layer: TextmodeLayer): void;
186
+ /**
187
+ * Run all registered pre-render hooks for a layer.
188
+ * Called by TextmodeLayer.$render() before drawing.
189
+ * @ignore
190
+ */
191
+ $runLayerPreRenderHooks(layer: TextmodeLayer): void;
192
+ /**
193
+ * Run all registered post-render hooks for a layer.
194
+ * Called by TextmodeLayer.$render() after drawing but before ASCII conversion.
195
+ * @ignore
196
+ */
197
+ $runLayerPostRenderHooks(layer: TextmodeLayer): void;
198
+ /**
199
+ * Run all registered pre-setup hooks.
200
+ * Called by Textmodifier before the user's setup callback.
201
+ * @ignore
202
+ */
203
+ $runPreSetupHooks(): Promise<void>;
204
+ /**
205
+ * Run all registered post-setup hooks.
206
+ * Called by Textmodifier after the user's setup callback completes.
207
+ * @ignore
208
+ */
209
+ $runPostSetupHooks(): Promise<void>;
73
210
  $disposeAll(): Promise<void>;
74
211
  private _createAPI;
75
212
  private _registerHook;
76
213
  private _removePluginHooks;
77
214
  private _runHooks;
215
+ private _runLayerLifecycleHooks;
216
+ private _runLayerRenderHooks;
217
+ /**
218
+ * Run setup lifecycle hooks in plugin installation order.
219
+ * Supports both synchronous and async hooks.
220
+ */
221
+ private _runSetupHooks;
222
+ private _addLayerExtension;
223
+ private _removeLayerExtension;
224
+ private _addMethodToLayerPrototype;
225
+ private _removeMethodFromLayerPrototype;
78
226
  }