Files
wow-design-wiki/motion/pattern-animations.md
T

214 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pattern Animations — 7 типов процедурных анимаций
> Основано на реализациях из [patterngen-oss](https://github.com/halfof8/patterngen-oss).
> 7 анимационных типов для SVG-паттернов, рендерящихся через Canvas 2D с таймлайном.
## Обзор
Каждый паттерн — это SVG-файл 40×40 px, который анимируется одним из 7 типов.
Рендер происходит на Canvas 2D с 4× масштабированием (EXPORT_SCALE = 4).
Базовый кадр 1920×1080, сетка 20 px, FPS = 24.
## Таймлайн
```
Фаза 1 (0 — durationMs): Title reveal (half-reveal с easing)
Фаза 2 (durationMs — 2×): Patterns reveal + squares reveal (staggered)
Фаза 3 (2× — 4× durationMs): Patterns hold + dots pulsation (loop 4s)
Цикл: repeat cycle = 4 × durationMs
```
---
## 1. Dots — fade-in с stagger
Каждый SVG-элемент проявляется индивидуально с рандомной задержкой.
**Механика:**
```
dotP = max(0, min(1, (progress - stagger * 0.6) / 0.4))
globalAlpha = dotP
```
**Использование:**
- Мягкое проявление множества мелких элементов
- Звёздные/точечные паттерны, частицы, текстуры
- Элементы с `stagger` из SVG (случайный при парсинге)
**Параметры:**
- `stagger` определяет задержку: 0 = мгновенно, 5 = максимальный разброс
- Визуально: элементы появляются поочерёдно, создавая «волну»
---
## 2. Capsule — рост из центра по длинной оси
Каждый элемент масштабируется от центра вдоль своей более длинной оси.
**Механика:**
```
elP = max(0, min(1, (progress - stagger * 0.3) / 0.7))
if (w >= h) {
// горизонтальный: ширина растёт, высота стоит
animW = w * elP
animX = cx - animW / 2
} else {
// вертикальный: высота растёт, ширина стоит
animH = h * elP
animY = cy - animH / 2
}
```
**Использование:**
- Анимация линий, полос, разделителей
- Эффект «заполнения» вдоль направления
- Элементы с rotation поддерживаются (через rotate transform)
---
## 3. Circle — pie-fill clockwise reveal
Полное SVG-изображение проявляется секторально, как таймер.
**Механика:**
```
cx = size / 2
cy = size / 2
startAngle = -PI / 2
endAngle = startAngle + PI * 2 * progress
ctx.arc(cx, cy, size, startAngle, endAngle)
ctx.drawImage(img, 0, 0, size, size)
```
**Использование:**
- Круговые паттерны, диаграммы, радары
- Прогресс-индикаторы, loading-анимации
- Полное изображение, не по-элементно
---
## 4. Arrow — slide up снизу
Полное изображение физически сдвигается вверх из-за нижнего края.
**Механика:**
```
offset = size * (1 - progress)
ctx.drawImage(img, 0, offset, size, size)
```
**Использование:**
- Элементы «влетают» снизу
- Эффект подъёма, выдвижения
- Подходит для контрастных паттернов на тёмном фоне
---
## 5. Square — scale down 1.6× → 1×
Изображение масштабируется от 1.6× до 1× (на 60% больше до нормального).
**Механика:**
```
s = 1 + (1 - progress) * 0.6
cx = size / 2
cy = size / 2
ctx.translate(cx, cy)
ctx.scale(s, s)
ctx.translate(-cx, -cy)
ctx.drawImage(img, 0, 0, size, size)
```
**Использование:**
- Резкий акцент, «взрывное» проявление
- Привлечение внимания к паттерну
- Квадратные/крестообразные элементы
---
## 6. Stripes — slide-in слева направо
Каждая полоса (элемент) сдвигается сверху вниз, сортировка по X.
**Механика:**
```
sorted = shapes.sort((a, b) => a.x - b.x)
stripeStart = (i / n) * 0.5
stripeP = max(0, min(1, (progress - stripeStart) / 0.5))
slideOffset = (1 - stripeP) * -size
ctx.translate(0, slideOffset)
```
**Использование:**
- Полосатые паттерны, штрих-код текстуры
- Горизонтальные линии, решётки
- Эффект «сканирования» слева направо
---
## 7. Cross — scale down 1.6× → 1×
Тот же алгоритм, что и `square`, но для крестообразных элементов.
Разница исключительно в семантике и визуальном контексте.
**Механика:**
```
// identical to square
s = 1 + (1 - progress) * 0.6
ctx.scale(s, s)
```
---
## Easing функции
| Название | Формула |
|---------------|---------|
| `linear` | `t` |
| `easeIn` | `t²` |
| `easeOut` | `t(2-t)` |
| `easeInOut` | `2t²` при t<0.5, `-1+(4-2t)t` при t≥0.5 |
| `easeInCubic` | `t³` |
| `easeOutCubic`| `1-(1-t)³` |
| `easeInOutCubic` | `4t³` при t<0.5, `1-(-2t+2)³/2` при t≥0.5 |
---
## SVG Spec
Каждый SVG-паттерн должен соответствовать формату:
```xml
<svg width="40" height="40" viewBox="0 0 40 40" fill="none">
<rect width="40" height="40" fill="white"/>
<!-- foreground shapes -->
<circle cx="20" cy="20" r="14" fill="black"/>
<rect x="10" y="10" width="20" height="20" rx="4" fill="black" stroke="black"/>
</svg>
```
**Правила:**
1. Размер: 40×40 px (viewBox 0 0 40 40)
2. Фон: `<rect width="40" height="40" fill="white"/>` (переокрашивается в runtime)
3.Foreground: `fill="black"` и/или `stroke="black"` (переокрашивается)
4. Тег `<defs>` игнорируется при парсинге
5. Вложенные `<g>` обрабатываются рекурсивно
6. Анимация определяется типом анимации, не структурой SVG
**Поддерживаемые теги:** `<rect>`, `<circle>`, `<path>`
**Transform:** `rotate(angle, ox, oy)` — угол поворота и точка вращения.
---
## Референсы кода
- `src/engine/animations.ts` — 7 switch-касов для каждого animType
- `src/engine/timeline.ts` — фаза titles → patterns → dots (цикл 4× duration)
- `src/engine/easing.ts` — 7 easing функций
- `src/core/patterns.ts` — парсинг SVG, colorizeSvg, svgToImage
- `src/export/exporter.ts` — экспорт PNG-секвенций (titles, patterns, dots)
- `src/types.ts` — PatternAnimType, SvgShapeInfo, PatternDef