@autumnsgrove/gossamer 0.1.0 → 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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/dist/animation.js +165 -0
  3. package/dist/animation.test.js +204 -0
  4. package/dist/characters.d.ts.map +1 -1
  5. package/dist/characters.js +176 -0
  6. package/dist/characters.test.js +115 -0
  7. package/dist/colors.d.ts +312 -0
  8. package/dist/colors.d.ts.map +1 -0
  9. package/dist/colors.js +199 -0
  10. package/dist/index.d.ts +5 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +79 -1308
  13. package/dist/index.test.js +92 -0
  14. package/dist/patterns.d.ts +119 -2
  15. package/dist/patterns.d.ts.map +1 -1
  16. package/dist/patterns.js +539 -0
  17. package/dist/patterns.test.js +223 -0
  18. package/dist/renderer.d.ts +27 -0
  19. package/dist/renderer.d.ts.map +1 -1
  20. package/dist/renderer.js +362 -0
  21. package/dist/svelte/GossamerBorder.svelte.d.ts +56 -1
  22. package/dist/svelte/GossamerBorder.svelte.d.ts.map +1 -0
  23. package/{src → dist}/svelte/GossamerClouds.svelte +6 -6
  24. package/dist/svelte/GossamerClouds.svelte.d.ts +31 -1
  25. package/dist/svelte/GossamerClouds.svelte.d.ts.map +1 -0
  26. package/dist/svelte/GossamerImage.svelte.d.ts +28 -1
  27. package/dist/svelte/GossamerImage.svelte.d.ts.map +1 -0
  28. package/dist/svelte/GossamerOverlay.svelte.d.ts +32 -1
  29. package/dist/svelte/GossamerOverlay.svelte.d.ts.map +1 -0
  30. package/dist/svelte/GossamerText.svelte.d.ts +29 -1
  31. package/dist/svelte/GossamerText.svelte.d.ts.map +1 -0
  32. package/dist/svelte/index.js +31 -3649
  33. package/dist/svelte/presets.d.ts +4 -2
  34. package/dist/svelte/presets.js +161 -0
  35. package/dist/utils/canvas.js +139 -0
  36. package/dist/utils/image.js +195 -0
  37. package/dist/utils/performance.js +205 -0
  38. package/package.json +20 -15
  39. package/dist/index.js.map +0 -1
  40. package/dist/style.css +0 -124
  41. package/dist/svelte/index.js.map +0 -1
  42. package/src/animation.test.ts +0 -254
  43. package/src/animation.ts +0 -243
  44. package/src/characters.test.ts +0 -148
  45. package/src/characters.ts +0 -164
  46. package/src/index.test.ts +0 -115
  47. package/src/index.ts +0 -203
  48. package/src/patterns.test.ts +0 -273
  49. package/src/patterns.ts +0 -316
  50. package/src/renderer.ts +0 -309
  51. package/src/svelte/index.ts +0 -75
  52. package/src/svelte/presets.ts +0 -174
  53. package/src/utils/canvas.ts +0 -210
  54. package/src/utils/image.ts +0 -275
  55. package/src/utils/performance.ts +0 -282
  56. /package/{src → dist}/svelte/GossamerBorder.svelte +0 -0
  57. /package/{src → dist}/svelte/GossamerImage.svelte +0 -0
  58. /package/{src → dist}/svelte/GossamerOverlay.svelte +0 -0
  59. /package/{src → dist}/svelte/GossamerText.svelte +0 -0
