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,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<T>(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<string, HTMLImageElement>();
|
||||
|
||||
export function svgToImage(svgText: string): Promise<HTMLImageElement> {
|
||||
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
|
||||
|
||||
```
|
||||
<sceneName>_<layer>_<frame>.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
|
||||
Reference in new issue
Block a user