feat(home): Hero 动态粒子层(入场浮现后静止)

新增 hero-particle-field 组件作为 Hero L3 层:品牌红点缀、Canvas + rAF
仅在 ~600ms 入场窗运行后冻结为静态帧,遵守「无持续循环动画」动效铁律;
prefers-reduced-motion 退化为一次性静态帧。固定种子 PRNG 保证视觉快照可复现。
同步更新 home-content-v15 接入与单测、home 视觉基线。

Co-Authored-By: 阿睿 <workbuddy@tencent.com>
This commit is contained in:
2026-09-01 07:57:12 +08:00
co-authored by 阿睿
parent ac21936785
commit 549c151c6a
13 changed files with 203 additions and 0 deletions
@@ -98,6 +98,16 @@ describe('HomeContentV15 - 浅色 Hero(暗黑模式 token 友好)', () => {
expect(hero.querySelector('img')).toBeNull();
});
it('mounts the brand-red dynamic particle layer (entrance-only, no continuous loop)', () => {
render(<HomeContentV15 />);
const hero = screen.getByTestId('hero-section');
const particles = screen.getByTestId('hero-particle-field');
expect(particles.tagName).toBe('CANVAS');
expect(particles).toHaveAttribute('aria-hidden', 'true');
expect(hero.contains(particles)).toBe(true);
});
it('keeps a single primary CTA and demotes the secondary action to a text link', () => {
render(<HomeContentV15 />);
+4
View File
@@ -6,6 +6,7 @@ import { ScrollReveal, StaggerReveal } from '@/components/ui/scroll-reveal';
import { Badge } from '@/components/ui/badge';
import { StaticLink } from '@/components/ui/static-link';
import { HeroProductVisual } from '@/components/sections/hero-product-visual';
import { HeroParticleField } from '@/components/sections/hero-particle-field';
import { ArrowRight, Lightbulb, Database, Layers, Code, Puzzle, Server, Quote, Calendar } from 'lucide-react';
import { cn } from '@/lib/utils';
import { EASE_OUT } from '@/components/ui/page-decoration';
@@ -177,6 +178,9 @@ function HeroSection({ heroData }: {
{!reduceMotion && (
<div ref={spotRef} className="absolute inset-0 pointer-events-none hero-dot-spot opacity-60" aria-hidden="true" />
)}
{/* L3 动态粒子(品牌红点缀):入场浮现后静止,rAF 仅跑 ~600ms,无持续循环;
reduced-motion 下退化为一次性静态帧 */}
<HeroParticleField />
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10 w-full py-16 sm:py-20 md:py-24 lg:py-24">
<div className="grid items-center gap-16 lg:grid-cols-[1.05fr_0.95fr]">