214214 .disclaim { margin-top : 34px ; padding : 30px 34px ; color : var (--dim ); font-size : 12.5px ; line-height : 1.9 ; }
215215 .disclaim b { color : var (--muted ); }
216216
217+ /* ===== 沉浸动画 ===== */
218+ # dust { position : fixed; inset : 0 ; width : 100vw ; height : 100vh ; z-index : -1 ; pointer-events : none; }
219+ .cursor-glow { position : fixed; top : 0 ; left : 0 ; width : 520px ; height : 520px ; margin : -260px 0 0 -260px ;
220+ background : radial-gradient (circle, rgba (217 , 174 , 107 , .26 ), rgba (217 , 174 , 107 , 0 ) 66% );
221+ mix-blend-mode : screen; pointer-events : none; z-index : 5 ; opacity : .95 ; }
222+ .bg-wrap .orb , .bg-lines , # dust { will-change : transform; }
223+
224+ /* 首屏入场:模糊聚焦 + 上浮 */
225+ .hero .badge { animation : heroFade .9s ease both; }
226+ .hero .eyebrow { animation : heroFade 1.1s ease .12s both; }
227+ .hero h1 { animation : heroTitle 1.5s ease both; }
228+
229+ /* 玻璃卡高光扫过(液态质感) */
230+ .feat , .person , .tech-item { position : relative; overflow : hidden; }
231+ .feat ::after , .person ::after , .tech-item ::after { content : "" ; position : absolute; top : -12% ; left : -85% ; width : 62% ; height : 124% ;
232+ background : linear-gradient (100deg , transparent, rgba (255 , 240 , 214 , .16 ), transparent);
233+ transform : skewX (-20deg ); transition : transform .9s cubic-bezier (.2 , .6 , .3 , 1 ); pointer-events : none; }
234+ .feat : hover ::after , .person : hover ::after , .tech-item : hover ::after { transform : skewX (-20deg ) translateX (300% ); }
235+
236+ @keyframes heroTitle { from { filter : blur (20px ); opacity : 0 ; transform : translateY (18px ); } to { filter : blur (0 ); opacity : 1 ; transform : none; } }
237+ @keyframes heroFade { from { opacity : 0 ; transform : translateY (12px ); } to { opacity : 1 ; transform : none; } }
238+
239+ @media (prefers-reduced-motion : reduce) {
240+ # dust , .cursor-glow { display : none; }
241+ .hero .badge , .hero .eyebrow , .hero h1 { animation : none; }
242+ .feat ::after , .person ::after , .tech-item ::after { display : none; }
243+ }
244+
217245 /* ===== 渐显 ===== */
218246 [data-reveal ] { opacity : 0 ; transform : translateY (34px ); transition : opacity 1s cubic-bezier (.22 , .68 , .28 , 1 ), transform 1s cubic-bezier (.22 , .68 , .28 , 1 ); }
219247 [data-reveal ].is-visible { opacity : 1 ; transform : translateY (0 ) !important ; }
238266< body >
239267< div class ="bg-wrap "> < div class ="orb a "> </ div > < div class ="orb b "> </ div > < div class ="orb c "> </ div > </ div >
240268< div class ="bg-lines "> </ div >
269+ < canvas id ="dust " aria-hidden ="true "> </ canvas >
270+ < div class ="cursor-glow " aria-hidden ="true "> </ div >
241271
242272<!-- 流体装饰曲线 -->
243273< svg class ="curve " style ="top:8%; left:-4%; width:420px; " viewBox ="0 0 420 220 " fill ="none "> < path d ="M20 200 C 80 60, 180 40, 260 150 S 380 190, 400 40 " stroke ="rgba(217,174,107,.5) " stroke-width ="2 " stroke-dasharray ="2 10 " stroke-linecap ="round "/> </ svg >
@@ -444,6 +474,61 @@ <h4>联系我们</h4>
444474 } ) ;
445475 } , { threshold : 0.12 , rootMargin : "0px 0px -40px 0px" } ) ;
446476 document . querySelectorAll ( "[data-reveal]" ) . forEach ( el => io . observe ( el ) ) ;
477+
478+ /* ---- 沉浸暖光粒子 ---- */
479+ ( ( ) => {
480+ const reduced = matchMedia ( "(prefers-reduced-motion: reduce)" ) . matches ;
481+ const c = document . getElementById ( "dust" ) ;
482+ if ( ! c || reduced ) return ;
483+ const ctx = c . getContext ( "2d" ) ;
484+ let W , H , dots = [ ] , mouse = { x : - 9999 , y : - 9999 } ;
485+ const resize = ( ) => { W = c . width = innerWidth ; H = c . height = innerHeight ; } ;
486+ resize ( ) ;
487+ const N = Math . min ( 70 , Math . floor ( W * H / 26000 ) ) ;
488+ const cols = [ "217,174,107" , "217,174,107" , "201,139,111" , "227,208,170" ] ;
489+ for ( let i = 0 ; i < N ; i ++ ) dots . push ( {
490+ x : Math . random ( ) * W , y : Math . random ( ) * H , r : 1 + Math . random ( ) * 2.2 ,
491+ c : cols [ i % cols . length ] , vx : ( Math . random ( ) - .5 ) * .25 , vy : ( Math . random ( ) - .5 ) * .25 ,
492+ p : Math . random ( ) * Math . PI * 2 , s : .4 + Math . random ( ) * .8 } ) ;
493+ const tick = ( ) => {
494+ ctx . clearRect ( 0 , 0 , W , H ) ;
495+ for ( const d of dots ) {
496+ d . x += d . vx ; d . y += d . vy ;
497+ const dx = d . x - mouse . x , dy = d . y - mouse . y , dd = dx * dx + dy * dy ;
498+ if ( dd < 36000 ) { d . x += dx / 200 ; d . y += dy / 200 ; }
499+ if ( d . x < - 10 ) d . x = W + 10 ; if ( d . x > W + 10 ) d . x = - 10 ;
500+ if ( d . y < - 10 ) d . y = H + 10 ; if ( d . y > H + 10 ) d . y = - 10 ;
501+ d . p += d . s * .012 ;
502+ ctx . beginPath ( ) ; ctx . arc ( d . x , d . y , d . r , 0 , 7 ) ;
503+ ctx . fillStyle = `rgba(${ d . c } ,${ .16 + .3 * ( .5 + Math . sin ( d . p ) * .5 ) } )` ;
504+ ctx . fill ( ) ;
505+ }
506+ requestAnimationFrame ( tick ) ;
507+ } ;
508+ tick ( ) ;
509+ addEventListener ( "resize" , resize ) ;
510+ addEventListener ( "mousemove" , e => { mouse . x = e . clientX ; mouse . y = e . clientY ; } ) ;
511+ } ) ( ) ;
512+
513+ /* ---- 暖光跟随 + 视差光斑 ---- */
514+ ( ( ) => {
515+ const glow = document . querySelector ( ".cursor-glow" ) ;
516+ const orbs = document . querySelectorAll ( ".bg-wrap .orb" ) ;
517+ if ( ! glow && ! orbs . length ) return ;
518+ let gx = innerWidth / 2 , gy = innerHeight / 2 , cx = gx , cy = gy , sy = scrollY ;
519+ addEventListener ( "mousemove" , e => { gx = e . clientX ; gy = e . clientY ; } ) ;
520+ const step = ( ) => {
521+ cx += ( gx - cx ) * .12 ; cy += ( gy - cy ) * .12 ;
522+ if ( glow ) glow . style . transform = `translate(${ cx } px, ${ cy } px)` ;
523+ const sc = scrollY ;
524+ orbs . forEach ( ( o , i ) => {
525+ const sp = .05 + i * .04 ;
526+ o . style . transform = `translate3d(${ ( innerWidth / 2 - gx ) * - sp } px, ${ ( sc - sy ) * - 1.1 * sp } px, 0)` ;
527+ } ) ;
528+ requestAnimationFrame ( step ) ;
529+ } ;
530+ requestAnimationFrame ( step ) ;
531+ } ) ( ) ;
447532</ script >
448533</ body >
449534</ html >
0 commit comments