@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.
Files changed (51) 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.js +176 -0
  5. package/dist/characters.test.js +115 -0
  6. package/dist/colors.js +199 -0
  7. package/dist/index.js +79 -1850
  8. package/dist/index.test.js +92 -0
  9. package/dist/patterns.js +539 -0
  10. package/dist/patterns.test.js +223 -0
  11. package/dist/renderer.js +362 -0
  12. package/dist/svelte/GossamerBorder.svelte.d.ts +56 -1
  13. package/dist/svelte/GossamerBorder.svelte.d.ts.map +1 -0
  14. package/dist/svelte/GossamerClouds.svelte.d.ts +31 -1
  15. package/dist/svelte/GossamerClouds.svelte.d.ts.map +1 -0
  16. package/dist/svelte/GossamerImage.svelte.d.ts +28 -1
  17. package/dist/svelte/GossamerImage.svelte.d.ts.map +1 -0
  18. package/dist/svelte/GossamerOverlay.svelte.d.ts +32 -1
  19. package/dist/svelte/GossamerOverlay.svelte.d.ts.map +1 -0
  20. package/dist/svelte/GossamerText.svelte.d.ts +29 -1
  21. package/dist/svelte/GossamerText.svelte.d.ts.map +1 -0
  22. package/dist/svelte/index.js +31 -3646
  23. package/dist/svelte/presets.d.ts +4 -2
  24. package/dist/svelte/presets.js +161 -0
  25. package/dist/utils/canvas.js +139 -0
  26. package/dist/utils/image.js +195 -0
  27. package/dist/utils/performance.js +205 -0
  28. package/package.json +18 -22
  29. package/dist/index.js.map +0 -1
  30. package/dist/style.css +0 -124
  31. package/dist/svelte/index.js.map +0 -1
  32. package/src/animation.test.ts +0 -254
  33. package/src/animation.ts +0 -243
  34. package/src/characters.test.ts +0 -148
  35. package/src/characters.ts +0 -219
  36. package/src/colors.ts +0 -234
  37. package/src/index.test.ts +0 -115
  38. package/src/index.ts +0 -234
  39. package/src/patterns.test.ts +0 -273
  40. package/src/patterns.ts +0 -760
  41. package/src/renderer.ts +0 -470
  42. package/src/svelte/index.ts +0 -75
  43. package/src/svelte/presets.ts +0 -174
  44. package/src/utils/canvas.ts +0 -210
  45. package/src/utils/image.ts +0 -275
  46. package/src/utils/performance.ts +0 -282
  47. /package/{src → dist}/svelte/GossamerBorder.svelte +0 -0
  48. /package/{src → dist}/svelte/GossamerClouds.svelte +0 -0
  49. /package/{src → dist}/svelte/GossamerImage.svelte +0 -0
  50. /package/{src → dist}/svelte/GossamerOverlay.svelte +0 -0
  51. /package/{src → dist}/svelte/GossamerText.svelte +0 -0
