# Banque de visuels — Notice Particules

Auto-générée à partir de CKLive via `chrome-devtools` MCP.
Tous les visuels viennent de l'UI réelle (rendu natif LiteGraph), pas de mock-up.

**Intégration dans la doc :** ✅ tous les visuels sont déjà branchés dans `../particles.html` : 46 PNG (44 nodes + showcase Force Attractor + showcase Spawn Continuous + chain complete) **+ 9 vidéos WebM** (8 recettes + hero atmosphère, autoplay/loop).

Scripts Python (idempotents, relançables) :
- `inject_screenshots.py` — branche les PNG dans les node-cards et recettes
- `inject_videos.py` — remplace les chain images des recettes par des `<video>` autoplay
- `encode_webm.py` — décode les frames JSON capturées vers WebM (VP9, qualité 32)

## `nodes/` — 44 portraits de nodes (scale 1:1, fond `--ck-canvas-2`)

Format : PNG, ~460px de large, hauteur variable selon le node, fond `#0d1117`.

### Spawn (3)
- `spawn_continuous.png` — émetteur constant
- `spawn_external.png` — entrée de particules externes
- `spawn_from_particle.png` — sub-emitter on_death / on_collision

### Init (3)
- `init_position.png` — 9 patterns géométriques + from_image
- `init_velocity.png` — cone / outward / inward / random
- `init_appearance.png` — color/opacity/size/lifetime + jitters

### Forces (7)
- `force_gravity.png` · `force_wind.png` · `force_drag.png`
- `force_attractor.png` · `force_turbulence.png` · `force_curl_noise.png`
- `force_field_image.png`

### Behaviors (5)
- `behavior_collide.png` · `behavior_flock.png` · `behavior_target.png`
- `behavior_seek_image.png` · `behavior_path_follow.png`

### Modify (11)
- `modify_over_life.png` · `modify_position.png` · `modify_rotation.png` · `modify_scale.png`
- `modify_color_by_index.png` · `modify_color_from_image.png`
- `modify_rotation_by_index.png` · `modify_rotation_over_life.png`
- `modify_velocity_ramp.png` · `modify_from_density.png` · `modify_reduce_smooth.png`

### Patterns (4)
- `pattern_linear.png` · `pattern_radial.png` · `pattern_grid.png` · `pattern_honeycomb.png`

### Clone (1)
- `clone.png`

### Render (7)
- `render_points.png` · `render_sprite.png` · `render_metaball.png`
- `render_connect.png` · `render_trail.png` · `render_ribbon.png` · `render_jfa_field.png`

### Bridges (2)
- `particle_to_shapes.png` · `particle_to_trails.png`

### System (1)
- `system.png` — wrapper Particle System (avec preview Output)

## `chains/` — 9 compositions de chaînes

Format : PNG ~1800px de large, auto-scaled pour faire tenir toute la chaîne, câbles colorés par phase, ports diamond visibles.

- `pipeline_overview.png` — spawn → init → force → modify → render (les 5 actes)
- `snowstorm.png` — Tempête de neige (6 nodes)
- `nebula.png` — Nébuleuse vivante (6 nodes)
- `bird_flock.png` — Nuée d'oiseaux (5 nodes)
- `fireworks.png` — Feu d'artifice radial (6 nodes ; certains liens ne se font pas car pattern→clone et spawn_from_particle utilisent des ports différents)
- `calligraphy.png` — Calligraphie vivante (4 nodes)
- `lava.png` — Lave en fusion (5 nodes)
- `silhouette.png` — Silhouette qui s'émiette (5 nodes)
- `constellation.png` — Constellation interactive (4 nodes)

## `previews/` — 2 captures GPU live (statiques, version V1)

Format : PNG 1024×576, rendu réel de la sim particulaire (streaming via blob URL depuis le backend Python/CUDA).

- `live_default.png` — chaîne par défaut du wrapper (1569 particules, "explosion" blanche)
- `live_snowstorm.png` — recette snowstorm telle quelle (1575 particules ; visuel dépouillé car absence de `init_appearance` dans la recette → particules sans taille/couleur explicites)

