From c7f0be809b468029a892644612cdf1437e102c9a Mon Sep 17 00:00:00 2001 From: Neo Date: Sat, 20 Jun 2026 17:30:26 +0500 Subject: [PATCH] Add patterngen-oss: pattern animations, blender pipeline, deterministic generation --- 00-overview.md | 11 +- media/blender-pipeline.md | 222 ++++++++++++++++++++++ motion/pattern-animations.md | 213 ++++++++++++++++++++++ system/deterministic-generation.md | 283 +++++++++++++++++++++++++++++ 4 files changed, 726 insertions(+), 3 deletions(-) create mode 100644 media/blender-pipeline.md create mode 100644 motion/pattern-animations.md create mode 100644 system/deterministic-generation.md diff --git a/00-overview.md b/00-overview.md index e6187fc..19c273e 100644 --- a/00-overview.md +++ b/00-overview.md @@ -1,7 +1,7 @@ --- title: Premium Design Wiki — Overview -description: Central index for all 79 design patterns, LLM prompts, and assets. -version: 2.1.0 +description: Central index for all 82 design patterns, LLM prompts, and assets. +version: 2.2.0 date: 2026-06-20 --- @@ -22,7 +22,9 @@ Encode premium web design taste into reusable patterns so LLMs can generate prof | 🎨 Systems | 6 patterns | ✅ Complete | | 🌐 Mobile | 21 token systems | ✅ Complete | | 🎯 Landing | 25 patterns | ✅ Complete | -| **Total** | **79 patterns** | **✅ Complete** | +| 🎬 Blender Pipeline | 1 pipeline spec | ✅ Complete | +| ⚙️ Deterministic Gen | 1 methodology | ✅ Complete | +| **Total** | **82 patterns + assets** | **✅ Complete** | ## 📁 Structure @@ -48,6 +50,7 @@ wow-design-wiki/ │ ├── magnetic-button.md │ ├── page-transitions.md │ ├── parallax-scroll.md +│ ├── pattern-animations.md │ ├── procedural-patterns.md │ └── staggered-reveal.md ├── typography/ @@ -56,6 +59,7 @@ wow-design-wiki/ │ └── kinetic-text.md ├── media/ │ ├── animated-illustration.md +│ ├── blender-pipeline.md │ ├── image-parallax.md │ ├── svg-animation.md │ └── video-mask.md @@ -68,6 +72,7 @@ wow-design-wiki/ │ ├── component-patterns.md │ ├── css-architecture.md │ ├── design-tokens.md +│ ├── deterministic-generation.md │ ├── glassmorphism.md │ ├── noise-texture.md │ └── responsive-patterns.md diff --git a/media/blender-pipeline.md b/media/blender-pipeline.md new file mode 100644 index 0000000..fecb38e --- /dev/null +++ b/media/blender-pipeline.md @@ -0,0 +1,222 @@ +# Blender Pipeline — Figma → PatternGen → 3D Compositing + +> Полный конвейер от Figma-дизайна до 3D-compositing в Blender. +> Основано на [patterngen-oss](https://github.com/halfof8/patterngen-oss) workflow. + +## Обзор + +``` +Figma (artboard 1920×1080) + ↓ Plugin "PatternGen Scene Export" +Scene JSON (titles as 2× PNG data URLs + colors + seed) + ↓ Load в PatternGen web app +Procedural pattern generation (Canvas 2D) + ↓ EXPORT (JSZip + FileSaver) +ZIP: scene_titles/*.png, scene_patterns/*.png, scene_dots/*.png + ↓ Blender addon "PatternGen Importer" +3 emissive planes с alpha-blending → Cycles/Eevee render +``` + +--- + +## Этап 1: Figma → Scene JSON + +### Подготовка артборда + +- Frame размер: **1920×1080 px** (Full HD) +- Grid: **20 px** (Layout Grid → Grid → 20 px) +- Каждый title — top-level child frame, размеры кратны 20 +- Название фрейма = `sceneName` (префикс для экспорта) +- Цвета: любые (плагин сканирует fills/strokes) + +### Экспорт + +1. Выбрать один или несколько фреймов 1920×1080 +2. **Plugins → Development → PatternGen Scene Export** +3. **Export Selected Frames** +4. Результат: `_patterngen.json` + +### Структура JSON + +```json +{ + "sceneName": "My Title", + "seed": 123456789, // 31-bit integer, determinism + "colors": ["#FF0000", "#00FF00", "#0000FF"], // detected colors + "titles": [ + { + "id": "title_1", + "x": 100, // snapped to 20px grid + "y": 200, + "w": 400, + "h": 100, + "img": "data:image/png;base64,..." // 2× retina PNG + } + ], + "defaults": { + "durationMs": 6000, + "density": 10, + "proximity": 2, + "stagger": 3, + "theme": "dark" + } +} +``` + +### Что экспортируется + +- **Titles**: 2× PNG (retina), data URL, позиции snapped к сетке +- **Color set**: уникальные цвета fills/strokes (кроме #000 и #FFF) +- **Seed**: 31-bit integer — детерминированная генерация паттернов +- **Scene defaults**: продолжительность, плотность, proximity, stagger, тема + +--- + +## Этап 2: PatternGen Web App + +### Загрузка + +1. Открыть PatternGen (localhost:5173) +2. Кнопка **LOAD** → выбрать `*_patterngen.json` +3. Паттерны генерируются **детерминированно по seed** +4. Сцена сразу готова к **PLAY** + +### Ручное редактирование + +- **Drag & Drop** PNG/JPG изображений на canvas (snap to 20 px grid) +- **Drag** для перемещения, drag off canvas для удаления +- **+ ADD COLOR** — до 3 кастомных цветов (color picker) +- Клик по swatch — toggle on/off + +### Параметры + +| Параметр | Диапазон | Описание | +|-------------|---------|----------| +| **Density** | 1–20 | Количество паттерн-элементов | +| **Proximity** | 1–20 | Минимальное расстояние от titles | +| **Stagger** | 0–5 | Разброс animation delay | +| **Grid** | toggle | 20 px reference grid | +| **Theme** | dark/light | UI theme | + +--- + +## Этап 3: Экспорт PNG-секвенций + +### Формат ZIP + +``` +scene_pattern_gen.zip +├── titles/ +│ scene_titles_00000.png +│ scene_titles_000001.png +│ ... +├── patterns/ +│ scene_patterns_00000.png +│ ... +└── dots/ + scene_dots_00000.png + ... +``` + +### Параметры экспорта + +- **Scale**: 4× (EXPORT_SCALE = 4 → 7680×4320px) +- **FPS**: 24 +- **Фон**: прозрачный (RGBA) +- **Слои**: 3 отдельных (titles, patterns, dots) + +### Фазы рендера + +``` +titles: durationMs (1×) — plays once +patterns: durationMs (1×) — plays once +dots: 4000ms loop — infinite loop +``` + +### Easing при экспорте + +Выбирается один из 7 типов: +`linear`, `easeIn`, `easeOut`, `easeInOut`, `easeInCubic`, `easeOutCubic`, `easeInOutCubic` + +--- + +## Этап 4: Blender Import + +### Установка + +1. Blender → **Edit → Preferences → Add-ons → Install…** +2. Выбрать `patterngen_importer.py` +3. Поставить галочку для активации +4. Открыть N-panel → вкладка **PatternGen** + +### Импорт сцены + +1. Установить **Scene Folder** на распакованную папку +2. Кнопка **Import Scene Folders** +3. Три planes создаются в origin + +### Конфигурация слоёв + +| Layer | Cyclic | Location (m) | Rotation | Scale | +|-------|--------|-------------|----------|-------| +| titles | off | (0, 0, 0) | 90° на X | 6×6×6 | +| patterns | off | (0, 0.1, 0) | 90° на X | 6×6×6 | +| dots | **on** | (0, 0.2, 0) | 90° на X | 6×6×6 | + +### Node Tree материалов + +``` +Image Texture (SEQUENCE, auto-refresh ON) + Color ─┬─► Principled BSDF › Base Color + └─► Principled BSDF › Emission Color (strength = 1) + Alpha ───► Principled BSDF › Alpha +``` + +### Image Sequence настройки + +- **Start Frame**: 0 +- **Frames**: количество PNG в папке +- **Offset**: 0 +- **Auto Refresh**: ON +- **Cyclic**: ON для `dots`, OFF для `titles`/`patterns` + +### Sync Start Frame + +1. Выбрать plane(s) (Shift+click или A для всех) +2. В секции **Sync Start Frame** ввести новое значение +3. **Apply to Selected** — все image-sequence текстуры обновлены + +### Замечания + +- **Blend Method**: `BLEND` (alpha renders clean в Eevee/Cycles) +- При артефактах сортировки переключить на `HASHED` +- Повторный импорт создаёт дубликаты (`.001`, `.002`) — удалить вручную +- Отступ 0.1m между слоями — только для предотвращения z-fighting +- Plane scale настроен по aspect ratio изображения (16:9) + +--- + +## Полный конвейер в цифрах + +| Параметр | Значение | +|----------|---------| +| Canvas | 1920×1080 | +| Export Scale | 4× (7680×4320) | +| FPS | 24 | +| Grid | 20 px | +| Duration | 6000ms (default) | +| Dots Loop | 4000ms | +| Cycle | 4× duration = 24s | +| Patterns | 7 animation types | +| Colors | 2 fixed + 3 custom max | +| Export Layers | 3 (titles, patterns, dots) | + +--- + +## Референсы кода + +- `figma-plugin/README.md` — Figma plugin setup, export format +- `blender-addon/README.md` — Blender addon installation, node tree +- `src/export/exporter.ts` — PNG sequence export, JSZip, FileSaver +- `src/engine/timeline.ts` — Phase 1/2/3 timing, dots loop +- `src/types.ts` — CANVAS_W/H, EXPORT_SCALE, FPS, GRID_SIZE diff --git a/motion/pattern-animations.md b/motion/pattern-animations.md new file mode 100644 index 0000000..ee02943 --- /dev/null +++ b/motion/pattern-animations.md @@ -0,0 +1,213 @@ +# 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 + + + + + + +``` + +**Правила:** +1. Размер: 40×40 px (viewBox 0 0 40 40) +2. Фон: `` (переокрашивается в runtime) +3.Foreground: `fill="black"` и/или `stroke="black"` (переокрашивается) +4. Тег `` игнорируется при парсинге +5. Вложенные `` обрабатываются рекурсивно +6. Анимация определяется типом анимации, не структурой SVG + +**Поддерживаемые теги:** ``, ``, `` + +**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 diff --git a/system/deterministic-generation.md b/system/deterministic-generation.md new file mode 100644 index 0000000..99dfb1e --- /dev/null +++ b/system/deterministic-generation.md @@ -0,0 +1,283 @@ +# Deterministic Generation — Seed-Based Layout Methodology + +> Детерминированная генерация паттернов с использованием seeded PRNG. +> Основано на [patterngen-oss](https://github.com/halfof8/patterngen-oss). + +## Обзор + +Каждая генерация паттернов **детерминирована** — одинаковый seed всегда даёт +идентичный layout. Это позволяет: +- Повторно воспроизводить удачные комбинации +- Синхронизировать дизайн между Figma и PatternGen +- Кэшировать результаты генерации +- Делиться сценами через JSON с seed + +--- + +## Seeded PRNG + +### Алгоритм + +```typescript +class SeededRNG { + private seed: number; + + constructor(seed: number) { + this.seed = seed & 0x7FFFFFFF; // 31-bit positive + } + + next(): number { + // LCG: Linear Congruential Generator + this.seed = (this.seed * 1103515245 + 12345) & 0x7FFFFFFF; + return this.seed / 0x7FFFFFFF; // range [0, 1) + } + + nextInt(min: number, max: number): number { + return Math.floor(this.next() * (max - min + 1)) + min; + } + + pick(array: T[]): T { + return array[this.nextInt(0, array.length - 1)]; + } +} +``` + +### Seed из Figma + +```json +{ + "seed": 123456789 +} +``` + +31-bit integer генерируется плагином Figma. Значение зашито в JSON +и передается в PatternGen. + +--- + +## Placement Engine + +### Input parameters + +| Параметр | Тип | Диапазон | Описание | +|----------|-----|----------|----------| +| `seed` | int | 0–2³¹-1 | Seed для PRNG | +| `density` | int | 1–20 | Количество элементов | +| `proximity` | int | 1–20 | Мин. расстояние до title (20 px grid units) | + +### Placement algorithm + +``` +1. Создать RNG из seed +2. Для каждого элемента: + a. Сгенерировать случайную позицию (x, y) + b. Проверить proximity к существующим элементам и title + c. Если too close → пересадить с тем же RNG state + d. Иначе → записать позицию +3. Для каждого элемента: + a. Выбрать случайный pattern из доступных + b. Выбрать случайную clipSide (top/bottom/left/right) + c. Выбрать случайную анимацию + d. Сгенерировать stagger delay +``` + +### Stagger calculation + +```typescript +const staggerWindow = Math.max(0, Math.min(0.85, (stagger / 5) * 0.8)); +const staggeredStart = element.animDelay * staggerWindow * durationMs; +const elemDur = durationMs * (1 - staggerWindow); +const localMs = cycleMs - staggeredStart; +const p = Math.max(0, Math.min(1, localMs / elemDur)); +``` + +--- + +## Animation Timeline + +### Фаза 1: Title Reveal (0 — durationMs) + +Title проявляется из центра по горизонтали (если wider) или вертикали (if taller). + +```typescript +const titleT = min(1, max(0, elapsedMs / durationMs)); +const titleEased = applyEasing(titleT, easing); + +if (title.w >= title.h) { + // wide title: half-reveal horizontally + halfReveal = (title.w / 2) * titleEased; + revealBox = { + x: cx - halfReveal, + y: title.y, + w: halfReveal * 2, + h: title.h + }; +} else { + // tall title: half-reveal vertically + halfReveal = (title.h / 2) * titleEased; + revealBox = { + x: title.x, + y: cy - halfReveal, + w: title.w, + h: halfReveal * 2 + }; +} +``` + +### Фаза 2: Pattern Reveal (durationMs — 2× durationMs) + +Паттерны проявляются с stagger-задержкой. + +### Фаза 3: Dots Loop (2× durationMs — 4× durationMs) + +Точки пульсируют синусоидой 4000ms цикл. + +```typescript +const fadeIn = min(1, loopMs / 800); +const wave = 0.5 + 0.5 * sin(2 * PI * dot.blinkSpeed * (loopMs / 1000) + dot.blinkPhase * 2 * PI); +const pulse = 0.15 + 0.85 * wave; +opacity = pulse * fadeIn; +``` + +--- + +## Color System + +### Fixed Colors + +```typescript +const FIXED_COLORS = ['#000000', '#FFFFFF']; +``` + +Черный и белый всегда доступны. + +### Custom Colors + +До 3 кастомных цветов добавляются через color picker. +Color pairs для паттернов генерируются алгоритмически: + +```typescript +// Для каждого pair custom_color: +bg = customColor; +fg = generateComplementary(customColor); +``` + +### SVG Colorization + +```typescript +function colorizeSvg(svgText: string, colors: ColorPair): string { + return svgText + .replace(/fill="white"/g, `fill="${colors.bg}"`) + .replace(/fill="black"/g, `fill="${colors.fg}"`) + .replace(/stroke="black"/g, `stroke="${colors.fg}"`); +} +``` + +SVG-паттерны хранят только `white` (фон) и `black` (foreground). +Окрашивание происходит в runtime. + +--- + +## Image Caching + +```typescript +const imageCache = new Map(); + +export function svgToImage(svgText: string): Promise { + if (imageCache.has(svgText)) return Promise.resolve(imageCache.get(svgText)!); + + return new Promise((resolve, reject) => { + const img = new Image(); + const blob = new Blob([svgText], { type: 'image/svg+xml;charset=utf-8' }); + const url = URL.createObjectURL(blob); + img.onload = () => { + URL.revokeObjectURL(url); + imageCache.set(svgText, img); + resolve(img); + }; + img.onerror = () => { + URL.revokeObjectURL(url); + reject(new Error('Failed to load SVG image')); + }; + img.src = url; + }); +} + +export function clearImageCache() { + imageCache.clear(); +} +``` + +--- + +## Export Pipeline + +### Layer structure + +``` +titles: durationMs (1×) — plays once +patterns: durationMs (1×) — plays once +dots: 4000ms loop — infinite loop +``` + +### Export scale + +- Canvas: 1920×1080 +- Export Scale: 4× → 7680×4320 +- FPS: 24 +- Format: PNG (RGBA, transparent background) + +### Frame calculation + +```typescript +const totalFrames = Math.ceil((layerDuration / 1000) * FPS); +const frameRatio = totalFrames > 1 ? frame / (totalFrames - 1) : 1; +``` + +### Naming convention + +``` +__.png + +Пример: +MyTitle_titles_00000.png +MyTitle_titles_00001.png +MyTitle_patterns_00000.png +MyTitle_dots_00000.png +``` + +--- + +## Использование determinism в дизайне + +### Scenario 1: Figma → PatternGen sync + +1. Экспортировать сцену из Figma (содержит seed) +2. Загрузить в PatternGen +3. Паттерны генерируются точно так же каждый раз +4. Можно итерировать параметры и снова генерировать тот же layout + +### Scenario 2: A/B testing + +1. Создать базовую сцену с seed +2. Экспортировать 10 раз с разными параметрами density/stagger +3. Каждый раз layout идентичен, но timing разный +4. Сравнить конверсию/визуальное впечатление + +### Scenario 3: Team collaboration + +1. Дизайнер делится scene JSON +2. Коллега загружает и видит ту же генерацию +3. Может менять цвета, паттерны, параметры +4. Seed остаётся — layout predictable + +--- + +## Референсы кода + +- `src/core/rng.ts` — SeededRNG класс, LCG algorithm +- `src/core/placement.ts` — Placement engine, proximity check +- `src/engine/timeline.ts` — Phase 1/2/3, dots loop +- `src/export/exporter.ts` — PNG export, frame calculation +- `src/export/renderer.ts` — Canvas rendering per frame +- `src/types.ts` — AnimationState, PatternAnimType