textmode.js 0.6.1 → 0.7.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 (27) hide show
  1. package/README.md +0 -2
  2. package/dist/textmode.esm.js +2405 -2027
  3. package/dist/textmode.umd.js +17 -9
  4. package/dist/types/index.d.ts +4 -0
  5. package/dist/types/rendering/webgl/core/Framebuffer.d.ts +2 -0
  6. package/dist/types/rendering/webgl/core/Renderer.d.ts +12 -1
  7. package/dist/types/rendering/webgl/core/Shader.d.ts +3 -0
  8. package/dist/types/rendering/webgl/utils/hash.d.ts +0 -16
  9. package/dist/types/textmode/Textmodifier.d.ts +4 -0
  10. package/dist/types/textmode/interfaces/ITextmodifier.d.ts +8 -2
  11. package/dist/types/textmode/layers/ILayerManager.d.ts +36 -0
  12. package/dist/types/textmode/layers/Layer2DCompositor.d.ts +74 -0
  13. package/dist/types/textmode/layers/LayerManager.d.ts +118 -0
  14. package/dist/types/textmode/layers/TextmodeLayer.d.ts +193 -0
  15. package/dist/types/textmode/layers/filters/FilterRegistry.d.ts +83 -0
  16. package/dist/types/textmode/layers/filters/LayerFilterManager.d.ts +74 -0
  17. package/dist/types/textmode/layers/filters/index.d.ts +3 -0
  18. package/dist/types/textmode/layers/filters/types.d.ts +123 -0
  19. package/dist/types/textmode/layers/index.d.ts +6 -0
  20. package/dist/types/textmode/layers/types.d.ts +74 -0
  21. package/dist/types/textmode/loading/LoadingScreenManager.d.ts +4 -4
  22. package/dist/types/textmode/managers/MouseManager.d.ts +6 -1
  23. package/dist/types/textmode/managers/TouchManager.d.ts +5 -0
  24. package/dist/types/textmode/mixins/interfaces/IKeyboardMixin.d.ts +0 -1
  25. package/dist/types/textmode/mixins/interfaces/IRenderingMixin.d.ts +80 -27
  26. package/dist/types/textmode/mixins/interfaces/ITouchMixin.d.ts +1 -1
  27. package/package.json +1 -1
@@ -9,6 +9,8 @@ export type { TextmodeFramebufferOptions } from './rendering/webgl';
9
9
  export { registerConversionStrategy, unregisterConversionStrategy, getConversionStrategy, } from './textmode/conversion';
10
10
  export type { TextmodeConversionStrategy, TextmodeConversionContext, TextmodeConversionMode, } from './textmode/conversion';
11
11
  export type { TextmodePlugin, TextmodePluginAPI, } from './textmode/managers/PluginManager';
12
+ export { FilterRegistry } from './textmode/layers';
13
+ export type { FilterName, BuiltInFilterName, BuiltInFilterParams, FilterContext, TextmodeFilterStrategy, } from './textmode/layers';
12
14
  export { TextmodeErrorLevel } from './errors/ErrorHandler';
13
15
  export { Textmode as textmode } from './Textmode';
14
16
  /** All loading screen related modules and types. */
@@ -17,6 +19,8 @@ export * as loading from './textmode/loading';
17
19
  export * as loadables from './textmode/loadables';
18
20
  /** All types and interfaces related to input event handling. */
19
21
  export * as input from './textmode/managers';
22
+ /** All modules and types related to multi-layered textmode rendering. */
23
+ export * as layering from './textmode/layers';
20
24
  /**
21
25
  * Exports the create, setErrorLevel, and version functions from the Textmode class for UMD compatibility,
22
26
  * so calls like `textmode.create()` can be used.
@@ -21,6 +21,8 @@ export type TextmodeFramebufferOptions = {
21
21
  width?: number;
22
22
  /** Height of the framebuffer in grid cells */
23
23
  height?: number;
24
+ /** Number of color attachments (1-8) */
25
+ attachments?: number;
24
26
  };