## `animations/` — 9 vidéos WebM (rendu GPU live, autoplay loop dans la doc)

Format : WebM VP9, 1024×576, 25 fps, ~3 s, 4-330 Ko.
Captures de 75 frames du blob `<img>` de l'overlay particle preview, encodées via ffmpeg (imageio-ffmpeg).
Toutes les recettes sont **tunées DA** (sprite, color, size, lifetime, intensity, etc.) — pas juste un câblage default.

| Slug | Recette | Taille | Notes DA |
|------|---------|--------|----------|
| `snowstorm.webm` | ❄️ Tempête de neige | 177 Ko | Flocons #F0F8FF, ligne haute, gravité + vent + rotation per_second |
| `nebula.webm` | 🌌 Nébuleuse vivante | 330 Ko | Curl noise + render_jfa_field + modify_color_by_index rainbow (très psychédélique, alternative à retuner si besoin) |
| `flock.webm` | 🦅 Nuée d'oiseaux | 93 Ko | behavior_flock defaults — visible mais moins cohésif qu'attendu (clusters distribués) |
| `fireworks.webm` | 🎆 Feu d'artifice radial | 43 Ko | Spawn bas + outward + rainbow colors + gravity + render_trail (excellent visuellement) |
| `calligraphy.webm` | 🖋 Calligraphie vivante | 228 Ko | Curl noise + render_ribbon, couleur crème — substitut de path_follow (absent de path input) |
| `lava.webm` | 🌊 Lave en fusion | 52 Ko | render_metaball threshold 0.85 — saturation blanche partielle persiste, peut être encore retunée |
| `dispersion.webm` | 💨 Silhouette / Dispersion | 42 Ko | Cluster + turbulence — substitut de init_position from_image (besoin d'une image input) |
| `constellation.webm` | 🕸 Constellation interactive | 208 Ko | render_connect, particules dispersées avec drag — sans behavior_target (qui aspire au centre) |
| `hero.webm` | 🎨 Hero atmosphère (loop infini) | 26 Ko | Particules vert accent CKLive, curl noise lent, opacity 0.7 — ambient background du hero |

## Pipeline technique (pour reproduire ou étendre)

Toute la mécanique est dans `chrome-devtools` MCP. Les helpers JS sont volatiles (perdus à chaque reload du navigateur) — voir l'historique de la session pour les recréer.

1. **Portraits** : `LiteGraph.createNode(type)` → place à (32, 32+title) → scale=1 → `lgc.draw()` → wait 1200ms → copy la zone exacte vers un canvas off-screen → `toDataURL()` → décode en PNG via Python.
2. **Chaînes** : N nodes alignés horizontalement, gap 60px → connect via 1er port "Particles" → scale auto-fit (max 1800×1100 viewport) → capture bbox englobante.
3. **Live previews** : créer un `generator/particle/system` wrapper → wait 1s init → modifier `wrapper.subgraph` (clear + add + connect) → dblclick wrapper pour ouvrir l'overlay `#ck-particle-preview-overlay` → wait 4s settle → drawImage de l'`<img>` blob interne vers un canvas off-screen → `toDataURL()`.

## Limites identifiées

- **Live previews polish** : les recettes de la doc sont des chaînes conceptuelles, pas des configs prêtes à rendre. Pour des previews léchées il faut tuner sprite/size/color/lifetime par recette (travail de DA par recette).
- **Wrapper `system.png`** : la hauteur du wrapper dépasse son `size` déclaré (Edit Particles + Output ajoutent du visuel sous-jacent). Le crop actuel laisse du grid en bas — peut être resserré.
- **Fireworks chain** : 2 liens ne se font pas car `pattern_radial → clone` et `spawn_from_particle → render_trail` utilisent des ports non-"Particles". Visible quand même, mais avec rupture de câble.
- **Cycle inner-subgraph** : entrer puis sortir du subgraph wrapper via dblclick + Esc casse l'attachement du LGC ; il faut recharger la page. Pour une batch live, il vaut mieux 1 reload par recette.
