@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/utils/performance.ts
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance Utilities
|
|
3
|
-
*
|
|
4
|
-
* Visibility detection, resource management, and optimization helpers.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Visibility observer callback type
|
|
9
|
-
*/
|
|
10
|
-
export type VisibilityCallback = (isVisible: boolean, entry: IntersectionObserverEntry) => void;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create an IntersectionObserver for visibility-based animation control
|
|
14
|
-
*
|
|
15
|
-
* @param element - Element to observe
|
|
16
|
-
* @param callback - Called when visibility changes
|
|
17
|
-
* @param threshold - Visibility threshold (0-1, default: 0.1)
|
|
18
|
-
* @returns Cleanup function to disconnect observer
|
|
19
|
-
*/
|
|
20
|
-
export function createVisibilityObserver(
|
|
21
|
-
element: Element,
|
|
22
|
-
callback: VisibilityCallback,
|
|
23
|
-
threshold: number = 0.1
|
|
24
|
-
): () => void {
|
|
25
|
-
const observer = new IntersectionObserver(
|
|
26
|
-
(entries) => {
|
|
27
|
-
for (const entry of entries) {
|
|
28
|
-
callback(entry.isIntersecting, entry);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
{ threshold }
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
observer.observe(element);
|
|
35
|
-
|
|
36
|
-
return () => {
|
|
37
|
-
observer.disconnect();
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Create a ResizeObserver for responsive canvas sizing
|
|
43
|
-
*
|
|
44
|
-
* @param element - Element to observe
|
|
45
|
-
* @param callback - Called on resize with new dimensions
|
|
46
|
-
* @param debounceMs - Debounce delay in ms (default: 100)
|
|
47
|
-
* @returns Cleanup function to disconnect observer
|
|
48
|
-
*/
|
|
49
|
-
export function createResizeObserver(
|
|
50
|
-
element: Element,
|
|
51
|
-
callback: (width: number, height: number, entry: ResizeObserverEntry) => void,
|
|
52
|
-
debounceMs: number = 100
|
|
53
|
-
): () => void {
|
|
54
|
-
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
55
|
-
|
|
56
|
-
const observer = new ResizeObserver((entries) => {
|
|
57
|
-
if (timeout) {
|
|
58
|
-
clearTimeout(timeout);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
timeout = setTimeout(() => {
|
|
62
|
-
const entry = entries[0];
|
|
63
|
-
if (entry) {
|
|
64
|
-
const { width, height } = entry.contentRect;
|
|
65
|
-
callback(width, height, entry);
|
|
66
|
-
}
|
|
67
|
-
}, debounceMs);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
observer.observe(element);
|
|
71
|
-
|
|
72
|
-
return () => {
|
|
73
|
-
if (timeout) {
|
|
74
|
-
clearTimeout(timeout);
|
|
75
|
-
}
|
|
76
|
-
observer.disconnect();
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if the user prefers reduced motion
|
|
82
|
-
*/
|
|
83
|
-
export function prefersReducedMotion(): boolean {
|
|
84
|
-
if (typeof window === 'undefined') return false;
|
|
85
|
-
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Create a listener for reduced motion preference changes
|
|
90
|
-
*
|
|
91
|
-
* @param callback - Called when preference changes
|
|
92
|
-
* @returns Cleanup function to remove listener
|
|
93
|
-
*/
|
|
94
|
-
export function onReducedMotionChange(callback: (prefersReduced: boolean) => void): () => void {
|
|
95
|
-
if (typeof window === 'undefined') {
|
|
96
|
-
return () => {};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
100
|
-
|
|
101
|
-
const handler = (event: MediaQueryListEvent) => {
|
|
102
|
-
callback(event.matches);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
mediaQuery.addEventListener('change', handler);
|
|
106
|
-
|
|
107
|
-
// Call immediately with current value
|
|
108
|
-
callback(mediaQuery.matches);
|
|
109
|
-
|
|
110
|
-
return () => {
|
|
111
|
-
mediaQuery.removeEventListener('change', handler);
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Check if the browser is in a low-power mode or has reduced capabilities
|
|
117
|
-
*/
|
|
118
|
-
export function isLowPowerMode(): boolean {
|
|
119
|
-
// Check for battery API (if available)
|
|
120
|
-
if (typeof navigator !== 'undefined' && 'getBattery' in navigator) {
|
|
121
|
-
// Battery API is async, so this is a simplified check
|
|
122
|
-
// Real implementation would need to be async
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Fallback: check for hardware concurrency
|
|
127
|
-
if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {
|
|
128
|
-
return navigator.hardwareConcurrency <= 2;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Get recommended FPS based on device capabilities
|
|
136
|
-
*/
|
|
137
|
-
export function getRecommendedFPS(): number {
|
|
138
|
-
if (prefersReducedMotion()) {
|
|
139
|
-
return 0; // No animation
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (isLowPowerMode()) {
|
|
143
|
-
return 15; // Low power mode
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Default for capable devices
|
|
147
|
-
return 30;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Performance monitoring for debugging
|
|
152
|
-
*/
|
|
153
|
-
export interface PerformanceMetrics {
|
|
154
|
-
fps: number;
|
|
155
|
-
frameTime: number;
|
|
156
|
-
droppedFrames: number;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Create a simple FPS counter
|
|
161
|
-
*/
|
|
162
|
-
export function createFPSCounter(): {
|
|
163
|
-
tick: () => void;
|
|
164
|
-
getFPS: () => number;
|
|
165
|
-
getMetrics: () => PerformanceMetrics;
|
|
166
|
-
reset: () => void;
|
|
167
|
-
} {
|
|
168
|
-
const frameTimes: number[] = [];
|
|
169
|
-
const maxSamples = 60;
|
|
170
|
-
let droppedFrames = 0;
|
|
171
|
-
let lastFrameTime = performance.now();
|
|
172
|
-
|
|
173
|
-
function tick(): void {
|
|
174
|
-
const now = performance.now();
|
|
175
|
-
const delta = now - lastFrameTime;
|
|
176
|
-
lastFrameTime = now;
|
|
177
|
-
|
|
178
|
-
frameTimes.push(now);
|
|
179
|
-
|
|
180
|
-
if (frameTimes.length > maxSamples) {
|
|
181
|
-
frameTimes.shift();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Count dropped frames (assuming 60fps target, frames taking >20ms are "dropped")
|
|
185
|
-
if (delta > 20) {
|
|
186
|
-
droppedFrames += Math.floor(delta / 16.67) - 1;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function getFPS(): number {
|
|
191
|
-
if (frameTimes.length < 2) return 0;
|
|
192
|
-
|
|
193
|
-
const oldest = frameTimes[0];
|
|
194
|
-
const newest = frameTimes[frameTimes.length - 1];
|
|
195
|
-
const elapsed = newest - oldest;
|
|
196
|
-
|
|
197
|
-
if (elapsed === 0) return 0;
|
|
198
|
-
|
|
199
|
-
return ((frameTimes.length - 1) / elapsed) * 1000;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function getMetrics(): PerformanceMetrics {
|
|
203
|
-
const fps = getFPS();
|
|
204
|
-
const frameTime = fps > 0 ? 1000 / fps : 0;
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
fps: Math.round(fps * 10) / 10,
|
|
208
|
-
frameTime: Math.round(frameTime * 100) / 100,
|
|
209
|
-
droppedFrames,
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function reset(): void {
|
|
214
|
-
frameTimes.length = 0;
|
|
215
|
-
droppedFrames = 0;
|
|
216
|
-
lastFrameTime = performance.now();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return { tick, getFPS, getMetrics, reset };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Request idle callback with fallback
|
|
224
|
-
*/
|
|
225
|
-
export function requestIdleCallback(
|
|
226
|
-
callback: () => void,
|
|
227
|
-
options?: { timeout?: number }
|
|
228
|
-
): number {
|
|
229
|
-
// Use globalThis for cross-environment compatibility
|
|
230
|
-
const global = globalThis as typeof globalThis & {
|
|
231
|
-
requestIdleCallback?: typeof window.requestIdleCallback;
|
|
232
|
-
setTimeout: typeof setTimeout;
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
if (typeof global.requestIdleCallback === 'function') {
|
|
236
|
-
return global.requestIdleCallback(callback, options);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Fallback using setTimeout
|
|
240
|
-
return global.setTimeout(callback, options?.timeout ?? 1) as unknown as number;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Cancel idle callback with fallback
|
|
245
|
-
*/
|
|
246
|
-
export function cancelIdleCallback(id: number): void {
|
|
247
|
-
// Use globalThis for cross-environment compatibility
|
|
248
|
-
const global = globalThis as typeof globalThis & {
|
|
249
|
-
cancelIdleCallback?: typeof window.cancelIdleCallback;
|
|
250
|
-
clearTimeout: typeof clearTimeout;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
if (typeof global.cancelIdleCallback === 'function') {
|
|
254
|
-
global.cancelIdleCallback(id);
|
|
255
|
-
} else {
|
|
256
|
-
global.clearTimeout(id);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Check if we're running in a browser environment
|
|
262
|
-
*/
|
|
263
|
-
export function isBrowser(): boolean {
|
|
264
|
-
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Check if Canvas is supported
|
|
269
|
-
*/
|
|
270
|
-
export function isCanvasSupported(): boolean {
|
|
271
|
-
if (!isBrowser()) return false;
|
|
272
|
-
|
|
273
|
-
const canvas = document.createElement('canvas');
|
|
274
|
-
return !!(canvas.getContext && canvas.getContext('2d'));
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Check if OffscreenCanvas is supported
|
|
279
|
-
*/
|
|
280
|
-
export function isOffscreenCanvasSupported(): boolean {
|
|
281
|
-
return typeof OffscreenCanvas !== 'undefined';
|
|
282
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|