@@ -25,20 +25,23 @@ interface ParallaxParticle {
2525 * Deterministic math prevents random values from causing SSR/CSR mismatches. */
2626function buildParticles ( ) : ParallaxParticle [ ] {
2727 const colors = [ '#10b981' , '#8b5cf6' , '#06b6d4' , '#3b82f6' , '#f59e0b' ] ;
28- return Array . from ( { length : PARALLAX_PARTICLE_COUNT } , ( _ , i ) : ParallaxParticle => ( {
29- id : i ,
30- // Spread particles across the container using prime-number strides
31- x : ( i * 17 + 11 ) % 100 ,
32- y : ( i * 23 + 7 ) % 100 ,
33- size : 4 + ( i % 5 ) * 2 , // range: 4–12 px
34- // Keep opacity low so particles never obscure the badge
35- opacity : 0.05 + ( i % 4 ) * 0.025 , // range: 0.05–0.125
36- // Vary depth so each "layer" of particles shifts by a different amount,
37- // creating the illusion of 3-D depth. depth 0.1 = farthest; 0.7 = nearest.
38- depth : 0.1 + ( i % 6 ) * 0.1 , // range: 0.1–0.6
39- color : colors [ i % colors . length ] ,
40- isCircle : i % 4 === 0 ,
41- } ) ) ;
28+ return Array . from (
29+ { length : PARALLAX_PARTICLE_COUNT } ,
30+ ( _ , i ) : ParallaxParticle => ( {
31+ id : i ,
32+ // Spread particles across the container using prime-number strides
33+ x : ( i * 17 + 11 ) % 100 ,
34+ y : ( i * 23 + 7 ) % 100 ,
35+ size : 4 + ( i % 5 ) * 2 , // range: 4–12 px
36+ // Keep opacity low so particles never obscure the badge
37+ opacity : 0.05 + ( i % 4 ) * 0.025 , // range: 0.05–0.125
38+ // Vary depth so each "layer" of particles shifts by a different amount,
39+ // creating the illusion of 3-D depth. depth 0.1 = farthest; 0.7 = nearest.
40+ depth : 0.1 + ( i % 6 ) * 0.1 , // range: 0.1–0.6
41+ color : colors [ i % colors . length ] ,
42+ isCircle : i % 4 === 0 ,
43+ } )
44+ ) ;
4245}
4346
4447// How many pixels a depth-1.0 particle shifts when the cursor is at the
@@ -399,29 +402,31 @@ export default function InteractiveViewer({
399402 Each particle shifts by (parallaxX * depth, parallaxY * depth) px relative
400403 to its base position, so "closer" particles (higher depth) shift more —
401404 creating the impression of a multi-layered isometric space. */ }
402- { particles . map ( ( particle ) : ReactElement => (
403- < div
404- key = { particle . id }
405- style = { {
406- position : 'absolute' ,
407- left : `${ particle . x } %` ,
408- top : `${ particle . y } %` ,
409- width : particle . size ,
410- height : particle . size ,
411- backgroundColor : particle . color ,
412- borderRadius : particle . isCircle ? '50%' : '2px' ,
413- boxShadow : `0 0 ${ particle . size * 2 } px ${ particle . color } 55` ,
414- opacity : isHovering ? particle . opacity * 1.8 : particle . opacity ,
415- // Particles shift in the SAME direction as the cursor offset to create
416- // a realistic parallax: near objects (depth ~0.6) move more than far ones.
417- transform : `translate(${ parallaxX * particle . depth } px, ${ parallaxY * particle . depth } px)` ,
418- // Smooth lerp toward the new position; opacity fades independently
419- transition : `transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.5s ease` ,
420- pointerEvents : 'none' ,
421- willChange : 'transform' ,
422- } }
423- />
424- ) ) }
405+ { particles . map (
406+ ( particle ) : ReactElement => (
407+ < div
408+ key = { particle . id }
409+ style = { {
410+ position : 'absolute' ,
411+ left : `${ particle . x } %` ,
412+ top : `${ particle . y } %` ,
413+ width : particle . size ,
414+ height : particle . size ,
415+ backgroundColor : particle . color ,
416+ borderRadius : particle . isCircle ? '50%' : '2px' ,
417+ boxShadow : `0 0 ${ particle . size * 2 } px ${ particle . color } 55` ,
418+ opacity : isHovering ? particle . opacity * 1.8 : particle . opacity ,
419+ // Particles shift in the SAME direction as the cursor offset to create
420+ // a realistic parallax: near objects (depth ~0.6) move more than far ones.
421+ transform : `translate(${ parallaxX * particle . depth } px, ${ parallaxY * particle . depth } px)` ,
422+ // Smooth lerp toward the new position; opacity fades independently
423+ transition : `transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.5s ease` ,
424+ pointerEvents : 'none' ,
425+ willChange : 'transform' ,
426+ } }
427+ />
428+ )
429+ ) }
425430 </ div >
426431
427432 { /* ── Card content ──────────────────────────────────────────────────────
0 commit comments