@@ -7,6 +7,10 @@ export default function EscherBackground() {
77 const INITIAL_RADIUS_DESKTOP_PX = 0 ;
88 const INITIAL_RADIUS_MOBILE_PX = 0 ;
99
10+ // Image margin configuration
11+ const IMAGE_TOP_MARGIN_VH = 5 ; // 10vh margin from top
12+ const IMAGE_BOTTOM_MARGIN_VH = 5 ; // 10vh margin from bottom
13+
1014 const canvasRef = useRef < HTMLCanvasElement > ( null ) ;
1115 const containerRef = useRef < HTMLDivElement > ( null ) ;
1216 const [ isLoaded , setIsLoaded ] = useState ( false ) ;
@@ -117,7 +121,7 @@ export default function EscherBackground() {
117121
118122 const gl = probeGl ;
119123 const image = new window . Image ( ) ;
120- image . src = "/images/hands2.webp " ;
124+ image . src = "/images/hands2.png " ;
121125
122126 const targetFps = isMobile ? 24 : 60 ;
123127 const fpsInterval = 1000 / targetFps ;
@@ -126,8 +130,16 @@ export default function EscherBackground() {
126130 const scrollSpeed = 0 ;
127131 const MOBILE_IMAGE_ZOOM = 1.4 ; // ← increase to zoom in on the image on mobile (e.g. 1.2 = 20% zoom)
128132 const IMAGE_ROTATION_DEG = - 30.0 ; // ← angle in degrees to rotate the underlying image clockwise
129- const fitContain = isMobile ? 1.0 : 0.0 ;
130- const mobileZoom = isMobile ? MOBILE_IMAGE_ZOOM : 1.0 ;
133+ const WAVE_INTENSITY = 0.3 ; // ← adjust wave strength (e.g. 0.8 is strong, 0.3 is minimalist/subtle)
134+ const HOVER_INTENSITY = 0.75 ; // ← adjust hover max strength
135+ const fitContain = 1.0 ;
136+
137+ // Calculate zoom accounting for padding
138+ const totalPaddingVh = IMAGE_TOP_MARGIN_VH + IMAGE_BOTTOM_MARGIN_VH ;
139+ const availableHeightVh = 100 - totalPaddingVh ;
140+ const paddingZoomFactor = availableHeightVh / 100 ;
141+ const baseZoom = isMobile ? MOBILE_IMAGE_ZOOM : 1.0 ;
142+ const mobileZoom = baseZoom * paddingZoomFactor ;
131143 // Cache DPR once — avoids recomputing on every render frame
132144 const dpr = Math . min ( window . devicePixelRatio || 1 , isMobile ? ( isIPhone ? 2.25 : 1.6 ) : 2.0 ) ;
133145 const floatPrecision = isMobile ? 'mediump' : 'highp' ;
@@ -192,9 +204,10 @@ export default function EscherBackground() {
192204 }
193205 ` }
194206
195- float effectiveRadius = u_baseRadius * (1.0 + shimmer * 0.5 + magEffect * 0.75);
207+ // Max possible radius used for early exit cull padding to save performance
208+ float maxPossibleRadius = u_baseRadius * (1.0 + shimmer * ${ WAVE_INTENSITY . toFixed ( 2 ) } + magEffect * ${ HOVER_INTENSITY . toFixed ( 2 ) } );
196209
197- if (dist > effectiveRadius + 0.5) {
210+ if (dist > maxPossibleRadius + 0.5) {
198211 gl_FragColor = vec4(0.0);
199212 return;
200213 }
@@ -224,7 +237,7 @@ export default function EscherBackground() {
224237 }
225238
226239 float offsetX = (u_resolution.x - drawWidth) * 0.5;
227- float offsetY = (u_resolution.y - drawHeight) * 0.5;
240+ float offsetY = (u_resolution.y - drawHeight) * 0.5 - (u_resolution.y * 0.03); // Move up by 5vh
228241
229242 // Sample UV directly from cellCenter + uvOffset
230243 float u = (cellCenter.x + uvOffset.x - offsetX) / drawWidth;
@@ -241,16 +254,29 @@ export default function EscherBackground() {
241254
242255 float brightness;
243256 if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
244- brightness = 255.0;
257+ // Match the image's background (white) so the pattern flows seamlessly
258+ brightness = 255.0;
245259 } else {
246260 vec4 color = texture2D(u_image, uv);
247261 brightness = dot(color.rgb, vec3(0.333333)) * 255.0;
248262 }
249263
250- float sizeFactor = (255.0 - brightness) / 255.0;
251- float dotSize = sizeFactor * effectiveRadius;
264+ float rawSizeFactor = (255.0 - brightness) / 255.0;
265+
266+ // Base size for the dot (0.15 min keeps background dots alive)
267+ float baseSize = max(0.15, rawSizeFactor) * u_baseRadius;
268+
269+ // Apply hover effect exactly like the original formulation
270+ float hoverBonus = baseSize * (magEffect * ${ HOVER_INTENSITY . toFixed ( 2 ) } );
271+
272+ // Make wave effects heavily independent of the image brightness!
273+ float effectScale = mix(0.65, 1.0, rawSizeFactor);
274+ float waveBonus = u_baseRadius * (shimmer * ${ WAVE_INTENSITY . toFixed ( 2 ) } ) * effectScale;
275+
276+ float dotSize = baseSize + waveBonus + hoverBonus;
252277
253- if (brightness < 240.0 && dotSize > 0.5) {
278+ // Always draw dots, but smaller ones for bright areas
279+ if (dotSize > 0.1) {
254280 float alpha = 1.0 - smoothstep(dotSize - 0.5, dotSize + 0.5, dist);
255281 if (alpha > 0.0) {
256282 gl_FragColor = vec4(0.0, 0.0, 0.0, alpha * 0.85);
0 commit comments