@autumnsgrove/gossamer 0.1.1 → 0.2.0
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/LICENSE +21 -0
- package/dist/animation.js +165 -0
- package/dist/animation.test.js +204 -0
- package/dist/characters.js +176 -0
- package/dist/characters.test.js +115 -0
- package/dist/colors.js +199 -0
- package/dist/index.js +79 -1850
- package/dist/index.test.js +92 -0
- package/dist/patterns.js +539 -0
- package/dist/patterns.test.js +223 -0
- package/dist/renderer.js +362 -0
- package/dist/svelte/GossamerBorder.svelte.d.ts +56 -1
- package/dist/svelte/GossamerBorder.svelte.d.ts.map +1 -0
- package/dist/svelte/GossamerClouds.svelte.d.ts +31 -1
- package/dist/svelte/GossamerClouds.svelte.d.ts.map +1 -0
- package/dist/svelte/GossamerImage.svelte.d.ts +28 -1
- package/dist/svelte/GossamerImage.svelte.d.ts.map +1 -0
- package/dist/svelte/GossamerOverlay.svelte.d.ts +32 -1
- package/dist/svelte/GossamerOverlay.svelte.d.ts.map +1 -0
- package/dist/svelte/GossamerText.svelte.d.ts +29 -1
- package/dist/svelte/GossamerText.svelte.d.ts.map +1 -0
- package/dist/svelte/index.js +31 -3646
- package/dist/svelte/presets.d.ts +4 -2
- package/dist/svelte/presets.js +161 -0
- package/dist/utils/canvas.js +139 -0
- package/dist/utils/image.js +195 -0
- package/dist/utils/performance.js +205 -0
- package/package.json +18 -22
- package/dist/index.js.map +0 -1
- package/dist/style.css +0 -124
- package/dist/svelte/index.js.map +0 -1
- package/src/animation.test.ts +0 -254
- package/src/animation.ts +0 -243
- package/src/characters.test.ts +0 -148
- package/src/characters.ts +0 -219
- package/src/colors.ts +0 -234
- package/src/index.test.ts +0 -115
- package/src/index.ts +0 -234
- package/src/patterns.test.ts +0 -273
- package/src/patterns.ts +0 -760
- package/src/renderer.ts +0 -470
- package/src/svelte/index.ts +0 -75
- package/src/svelte/presets.ts +0 -174
- package/src/utils/canvas.ts +0 -210
- package/src/utils/image.ts +0 -275
- package/src/utils/performance.ts +0 -282
- /package/{src → dist}/svelte/GossamerBorder.svelte +0 -0
- /package/{src → dist}/svelte/GossamerClouds.svelte +0 -0
- /package/{src → dist}/svelte/GossamerImage.svelte +0 -0
- /package/{src → dist}/svelte/GossamerOverlay.svelte +0 -0
- /package/{src → dist}/svelte/GossamerText.svelte +0 -0
package/src/renderer.ts
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gossamer Core Renderer
|
|
3
|
-
*
|
|
4
|
-
* Canvas-based ASCII rendering engine. Converts image data to ASCII characters
|
|
5
|
-
* by mapping brightness values to a character set.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Define locally to avoid circular dependency with index.ts
|
|
9
|
-
const DEFAULT_CHARACTERS = ' .:-=+*#%@';
|
|
10
|
-
|
|
11
|
-
function calculateBrightness(r: number, g: number, b: number): number {
|
|
12
|
-
return 0.21 * r + 0.72 * g + 0.07 * b;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Configuration for the Gossamer renderer
|
|
17
|
-
*/
|
|
18
|
-
export interface RenderConfig {
|
|
19
|
-
/** Canvas element to render to */
|
|
20
|
-
canvas: HTMLCanvasElement;
|
|
21
|
-
/** Character set ordered from light to dark */
|
|
22
|
-
characters: string;
|
|
23
|
-
/** Width of each character cell in pixels */
|
|
24
|
-
cellWidth: number;
|
|
25
|
-
/** Height of each character cell in pixels */
|
|
26
|
-
cellHeight: number;
|
|
27
|
-
/** Color for rendering characters */
|
|
28
|
-
color: string;
|
|
29
|
-
/** Background color (empty string for transparent) */
|
|
30
|
-
backgroundColor: string;
|
|
31
|
-
/** Font family */
|
|
32
|
-
fontFamily: string;
|
|
33
|
-
/** Custom brightness calculation function */
|
|
34
|
-
brightnessFunction: (r: number, g: number, b: number) => number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Default render configuration
|
|
39
|
-
*/
|
|
40
|
-
const DEFAULT_RENDER_CONFIG: Omit<RenderConfig, 'canvas'> = {
|
|
41
|
-
characters: DEFAULT_CHARACTERS,
|
|
42
|
-
cellWidth: 8,
|
|
43
|
-
cellHeight: 12,
|
|
44
|
-
color: '#ffffff',
|
|
45
|
-
backgroundColor: '',
|
|
46
|
-
fontFamily: 'monospace',
|
|
47
|
-
brightnessFunction: calculateBrightness,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Core ASCII renderer class
|
|
52
|
-
*
|
|
53
|
-
* Handles all canvas rendering operations for ASCII effects.
|
|
54
|
-
* Supports both static rendering and animation loops.
|
|
55
|
-
*/
|
|
56
|
-
export class GossamerRenderer {
|
|
57
|
-
private ctx: CanvasRenderingContext2D;
|
|
58
|
-
private config: RenderConfig;
|
|
59
|
-
private animationId: number | null = null;
|
|
60
|
-
private lastFrameTime: number = 0;
|
|
61
|
-
private isRunning: boolean = false;
|
|
62
|
-
|
|
63
|
-
// Performance: Character texture atlas
|
|
64
|
-
private charAtlas: OffscreenCanvas | HTMLCanvasElement | null = null;
|
|
65
|
-
private atlasCharacters: string = '';
|
|
66
|
-
|
|
67
|
-
constructor(canvas: HTMLCanvasElement, config: Partial<Omit<RenderConfig, 'canvas'>> = {}) {
|
|
68
|
-
const context = canvas.getContext('2d');
|
|
69
|
-
if (!context) {
|
|
70
|
-
throw new Error('Failed to get 2D rendering context');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
this.ctx = context;
|
|
74
|
-
this.config = {
|
|
75
|
-
canvas,
|
|
76
|
-
...DEFAULT_RENDER_CONFIG,
|
|
77
|
-
...config,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
this.setupCanvas();
|
|
81
|
-
this.buildCharacterAtlas();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Build character texture atlas for fast rendering
|
|
86
|
-
* Pre-renders all characters to an offscreen canvas, then uses drawImage
|
|
87
|
-
* instead of fillText for 5-10x faster rendering
|
|
88
|
-
*/
|
|
89
|
-
private buildCharacterAtlas(): void {
|
|
90
|
-
const { characters, cellWidth, cellHeight, color, fontFamily } = this.config;
|
|
91
|
-
|
|
92
|
-
// Skip if atlas already built with same characters
|
|
93
|
-
if (this.atlasCharacters === characters && this.charAtlas) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Create offscreen canvas (use OffscreenCanvas if available for better perf)
|
|
98
|
-
const atlasWidth = characters.length * cellWidth;
|
|
99
|
-
const atlasHeight = cellHeight;
|
|
100
|
-
|
|
101
|
-
if (typeof OffscreenCanvas !== 'undefined') {
|
|
102
|
-
this.charAtlas = new OffscreenCanvas(atlasWidth, atlasHeight);
|
|
103
|
-
} else {
|
|
104
|
-
this.charAtlas = document.createElement('canvas');
|
|
105
|
-
this.charAtlas.width = atlasWidth;
|
|
106
|
-
this.charAtlas.height = atlasHeight;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const ctx = this.charAtlas.getContext('2d');
|
|
110
|
-
if (!ctx) {
|
|
111
|
-
this.charAtlas = null;
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Clear with transparent background
|
|
117
|
-
ctx.clearRect(0, 0, atlasWidth, atlasHeight);
|
|
118
|
-
|
|
119
|
-
// Render each character
|
|
120
|
-
ctx.fillStyle = color;
|
|
121
|
-
ctx.font = `${cellHeight}px ${fontFamily}`;
|
|
122
|
-
ctx.textBaseline = 'top';
|
|
123
|
-
|
|
124
|
-
for (let i = 0; i < characters.length; i++) {
|
|
125
|
-
const char = characters[i];
|
|
126
|
-
if (char !== ' ') {
|
|
127
|
-
ctx.fillText(char, i * cellWidth, 0);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
this.atlasCharacters = characters;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Set up the canvas with optimal rendering settings
|
|
136
|
-
*/
|
|
137
|
-
private setupCanvas(): void {
|
|
138
|
-
const { fontFamily, cellHeight } = this.config;
|
|
139
|
-
|
|
140
|
-
// Set font for consistent character sizing
|
|
141
|
-
this.ctx.font = `${cellHeight}px ${fontFamily}`;
|
|
142
|
-
this.ctx.textBaseline = 'top';
|
|
143
|
-
|
|
144
|
-
// Enable image smoothing for better quality
|
|
145
|
-
this.ctx.imageSmoothingEnabled = true;
|
|
146
|
-
this.ctx.imageSmoothingQuality = 'high';
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Update the renderer configuration
|
|
151
|
-
*/
|
|
152
|
-
updateConfig(config: Partial<Omit<RenderConfig, 'canvas'>>): void {
|
|
153
|
-
const needsAtlasRebuild =
|
|
154
|
-
config.characters !== undefined ||
|
|
155
|
-
config.color !== undefined ||
|
|
156
|
-
config.cellWidth !== undefined ||
|
|
157
|
-
config.cellHeight !== undefined ||
|
|
158
|
-
config.fontFamily !== undefined;
|
|
159
|
-
|
|
160
|
-
this.config = { ...this.config, ...config };
|
|
161
|
-
this.setupCanvas();
|
|
162
|
-
|
|
163
|
-
if (needsAtlasRebuild) {
|
|
164
|
-
this.atlasCharacters = ''; // Force rebuild
|
|
165
|
-
this.buildCharacterAtlas();
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Resize the canvas to match new dimensions
|
|
171
|
-
*/
|
|
172
|
-
resize(width: number, height: number): void {
|
|
173
|
-
const { canvas } = this.config;
|
|
174
|
-
canvas.width = width;
|
|
175
|
-
canvas.height = height;
|
|
176
|
-
this.setupCanvas();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Get the current canvas dimensions
|
|
181
|
-
*/
|
|
182
|
-
getDimensions(): { width: number; height: number } {
|
|
183
|
-
return {
|
|
184
|
-
width: this.config.canvas.width,
|
|
185
|
-
height: this.config.canvas.height,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Calculate the number of cells that fit in the canvas
|
|
191
|
-
*/
|
|
192
|
-
getCellCount(): { cols: number; rows: number } {
|
|
193
|
-
const { width, height } = this.getDimensions();
|
|
194
|
-
const { cellWidth, cellHeight } = this.config;
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
cols: Math.ceil(width / cellWidth),
|
|
198
|
-
rows: Math.ceil(height / cellHeight),
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Clear the canvas
|
|
204
|
-
*/
|
|
205
|
-
clear(): void {
|
|
206
|
-
const { canvas, backgroundColor } = this.config;
|
|
207
|
-
|
|
208
|
-
if (backgroundColor) {
|
|
209
|
-
this.ctx.fillStyle = backgroundColor;
|
|
210
|
-
this.ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
211
|
-
} else {
|
|
212
|
-
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Render a single frame from image data
|
|
218
|
-
*/
|
|
219
|
-
renderFrame(imageData: ImageData): void {
|
|
220
|
-
const { canvas, characters, cellWidth, cellHeight, color, brightnessFunction } = this.config;
|
|
221
|
-
const { width, data } = imageData;
|
|
222
|
-
|
|
223
|
-
this.clear();
|
|
224
|
-
this.ctx.fillStyle = color;
|
|
225
|
-
|
|
226
|
-
for (let y = 0; y < canvas.height; y += cellHeight) {
|
|
227
|
-
for (let x = 0; x < canvas.width; x += cellWidth) {
|
|
228
|
-
const brightness = this.getCellBrightness(data, x, y, width, cellWidth, cellHeight, brightnessFunction);
|
|
229
|
-
const charIndex = Math.floor((brightness / 255) * (characters.length - 1));
|
|
230
|
-
const char = characters[Math.min(charIndex, characters.length - 1)];
|
|
231
|
-
|
|
232
|
-
if (char !== ' ') {
|
|
233
|
-
this.ctx.fillText(char, x, y);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Render ASCII from a brightness grid (for pattern-based rendering)
|
|
241
|
-
*/
|
|
242
|
-
renderFromBrightnessGrid(grid: number[][]): void {
|
|
243
|
-
const { characters, cellWidth, cellHeight, color } = this.config;
|
|
244
|
-
|
|
245
|
-
this.clear();
|
|
246
|
-
this.ctx.fillStyle = color;
|
|
247
|
-
|
|
248
|
-
for (let row = 0; row < grid.length; row++) {
|
|
249
|
-
for (let col = 0; col < grid[row].length; col++) {
|
|
250
|
-
const brightness = grid[row][col];
|
|
251
|
-
const charIndex = Math.floor((brightness / 255) * (characters.length - 1));
|
|
252
|
-
const char = characters[Math.min(charIndex, characters.length - 1)];
|
|
253
|
-
|
|
254
|
-
if (char !== ' ') {
|
|
255
|
-
this.ctx.fillText(char, col * cellWidth, row * cellHeight);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Render ASCII with per-cell colors (for colored image rendering)
|
|
263
|
-
*/
|
|
264
|
-
renderWithColors(data: Array<{ char: string; color: string; x: number; y: number }>): void {
|
|
265
|
-
this.clear();
|
|
266
|
-
|
|
267
|
-
for (const { char, color, x, y } of data) {
|
|
268
|
-
if (char !== ' ') {
|
|
269
|
-
this.ctx.fillStyle = color;
|
|
270
|
-
this.ctx.fillText(char, x, y);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* PERFORMANCE: Render from BrightnessBuffer using texture atlas
|
|
277
|
-
*
|
|
278
|
-
* Uses pre-rendered character sprites instead of fillText calls.
|
|
279
|
-
* 5-10x faster than renderFromBrightnessGrid for large canvases.
|
|
280
|
-
*
|
|
281
|
-
* @param buffer - BrightnessBuffer from fillBrightnessBuffer
|
|
282
|
-
*/
|
|
283
|
-
renderFromBuffer(buffer: { data: Uint8Array; cols: number; rows: number }): void {
|
|
284
|
-
const { characters, cellWidth, cellHeight } = this.config;
|
|
285
|
-
|
|
286
|
-
this.clear();
|
|
287
|
-
|
|
288
|
-
// Fall back to fillText if atlas not available
|
|
289
|
-
if (!this.charAtlas) {
|
|
290
|
-
this.ctx.fillStyle = this.config.color;
|
|
291
|
-
const charLen = characters.length - 1;
|
|
292
|
-
let idx = 0;
|
|
293
|
-
for (let row = 0; row < buffer.rows; row++) {
|
|
294
|
-
for (let col = 0; col < buffer.cols; col++) {
|
|
295
|
-
const brightness = buffer.data[idx++];
|
|
296
|
-
const charIndex = (brightness / 255 * charLen) | 0;
|
|
297
|
-
const char = characters[Math.min(charIndex, charLen)];
|
|
298
|
-
if (char !== ' ') {
|
|
299
|
-
this.ctx.fillText(char, col * cellWidth, row * cellHeight);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Use atlas for fast rendering via drawImage
|
|
307
|
-
const charLen = characters.length - 1;
|
|
308
|
-
let idx = 0;
|
|
309
|
-
|
|
310
|
-
for (let row = 0; row < buffer.rows; row++) {
|
|
311
|
-
const y = row * cellHeight;
|
|
312
|
-
for (let col = 0; col < buffer.cols; col++) {
|
|
313
|
-
const brightness = buffer.data[idx++];
|
|
314
|
-
const charIndex = (brightness / 255 * charLen) | 0;
|
|
315
|
-
|
|
316
|
-
// Skip space characters (index 0 in most charsets)
|
|
317
|
-
if (charIndex === 0 && characters[0] === ' ') {
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Draw from atlas: source is the character's position in the atlas
|
|
322
|
-
this.ctx.drawImage(
|
|
323
|
-
this.charAtlas,
|
|
324
|
-
charIndex * cellWidth, 0, cellWidth, cellHeight, // source
|
|
325
|
-
col * cellWidth, y, cellWidth, cellHeight // destination
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* PERFORMANCE: Render brightness grid using atlas (legacy grid format)
|
|
333
|
-
*
|
|
334
|
-
* @param grid - 2D array of brightness values
|
|
335
|
-
*/
|
|
336
|
-
renderGridFast(grid: number[][]): void {
|
|
337
|
-
const { characters, cellWidth, cellHeight } = this.config;
|
|
338
|
-
|
|
339
|
-
this.clear();
|
|
340
|
-
|
|
341
|
-
if (!this.charAtlas) {
|
|
342
|
-
// Fallback to standard method
|
|
343
|
-
this.renderFromBrightnessGrid(grid);
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const charLen = characters.length - 1;
|
|
348
|
-
|
|
349
|
-
for (let row = 0; row < grid.length; row++) {
|
|
350
|
-
const y = row * cellHeight;
|
|
351
|
-
const rowData = grid[row];
|
|
352
|
-
for (let col = 0; col < rowData.length; col++) {
|
|
353
|
-
const brightness = rowData[col];
|
|
354
|
-
const charIndex = (brightness / 255 * charLen) | 0;
|
|
355
|
-
|
|
356
|
-
if (charIndex === 0 && characters[0] === ' ') {
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
this.ctx.drawImage(
|
|
361
|
-
this.charAtlas,
|
|
362
|
-
charIndex * cellWidth, 0, cellWidth, cellHeight,
|
|
363
|
-
col * cellWidth, y, cellWidth, cellHeight
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Calculate average brightness for a cell region
|
|
371
|
-
*/
|
|
372
|
-
private getCellBrightness(
|
|
373
|
-
data: Uint8ClampedArray,
|
|
374
|
-
startX: number,
|
|
375
|
-
startY: number,
|
|
376
|
-
imageWidth: number,
|
|
377
|
-
cellWidth: number,
|
|
378
|
-
cellHeight: number,
|
|
379
|
-
brightnessFunction: (r: number, g: number, b: number) => number
|
|
380
|
-
): number {
|
|
381
|
-
let total = 0;
|
|
382
|
-
let count = 0;
|
|
383
|
-
|
|
384
|
-
for (let cy = 0; cy < cellHeight; cy++) {
|
|
385
|
-
for (let cx = 0; cx < cellWidth; cx++) {
|
|
386
|
-
const px = ((startY + cy) * imageWidth + (startX + cx)) * 4;
|
|
387
|
-
if (px >= 0 && px + 2 < data.length) {
|
|
388
|
-
total += brightnessFunction(data[px], data[px + 1], data[px + 2]);
|
|
389
|
-
count++;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return count > 0 ? total / count : 0;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Start an animation loop with FPS limiting
|
|
399
|
-
*/
|
|
400
|
-
startAnimation(
|
|
401
|
-
updateFn: (time: number, deltaTime: number) => ImageData | number[][],
|
|
402
|
-
fps: number = 30
|
|
403
|
-
): void {
|
|
404
|
-
if (this.isRunning) {
|
|
405
|
-
this.stopAnimation();
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
this.isRunning = true;
|
|
409
|
-
const frameInterval = 1000 / fps;
|
|
410
|
-
this.lastFrameTime = performance.now();
|
|
411
|
-
|
|
412
|
-
const animate = (currentTime: number): void => {
|
|
413
|
-
if (!this.isRunning) return;
|
|
414
|
-
|
|
415
|
-
const deltaTime = currentTime - this.lastFrameTime;
|
|
416
|
-
|
|
417
|
-
if (deltaTime >= frameInterval) {
|
|
418
|
-
const result = updateFn(currentTime, deltaTime);
|
|
419
|
-
|
|
420
|
-
if (result instanceof ImageData) {
|
|
421
|
-
this.renderFrame(result);
|
|
422
|
-
} else {
|
|
423
|
-
this.renderFromBrightnessGrid(result);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
this.lastFrameTime = currentTime - (deltaTime % frameInterval);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
this.animationId = requestAnimationFrame(animate);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
this.animationId = requestAnimationFrame(animate);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Stop the animation loop
|
|
437
|
-
*/
|
|
438
|
-
stopAnimation(): void {
|
|
439
|
-
this.isRunning = false;
|
|
440
|
-
if (this.animationId !== null) {
|
|
441
|
-
cancelAnimationFrame(this.animationId);
|
|
442
|
-
this.animationId = null;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Check if animation is currently running
|
|
448
|
-
*/
|
|
449
|
-
isAnimating(): boolean {
|
|
450
|
-
return this.isRunning;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Pause animation (can be resumed)
|
|
455
|
-
*/
|
|
456
|
-
pause(): void {
|
|
457
|
-
this.isRunning = false;
|
|
458
|
-
if (this.animationId !== null) {
|
|
459
|
-
cancelAnimationFrame(this.animationId);
|
|
460
|
-
this.animationId = null;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Clean up and destroy the renderer
|
|
466
|
-
*/
|
|
467
|
-
destroy(): void {
|
|
468
|
-
this.stopAnimation();
|
|
469
|
-
}
|
|
470
|
-
}
|
package/src/svelte/index.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gossamer - Svelte 5 Components
|
|
3
|
-
*
|
|
4
|
-
* ASCII visual effects components for Svelte applications.
|
|
5
|
-
*
|
|
6
|
-
* @packageDocumentation
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// =============================================================================
|
|
10
|
-
// Components
|
|
11
|
-
// =============================================================================
|
|
12
|
-
|
|
13
|
-
export { default as GossamerClouds } from './GossamerClouds.svelte';
|
|
14
|
-
export { default as GossamerImage } from './GossamerImage.svelte';
|
|
15
|
-
export { default as GossamerText } from './GossamerText.svelte';
|
|
16
|
-
export { default as GossamerOverlay } from './GossamerOverlay.svelte';
|
|
17
|
-
export { default as GossamerBorder } from './GossamerBorder.svelte';
|
|
18
|
-
|
|
19
|
-
// =============================================================================
|
|
20
|
-
// Component Types
|
|
21
|
-
// =============================================================================
|
|
22
|
-
|
|
23
|
-
export type { GossamerCloudsProps } from './GossamerClouds.svelte';
|
|
24
|
-
export type { GossamerImageProps } from './GossamerImage.svelte';
|
|
25
|
-
export type { GossamerTextProps } from './GossamerText.svelte';
|
|
26
|
-
export type { GossamerOverlayProps, BlendMode } from './GossamerOverlay.svelte';
|
|
27
|
-
export type { GossamerBorderProps, BorderStyle } from './GossamerBorder.svelte';
|
|
28
|
-
|
|
29
|
-
// =============================================================================
|
|
30
|
-
// Presets
|
|
31
|
-
// =============================================================================
|
|
32
|
-
|
|
33
|
-
export {
|
|
34
|
-
PRESETS,
|
|
35
|
-
grovePresets,
|
|
36
|
-
seasonalPresets,
|
|
37
|
-
ambientPresets,
|
|
38
|
-
getPreset,
|
|
39
|
-
getPresetNames,
|
|
40
|
-
getPresetsByCategory,
|
|
41
|
-
} from './presets';
|
|
42
|
-
|
|
43
|
-
// =============================================================================
|
|
44
|
-
// Re-exports from Core
|
|
45
|
-
// =============================================================================
|
|
46
|
-
|
|
47
|
-
export {
|
|
48
|
-
// Core types
|
|
49
|
-
type GossamerConfig,
|
|
50
|
-
type PresetConfig,
|
|
51
|
-
type PatternConfig,
|
|
52
|
-
type PatternType,
|
|
53
|
-
type CharacterSet,
|
|
54
|
-
|
|
55
|
-
// Constants
|
|
56
|
-
DEFAULT_CHARACTERS,
|
|
57
|
-
DEFAULT_CONFIG,
|
|
58
|
-
CHARACTER_SETS,
|
|
59
|
-
|
|
60
|
-
// Core functions
|
|
61
|
-
calculateBrightness,
|
|
62
|
-
brightnessToChar,
|
|
63
|
-
|
|
64
|
-
// Character utilities
|
|
65
|
-
getCharacterSet,
|
|
66
|
-
getCharacters,
|
|
67
|
-
getCharacterSetNames,
|
|
68
|
-
invertCharacters,
|
|
69
|
-
|
|
70
|
-
// Performance utilities
|
|
71
|
-
prefersReducedMotion,
|
|
72
|
-
|
|
73
|
-
// Version
|
|
74
|
-
VERSION,
|
|
75
|
-
} from '../index';
|
package/src/svelte/presets.ts
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Preset configurations for Gossamer effects
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { PresetConfig } from '../index';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Grove-themed presets
|
|
9
|
-
* Organic, nature-inspired effects
|
|
10
|
-
*/
|
|
11
|
-
export const grovePresets: Record<string, PresetConfig> = {
|
|
12
|
-
'grove-mist': {
|
|
13
|
-
name: 'Grove Mist',
|
|
14
|
-
description: 'Soft fog effect drifting through the trees',
|
|
15
|
-
characters: ' ·∙•◦',
|
|
16
|
-
pattern: 'perlin',
|
|
17
|
-
frequency: 0.03,
|
|
18
|
-
amplitude: 0.8,
|
|
19
|
-
speed: 0.3,
|
|
20
|
-
opacity: 0.2,
|
|
21
|
-
},
|
|
22
|
-
'grove-fireflies': {
|
|
23
|
-
name: 'Grove Fireflies',
|
|
24
|
-
description: 'Twinkling points of light in the darkness',
|
|
25
|
-
characters: ' ·*✦✧',
|
|
26
|
-
pattern: 'static',
|
|
27
|
-
frequency: 0.01,
|
|
28
|
-
amplitude: 1.2,
|
|
29
|
-
speed: 0.8,
|
|
30
|
-
opacity: 0.3,
|
|
31
|
-
},
|
|
32
|
-
'grove-rain': {
|
|
33
|
-
name: 'Grove Rain',
|
|
34
|
-
description: 'Gentle rain falling through the canopy',
|
|
35
|
-
characters: ' │\\|/',
|
|
36
|
-
pattern: 'waves',
|
|
37
|
-
frequency: 0.05,
|
|
38
|
-
amplitude: 1.0,
|
|
39
|
-
speed: 1.5,
|
|
40
|
-
opacity: 0.15,
|
|
41
|
-
},
|
|
42
|
-
'grove-dew': {
|
|
43
|
-
name: 'Grove Dew',
|
|
44
|
-
description: 'Morning dew glistening on spider silk',
|
|
45
|
-
characters: ' ·∘∙●',
|
|
46
|
-
pattern: 'fbm',
|
|
47
|
-
frequency: 0.04,
|
|
48
|
-
amplitude: 0.7,
|
|
49
|
-
speed: 0.1,
|
|
50
|
-
opacity: 0.15,
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Seasonal presets
|
|
56
|
-
* Effects themed around the four seasons
|
|
57
|
-
*/
|
|
58
|
-
export const seasonalPresets: Record<string, PresetConfig> = {
|
|
59
|
-
'winter-snow': {
|
|
60
|
-
name: 'Winter Snow',
|
|
61
|
-
description: 'Gentle snowfall on a quiet night',
|
|
62
|
-
characters: ' ·∙*❄',
|
|
63
|
-
pattern: 'perlin',
|
|
64
|
-
frequency: 0.04,
|
|
65
|
-
amplitude: 0.9,
|
|
66
|
-
speed: 0.5,
|
|
67
|
-
opacity: 0.25,
|
|
68
|
-
},
|
|
69
|
-
'autumn-leaves': {
|
|
70
|
-
name: 'Autumn Leaves',
|
|
71
|
-
description: 'Scattered leaves drifting on the wind',
|
|
72
|
-
characters: ' 🍂·∙',
|
|
73
|
-
pattern: 'perlin',
|
|
74
|
-
frequency: 0.06,
|
|
75
|
-
amplitude: 1.1,
|
|
76
|
-
speed: 0.4,
|
|
77
|
-
opacity: 0.2,
|
|
78
|
-
},
|
|
79
|
-
'spring-petals': {
|
|
80
|
-
name: 'Spring Petals',
|
|
81
|
-
description: 'Cherry blossom petals floating on the breeze',
|
|
82
|
-
characters: ' ·✿❀',
|
|
83
|
-
pattern: 'waves',
|
|
84
|
-
frequency: 0.05,
|
|
85
|
-
amplitude: 0.8,
|
|
86
|
-
speed: 0.6,
|
|
87
|
-
opacity: 0.2,
|
|
88
|
-
},
|
|
89
|
-
'summer-heat': {
|
|
90
|
-
name: 'Summer Heat',
|
|
91
|
-
description: 'Heat shimmer rising from sun-warmed ground',
|
|
92
|
-
characters: ' ~≈∿',
|
|
93
|
-
pattern: 'waves',
|
|
94
|
-
frequency: 0.08,
|
|
95
|
-
amplitude: 1.3,
|
|
96
|
-
speed: 1.0,
|
|
97
|
-
opacity: 0.1,
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Ambient presets
|
|
103
|
-
* Subtle background textures
|
|
104
|
-
*/
|
|
105
|
-
export const ambientPresets: Record<string, PresetConfig> = {
|
|
106
|
-
'ambient-static': {
|
|
107
|
-
name: 'Ambient Static',
|
|
108
|
-
description: 'Gentle static noise texture',
|
|
109
|
-
characters: ' .:',
|
|
110
|
-
pattern: 'static',
|
|
111
|
-
frequency: 0.1,
|
|
112
|
-
amplitude: 0.5,
|
|
113
|
-
speed: 0.2,
|
|
114
|
-
opacity: 0.08,
|
|
115
|
-
},
|
|
116
|
-
'ambient-waves': {
|
|
117
|
-
name: 'Ambient Waves',
|
|
118
|
-
description: 'Soft flowing wave pattern',
|
|
119
|
-
characters: ' ·~',
|
|
120
|
-
pattern: 'waves',
|
|
121
|
-
frequency: 0.02,
|
|
122
|
-
amplitude: 0.6,
|
|
123
|
-
speed: 0.3,
|
|
124
|
-
opacity: 0.1,
|
|
125
|
-
},
|
|
126
|
-
'ambient-clouds': {
|
|
127
|
-
name: 'Ambient Clouds',
|
|
128
|
-
description: 'Drifting cloud-like patterns',
|
|
129
|
-
characters: ' .:-',
|
|
130
|
-
pattern: 'fbm',
|
|
131
|
-
frequency: 0.02,
|
|
132
|
-
amplitude: 0.7,
|
|
133
|
-
speed: 0.15,
|
|
134
|
-
opacity: 0.12,
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* All presets combined for easy access
|
|
140
|
-
*/
|
|
141
|
-
export const PRESETS: Record<string, PresetConfig> = {
|
|
142
|
-
...grovePresets,
|
|
143
|
-
...seasonalPresets,
|
|
144
|
-
...ambientPresets,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Get a preset by name
|
|
149
|
-
*/
|
|
150
|
-
export function getPreset(name: string): PresetConfig | undefined {
|
|
151
|
-
return PRESETS[name];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* List all available preset names
|
|
156
|
-
*/
|
|
157
|
-
export function getPresetNames(): string[] {
|
|
158
|
-
return Object.keys(PRESETS);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* List preset names by category
|
|
163
|
-
*/
|
|
164
|
-
export function getPresetsByCategory(): {
|
|
165
|
-
grove: string[];
|
|
166
|
-
seasonal: string[];
|
|
167
|
-
ambient: string[];
|
|
168
|
-
} {
|
|
169
|
-
return {
|
|
170
|
-
grove: Object.keys(grovePresets),
|
|
171
|
-
seasonal: Object.keys(seasonalPresets),
|
|
172
|
-
ambient: Object.keys(ambientPresets),
|
|
173
|
-
};
|
|
174
|
-
}
|