package/src/index.ts DELETED
@@ -1,234 +0,0 @@
1
- /**
2
- * Gossamer - ASCII Visual Effects Library
3
- *
4
- * Threads of light. Delicate textures woven through your space.
5
- *
6
- * @packageDocumentation
7
- */
8
-
9
- // =============================================================================
10
- // Core Types
11
- // =============================================================================
12
-
13
- /**
14
- * Core configuration for ASCII rendering
15
- */
16
- export interface GossamerConfig {
17
- /** Character set for ASCII rendering (light to dark) */
18
- characters?: string;
19
- /** Cell width in pixels */
20
- cellWidth?: number;
21
- /** Cell height in pixels */
22
- cellHeight?: number;
23
- /** Foreground color */
24
- color?: string;
25
- /** Background color (transparent if not set) */
26
- backgroundColor?: string;
27
- /** Font family for ASCII characters */
28
- fontFamily?: string;
29
- /** Enable animation loop */
30
- animate?: boolean;
31
- /** Target FPS for animation */
32
- fps?: number;
33
- }
34
-
35
- /**
36
- * Preset configuration for effects
37
- */
38
- export interface PresetConfig {
39
- /** Preset display name */
40
- name: string;
41
- /** Preset description */
42
- description: string;
43
- /** Character set */
44
- characters: string;
45
- /** Pattern type */
46
- pattern: 'perlin' | 'waves' | 'static' | 'ripple' | 'fbm' | 'clouds' | 'plasma' | 'vortex' | 'matrix' | 'gradient' | 'diamond' | 'fractal';
47
- /** Pattern frequency */
48
- frequency: number;
49
- /** Pattern amplitude */
50
- amplitude: number;
51
- /** Animation speed */
52
- speed: number;
53
- /** Default opacity */
54
- opacity: number;
55
- }
56
-
57
- // =============================================================================
58
- // Constants
59
- // =============================================================================
60
-
61
- /**
62
- * Default character set ordered from light to dark
63
- */
64
- export const DEFAULT_CHARACTERS = ' .:-=+*#%@';
65
-
66
- /**
67
- * Default configuration values
68
- */
69
- export const DEFAULT_CONFIG: Required<GossamerConfig> = {
70
- characters: DEFAULT_CHARACTERS,
71
- cellWidth: 8,
72
- cellHeight: 12,
73
- color: '#ffffff',
74
- backgroundColor: '',
75
- fontFamily: 'monospace',
76
- animate: false,
77
- fps: 30,
78
- };
79
-
80
- // =============================================================================
81
- // Core Functions
82
- // =============================================================================
83
-
84
- /**
85
- * Calculate brightness from RGB values using luminance formula
86
- * Uses the standard luminance coefficients: 0.21 R + 0.72 G + 0.07 B
87
- */
88
- export function calculateBrightness(r: number, g: number, b: number): number {
89
- return 0.21 * r + 0.72 * g + 0.07 * b;
90
- }
91
-
92
- /**
93
- * Map a brightness value (0-255) to an ASCII character
94
- */
95
- export function brightnessToChar(
96
- brightness: number,
97
- characters: string = DEFAULT_CHARACTERS
98
- ): string {
99
- const index = Math.floor((brightness / 255) * (characters.length - 1));
100
- return characters[Math.min(index, characters.length - 1)];
101
- }
102
-
103
- // =============================================================================
104
- // Module Exports
105
- // =============================================================================
106
-
107
- // Renderer
108
- export { GossamerRenderer } from './renderer';
109
- export type { RenderConfig } from './renderer';
110
-
111
- // Patterns
112
- export {
113
- // Core noise functions
114
- perlinNoise2D,
115
- fbmNoise,
116
- staticNoise,
117
- seededNoise2D,
118
- // Pattern generators
119
- wavePattern,
120
- ripplePattern,
121
- cloudsPattern,
122
- plasmaPattern,
123
- vortexPattern,
124
- matrixPattern,
125
- gradientPattern,
126
- diamondPattern,
127
- fractalPattern,
128
- // Grid generation (legacy API)
129
- generateBrightnessGrid,
130
- gridToImageData,
131
- // Performance-optimized API
132
- createBrightnessBuffer,
133
- fillBrightnessBuffer,
134
- getBufferValue,
135
- // Config
136
- DEFAULT_PATTERN_CONFIG,
137
- } from './patterns';
138
- export type { PatternConfig, PatternType, BrightnessBuffer } from './patterns';
139
-
140
- // Characters
141
- export {
142
- CHARACTER_SETS,
143
- getCharacterSet,
144
- getCharacters,
145
- getCharacterSetNames,
146
- createCharacterSet,
147
- validateCharacterSet,
148
- invertCharacters,
149
- } from './characters';
150
- export type { CharacterSet } from './characters';
151
-
152
- // Colors (Grove palette)
153
- export {
154
- GROVE_GREEN,
155
- CREAM,
156
- BARK,
157
- STATUS,
158
- GROVE_COLORS,
159
- GLASS_SCHEMES,
160
- getGroveColor,
161
- getGlassScheme,
162
- getGroveColorNames,
163
- getGlassSchemeNames,
164
- hexToRgba,
165
- } from './colors';
166
- export type { ColorDef, GroveColorName, GlassSchemeName } from './colors';
167
-
168
- // Animation
169
- export {
170
- createAnimationLoop,
171
- throttle,
172
- debounce,
173
- calculateFPS,
174
- easings,
175
- } from './animation';
176
- export type { AnimationState, AnimationOptions, EasingFunction } from './animation';
177
-
178
- // Canvas Utilities
179
- export {
180
- createCanvas,
181
- getDevicePixelRatio,
182
- resizeCanvasToContainer,
183
- createOffscreenCanvas,
184
- clearCanvas,
185
- getImageData,
186
- optimizeContext,
187
- setupTextRendering,
188
- measureTextWidth,
189
- calculateCellSize,
190
- setBlendMode,
191
- } from './utils/canvas';
192
- export type { CanvasOptions } from './utils/canvas';
193
-
194
- // Image Utilities
195
- export {
196
- loadImage,
197
- loadAndScaleImage,
198
- imageToPixelData,
199
- extractBrightness,
200
- sampleImageCells,
201
- rgbToHex,
202
- hexToRgb,
203
- adjustBrightness,
204
- adjustContrast,
205
- invertColors,
206
- toGrayscale,
207
- } from './utils/image';
208
- export type { ImageLoadOptions } from './utils/image';
209
-
210
- // Performance Utilities
211
- export {
212
- createVisibilityObserver,
213
- createResizeObserver,
214
- prefersReducedMotion,
215
- onReducedMotionChange,
216
- isLowPowerMode,
217
- getRecommendedFPS,
218
- createFPSCounter,
219
- requestIdleCallback,
220
- cancelIdleCallback,
221
- isBrowser,
222
- isCanvasSupported,
223
- isOffscreenCanvasSupported,
224
- } from './utils/performance';
225
- export type { VisibilityCallback, PerformanceMetrics } from './utils/performance';
226
-
227
- // =============================================================================
228
- // Version
229
- // =============================================================================
230
-
231
- /**
232
- * Gossamer version
233
- */
234
- export const VERSION = '0.1.0';
@@ -1,273 +0,0 @@
1
- /**
2
- * Tests for pattern generators
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import {
6
- perlinNoise2D,
7
- fbmNoise,
8
- wavePattern,
9
- ripplePattern,
10
- staticNoise,
11
- seededNoise2D,
12
- generateBrightnessGrid,
13
- gridToImageData,
14
- DEFAULT_PATTERN_CONFIG,
15
- } from './patterns';
16
-
17
- describe('perlinNoise2D', () => {
18
- it('should return value between -1 and 1', () => {
19
- for (let i = 0; i < 100; i++) {
20
- const x = Math.random() * 100;
21
- const y = Math.random() * 100;
22
- const value = perlinNoise2D(x, y);
23
- expect(value).toBeGreaterThanOrEqual(-1);
24
- expect(value).toBeLessThanOrEqual(1);
25
- }
26
- });
27
-
28
- it('should be deterministic (same input = same output)', () => {
29
- const val1 = perlinNoise2D(5.5, 3.2);
30
- const val2 = perlinNoise2D(5.5, 3.2);
31
- expect(val1).toBe(val2);
32
- });
33
-
34
- it('should vary with position', () => {
35
- // Use non-integer coordinates (Perlin returns 0 at integer coords)
36
- const val1 = perlinNoise2D(0.5, 0.5);
37
- const val2 = perlinNoise2D(10.5, 10.5);
38
- expect(val1).not.toBe(val2);
39
- });
40
-
41
- it('should produce smooth transitions', () => {
42
- const val1 = perlinNoise2D(1.0, 1.0);
43
- const val2 = perlinNoise2D(1.01, 1.01);
44
- const diff = Math.abs(val1 - val2);
45
- expect(diff).toBeLessThan(0.1);
46
- });
47
- });
48
-
49
- describe('fbmNoise', () => {
50
- it('should return value between -1 and 1', () => {
51
- for (let i = 0; i < 50; i++) {
52
- const x = Math.random() * 100;
53
- const y = Math.random() * 100;
54
- const value = fbmNoise(x, y);
55
- expect(value).toBeGreaterThanOrEqual(-1);
56
- expect(value).toBeLessThanOrEqual(1);
57
- }
58
- });
59
-
60
- it('should be deterministic', () => {
61
- const val1 = fbmNoise(3.3, 7.7);
62
- const val2 = fbmNoise(3.3, 7.7);
63
- expect(val1).toBe(val2);
64
- });
65
-
66
- it('should accept octaves parameter', () => {
67
- // Use non-integer coordinates (noise returns 0 at integer coords)
68
- const val1 = fbmNoise(5.5, 5.5, 2);
69
- const val2 = fbmNoise(5.5, 5.5, 8);
70
- // Different octaves should produce different results
71
- expect(val1).not.toBe(val2);
72
- });
73
-
74
- it('should accept persistence parameter', () => {
75
- // Use non-integer coordinates (noise returns 0 at integer coords)
76
- const val1 = fbmNoise(5.5, 5.5, 4, 0.3);
77
- const val2 = fbmNoise(5.5, 5.5, 4, 0.7);
78
- expect(val1).not.toBe(val2);
79
- });
80
- });
81
-
82
- describe('wavePattern', () => {
83
- it('should return value between -1 and 1', () => {
84
- for (let t = 0; t < 10; t++) {
85
- const value = wavePattern(50, 50, t);
86
- expect(value).toBeGreaterThanOrEqual(-1);
87
- expect(value).toBeLessThanOrEqual(1);
88
- }
89
- });
90
-
91
- it('should vary with time', () => {
92
- const val1 = wavePattern(10, 10, 0);
93
- const val2 = wavePattern(10, 10, 5);
94
- expect(val1).not.toBe(val2);
95
- });
96
-
97
- it('should use custom config', () => {
98
- const config = { frequency: 0.1, amplitude: 0.5, speed: 1.0 };
99
- const value = wavePattern(10, 10, 1, config);
100
- expect(Math.abs(value)).toBeLessThanOrEqual(0.5);
101
- });
102
- });
103
-
104
- describe('ripplePattern', () => {
105
- it('should return value between -1 and 1', () => {
106
- for (let i = 0; i < 50; i++) {
107
- const value = ripplePattern(
108
- Math.random() * 100,
109
- Math.random() * 100,
110
- 50,
111
- 50,
112
- Math.random() * 10
113
- );
114
- expect(value).toBeGreaterThanOrEqual(-1);
115
- expect(value).toBeLessThanOrEqual(1);
116
- }
117
- });
118
-
119
- it('should vary with distance from center', () => {
120
- const centerVal = ripplePattern(50, 50, 50, 50, 0);
121
- const edgeVal = ripplePattern(100, 50, 50, 50, 0);
122
- expect(centerVal).not.toBe(edgeVal);
123
- });
124
-
125
- it('should animate over time', () => {
126
- const val1 = ripplePattern(60, 60, 50, 50, 0);
127
- const val2 = ripplePattern(60, 60, 50, 50, 1);
128
- expect(val1).not.toBe(val2);
129
- });
130
- });
131
-
132
- describe('staticNoise', () => {
133
- it('should return value between 0 and 1', () => {
134
- for (let i = 0; i < 100; i++) {
135
- const value = staticNoise();
136
- expect(value).toBeGreaterThanOrEqual(0);
137
- expect(value).toBeLessThanOrEqual(1);
138
- }
139
- });
140
-
141
- it('should be deterministic with seed', () => {
142
- const val1 = staticNoise(12345);
143
- const val2 = staticNoise(12345);
144
- expect(val1).toBe(val2);
145
- });
146
-
147
- it('should vary with different seeds', () => {
148
- const val1 = staticNoise(1);
149
- const val2 = staticNoise(2);
150
- expect(val1).not.toBe(val2);
151
- });
152
- });
153
-
154
- describe('seededNoise2D', () => {
155
- it('should return value between 0 and 1', () => {
156
- for (let i = 0; i < 100; i++) {
157
- const value = seededNoise2D(Math.random() * 100, Math.random() * 100);
158
- expect(value).toBeGreaterThanOrEqual(0);
159
- expect(value).toBeLessThanOrEqual(1);
160
- }
161
- });
162
-
163
- it('should be deterministic', () => {
164
- const val1 = seededNoise2D(5, 10, 42);
165
- const val2 = seededNoise2D(5, 10, 42);
166
- expect(val1).toBe(val2);
167
- });
168
-
169
- it('should vary with coordinates', () => {
170
- const val1 = seededNoise2D(0, 0);
171
- const val2 = seededNoise2D(10, 10);
172
- expect(val1).not.toBe(val2);
173
- });
174
-
175
- it('should vary with seed', () => {
176
- const val1 = seededNoise2D(5, 5, 0);
177
- const val2 = seededNoise2D(5, 5, 100);
178
- expect(val1).not.toBe(val2);
179
- });
180
- });
181
-
182
- describe('DEFAULT_PATTERN_CONFIG', () => {
183
- it('should have expected default values', () => {
184
- expect(DEFAULT_PATTERN_CONFIG.frequency).toBe(0.05);
185
- expect(DEFAULT_PATTERN_CONFIG.amplitude).toBe(1.0);
186
- expect(DEFAULT_PATTERN_CONFIG.speed).toBe(0.5);
187
- });
188
- });
189
-
190
- describe('generateBrightnessGrid', () => {
191
- it('should generate grid with correct dimensions', () => {
192
- const grid = generateBrightnessGrid(10, 8, 'perlin');
193
- expect(grid.length).toBe(8); // rows
194
- expect(grid[0].length).toBe(10); // cols
195
- });
196
-
197
- it('should generate brightness values between 0 and 255', () => {
198
- const grid = generateBrightnessGrid(20, 15, 'perlin');
199
- for (const row of grid) {
200
- for (const value of row) {
201
- expect(value).toBeGreaterThanOrEqual(0);
202
- expect(value).toBeLessThanOrEqual(255);
203
- expect(Number.isInteger(value)).toBe(true);
204
- }
205
- }
206
- });
207
-
208
- it('should support all pattern types', () => {
209
- const patterns: Array<'perlin' | 'waves' | 'static' | 'ripple' | 'fbm'> = [
210
- 'perlin',
211
- 'waves',
212
- 'static',
213
- 'ripple',
214
- 'fbm',
215
- ];
216
-
217
- for (const pattern of patterns) {
218
- const grid = generateBrightnessGrid(5, 5, pattern);
219
- expect(grid.length).toBe(5);
220
- expect(grid[0].length).toBe(5);
221
- }
222
- });
223
-
224
- it('should use time parameter for animation', () => {
225
- const grid1 = generateBrightnessGrid(10, 10, 'perlin', 0);
226
- const grid2 = generateBrightnessGrid(10, 10, 'perlin', 100);
227
-
228
- // At least some values should differ
229
- let hasDifference = false;
230
- for (let r = 0; r < 10 && !hasDifference; r++) {
231
- for (let c = 0; c < 10 && !hasDifference; c++) {
232
- if (grid1[r][c] !== grid2[r][c]) {
233
- hasDifference = true;
234
- }
235
- }
236
- }
237
- expect(hasDifference).toBe(true);
238
- });
239
- });
240
-
241
- // Note: gridToImageData tests require browser environment with canvas support
242
- // These tests are skipped in Node.js/jsdom as ImageData is not available
243
- describe.skip('gridToImageData (browser only)', () => {
244
- it('should create ImageData with correct dimensions', () => {
245
- const grid = [
246
- [100, 150],
247
- [200, 50],
248
- ];
249
- const imageData = gridToImageData(grid, 8, 12);
250
-
251
- expect(imageData.width).toBe(16); // 2 cols * 8
252
- expect(imageData.height).toBe(24); // 2 rows * 12
253
- });
254
-
255
- it('should fill cells with brightness values', () => {
256
- const grid = [[128]]; // Single cell
257
- const imageData = gridToImageData(grid, 2, 2);
258
-
259
- // Check first pixel (should be brightness 128)
260
- expect(imageData.data[0]).toBe(128); // R
261
- expect(imageData.data[1]).toBe(128); // G
262
- expect(imageData.data[2]).toBe(128); // B
263
- expect(imageData.data[3]).toBe(255); // A (full opacity)
264
- });
265
-
266
- it('should handle empty grid', () => {
267
- const grid: number[][] = [];
268
- const imageData = gridToImageData(grid, 8, 12);
269
-
270
- expect(imageData.width).toBe(0);
271
- expect(imageData.height).toBe(0);
272
- });
273
- });