@ivanalbizu/astro-webgl-hover 0.0.1 → 0.0.2
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/package.json +1 -1
- package/src/components/WebglHoverImage.astro +14 -14
- package/src/lib/webgl-hover/WebglHover.ts +5 -2
- package/src/lib/webgl-hover/config.ts +1 -1
- package/src/lib/webgl-hover/index.ts +13 -13
- package/src/lib/webgl-hover/performance.ts +6 -6
- package/src/lib/webgl-hover/utils.ts +1 -1
package/package.json
CHANGED
|
@@ -40,22 +40,22 @@ const finalHeight1 = height1 || height;
|
|
|
40
40
|
<slot />
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
|
-
<style
|
|
43
|
+
<style define:vars={{ width, height }}>
|
|
44
44
|
.whi-plane {
|
|
45
45
|
aspect-ratio: var(--width) / var(--height);
|
|
46
46
|
position: relative;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
}
|
|
48
|
+
.whi-plane img {
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: 0;
|
|
51
|
+
left: 0;
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
opacity: 0;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
.whi-plane imgdata-sampler="texture0"] {
|
|
58
|
+
opacity: 1;
|
|
59
|
+
transition: opacity 0.5s ease-out;
|
|
60
60
|
}
|
|
61
61
|
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Main class for handling WebGL hover effects with Curtains.js
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { Plane } from 'curtainsjs';
|
|
@@ -37,7 +37,7 @@ export class WebglHover {
|
|
|
37
37
|
this.webGLCurtain = curtains;
|
|
38
38
|
this.planeElement = planeElement;
|
|
39
39
|
|
|
40
|
-
// Bind handlers
|
|
40
|
+
// Bind handlers for proper cleanup on destroy
|
|
41
41
|
this.boundHandleMouseEnter = this.handleMouseEnter.bind(this);
|
|
42
42
|
this.boundHandleMouseOut = this.handleMouseOut.bind(this);
|
|
43
43
|
|
|
@@ -53,6 +53,7 @@ export class WebglHover {
|
|
|
53
53
|
this.intensity = options.intensity;
|
|
54
54
|
this.displacementAngle = options.displacementAngle;
|
|
55
55
|
|
|
56
|
+
// Convert intensity + angle to displacement vector [x, y]
|
|
56
57
|
const displacement = calculateDisplacementVector(options.intensity, options.displacementAngle);
|
|
57
58
|
|
|
58
59
|
this.params = {
|
|
@@ -90,6 +91,7 @@ export class WebglHover {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
// Only update time uniform when animating (performance optimization)
|
|
93
95
|
private startRenderLoop(): void {
|
|
94
96
|
this.plane.onRender(() => {
|
|
95
97
|
if (this.isAnimating) {
|
|
@@ -156,6 +158,7 @@ export class WebglHover {
|
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
|
|
161
|
+
// Manual progress control (used by debug panel timeline)
|
|
159
162
|
public setProgress(progress: number): void {
|
|
160
163
|
if (!this.plane) return;
|
|
161
164
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WebGL Hover -
|
|
2
|
+
* WebGL Hover - Main Entry Point
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Initializes WebGL hover effects with Curtains.js and GSAP
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Curtains } from 'curtainsjs';
|
|
@@ -82,7 +82,7 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
82
82
|
import('lil-gui').then(({ default: GUI }) => {
|
|
83
83
|
const gui = new GUI({ title: 'WebGL Hover Debug' });
|
|
84
84
|
|
|
85
|
-
//
|
|
85
|
+
// Instance selector (no "All" option)
|
|
86
86
|
const targetOptions: Record<string, number> = {};
|
|
87
87
|
instances.forEach((_, i) => {
|
|
88
88
|
targetOptions[`Image ${i + 1}`] = i;
|
|
@@ -94,7 +94,7 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
94
94
|
return instances[selectorConfig.target];
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
//
|
|
97
|
+
// Load initial config from the first image
|
|
98
98
|
const initialConfig = instances[0].getConfig();
|
|
99
99
|
const debugConfig = {
|
|
100
100
|
intensity: initialConfig.intensity ?? config.intensity,
|
|
@@ -115,9 +115,9 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
115
115
|
manualControl: false,
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
// Controllers
|
|
118
|
+
// Controllers to update values when switching images
|
|
119
119
|
const controllers: any[] = [];
|
|
120
|
-
//
|
|
120
|
+
// Animation controllers (disabled in manual mode)
|
|
121
121
|
const animControllers: any[] = [];
|
|
122
122
|
|
|
123
123
|
const loadConfigFromInstance = (index: number) => {
|
|
@@ -134,19 +134,19 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
134
134
|
debugConfig.easeIn = instanceConfig.easeIn ?? debugConfig.easeIn;
|
|
135
135
|
debugConfig.easeOut = instanceConfig.easeOut ?? debugConfig.easeOut;
|
|
136
136
|
|
|
137
|
-
//
|
|
137
|
+
// Update all controllers
|
|
138
138
|
controllers.forEach((c) => c.updateDisplay());
|
|
139
139
|
};
|
|
140
140
|
|
|
141
|
-
//
|
|
141
|
+
// Initial highlight on the first image
|
|
142
142
|
instances[0].setDebugHighlight(true);
|
|
143
143
|
|
|
144
144
|
gui.add(selectorConfig, 'target', targetOptions).name('Target').onChange((index: number) => {
|
|
145
|
-
//
|
|
145
|
+
// Remove highlight from all and apply to selected
|
|
146
146
|
instances.forEach((inst, i) => inst.setDebugHighlight(i === index));
|
|
147
147
|
|
|
148
148
|
loadConfigFromInstance(index);
|
|
149
|
-
// Reset timeline progress
|
|
149
|
+
// Reset timeline progress on change
|
|
150
150
|
timelineConfig.progress = 0;
|
|
151
151
|
controllers.forEach((c) => c.updateDisplay());
|
|
152
152
|
});
|
|
@@ -182,12 +182,12 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
182
182
|
if (enabled) {
|
|
183
183
|
setTargetProgress(timelineConfig.progress);
|
|
184
184
|
} else {
|
|
185
|
-
//
|
|
185
|
+
// Return to idle state when disabled
|
|
186
186
|
setTargetProgress(0);
|
|
187
187
|
timelineConfig.progress = 0;
|
|
188
188
|
controllers.forEach((c) => c.updateDisplay());
|
|
189
189
|
}
|
|
190
|
-
//
|
|
190
|
+
// Disable/enable animation controllers
|
|
191
191
|
animControllers.forEach((c) => c.enable(!enabled));
|
|
192
192
|
})
|
|
193
193
|
);
|
|
@@ -204,7 +204,7 @@ function initDebugMode(instances: WebglHover[], config: WebglHoverConfig): void
|
|
|
204
204
|
controllers.push(folderParams.add(debugConfig, 'noiseScale', 0, 20).name('Noise Scale').onChange(updateTargetInstance));
|
|
205
205
|
controllers.push(folderParams.add(debugConfig, 'rgbShiftIntensity', 0, 1).name('RGB Shift').onChange(updateTargetInstance));
|
|
206
206
|
|
|
207
|
-
// Animation folder (
|
|
207
|
+
// Animation folder (disabled in manual mode)
|
|
208
208
|
const folderAnim = gui.addFolder('Animation');
|
|
209
209
|
const durationInCtrl = folderAnim.add(debugConfig, 'durationIn', 0.1, 3).name('Duration In').onChange(updateTargetInstance);
|
|
210
210
|
const durationOutCtrl = folderAnim.add(debugConfig, 'durationOut', 0.1, 3).name('Duration Out').onChange(updateTargetInstance);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Performance detection and fallbacks for WebGL Hover
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
interface NavigatorWithExtensions extends Navigator {
|
|
@@ -12,18 +12,18 @@ interface NavigatorWithExtensions extends Navigator {
|
|
|
12
12
|
export function isLowPerformance(): boolean {
|
|
13
13
|
const nav = navigator as NavigatorWithExtensions;
|
|
14
14
|
|
|
15
|
-
// 1.
|
|
15
|
+
// 1. Detect "Data Saver" mode from Browser/OS
|
|
16
16
|
if (nav.connection?.saveData) {
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// 2.
|
|
21
|
-
// deviceMemory (RAM
|
|
20
|
+
// 2. Hardware Heuristics
|
|
21
|
+
// deviceMemory (RAM in GB) - Chrome/Edge only. Values: 0.25, 0.5, 1, 2, 4, 8...
|
|
22
22
|
const memory = nav.deviceMemory;
|
|
23
|
-
// hardwareConcurrency (
|
|
23
|
+
// hardwareConcurrency (CPU Cores)
|
|
24
24
|
const cores = navigator.hardwareConcurrency;
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// If less than 4GB RAM or 2 or fewer cores, assume low-end.
|
|
27
27
|
return (memory !== undefined && memory < 4) || (cores !== undefined && cores <= 2);
|
|
28
28
|
}
|
|
29
29
|
|