package/src/renderer.ts DELETED
@@ -1,309 +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
- constructor(canvas: HTMLCanvasElement, config: Partial<Omit<RenderConfig, 'canvas'>> = {}) {
64
- const context = canvas.getContext('2d');
65
- if (!context) {
66
- throw new Error('Failed to get 2D rendering context');
67
- }
68
-
69
- this.ctx = context;
70
- this.config = {
71
- canvas,
72
- ...DEFAULT_RENDER_CONFIG,
73
- ...config,
74
- };
75
-
76
- this.setupCanvas();
77
- }
78
-
79
- /**
80
- * Set up the canvas with optimal rendering settings
81
- */
82
- private setupCanvas(): void {
83
- const { fontFamily, cellHeight } = this.config;
84
-
85
- // Set font for consistent character sizing
86
- this.ctx.font = `${cellHeight}px ${fontFamily}`;
87
- this.ctx.textBaseline = 'top';
88
-
89
- // Enable image smoothing for better quality
90
- this.ctx.imageSmoothingEnabled = true;
91
- this.ctx.imageSmoothingQuality = 'high';
92
- }
93
-
94
- /**
95
- * Update the renderer configuration
96
- */
97
- updateConfig(config: Partial<Omit<RenderConfig, 'canvas'>>): void {
98
- this.config = { ...this.config, ...config };
99
- this.setupCanvas();
100
- }
101
-
102
- /**
103
- * Resize the canvas to match new dimensions
104
- */
105
- resize(width: number, height: number): void {
106
- const { canvas } = this.config;
107
- canvas.width = width;
108
- canvas.height = height;
109
- this.setupCanvas();
110
- }
111
-
112
- /**
113
- * Get the current canvas dimensions
114
- */
115
- getDimensions(): { width: number; height: number } {
116
- return {
117
- width: this.config.canvas.width,
118
- height: this.config.canvas.height,
119
- };
120
- }
121
-
122
- /**
123
- * Calculate the number of cells that fit in the canvas
124
- */
125
- getCellCount(): { cols: number; rows: number } {
126
- const { width, height } = this.getDimensions();
127
- const { cellWidth, cellHeight } = this.config;
128
-
129
- return {
130
- cols: Math.ceil(width / cellWidth),
131
- rows: Math.ceil(height / cellHeight),
132
- };
133
- }
134
-
135
- /**
136
- * Clear the canvas
137
- */
138
- clear(): void {
139
- const { canvas, backgroundColor } = this.config;
140
-
141
- if (backgroundColor) {
142
- this.ctx.fillStyle = backgroundColor;
143
- this.ctx.fillRect(0, 0, canvas.width, canvas.height);
144
- } else {
145
- this.ctx.clearRect(0, 0, canvas.width, canvas.height);
146
- }
147
- }
148
-
149
- /**
150
- * Render a single frame from image data
151
- */
152
- renderFrame(imageData: ImageData): void {
153
- const { canvas, characters, cellWidth, cellHeight, color, brightnessFunction } = this.config;
154
- const { width, data } = imageData;
155
-
156
- this.clear();
157
- this.ctx.fillStyle = color;
158
-
159
- for (let y = 0; y < canvas.height; y += cellHeight) {
160
- for (let x = 0; x < canvas.width; x += cellWidth) {
161
- const brightness = this.getCellBrightness(data, x, y, width, cellWidth, cellHeight, brightnessFunction);
162
- const charIndex = Math.floor((brightness / 255) * (characters.length - 1));
163
- const char = characters[Math.min(charIndex, characters.length - 1)];
164
-
165
- if (char !== ' ') {
166
- this.ctx.fillText(char, x, y);
167
- }
168
- }
169
- }
170
- }
171
-
172
- /**
173
- * Render ASCII from a brightness grid (for pattern-based rendering)
174
- */
175
- renderFromBrightnessGrid(grid: number[][]): void {
176
- const { characters, cellWidth, cellHeight, color } = this.config;
177
-
178
- this.clear();
179
- this.ctx.fillStyle = color;
180
-
181
- for (let row = 0; row < grid.length; row++) {
182
- for (let col = 0; col < grid[row].length; col++) {
183
- const brightness = grid[row][col];
184
- const charIndex = Math.floor((brightness / 255) * (characters.length - 1));
185
- const char = characters[Math.min(charIndex, characters.length - 1)];
186
-
187
- if (char !== ' ') {
188
- this.ctx.fillText(char, col * cellWidth, row * cellHeight);
189
- }
190
- }
191
- }
192
- }
193
-
194
- /**
195
- * Render ASCII with per-cell colors (for colored image rendering)
196
- */
197
- renderWithColors(data: Array<{ char: string; color: string; x: number; y: number }>): void {
198
- this.clear();
199
-
200
- for (const { char, color, x, y } of data) {
201
- if (char !== ' ') {
202
- this.ctx.fillStyle = color;
203
- this.ctx.fillText(char, x, y);
204
- }
205
- }
206
- }
207
-
208
- /**
209
- * Calculate average brightness for a cell region
210
- */
211
- private getCellBrightness(
212
- data: Uint8ClampedArray,
213
- startX: number,
214
- startY: number,
215
- imageWidth: number,
216
- cellWidth: number,
217
- cellHeight: number,
218
- brightnessFunction: (r: number, g: number, b: number) => number
219
- ): number {
220
- let total = 0;
221
- let count = 0;
222
-
223
- for (let cy = 0; cy < cellHeight; cy++) {
224
- for (let cx = 0; cx < cellWidth; cx++) {
225
- const px = ((startY + cy) * imageWidth + (startX + cx)) * 4;
226
- if (px >= 0 && px + 2 < data.length) {
227
- total += brightnessFunction(data[px], data[px + 1], data[px + 2]);
228
- count++;
229
- }
230
- }
231
- }
232
-
233
- return count > 0 ? total / count : 0;
234
- }
235
-
236
- /**
237
- * Start an animation loop with FPS limiting
238
- */
239
- startAnimation(
240
- updateFn: (time: number, deltaTime: number) => ImageData | number[][],
241
- fps: number = 30
242
- ): void {
243
- if (this.isRunning) {
244
- this.stopAnimation();
245
- }
246
-
247
- this.isRunning = true;
248
- const frameInterval = 1000 / fps;
249
- this.lastFrameTime = performance.now();
250
-
251
- const animate = (currentTime: number): void => {
252
- if (!this.isRunning) return;
253
-
254
- const deltaTime = currentTime - this.lastFrameTime;
255
-
256
- if (deltaTime >= frameInterval) {
257
- const result = updateFn(currentTime, deltaTime);
258
-
259
- if (result instanceof ImageData) {
260
- this.renderFrame(result);
261
- } else {
262
- this.renderFromBrightnessGrid(result);
263
- }
264
-
265
- this.lastFrameTime = currentTime - (deltaTime % frameInterval);
266
- }
267
-
268
- this.animationId = requestAnimationFrame(animate);
269
- };
270
-
271
- this.animationId = requestAnimationFrame(animate);
272
- }
273
-
274
- /**
275
- * Stop the animation loop
276
- */
277
- stopAnimation(): void {
278
- this.isRunning = false;
279
- if (this.animationId !== null) {
280
- cancelAnimationFrame(this.animationId);
281
- this.animationId = null;
282
- }
283
- }
284
-
285
- /**
286
- * Check if animation is currently running
287
- */
288
- isAnimating(): boolean {
289
- return this.isRunning;
290
- }
291
-
292
- /**
293
- * Pause animation (can be resumed)
294
- */
295
- pause(): void {
296
- this.isRunning = false;
297
- if (this.animationId !== null) {
298
- cancelAnimationFrame(this.animationId);
299
- this.animationId = null;
300
- }
301
- }
302
-
303
- /**
304
- * Clean up and destroy the renderer
305
- */
306
- destroy(): void {
307
- this.stopAnimation();
308
- }
309
- }
@@ -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';
@@ -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
- }