25
27
  /**
26
28
  * Framebuffer class for managing offscreen rendering targets initialized via {@link Textmodifier.createFramebuffer}.
@@ -17,8 +17,10 @@ export declare class GLRenderer implements IRenderer {
17
17
  private _userUniforms;
18
18
  private _framebufferBindingStack;
19
19
  private _viewportStack;
20
+ private _attachmentCountStack;
20
21
  private _currentFramebuffer;
21
22
  private _currentViewport;
23
+ private _currentAttachmentCount;
22
24
  constructor(gl: WebGL2RenderingContext);
23
25
  /**
24
26
  * Push current framebuffer and viewport state onto the stack.
@@ -36,7 +38,7 @@ export declare class GLRenderer implements IRenderer {
36
38
  * Bind a framebuffer and update CPU-side tracking.
37
39
  * @internal
38
40
  */
39
- $bindFramebuffer(framebuffer: WebGLFramebuffer | null, width: number, height: number): void;
41
+ $bindFramebuffer(framebuffer: WebGLFramebuffer | null, width: number, height: number, attachmentCount?: number): void;
40
42
  $shader(shader: GLShader): void;
41
43
  $createShader(vertexSource: string, fragmentSource: string): GLShader;
42
44
  $setUserShader(shader: GLShader | null): void;
