Skip to content

Commit 3cfd233

Browse files
committed
Add immersive animations: particle dust, cursor glow, parallax orbs, hero focus-in, glass sheen
1 parent e80a09e commit 3cfd233

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

index.html

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,34 @@
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; }
@@ -238,6 +266,8 @@
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

Comments
 (0)