@utsp/render 0.10.0 → 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.
- package/README.md +102 -8
- package/dist/2d/index.cjs +34 -0
- package/dist/2d/index.d.ts +907 -0
- package/dist/2d/index.mjs +34 -0
- package/dist/ansi/index.cjs +2 -0
- package/dist/ansi/index.d.ts +132 -0
- package/dist/ansi/index.mjs +2 -0
- package/dist/common/index.cjs +50 -0
- package/dist/common/index.d.ts +390 -0
- package/dist/common/index.mjs +50 -0
- package/dist/gl/index.cjs +127 -0
- package/dist/gl/index.d.ts +802 -0
- package/dist/gl/index.mjs +127 -0
- package/dist/index.cjs +10 -9
- package/dist/index.d.ts +154 -4
- package/dist/index.mjs +10 -9
- package/package.json +40 -3
|
@@ -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};
|