@@ -54,6 +56,15 @@ export declare class GLRenderer implements IRenderer {
54
56
  $createFramebuffer(width: number, height: number, attachmentCount?: number, options?: FramebufferOptions): GLFramebuffer;
55
57
  $background(r: number, g?: number, b?: number, a?: number): void;
56
58
  $clear(r?: number, g?: number, b?: number, a?: number): void;
59
+ /**
60
+ * Internal MRT-aware clear implementation.
61
+ * @param r Red component (0-1)
62
+ * @param g Green component (0-1)
63
+ * @param b Blue component (0-1)
64
+ * @param a Alpha component (0-1)
65
+ * @param preserveCharData If true, clears attachment 0 to (1, 1, 0, 0); if false, clears to (0, 0, 0, 0)
66
+ */
67
+ private _clearMRT;
57
68
  $resetViewport(): void;
58
69
  $flushInstances(): void;
59
70
  $dispose(): void;
@@ -13,6 +13,8 @@ export declare class GLShader {
13
13
  private _uniformLocations;
14
14
  private _uniformTypes;
15
15
  private _textureUnitCounter;
16
+ private _textureUnitAssignments;
17
+ private _maxTextureUnits;
16
18
  /**
17
19
  * Creates a new GLShader instance.
18
20
  * @param gl The WebGL rendering context.
@@ -37,6 +39,7 @@ export declare class GLShader {
37
39
  * Set a single uniform value with automatic texture unit management and proper type detection
38
40
  */
39
41
  $setUniform(name: string, value: UniformValue): void;
42
+ private _acquireTextureUnit;
40
43
  /**
41
44
  * Get the WebGL program
42
45
  */
@@ -67,22 +67,6 @@ export declare function hashArray(arr: number[] | number[][]): number;
67
67
  * ```
68
68
  */
69
69
  export declare function hashTypedArray(arr: Float32Array | Int32Array): number;
70
- /**
71
- * Hash an object by converting it to a string representation.
72
- * Uses the object's memory address (toString) as the hash basis.
73
- *
74
- * This is useful for WebGL objects like textures, buffers, etc.
75
- * where identity is more important than value equality.
76
- *
77
- * @param obj - Object to hash
78
- * @returns Hash based on object identity
79
- *
80
- * @example
81
- * ```typescript
82
- * const texture = gl.createTexture();
83
- * hashObject(texture) // → hash based on texture identity
84
- * ```
85
- */
86
70
  export declare function hashObject(obj: any): number;
87
71
  /**
88
72
  * Combine two hash values into a single hash.
@@ -18,6 +18,8 @@ import type { IKeyboardMixin } from './mixins/interfaces/IKeyboardMixin';
18
18
  import type { ITouchMixin } from './mixins/interfaces/ITouchMixin';
19
19
  import type { IMouseMixin } from './mixins/interfaces/IMouseMixin';
20
20
  import { LoadingScreenManager } from './loading/LoadingScreenManager';
21
+ import { LayerManager } from './layers/LayerManager';
22
+ import type { TextmodeLayerManager } from './layers';
21
23
  declare const Textmodifier_base: {
22
24
  new (): {};
23
25
  };
@@ -43,6 +45,7 @@ export declare class Textmodifier extends Textmodifier_base implements ITextmodi
43
45
  _textmodeConversionShader: GLShader;
44
46
  _textmodeFramebuffer: GLFramebuffer;
45
47
  _presentShader: GLShader;
48
+ _layerManager: TextmodeLayerManager;
46
49
  private _pluginManager;
47
50
  private _destroyRequested;
48
51
  private _isRenderingFrame;
@@ -84,6 +87,7 @@ export declare class Textmodifier extends Textmodifier_base implements ITextmodi
84
87
  get isDisposed(): boolean;
85
88
  get overlay(): TextmodeImage | undefined;
86
89
  get loading(): LoadingScreenManager;
90
+ get layers(): LayerManager;
87
91
  $registerSource(source: TextmodeSource): void;
88
92
  }
89
93
  export interface Textmodifier extends IRenderingMixin, IFontMixin, IAnimationMixin, IMouseMixin, ITouchMixin, IKeyboardMixin {
@@ -16,6 +16,7 @@ import type { ITouchMixin } from '../mixins/interfaces/ITouchMixin';
16
16
  import type { IMouseMixin } from '../mixins/interfaces/IMouseMixin';
17
17
  import type { IAnimationMixin } from '../mixins/interfaces/IAnimationMixin';
18
18
  import type { LoadingScreenManager } from '../loading/LoadingScreenManager';
19
+ import type { TextmodeLayerManager } from '../layers';
19
20
  /**
20
21
  * Manages textmode rendering on a [`HTMLCanvasElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement) and provides methods for drawing,
21
22
  * exporting, font management, event handling, and animation control.
@@ -53,6 +54,8 @@ export interface ITextmodifier extends IRenderingMixin, IFontMixin, IAnimationMi
53
54
  readonly _loading: LoadingScreenManager;
54
55
  /** Sources registered for rendering @ignore */
55
56
  readonly _sources: Set<TextmodeSource>;
57
+ /** Layer manager for handling multiple layers @ignore */
58
+ readonly _layerManager: TextmodeLayerManager;
56
59
  /** @ignore */
57
60
  $registerSource(source: TextmodeSource): void;
58
61
  /** Main render method @ignore */
@@ -95,9 +98,12 @@ export interface ITextmodifier extends IRenderingMixin, IFontMixin, IAnimationMi
95
98
  */
96
99
  setup(callback: () => void): void;
97
100
  /**
98
- * Set a draw callback function that will be executed before each render.
101
+ * Set a draw callback function for the base layer.
99
102
  *
100
- * This callback function is where all drawing commands should be placed for textmode rendering.
103
+ * This callback function is where all drawing commands should be placed for textmode rendering on the main layer.
104
+ *
105
+ * If multiple layers are added via {@link Textmodifier.layers}, each layer can have its own draw callback set via {@link TextmodeLayer.draw}.
106
+ * This allows for complex multi-layered compositions with independent rendering logic per layer.
101
107
  *
102
108
  * @param callback The function to call before each render
103
109
  *
@@ -0,0 +1,36 @@
1
+ import type { TextmodeLayer } from './TextmodeLayer';
2
+ import type { TextmodeLayerOptions } from './types';
3
+ export interface ILayerManager {
4
+ /**
5
+ * Get all user layers as a readonly array.
6
+ */
7
+ readonly all: readonly TextmodeLayer[];
8
+ /**
9
+ * The base layer that is always rendered at the bottom of the layer stack.
10
+ * This layer represents the main drawing content before any user layers are composited.
11
+ */
12
+ readonly base: TextmodeLayer;
13
+ /**
14
+ * Add a new layer to the manager.
15
+ * @param options Layer configuration options.
16
+ * @returns The newly added layer.
17
+ */
18
+ add(options?: TextmodeLayerOptions): TextmodeLayer;
19
+ /**
20
+ * Remove a layer from the manager.
21
+ * @param layer The layer to remove.
22
+ */
23
+ remove(layer: TextmodeLayer): void;
24
+ /**
25
+ * Move a layer to a new index in the layer stack.
26
+ * @param layer The layer to move.
27
+ * @param newIndex The new index for the layer.
28
+ */
29
+ move(layer: TextmodeLayer, newIndex: number): void;
30
+ /**
31
+ * Swap the order of two layers if they exist in the same collection.
32
+ * @param layerA The first layer to swap.
33
+ * @param layerB The second layer to swap.
34
+ */
35
+ swap(layerA: TextmodeLayer, layerB: TextmodeLayer): void;
36
+ }
@@ -0,0 +1,74 @@
1
+ import type { GLRenderer, GLFramebuffer } from '../../rendering';
2
+ import type { TextmodeGrid } from '../Grid';
3
+ import type { TextmodeLayer } from './TextmodeLayer';
4
+ /**
5
+ * Parameters for the composite operation.
6
+ */
7
+ export interface CompositeParams {
8
+ /** The base texture to composite onto. */
9
+ baseTexture: WebGLTexture;
10
+ /** The target framebuffer to render the final result into. */
11
+ targetFramebuffer: GLFramebuffer;
12
+ /** The background color as RGBA values (0-1 range). */
13
+ backgroundColor: [number, number, number, number];
14
+ /** The base layer configuration (visibility, opacity, offset). */
15
+ baseLayer: TextmodeLayer;
16
+ /** The array of user layers to composite on top of the base. */
17
+ layers: readonly TextmodeLayer[];
18
+ }
19
+ /**
20
+ * Handles the compositing of multiple layers using shader-based blending.
21
+ *
22
+ * This class is responsible for:
23
+ * - Managing ping-pong framebuffers for layer compositing
24
+ * - Applying blend modes via the composite shader
25
+ * - Rendering the final composited result to a target framebuffer
26
+ *
27
+ * @ignore
28
+ *
29
+ * @remarks
30
+ * The compositor uses a ping-pong buffer technique to avoid WebGL feedback loops
31
+ * when reading from and writing to textures during blend operations.
32
+ */
33
+ export declare class Layer2DCompositor {
34
+ private readonly _renderer;
35
+ private readonly _blendShader;
36
+ private _pingPongBuffers;
37
+ private _currentPingPongIndex;
38
+ /**
39
+ * Create a new LayerCompositor.
40
+ * @param renderer The WebGL renderer instance.
41
+ */
42
+ constructor(renderer: GLRenderer);
43
+ /**
44
+ * Initialize the compositor's framebuffers.
45
+ * @param grid The grid defining the render dimensions.
46
+ * @ignore
47
+ */
48
+ $initialize(grid: TextmodeGrid): void;
49
+ /**
50
+ * Composite all layers onto the target framebuffer.
51
+ * @param params The composite parameters.
52
+ * @param grid The grid defining render dimensions.
53
+ */
54
+ $composite(params: CompositeParams, grid: TextmodeGrid): void;
55
+ /**
56
+ * Blend a single layer onto the current composite.
57
+ */
58
+ private _blendLayer;
59
+ /**
60
+ * Copy the final composite result to the target framebuffer.
61
+ */
62
+ private _copyToTarget;
63
+ /**
64
+ * Resize the compositor's framebuffers.
65
+ * @param grid The grid defining the new dimensions.
66
+ * @ignore
67
+ */
68
+ $resize(grid: TextmodeGrid): void;
69
+ /**
70
+ * Dispose of all compositor resources.
71
+ * @ignore
72
+ */
73
+ $dispose(): void;
74
+ }
@@ -0,0 +1,118 @@
1
+ import type { GLFramebuffer } from '../../rendering';
2
+ import type { Textmodifier } from '../Textmodifier';
3
+ import { TextmodeLayer } from './TextmodeLayer';
4
+ import { LayerFilterManager } from './filters';
5
+ import type { TextmodeLayerOptions } from './types';
6
+ import type { ILayerManager } from './ILayerManager';
7
+ /**
8
+ * Manages all user-defined layers within a Textmodifier instance.
9
+ *
10
+ * This manager is responsible for:
11
+ * - Managing the collection of user layers (add, remove, move, swap)
12
+ * - Coordinating layer rendering and compositing
13
+ *
14
+ * The instance of this class can be accessed via {@link Textmodifier.layers}.
15
+ *
16
+ * The base layer at {@link Textmodifier.baseLayer} is not part of this manager's
17
+ * public layer stack, but is instead managed internally.
18
+ */
19
+ export declare class LayerManager implements ILayerManager {
20
+ private readonly _textmodifier;
21
+ private readonly _renderer;
22
+ private readonly _conversionShader;
23
+ private readonly _compositor2D;
24
+ private readonly _filterManager;
25
+ private readonly _pendingLayers;
26
+ private readonly _layers;
27
+ private readonly _baseLayer;
28
+ private _baseFramebuffer;
29
+ private _baseRawFramebuffer;
30
+ private _isReady;
31
+ /**
32
+ * Create a new LayerManager.
33
+ * @param textmodifier The Textmodifier instance this manager belongs to.
34
+ * @ignore
35
+ */
36
+ constructor(textmodifier: Textmodifier);
37
+ add(options?: TextmodeLayerOptions): TextmodeLayer;
38
+ remove(layer: TextmodeLayer): void;
39
+ move(layer: TextmodeLayer, newIndex: number): void;
40
+ swap(layerA: TextmodeLayer, layerB: TextmodeLayer): void;
41
+ /**
42
+ * Initialize all pending layers and the compositor.
43
+ * @ignore
44
+ */
45
+ $initialize(): void;
46
+ /**
47
+ * Render all layers (base and user) and composite them to the target framebuffer.
48
+ * @param targetFramebuffer The framebuffer to render the final composited result to.
49
+ * @param backgroundColor The background color as RGBA values (0-1 range).
50
+ * @ignore
51
+ */
52
+ $renderAndComposite(targetFramebuffer: GLFramebuffer, backgroundColor: [number, number, number, number]): void;
53
+ /**
54
+ * Render all user layers to their respective framebuffers.
55
+ */
56
+ private _renderUserLayers;
57
+ /**
58
+ * Composite all layers onto the target framebuffer.
59
+ */
60
+ private _compositeLayers;
61
+ /**
62
+ * Resize all layers and the compositor to match the current grid dimensions.
63
+ * @ignore
64
+ */
65
+ $resize(): void;
66
+ /**
67
+ * Dispose of the layer manager, all layers, and the compositor.
68
+ * @ignore
69
+ */
70
+ $dispose(): void;
71
+ get all(): readonly TextmodeLayer[];
72
+ get base(): TextmodeLayer;
73
+ /**
74
+ * Access the filter registry for this Textmodifier instance.
75
+ *
76
+ * Use this to define or register custom filters scoped to this instance.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * // Define a filter using the simplified API
81
+ * const shader = await t.createShader(vertSrc, fragSrc);
82
+ * t.layers.filters.define('brightness', shader, { amount: 1.0 });
83
+ *
84
+ * // Register a custom filter strategy
85
+ * t.layers.filters.register({
86
+ * id: 'custom',
87
+ * createShader() { return shader; },
88
+ * createUniforms(params, ctx) { return { ... }; }
89
+ * });
90
+ *
91
+ * // Use the filter
92
+ * t.layers.base.filter('brightness', 1.5);
93
+ * ```
94
+ */
95
+ get filters(): LayerFilterManager;
96
+ /**
97
+ * Initialize a single layer with required dependencies.
98
+ */
99
+ private _initializeLayer;
100
+ /**
101
+ * Initialize the base layer with external (shared) framebuffers.
102
+ * The base layer shares the main textmode draw framebuffer and uses
103
+ * the manager's base framebuffer for ASCII output.
104
+ */
105
+ private _initializeBaseLayer;
106
+ /**
107
+ * Remove a layer from a collection and dispose it.
108
+ */
109
+ private _removeFromCollection;
110
+ /**
111
+ * Move a layer to a new index within a collection.
112
+ */
113
+ private _moveInCollection;
114
+ /**
115
+ * Swap two layers within a collection.
116
+ */
117
+ private _swapInCollection;
118
+ }
@@ -0,0 +1,193 @@
1
+ import type { GLFramebuffer, GLShader } from '../../rendering';
2
+ import type { TextmodeGrid } from '../Grid';
3
+ import type { Textmodifier } from '../Textmodifier';
4
+ import type { TextmodeLayerBlendMode, TextmodeLayerOptions, LayerDependencies } from './types';
5
+ import type { FilterName, BuiltInFilterName, BuiltInFilterParams, QueuedFilter } from './filters';
6
+ /**
7
+ * A single layer within a multi-layered textmode rendering context.
8
+ *
9
+ * Layers are composited together using various blend modes
10
+ * to create complex visual effects. Each layer can be independently
11
+ * manipulated in terms of visibility, opacity, blend mode, and position.
12
+ *
13
+ * You can draw on each layer by providing a draw callback function,
14
+ * like you would with the base layer's {@link Textmodifier.draw} method.
15
+ *
16
+ * The base layer, which is always present at the bottom of the layer stack,
17
+ * can be accessed via {@link Textmodifier.baseLayer}.
18
+ */
19
+ export declare class TextmodeLayer {
20
+ /** @ignore */
21
+ $visible: boolean;
22
+ /** @ignore */
23
+ $opacity: number;
24
+ /** @ignore */
25
+ $blendMode: TextmodeLayerBlendMode;
26
+ /** @ignore */
27
+ $offsetX: number;
28
+ /** @ignore */
29
+ $offsetY: number;
30
+ private _deps?;
31
+ private _drawFramebuffer?;
32
+ private _asciiFramebuffer?;
33
+ private _rawAsciiFramebuffer?;
34
+ private _drawCallback;
35
+ private _hasRenderableContent;
36
+ private _ownsFramebuffers;
37
+ private _filterQueue;
38
+ /**
39
+ * Create a new TextmodeLayer with the given options.
40
+ * @param options Layer configuration options.
41
+ * @ignore
42
+ */
43
+ constructor(options?: TextmodeLayerOptions);
44
+ /**
45
+ * Return true when this layer has a user-provided draw callback.
46
+ * @ignore
47
+ */
48
+ $hasDraw(): boolean;
49
+ /**
50
+ * Get and clear the filter queue. Used by LayerManager for base layer filter processing.
51
+ * @returns The current filter queue, which is then cleared.
52
+ * @ignore
53
+ */
54
+ $consumeFilterQueue(): QueuedFilter[];
55
+ /**
56
+ * Run the layer's draw callback in the calling context. This does NOT
57
+ * manage framebuffer binding; the caller must ensure the correct
58
+ * framebuffer is bound before invoking this.
59
+ * @ignore
60
+ */
61
+ $runDraw(textmodifier: Textmodifier): void;
62
+ /**
63
+ * Define this layers draw callback.
64
+ * @param callback The function to call when drawing this layer.
65
+ */
66
+ draw(callback: () => void): void;
67
+ /**
68
+ * Show this layer for rendering.
69
+ */
70
+ show(): void;
71
+ /**
72
+ * Hide this layer from rendering.
73
+ */
74
+ hide(): void;
75
+ /**
76
+ * Define or retrieve the layer's opacity.
77
+ * @param opacity The opacity value to set (between 0 and 1).
78
+ * @returns The current opacity if no parameter is provided.
79
+ */
80
+ opacity(opacity?: number): number | void;
81
+ /**
82
+ * Set or get the layer's blend mode.
83
+ * @param mode The blend mode to set.
84
+ * @returns The current blend mode if no parameter is provided.
85
+ */
86
+ blendMode(mode: TextmodeLayerBlendMode): TextmodeLayerBlendMode | void;
87
+ /**
88
+ * Set or get the layer's offset in pixels.
89
+ * @param x The x offset in pixels.
90
+ * @param y The y offset in pixels.
91
+ * @returns The current offset if no parameters are provided.
92
+ */
93
+ offset(x?: number, y?: number): {
94
+ x: number;
95
+ y: number;
96
+ } | void;
97
+ /**
98
+ * Apply a post-processing filter to this layer's rendered output.
99
+ *
100
+ * Filters are applied after ASCII conversion in the order they are called.
101
+ * Call this method within your layer's draw callback to apply effects.
102
+ *
103
+ * @param name The name of the filter to apply (built-in or custom registered filter)
104
+ * @param params Optional parameters for the filter
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * layer.draw(function() {
109
+ * // Drawing commands...
110
+ * this.rect(10, 10);
111
+ *
112
+ * // Apply filters in sequence
113
+ * layer.filter('invert');
114
+ * layer.filter('hueRotate', 45);
115
+ * layer.filter('glow', { intensity: 0.8, radius: 10 });
116
+ * layer.filter('crt');
117
+ * });
118
+ * ```
119
+ *
120
+ * **Color Adjustment Filters:**
121
+ * - `'invert'` - Inverts all colors
122
+ * - `'grayscale'` - Converts to grayscale (param: amount 0-1, default 1)
123
+ * - `'sepia'` - Applies sepia tone (param: amount 0-1, default 1)
124
+ * - `'hueRotate'` - Rotates hue (param: angle in degrees)
125
+ * - `'saturate'` - Adjusts saturation (param: amount, 1 = normal)
126
+ * - `'brightness'` - Adjusts brightness (param: amount, 1 = normal)
127
+ * - `'contrast'` - Adjusts contrast (param: amount, 1 = normal)
128
+ * - `'threshold'` - Black/white threshold (param: threshold 0-1)
129
+ *
130
+ * **Post-Processing Effects:**
131
+ * - `'blur'` - Gaussian blur (param: radius in pixels)
132
+ * - `'glow'` - Bloom/glow effect (params: intensity, radius, threshold)
133
+ * - `'chromaticAberration'` - RGB color fringing (param: amount, direction)
134
+ * - `'scanlines'` - Horizontal scanlines (params: spacing, intensity, offset)
135
+ * - `'crt'` - Full CRT monitor effect (params: curvature, scanlineIntensity, vignetteIntensity, brightness)
136
+ * - `'vignette'` - Darkened edges (params: intensity, softness)
137
+ * - `'pixelate'` - Pixelation effect (param: pixelSize)
138
+ * - `'noise'` - Random noise overlay (params: intensity, seed)
139
+ *
140
+ * Custom filters can be registered using {@link registerFilterStrategy}.
141
+ */
142
+ filter<T extends BuiltInFilterName>(name: T, params?: BuiltInFilterParams[T]): void;
143
+ filter(name: FilterName, params?: unknown): void;
144
+ /**
145
+ * Attach necessary dependencies for this layer to function.
146
+ * @param deps Dependencies required by the layer.
147
+ * @ignore
148
+ */
149
+ $attachDependencies(deps: LayerDependencies): void;
150
+ /**
151
+ * Render the layer's content into its ASCII framebuffer.
152
+ * @param textmodifier The Textmodifier instance.
153
+ * @param conversionShader The shader used for conversion.
154
+ * @ignore
155
+ */
156
+ $render(textmodifier: Textmodifier, conversionShader: GLShader): void;
157
+ /**
158
+ * Resize the layer's framebuffers to match the given grid dimensions.
159
+ * @param grid The TextmodeGrid instance.
160
+ * @ignore
161
+ */
162
+ $resize(grid: TextmodeGrid): void;
163
+ /**
164
+ * Dispose of the layer's resources.
165
+ * @ignore
166
+ */
167
+ $dispose(): void;
168
+ /**
169
+ * Returns the WebGL texture of the final ASCII framebuffer.
170
+ * If the layer is not yet initialized, returns undefined.
171
+ */
172
+ get texture(): WebGLTexture | undefined;
173
+ /**
174
+ * Returns the width of the final ASCII framebuffer in pixels.
175
+ * If the layer is not yet initialized, returns 0.
176
+ */
177
+ get width(): number;
178
+ /**
179
+ * Returns the height of the final ASCII framebuffer in pixels.
180
+ * If the layer is not yet initialized, returns 0.
181
+ */
182
+ get height(): number;
183
+ /**
184
+ * Return true when this layer has renderable content.
185
+ * @ignore
186
+ */
187
+ get $hasRenderableContent(): boolean;
188
+ /**
189
+ * Returns the draw framebuffer for this layer. If the layer is not yet initialized, returns undefined.
190
+ */
191
+ get drawFramebuffer(): GLFramebuffer | undefined;
192
+ private _initializeFramebuffers;
193
+ }
@@ -0,0 +1,83 @@
1
+ import type { GLRenderer, GLShader } from '../../../rendering';
2
+ import type { TextmodeFilterStrategy, FilterName } from './types';
3
+ /**
4
+ * Instance-based registry for filter strategies.
5
+ *
6
+ * Each {@link Textmodifier} instance has its own FilterRegistry, allowing
7
+ * filters to be scoped to a specific instance rather than registered globally.
8
+ *
9
+ * Access via `t.layers.filters`.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // Define a simple filter with the declarative API
14
+ * t.layers.filters.define('blur', blurShader, { radius: 5.0 });
15
+ *
16
+ * // Register a custom filter strategy
17
+ * t.layers.filters.register({
18
+ * id: 'custom',
19
+ * createShader(ctx) { ... },
20
+ * createUniforms(params, ctx) { ... }
21
+ * });
22
+ *
23
+ * // Use the filter
24
+ * t.layers.base.filter('blur', { radius: 10 });
25
+ * ```
26
+ */
27
+ export declare class FilterRegistry {
28
+ private readonly _renderer;
29
+ private readonly _filters;
30
+ private readonly _shaderCache;
31
+ /**
32
+ * Create a new FilterRegistry.
33
+ * @param renderer The WebGL renderer instance
34
+ * @internal
35
+ */
36
+ constructor(renderer: GLRenderer);
37
+ /**
38
+ * Define a filter using a simplified declarative syntax.
39
+ *
40
+ * This is the easiest way to create filters for add-on libraries.
41
+ * The shader is compiled immediately and cached.
42
+ *
43
+ * @param id Unique filter identifier
44
+ * @param shader Pre-compiled GLShader, fragment shader source string, or path to a fragment shader file (.frag or .glsl)
45
+ * @param uniforms Default uniform values. Keys map uniform names to [paramName, defaultValue] tuples.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // With pre-compiled shader (recommended for add-ons)
50
+ * const shader = await t.createShader(vertSrc, fragSrc);
51
+ * t.layers.filters.define('brightness', shader, { u_amount: ['amount', 1.0] });
52
+ *
53
+ * // With a path to a fragment shader file
54
+ * await t.layers.filters.define('brightness', './brightness.frag', { u_amount: ['amount', 1.0] });
55
+ *
56
+ * // Usage:
57
+ * t.layers.base.filter('brightness', 1.5);
58
+ * t.layers.base.filter('brightness', { amount: 1.5 });
59
+ * ```
60
+ */
61
+ $register(id: FilterName, shader: GLShader | string, defs?: Record<string, [paramName: string, defaultValue: unknown]>): Promise<void>;
62
+ /**
63
+ * Unregister a filter by its ID.
64
+ *
65
+ * @param id The filter ID to unregister
66
+ * @returns true if the filter was unregistered, false if it wasn't found
67
+ */
68
+ $unregister(id: FilterName): boolean;
69
+ /**
70
+ * Get a filter strategy by ID.
71
+ * @internal
72
+ */
73
+ $get(id: FilterName): TextmodeFilterStrategy | undefined;
74
+ /**
75
+ * Dispose all resources.
76
+ * @internal
77
+ */
78
+ $dispose(): void;
79
+ /**
80
+ * Register all built-in filters.
81
+ */
82
+ private _registerBuiltInFilters;
83
+ }