design-systems: add 74 brand DESIGN.md files (VoltAgent/awesome-design-md)
- 74 brands: airbnb, stripe, apple, figma, linear, vercel, etc. - 147 files: DESIGN.md + README.md per brand (~2.1 MB) - Each DESIGN.md contains structured brand analysis (colors, typography, components) - Updated 00-overview.md with new design-systems directory
This commit is contained in:
1 parent
e3738f2b3e
commit
76c4c5b4fe
233 files changed
+54886
-1
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user