@utsp/render 0.11.0-nightly.20251213152020.671c815 → 0.11.0-nightly.20251213232121.8b318c1

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.
@@ -0,0 +1,390 @@
1
+ import { PostProcessConfig, ScanlinesConfig } from '@utsp/types';
2
+ export { IColorPalette, IRenderer, PostProcessConfig, RenderState, ScanlinesConfig } from '@utsp/types';
3
+
4
+ /**
5
+ * Default color palette (VGA colors + extended)
6
+ * Maps palette index to CSS color string
7
+ */
8
+ declare const DEFAULT_PALETTE: readonly string[];
9
+ /**
10
+ * Convert a color palette index to CSS color string
11
+ */
12
+ declare function paletteIndexToColor(index: number, palette?: readonly string[]): string;
13
+ /**
14
+ * Convert CSS color string to palette index (finds closest match)
15
+ */
16
+ declare function colorToPaletteIndex(color: string, palette?: readonly string[]): number;
17
+
18
+ /**
19
+ * 🔲 GridOverlay - Classe réutilisable pour gérer le canvas de grille de débogage
20
+ *
21
+ * Gère un canvas 2D superposé qui affiche une grille de cellules.
22
+ * Au lieu de simples lignes, dessine un cadre fin à l'intérieur de chaque cellule
23
+ * pour une meilleure visualisation.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const grid = new GridOverlay(containerElement);
28
+ * grid.setDimensions(80, 24, 10, 16);
29
+ * grid.render();
30
+ * ```
31
+ */
32
+ declare class GridOverlay {
33
+ private canvas;
34
+ private ctx;
35
+ private container;
36
+ private cols;
37
+ private rows;
38
+ private cellWidth;
39
+ private cellHeight;
40
+ private offsetX;
41
+ private offsetY;
42
+ private strokeColor;
43
+ private lineWidth;
44
+ /**
45
+ * Crée une nouvelle overlay de grille
46
+ * @param container - Élément parent qui contiendra le canvas
47
+ * @param options - Options de configuration
48
+ */
49
+ constructor(container: HTMLElement, options?: {
50
+ strokeColor?: string;
51
+ lineWidth?: number;
52
+ zIndex?: number;
53
+ });
54
+ /**
55
+ * Configure les dimensions de la grille
56
+ * @param cols - Nombre de colonnes
57
+ * @param rows - Nombre de lignes
58
+ * @param cellWidth - Largeur d'une cellule en pixels
59
+ * @param cellHeight - Hauteur d'une cellule en pixels
60
+ * @param offsetX - Décalage horizontal (optionnel)
61
+ * @param offsetY - Décalage vertical (optionnel)
62
+ */
63
+ setDimensions(cols: number, rows: number, cellWidth: number, cellHeight: number, offsetX?: number, offsetY?: number): void;
64
+ /**
65
+ * Configure la taille physique du canvas
66
+ * Le canvas doit avoir la MÊME approche que le canvas principal WebGL :
67
+ * - Résolution physique = dimensions de base (SANS DPR)
68
+ * - Taille CSS = dimensions de base
69
+ * - Le scaling visuel est fait via transform: scale()
70
+ *
71
+ * @param baseWidth - Largeur de base en pixels
72
+ * @param baseHeight - Hauteur de base en pixels
73
+ */
74
+ setCanvasSize(baseWidth: number, baseHeight: number): void;
75
+ /**
76
+ * Configure les options visuelles
77
+ * @param options - Options de rendu
78
+ */
79
+ setStyle(options: {
80
+ strokeColor?: string;
81
+ lineWidth?: number;
82
+ }): void;
83
+ /**
84
+ * Configure la transformation et le positionnement du canvas de grille
85
+ * pour qu'il corresponde exactement au canvas principal (pixel-perfect scaling)
86
+ *
87
+ * APPROCHE SIMPLE : On ne fait PAS de transform: scale().
88
+ * On définit le canvas à la taille finale (scalée) directement,
89
+ * et on le positionne exactement où est le canvas principal.
90
+ *
91
+ * Le dessin de la grille doit alors être fait à l'échelle scalée.
92
+ *
93
+ * @param scale - Facteur de scale (même valeur que le canvas principal)
94
+ * @param baseWidth - Largeur de base du canvas (avant scale)
95
+ * @param baseHeight - Hauteur de base du canvas (avant scale)
96
+ * @param mainCanvasRect - Le getBoundingClientRect() du canvas principal
97
+ * @param containerRect - Le getBoundingClientRect() du container
98
+ */
99
+ setTransform(_scale: number, _baseWidth: number, _baseHeight: number, mainCanvasRect: DOMRect, containerRect: DOMRect): void;
100
+ /**
101
+ * Dessine la grille avec des lignes fines continues
102
+ * Les lignes sont dessinées aux bords exacts des cellules.
103
+ */
104
+ render(): void;
105
+ /**
106
+ * Met à jour et redessine la grille avec de nouvelles dimensions
107
+ * Méthode pratique qui combine setDimensions, setCanvasSize et render
108
+ *
109
+ * @param cols - Nombre de colonnes
110
+ * @param rows - Nombre de lignes
111
+ * @param cellWidth - Largeur d'une cellule
112
+ * @param cellHeight - Hauteur d'une cellule
113
+ * @param displayWidth - Largeur d'affichage du canvas
114
+ * @param displayHeight - Hauteur d'affichage du canvas
115
+ * @param offsetX - Décalage horizontal (optionnel)
116
+ * @param offsetY - Décalage vertical (optionnel)
117
+ */
118
+ update(cols: number, rows: number, cellWidth: number, cellHeight: number, displayWidth: number, displayHeight: number, offsetX?: number, offsetY?: number): void;
119
+ /**
120
+ * Affiche ou cache la grille
121
+ * @param visible - true pour afficher, false pour cacher
122
+ */
123
+ setVisible(visible: boolean): void;
124
+ /**
125
+ * Supprime le canvas de grille du DOM
126
+ */
127
+ destroy(): void;
128
+ /**
129
+ * Retourne le canvas HTML
130
+ */
131
+ getCanvas(): HTMLCanvasElement;
132
+ }
133
+
134
+ /**
135
+ * AutoplayOverlay - Displays a play button overlay that must be clicked to start the application
136
+ *
137
+ * This is useful for:
138
+ * - Audio APIs that require user interaction before playing
139
+ * - Preventing automatic resource consumption
140
+ * - Better UX on mobile where autoplay may not be desired
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * const overlay = new AutoplayOverlay(container, {
145
+ * buttonText: 'Click to Start',
146
+ * onStart: () => {
147
+ * // Application starts here
148
+ * }
149
+ * });
150
+ *
151
+ * // To programmatically start (e.g., if autoplay is enabled):
152
+ * overlay.start();
153
+ *
154
+ * // Cleanup:
155
+ * overlay.destroy();
156
+ * ```
157
+ */
158
+ interface AutoplayOverlayOptions {
159
+ /** Text to display on the button (default: 'Click to Start') */
160
+ buttonText?: string;
161
+ /** Callback when user clicks the button */
162
+ onStart?: () => void;
163
+ /** Background color of the overlay (default: 'rgba(0, 0, 0, 0.8)') */
164
+ backgroundColor?: string;
165
+ /** Button background color (default: '#4a90d9') */
166
+ buttonColor?: string;
167
+ /** Button hover color (default: '#357abd') */
168
+ buttonHoverColor?: string;
169
+ /** Button text color (default: '#ffffff') */
170
+ buttonTextColor?: string;
171
+ /** Z-index of the overlay (default: 1000) */
172
+ zIndex?: number;
173
+ }
174
+ declare class AutoplayOverlay {
175
+ private container;
176
+ private overlayDiv;
177
+ private button;
178
+ private options;
179
+ private started;
180
+ private onStartCallback?;
181
+ constructor(container: HTMLElement, options?: AutoplayOverlayOptions);
182
+ /**
183
+ * Create the overlay DOM elements
184
+ */
185
+ private createOverlay;
186
+ /**
187
+ * Start the application (hide overlay and call onStart callback)
188
+ * Can be called programmatically if autoplay is enabled
189
+ */
190
+ start(): void;
191
+ /**
192
+ * Check if the overlay has been started
193
+ */
194
+ isStarted(): boolean;
195
+ /**
196
+ * Check if the overlay is currently visible
197
+ */
198
+ isVisible(): boolean;
199
+ /**
200
+ * Remove the overlay from DOM
201
+ */
202
+ private removeOverlay;
203
+ /**
204
+ * Set the button text
205
+ */
206
+ setButtonText(text: string): void;
207
+ /**
208
+ * Update the onStart callback
209
+ */
210
+ setOnStart(callback: () => void): void;
211
+ /**
212
+ * Destroy the overlay and cleanup
213
+ */
214
+ destroy(): void;
215
+ }
216
+
217
+ /**
218
+ * PostProcessOverlay - Static overlay canvas for post-processing effects
219
+ *
220
+ * This overlay is completely INDEPENDENT of the terminal renderer.
221
+ * It covers the entire container and draws effects at native screen resolution.
222
+ *
223
+ * 🎯 SIMPLE DESIGN:
224
+ * - Canvas fills 100% of the parent container
225
+ * - Effects are drawn at native resolution (no scaling needed)
226
+ * - ResizeObserver handles container size changes
227
+ * - No synchronization with TerminalGL required
228
+ *
229
+ * 🎨 EFFECTS:
230
+ * - Scanlines: Horizontal, vertical, or grid patterns
231
+ * - Lines are drawn at fixed pixel intervals (e.g., every 2 pixels)
232
+ * - Works regardless of terminal scale or cell size
233
+ *
234
+ * 🛡️ ROBUST:
235
+ * - Uses !important on critical CSS properties
236
+ * - pointer-events: none to not interfere with input
237
+ * - Redraws only on config change or container resize
238
+ */
239
+
240
+ /**
241
+ * Options for PostProcessOverlay constructor
242
+ */
243
+ interface PostProcessOverlayOptions {
244
+ }
245
+ /**
246
+ * Static post-processing overlay
247
+ *
248
+ * Key design principles:
249
+ * 1. INDEPENDENT of TerminalGL - no sync required
250
+ * 2. Fills entire container at native resolution
251
+ * 3. Rendered ONCE when configured (no per-frame cost)
252
+ * 4. Own ResizeObserver for container size changes
253
+ */
254
+ declare class PostProcessOverlay {
255
+ private canvas;
256
+ private ctx;
257
+ private containerDiv;
258
+ private parentElement;
259
+ private resizeObserver;
260
+ private width;
261
+ private height;
262
+ private currentConfig;
263
+ private configHash;
264
+ constructor(parentElement: HTMLElement, _options?: PostProcessOverlayOptions);
265
+ /**
266
+ * Handle container resize
267
+ */
268
+ private handleResize;
269
+ /**
270
+ * Set the post-processing configuration
271
+ * Only re-renders if config actually changed
272
+ */
273
+ setConfig(config: PostProcessConfig | null): void;
274
+ /**
275
+ * Update scanlines configuration
276
+ */
277
+ setScanlines(config: ScanlinesConfig | null): void;
278
+ /**
279
+ * Enable/disable scanlines with default settings
280
+ */
281
+ setScanlinesEnabled(enabled: boolean): void;
282
+ /**
283
+ * Set scanlines opacity (0-1)
284
+ */
285
+ setScanlinesOpacity(opacity: number): void;
286
+ /**
287
+ * Set scanlines pattern
288
+ */
289
+ setScanlinesPattern(pattern: 'horizontal' | 'vertical' | 'grid'): void;
290
+ /**
291
+ * Set scanlines spacing (pixels between lines)
292
+ */
293
+ setScanlinesSpacing(spacing: number): void;
294
+ /**
295
+ * Get current configuration
296
+ */
297
+ getConfig(): PostProcessConfig | null;
298
+ /**
299
+ * Check if any effect is currently active
300
+ */
301
+ isActive(): boolean;
302
+ /**
303
+ * Cleanup resources
304
+ */
305
+ destroy(): void;
306
+ /**
307
+ * @deprecated No longer needed - overlay is independent of renderer
308
+ */
309
+ syncWithRenderer(_renderer: unknown): void;
310
+ /**
311
+ * @deprecated No longer needed - overlay handles its own resize
312
+ */
313
+ resize(_cols: number, _rows: number): void;
314
+ /**
315
+ * @deprecated No longer needed - overlay is independent
316
+ */
317
+ setCellDimensions(_cellWidth: number, _cellHeight: number): void;
318
+ private show;
319
+ private hide;
320
+ private clear;
321
+ private isActiveConfig;
322
+ /**
323
+ * Render all active effects to the canvas
324
+ */
325
+ private render;
326
+ /**
327
+ * Render scanlines pattern at native resolution
328
+ *
329
+ * Simply draws lines at fixed pixel intervals across the entire canvas.
330
+ * Completely independent of terminal scaling.
331
+ */
332
+ private renderScanlines;
333
+ /**
334
+ * Create a hash of the config to detect changes
335
+ */
336
+ private hashConfig;
337
+ }
338
+
339
+ /**
340
+ * Atlas Utilities
341
+ *
342
+ * Shared utilities for block-based font atlas calculations.
343
+ * Used by both TerminalGL (WebGL) and ImageFontAtlas (Canvas2D).
344
+ */
345
+ /**
346
+ * Number of 256-char blocks in an atlas
347
+ * - 1 block = 16×16 grid = 256 chars (8-bit)
348
+ * - 4 blocks = 32×32 grid = 1024 chars (10-bit)
349
+ * - 16 blocks = 64×64 grid = 4096 chars (12-bit)
350
+ */
351
+ type AtlasBlocks = 1 | 4 | 16;
352
+ /**
353
+ * Get the number of columns in the atlas grid
354
+ * @param blocks - Number of 256-char blocks (1, 4, or 16)
355
+ * @returns Number of character columns (16, 32, or 64)
356
+ */
357
+ declare function getAtlasColumns(blocks: AtlasBlocks): number;
358
+ /**
359
+ * Get the maximum valid charCode for a given atlas size
360
+ * @param blocks - Number of 256-char blocks (1, 4, or 16)
361
+ * @returns Maximum charCode (255, 1023, or 4095)
362
+ */
363
+ declare function getMaxCharCode(blocks: AtlasBlocks): number;
364
+ /**
365
+ * Get character grid position in a block-based atlas
366
+ *
367
+ * Atlas layout for multi-block fonts:
368
+ * - Each block contains 256 chars in a 16×16 grid
369
+ * - Blocks are arranged in a square:
370
+ * - 1 block: 1×1 (16×16 chars total)
371
+ * - 4 blocks: 2×2 (32×32 chars total)
372
+ * - 16 blocks: 4×4 (64×64 chars total)
373
+ *
374
+ * CharCode mapping:
375
+ * charCode 0-255 → Block 0 (top-left)
376
+ * charCode 256-511 → Block 1 (top-right for 4+ blocks)
377
+ * charCode 512-767 → Block 2 (bottom-left for 4 blocks)
378
+ * etc.
379
+ *
380
+ * @param charCode - Character code (0 to maxCharCode)
381
+ * @param blocks - Number of 256-char blocks (1, 4, or 16)
382
+ * @returns Grid position { col, row } in the atlas
383
+ */
384
+ declare function getCharGridPosition(charCode: number, blocks: AtlasBlocks): {
385
+ col: number;
386
+ row: number;
387
+ };
388
+
389
+ export { AutoplayOverlay, DEFAULT_PALETTE, GridOverlay, PostProcessOverlay, colorToPaletteIndex, getAtlasColumns, getCharGridPosition, getMaxCharCode, paletteIndexToColor };
390
+ export type { AtlasBlocks, AutoplayOverlayOptions, PostProcessOverlayOptions };
@@ -0,0 +1,50 @@
1
+ var S=Object.defineProperty;var T=(a,t,e)=>t in a?S(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var h=(a,t)=>S(a,"name",{value:t,configurable:!0});var s=(a,t,e)=>(T(a,typeof t!="symbol"?t+"":t,e),e);var b=["#000000","#800000","#008000","#808000","#000080","#800080","#008080","#c0c0c0","#808080","#ff0000","#00ff00","#ffff00","#0000ff","#ff00ff","#00ffff","#ffffff","#080808","#121212","#1c1c1c","#262626","#303030","#3a3a3a","#444444","#4e4e4e","#585858","#626262","#6c6c6c","#767676","#808080","#8a8a8a","#949494","#9e9e9e","#a80000","#00a800","#a8a800","#0000a8","#a800a8","#00a8a8","#a8a8a8","#545454","#fc5454","#54fc54","#fcfc54","#5454fc","#fc54fc","#54fcfc","#fcfcfc","#000000",...Array(192).fill("#808080")];function E(a,t=b){return a<0||a>=t.length?"#ff00ff":t[a]}h(E,"paletteIndexToColor");function D(a,t=b){let e=t.indexOf(a.toLowerCase());return e>=0?e:0}h(D,"colorToPaletteIndex");var y=class y{constructor(t,e){s(this,"canvas");s(this,"ctx");s(this,"container");s(this,"cols",0);s(this,"rows",0);s(this,"cellWidth",0);s(this,"cellHeight",0);s(this,"offsetX",0);s(this,"offsetY",0);s(this,"strokeColor","rgba(80, 80, 80, 0.4)");s(this,"lineWidth",1);this.container=t,this.canvas=document.createElement("canvas"),this.canvas.className="grid-overlay-canvas";let o=e?.zIndex??10;this.canvas.style.cssText=`
2
+ display: block !important;
3
+ position: absolute !important;
4
+ pointer-events: none !important;
5
+ image-rendering: pixelated !important;
6
+ image-rendering: crisp-edges !important;
7
+ z-index: ${o} !important;
8
+ `,this.container.appendChild(this.canvas);let i=this.canvas.getContext("2d");if(!i)throw new Error("[GridOverlay] Impossible de cr\xE9er le contexte 2D");this.ctx=i,e&&(e.strokeColor&&(this.strokeColor=e.strokeColor),e.lineWidth!==void 0&&(this.lineWidth=e.lineWidth))}setDimensions(t,e,o,i,r=0,c=0){this.cols=t,this.rows=e,this.cellWidth=o,this.cellHeight=i,this.offsetX=r,this.offsetY=c}setCanvasSize(t,e){this.canvas.width=t,this.canvas.height=e,this.ctx.setTransform(1,0,0,1,0,0)}setStyle(t){t.strokeColor&&(this.strokeColor=t.strokeColor),t.lineWidth!==void 0&&(this.lineWidth=t.lineWidth)}setTransform(t,e,o,i,r){let c=i.left-r.left,l=i.top-r.top,n=i.width,v=i.height;(this.canvas.width!==n||this.canvas.height!==v)&&(this.canvas.width=n,this.canvas.height=v);let p=this.canvas.style;p.width=`${n}px`,p.height=`${v}px`,p.left=`${c}px`,p.top=`${l}px`}render(){if(!this.ctx)return;let t=this.cols*this.cellWidth,e=this.rows*this.cellHeight,o=t>0?this.canvas.width/t:1,i=e>0?this.canvas.height/e:1,r=Math.min(o,i),c=this.cellWidth*r,l=this.cellHeight*r,n=this.cols*c,v=this.rows*l,p=this.offsetX*r,m=this.offsetY*r;if(!(n===0||v===0)){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.strokeStyle=this.strokeColor,this.ctx.lineWidth=Math.max(1,this.lineWidth*r),this.ctx.beginPath();for(let d=0;d<=this.cols;d++){let u=p+d*c+.5;this.ctx.moveTo(u,m),this.ctx.lineTo(u,m+v)}for(let d=0;d<=this.rows;d++){let u=m+d*l+.5;this.ctx.moveTo(p,u),this.ctx.lineTo(p+n,u)}this.ctx.stroke()}}update(t,e,o,i,r,c,l=0,n=0){this.setDimensions(t,e,o,i,l,n),this.setCanvasSize(r,c),this.render()}setVisible(t){this.canvas.style.display=t?"block":"none"}destroy(){this.canvas.parentElement&&this.canvas.parentElement.removeChild(this.canvas)}getCanvas(){return this.canvas}};h(y,"GridOverlay");var g=y;var x=class x{constructor(t,e={}){s(this,"container");s(this,"overlayDiv",null);s(this,"button",null);s(this,"options");s(this,"started",!1);s(this,"onStartCallback");this.container=t,this.options={buttonText:e.buttonText??"Click to Start",onStart:e.onStart??(()=>{}),backgroundColor:e.backgroundColor??"rgba(0, 0, 0, 0.8)",buttonColor:e.buttonColor??"#4a90d9",buttonHoverColor:e.buttonHoverColor??"#357abd",buttonTextColor:e.buttonTextColor??"#ffffff",zIndex:e.zIndex??1e3},this.onStartCallback=e.onStart,this.createOverlay()}createOverlay(){let t=window.getComputedStyle(this.container).position;t!=="relative"&&t!=="absolute"&&t!=="fixed"&&(this.container.style.position="relative"),this.overlayDiv=document.createElement("div"),this.overlayDiv.className="utsp-autoplay-overlay",this.overlayDiv.style.cssText=`
9
+ position: absolute !important;
10
+ top: 0 !important;
11
+ left: 0 !important;
12
+ width: 100% !important;
13
+ height: 100% !important;
14
+ background-color: ${this.options.backgroundColor} !important;
15
+ display: flex !important;
16
+ justify-content: center !important;
17
+ align-items: center !important;
18
+ z-index: ${this.options.zIndex} !important;
19
+ cursor: pointer !important;
20
+ `,this.button=document.createElement("button"),this.button.className="utsp-autoplay-button",this.button.textContent=this.options.buttonText,this.button.style.cssText=`
21
+ padding: 16px 32px !important;
22
+ font-size: 18px !important;
23
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif !important;
24
+ font-weight: 600 !important;
25
+ color: ${this.options.buttonTextColor} !important;
26
+ background-color: ${this.options.buttonColor} !important;
27
+ border: none !important;
28
+ border-radius: 8px !important;
29
+ cursor: pointer !important;
30
+ transition: background-color 0.2s ease, transform 0.1s ease !important;
31
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
32
+ `,this.button.addEventListener("mouseenter",()=>{this.button&&(this.button.style.backgroundColor=`${this.options.buttonHoverColor} !important`,this.button.style.transform="scale(1.05)")}),this.button.addEventListener("mouseleave",()=>{this.button&&(this.button.style.backgroundColor=`${this.options.buttonColor} !important`,this.button.style.transform="scale(1)")}),this.button.addEventListener("click",e=>{e.stopPropagation(),this.start()}),this.overlayDiv.addEventListener("click",()=>{this.start()}),this.overlayDiv.appendChild(this.button),this.container.appendChild(this.overlayDiv)}start(){this.started||(this.started=!0,this.overlayDiv&&(this.overlayDiv.style.transition="opacity 0.3s ease",this.overlayDiv.style.opacity="0",setTimeout(()=>{this.removeOverlay()},300)),this.onStartCallback&&this.onStartCallback())}isStarted(){return this.started}isVisible(){return this.overlayDiv!==null&&!this.started}removeOverlay(){this.overlayDiv&&this.overlayDiv.parentElement&&this.overlayDiv.parentElement.removeChild(this.overlayDiv),this.overlayDiv=null,this.button=null}setButtonText(t){this.options.buttonText=t,this.button&&(this.button.textContent=t)}setOnStart(t){this.onStartCallback=t}destroy(){this.removeOverlay(),this.started=!1}};h(x,"AutoplayOverlay");var C=x;import{POST_PROCESS_DEFAULTS as f}from"@utsp/types";var w=class w{constructor(t,e){s(this,"canvas");s(this,"ctx");s(this,"containerDiv");s(this,"parentElement");s(this,"resizeObserver");s(this,"width",0);s(this,"height",0);s(this,"currentConfig",null);s(this,"configHash","");this.parentElement=t,this.containerDiv=document.createElement("div"),this.containerDiv.className="postprocess-container",this.containerDiv.style.cssText=`
33
+ position: absolute !important;
34
+ top: 0 !important;
35
+ left: 0 !important;
36
+ right: 0 !important;
37
+ bottom: 0 !important;
38
+ width: 100% !important;
39
+ height: 100% !important;
40
+ pointer-events: none !important;
41
+ z-index: 10 !important;
42
+ overflow: hidden !important;
43
+ `,this.canvas=document.createElement("canvas"),this.canvas.className="postprocess-canvas",this.canvas.style.cssText=`
44
+ position: absolute !important;
45
+ top: 0 !important;
46
+ left: 0 !important;
47
+ width: 100% !important;
48
+ height: 100% !important;
49
+ pointer-events: none !important;
50
+ `;let o=this.canvas.getContext("2d",{alpha:!0});if(!o)throw new Error("PostProcessOverlay: Failed to get 2D context");this.ctx=o,this.containerDiv.appendChild(this.canvas),this.parentElement.appendChild(this.containerDiv),this.resizeObserver=new ResizeObserver(r=>{for(let c of r){let{width:l,height:n}=c.contentRect;l>0&&n>0&&this.handleResize(Math.floor(l),Math.floor(n))}}),this.resizeObserver.observe(this.parentElement);let i=this.parentElement.getBoundingClientRect();i.width>0&&i.height>0&&this.handleResize(Math.floor(i.width),Math.floor(i.height)),this.hide()}handleResize(t,e){this.width===t&&this.height===e||(this.width=t,this.height=e,this.canvas.width=t,this.canvas.height=e,this.currentConfig&&this.isActive()&&this.render())}setConfig(t){let e=this.hashConfig(t);if(e!==this.configHash){if(this.currentConfig=t,this.configHash=e,!t||!this.isActiveConfig(t)){this.clear(),this.hide();return}this.show(),this.render()}}setScanlines(t){t===null?this.setConfig({scanlines:{enabled:!1}}):this.setConfig({scanlines:t})}setScanlinesEnabled(t){if(t){let e=this.currentConfig?.scanlines;this.setScanlines({enabled:!0,opacity:e?.opacity??f.scanlines.opacity,pattern:e?.pattern??"horizontal",spacing:e?.spacing??2,thickness:e?.thickness??1,color:e?.color??{r:0,g:0,b:0}})}else this.setScanlines({enabled:!1})}setScanlinesOpacity(t){let e=Math.max(0,Math.min(1,t)),o=this.currentConfig?.scanlines;this.setScanlines({enabled:o?.enabled??!0,opacity:e,pattern:o?.pattern??"horizontal",spacing:o?.spacing??2,thickness:o?.thickness??1,color:o?.color??{r:0,g:0,b:0}})}setScanlinesPattern(t){let e=this.currentConfig?.scanlines;this.setScanlines({enabled:e?.enabled??!0,opacity:e?.opacity??f.scanlines.opacity,pattern:t,spacing:e?.spacing??2,thickness:e?.thickness??1,color:e?.color??{r:0,g:0,b:0}})}setScanlinesSpacing(t){let e=Math.max(2,Math.round(t)),o=this.currentConfig?.scanlines;this.setScanlines({enabled:o?.enabled??!0,opacity:o?.opacity??f.scanlines.opacity,pattern:o?.pattern??"horizontal",spacing:e,thickness:o?.thickness??1,color:o?.color??{r:0,g:0,b:0}})}getConfig(){return this.currentConfig}isActive(){return this.isActiveConfig(this.currentConfig)}destroy(){this.resizeObserver.disconnect(),this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv)}syncWithRenderer(t){}resize(t,e){}setCellDimensions(t,e){}show(){this.containerDiv.style.display="block"}hide(){this.containerDiv.style.display="none"}clear(){this.ctx.clearRect(0,0,this.width,this.height)}isActiveConfig(t){return t?.scanlines?.enabled??!1}render(){this.clear(),this.currentConfig?.scanlines?.enabled&&this.renderScanlines(this.currentConfig.scanlines)}renderScanlines(t){let e=t.opacity??f.scanlines.opacity,o=t.pattern??"horizontal",i=t.spacing??2,r=t.thickness??1,c=t.color??{r:0,g:0,b:0},l=this.ctx;switch(l.fillStyle=`rgba(${c.r}, ${c.g}, ${c.b}, ${e})`,o){case"horizontal":for(let n=i-1;n<this.height;n+=i)l.fillRect(0,n,this.width,r);break;case"vertical":for(let n=i-1;n<this.width;n+=i)l.fillRect(n,0,r,this.height);break;case"grid":for(let n=i-1;n<this.height;n+=i)l.fillRect(0,n,this.width,r);for(let n=i-1;n<this.width;n+=i)l.fillRect(n,0,r,this.height);break}}hashConfig(t){return t?JSON.stringify(t):"null"}};h(w,"PostProcessOverlay");var k=w;function O(a){return Math.sqrt(a)*16}h(O,"getAtlasColumns");function P(a){return a*256-1}h(P,"getMaxCharCode");function M(a,t){let e=Math.floor(a/256),o=a%256,i=Math.sqrt(t),r=e%i,c=Math.floor(e/i),l=o%16,n=Math.floor(o/16);return{col:r*16+l,row:c*16+n}}h(M,"getCharGridPosition");export{C as AutoplayOverlay,b as DEFAULT_PALETTE,g as GridOverlay,k as PostProcessOverlay,D as colorToPaletteIndex,O as getAtlasColumns,M as getCharGridPosition,P as getMaxCharCode,E as paletteIndexToColor};