Initial commit: 79+ design patterns, LLM prompts, and assets

This commit is contained in:
Neo committed 2026-06-20 17:06:07 +05:00
commit 2b42a76d6d
112 files changed
+13652

No files matched your search

+229
View File
@@ -0,0 +1,229 @@
---
name: motion/procedural-patterns
title: Procedural Pattern Generator
description: Canvas-based procedural generation of animated patterns around title elements. Uses occupancy grid, BFS proximity map, and seeded RNG for deterministic layout.
tags: [motion, procedural, pattern, canvas, generation, animation, title-card]
source: github.com/halfof8/patterngen-oss
---
# Procedural Pattern Generator
## Что это
Инструментарий для автоматического создания анимированных заставок с процедурно размещёнными паттернами вокруг заголовков. Состоит из трёх компонентов:
1. **Web App** (React + Canvas 2D) — основной генератор
2. **Figma Plugin** — импорт дизайна из Figma
3. **Blender Add-on** — импорт PNG-последовательностей как emissive planes
Пайплайн: Figma → Web App (генерация) → PNG-последовательности → Blender (композиция).
## Алгоритм размещения
### 1. Occupancy Grid
Сетка 20px на 1920×1080 (96×54 ячеек). Title-элементы занимают ячейки, помечая их как занятые.
```typescript
class GridOccupancy {
private cells: boolean[][]; // GRID_ROWS × GRID_COLS
markRect(x, y, w, h) { /* occupy cells */ }
isBlockFree(col, row, spanCols, spanRows) { /* collision check */ }
findFreeBlocks(spanCols, spanRows, align) { /* find valid positions */ }
}
```
### 2. BFS Proximity Map
BFS от всех title-элементов к каждой ячейке сетки. Определяет «зону влияния» — где паттерны могут появляться относительно заголовка.
```typescript
function buildProximityMap(titles): number[][] {
const dist: number[][] = fill(Infinity);
// BFS from all title edges
while (queue.length > 0) {
const [cx, cy] = queue.shift();
for (const [dx, dy] of neighbors) {
const nd = dist[cy+dy][cx+dx];
if (nd > dist[cy][cx] + 1) {
dist[cy+dy][cx+dx] = dist[cy][cx] + 1;
queue.push([cx+dx, cy+dy]);
}
}
}
}
```
### 3. Seeded Placement
Deterministic RNG (mulberry32). Same seed = identical layout.
```typescript
function mulberry32(seed) {
let state = seed >>> 0;
return () => {
state = (state + 0x6D2B79F5) >>> 0;
let t = state;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
```
## 7 типов анимации паттернов
| Тип | Эффект | CSS/Canvas |
|-----|--------|------------|
| `dots` | Поэлементный fade-in со stagger | `globalAlpha` per shape |
| `capsule` | Рост от центра по длинной оси | Clip rect grow |
| `circle` | Pie-fill по часовой | Arc + clip |
| `arrow` | Slide up снизу | `translateY` offset |
| `square` | Scale 1.6× → 1× | `scale()` transform |
| `stripes` | Полосы slide-in staggered | Y-offset per stripe |
| `cross` | Scale 1.6× → 1× | `scale()` transform |
## Timeline: 3 фазы
```
0──────────→ durationMs ──────────→ 2×durationMs ──────────→ 4×durationMs (loop)
│ ФАЗА 1 │ ФАЗА 2 │ ФАЗА 3 │
│ Title reveal │ Pattern reveal │ Dots pulse │
│ half-reveal из центра │ clip-side reveal │ sin wave │
```
```typescript
// Фазовая логика timeline
function evaluate(elapsedMs, durationMs, titles, patterns, dots, easing) {
// Phase 1: Title reveal (0→1×)
const titleT = Math.min(1, elapsedMs / durationMs);
const titleEased = applyEasing(titleT, easing); // half-reveal
// Phase 2: Pattern reveal (1×→2×)
const cycleMs = afterTitle % (4 * durationMs);
// Phase 3: Dots pulse (2×→4×)
const holdMs = cycleMs - durationMs;
const pulse = 0.15 + 0.85 * (0.5 + 0.5 * Math.sin(2π * speed * t + phase));
}
```
## Color System
```typescript
function getPairsForColor(primary: string): ColorPair[] {
const lum = luminance(r, g, b);
const dark = mixRGB(primary, #000000, 0.45);
const light = mixRGB(primary, #FFFFFF, 0.35);
if (lum > 0.5) {
return [
{ bg: primary, fg: '#000000' },
{ bg: dark, fg: primary },
{ bg: primary, fg: dark },
];
}
// inverted for dark colors
}
```
Конвенция SVG-паттернов (40×40): `fill="white"` = фон (перекрашивается runtime), `fill="black"` / `stroke="black"` = foreground.
## Figma Plugin
Экспортирует фреймы 1920×1080 в JSON. Каждый слой экспортируется как 2× PNG, цвета автодетектятся.
```javascript
// code.js — экспорт слоя
bytes = await child.exportAsync({
format: 'PNG',
constraint: { type: 'SCALE', value: 2 },
});
// Автодетект цветов
collectUsedColors(node, usedColors); // BFS по иерархии
```
## Blender Add-on
Импорт ZIP с 3 PNG-последовательностями (titles, patterns, dots) как emissive planes:
```python
# Создаёт plane с aspect-ratio из разрешения PNG
plane.scale = (6.0, 6.0, 6.0)
plane.rotation_euler = (90°, 0, 0)
# Emissive shader node graph
tex.image.source = 'SEQUENCE'
tex.image_user.use_cyclic = cyclic # dots = True
nt.links.new(tex.outputs['Color'], bsdf.inputs['Emission'])
nt.links.new(tex.outputs['Alpha'], bsdf.inputs['Alpha'])
```
## Ключевые параметры
| Параметр | Диапазон | Описание |
|----------|----------|----------|
| density | 1–20 | Количество паттернов (формула: `3 + 40 × (d/10)²`) |
| proximity | 1–20 | Зона влияния от title (maxRadius = `2 + proximity × 2.5`) |
| stagger | 0–5 | Stagger window: `(stagger/5) × 0.8` |
| durationMs | 100–20000 | Длительность фазы |
| EXPORT_SCALE | 4 | Рендер в 4× разрешении |
| FPS | 24 | Частота кадров |
## Anti-patterns
| ❌ Плохо | ✅ Хорошо |
|----------|-----------|
| Паттерны накладываются на title | BFS proximity map ограничивает placement |
| Без collision detection | Occupancy grid предотвращает наложения |
| Рандомная расстановка | Seeded RNG — детерминизм для итераций |
| Паттерны без анимации | 7 типов анимации с clip-side |
| Фиксированные цвета | Алгоритмическая генерация color pairs |
| Рендер без bg/fg разделения | white→bg, black→fg runtime colorize |
| 1 кадр = 1 экспорт | Layer export: titles/patterns/dots separately |
## Где используется
- **patterngen-oss** (github.com/halfof8/patterngen-oss) — open-source референс
- Title cards в motion design
- Анимированные фоны лендингов
- Procedural patterns для социальных сетей
- Генерация фоновых текстур для 3D-композиций в Blender
## CV Service Validation
Процедурные паттерны рендерятся на Canvas 2D — это клиентская генерация, не серверная. Для валидации дизайна страницы с pattern-генератором:
```bash
curl -X POST http://localhost:8001/design/full-analysis \
-H "Content-Type: application/json" \
-d '{"html": "<HTML>", "full_analysis": true}'
```
**Особенности:** Canvas-элементы не оцениваются по semantic HTML — паттерны — это визуальный слой. Оценивается обёртка (header, sidebar, controls).
## Технические детали
```
Структура проекта:
├── src/store.ts # Zustand store — 373 строки, вся бизнес-логика
├── src/core/
│ ├── patterns.ts # Load SVG, colorize (white→bg, black→fg)
│ ├── colors.ts # getPairsForColor, luminance-based
│ ├── grid.ts # GridOccupancy + snapToGrid(20px)
│ ├── placement.ts # generatePlacement — BFS + occupancy
│ └── rng.ts # mulberry32 seeded RNG
├── src/engine/
│ ├── animations.ts # 7 анимаций (drawAnimatedPattern)
│ ├── easing.ts # 7 easing функций
│ └── timeline.ts # evaluate() — фазовая логика
├── src/export/
│ ├── renderer.ts # renderFrame() — canvas layer compositing
│ └── exporter.ts # exportAll() → ZIP with 3 layers × 24fps
├── figma-plugin/
│ ├── code.js # Figma sandbox export
│ └── ui.html # Plugin UI
└── blender-addon/
└── patterngen_importer.py # Blender 3.4+ operator
```
**Зависимости:** React 18, Zustand 5, JSZip, FileSaver, Vite