# 动效说明（专业版）

> 大白话版见 [动效说明-大白话.md](./动效说明-大白话.md)

复刻 tasteskill.dev Hero 卡片轨迹：单一标量进度驱动参数化路径采样；指针事件是进度的调制输入，而非自由平面位移。

实现：`src/react/CardOrbit.tsx` · `src/core/path.ts` · `src/core/createOrbit.ts`

---

## 管道总览

```mermaid
flowchart LR
  A["自动播放 rAF"] --> P["progress ∈ [0,1)"]
  B["指针拖动"] --> P
  P --> C["每张卡 phase"]
  C --> D["分段路径 x,y"]
  D --> E["depth 包络"]
  E --> F["CSS transform"]
```

| 概念 | 定义 |
|------|------|
| 核心模型 | 单一标量 `progress` 驱动路径采样；拖拽为进度的二次输入 |
| 位置约束 | 恒为 `f(path(phase(progress)))`，无独立 `(dx, dy)` 位移积分 |
| 与动画库关系 | 本 Hero 不依赖 Motion/GSAP 的 drag 路径约束 |

---

## 1. 进度时钟

```mermaid
sequenceDiagram
  participant rAF as requestAnimationFrame
  participant Drag as Pointer
  participant P as progress
  rAF->>P: 未拖动时 += 45e-6 × dt
  Drag->>P: 拖动时 += 8e-4 × (dy + 0.25×dx)
  Note over P: 拖动期间暂停自动推进
```

空闲时以固定角速度积分全局进度；交互时切换为指针位移映射的进度增量，并暂停自动积分。

- 自动：`progress = (progress + 45e-6 · Δt) mod 1`
- 拖动：`Δ = Δy + 0.25·Δx`，`progress += 8e-4 · Δ`
- `setPointerCapture` 保证指针离开元素边界后仍可持续采样

---

## 2. 相位错开

```mermaid
flowchart TB
  subgraph loop["单位环 progress"]
    direction LR
    C0["卡0"] --- C1["卡1"] --- C2["卡2"] --- C3["卡3"] --- C4["卡4"] --- C5["卡5"] --- C6["卡6"]
  end
```

七张卡在单位环上均匀相位偏移：

```ts
phase = (i / 7 + progress) % 1
```

可见性由窗口函数门控：`phase ∈ (0, 0.72)`。窗口内归一化为路径参数：

```ts
local = phase / 0.72   // ∈ [0, 1]
```

---

## 3. 分段路径

路径弧长权重：上升 `280` · 四分之一圆弧 `(π/2)·90` · 退出 `240`。

**坐标投影演示（动画）：** [轨道演示.html](./轨道演示.html) — 以舞台中心为原点，绘制 `x%`/`y%` 平面轨迹与 `local` 示踪点。

```mermaid
flowchart LR
  R["① 上升直线<br/>x=-10, y 上爬"] --> A["② 四分之一圆<br/>x,y = cos/sin"]
  A --> X["③ 横向退出<br/>y=70, x 右移"]
```

```text
  上升 (x≈-10)          圆弧 (cos/sin)           退出 (y≈70)
        │                      ╭──╮                   ──→
        │                   ╭──╯  │
        ▼                   │     │
        ●───────────────────●─────●───────────────────●
```

| 段 | 参数化 |
|----|--------|
| 上升 | 固定 `x=-10` 的线性插值，权重 `280` |
| 圆弧 | 极角 180°→270° 的四分之一圆：`x = 80 + 90·cos(θ)`，`y = -20 - 90·sin(θ)` |
| 退出 | 固定 `y=70` 的线性水平位移，权重 `240` |

设 `F = 280 / pathLen`，`G = (280 + arc) / pathLen`，则 `local < F` / `< G` / 其余分别落入三段。

---

## 4. 景深与投影

```mermaid
flowchart TB
  L["local"] --> S["sin 包络 → depth"]
  S --> T["translate3d Z / scale / opacity / z-index"]
  S --> R["rotateX / rotateY"]
  ST["perspective: 3400px<br/>+ preserve-3d 倾斜"] --> T
```

沿路径参数施加正弦包络得到标量 `depth`，再线性映射到透视 Z、缩放、透明度与堆叠序。舞台外层 `perspective: 3400px`，内层 `preserve-3d` 施加固定视点倾斜（约 `rotateX(3deg) rotateY(-4deg)`）。

```ts
translate3d(
  calc(-50% + ${x}%),
  calc(-50% + ${y}%),
  ${-1000 + 1280 * depth}px
)
rotateX(${4 - 2 * depth}deg)
rotateY(${-3 + 6 * local}deg)
scale(${0.44 + 0.74 * depth})
```

---

## 边界说明

| 非目标 | 实际做法 |
|--------|----------|
| Motion/GSAP `drag` + 路径约束 | 手写 rAF + 分段函数 |
| 每卡独立物理拖拽 | 共享 `progress`；位置为路径求值 |

**一句话：** 参数化路径上的进度驱动动画；指针事件是进度的调制输入。
