# Pipeline PixelLab — génération des visuels

Extrait de `CLAUDE.md` le 27/08/2026. Le pipeline est **à l'arrêt**: les 315
visuels sont produits et le quota ne se renouvelle que le **25/09/2026**. Ces
douze leçons ont été payées pendant la production; les relire avant de relancer
un lot évite de les repayer.

Portée locale à ce projet (`~/.claude.json`). Le serveur parle aussi en
JSON-RPC direct sur `https://api.pixellab.ai/mcp` (en-tête
`Authorization: Bearer`), ce qui permet de scripter tout un lot sans passer par
les outils MCP de la session.

Portée locale à ce projet (`~/.claude.json`). `create_character` puis
`animate_character`. Le serveur parle aussi en JSON-RPC direct sur
`https://api.pixellab.ai/mcp` (en-tête `Authorization: Bearer`), ce qui permet de
scripter tout un lot sans passer par les outils MCP de la session.

- **PixelLab rend des images séparées, jamais une feuille** (`frame_000.png`,
  `frame_001.png`…). Les composer en bande horizontale avant de les poser dans
  `assets/`, sinon la découpe `colonnes × rangées` n'a rien à découper.
- **Animer la vue sud seule** (`directions: ["south"]`) : `VisualHolder` ignore
  les directions (§6). La création `mode: "v3"` produit toujours 8 rotations,
  pour environ 2 générations à ces tailles: on n'en garde que la sud.
- **`frame_count: 6` rend 7 images** : la pose de départ est conservée comme
  image 0. Le `count` du visuel suit le nombre réellement composé.
- **Les URLs Backblaze répondent, mais refusent une requête sans `User-Agent`**
  (401), et un fichier tout juste publié peut mettre quelques secondes à
  répondre : en-tête explicite plus deux ou trois réessais.
- **Dix travaux simultanés au maximum** (abonnement Tier 2), et une création v3
  compte plusieurs travaux internes. Une boucle qui relit `list_jobs` et relance
  ce qui est libre traite 48 créatures en une heure environ.
- **Une créature n'est finie qu'avec sa marche** : la vue sud arrive bien avant
  l'animation. Un pipeline qui classe l'entrée dès la vue sud perd la marche.
- **Une marche peut revenir incomplète, et une relance crée un second groupe.**
  Le service rend direction par direction et l'une peut manquer; il faut
  redemander les manquantes en passant `animation_group_id`. Sans lui, le
  personnage se retrouve avec **deux animations du même nom**, chacune portant
  une partie des directions. Un lecteur qui indexe par nom laisse le second
  groupe écraser le premier, croit une direction manquante et la redemande sans
  fin. Fusionner les groupes homonymes à la lecture.
- **L'échelle d'un visuel se mesure, elle ne se devine pas** : prendre la hauteur
  réellement dessinée (hors marge transparente) et la ramener au corps de
  référence — `18 × size_multiplier` de rayon, donc 36 px de diamètre à
  l'échelle 1, plus un débord d'environ 1,6. Elle ne doit dépendre que de
  l'image: le multiplicateur de taille de la fiche se multiplie ensuite.
- **Se mesurer sur la même pose des deux côtés — la case sud, image 0.** Le
  service rend chaque animation sur le canevas qu'il lui faut: un repos tient
  dans 160 px, une marche demande 224 px pour loger le mouvement. Mesurer le
  canevas, ou prendre la plus grande case de la feuille (une jambe tendue en
  marche, la bête au calme au repos), donne deux références incomparables et la
  créature **change de taille en changeant d'état**. Sur les clients l'écart
  atteignait 133 %. La case sud au repos vaut ~155 px dans toutes les feuilles
  d'un même personnage: elle est la seule mesure qui s'accorde.
- **Remplacer une image sans remesurer son échelle est le pire des deux
  mondes** : l'ancienne échelle appliquée au nouveau dessin donnait 186 px
  debout contre 132 px en marchant. Toute refonte d'asset se termine par une
  remesure et une republication, jamais par la seule écriture du PNG.
- **Un objet à plusieurs faces se demande en une fois** : quatre images libres
  donnent quatre meubles différents posés sur un bout de sol.
  `create_8_direction_object` rend le *même* objet sous huit angles (~25
  générations, carré, 24 à 168 px) — c'est ce qui remplit `front/right/back/left`.
- **Le poids d'une image libre est d'une génération** (`create_image_pixflux`,
  10 à 40 s, jusqu'à 400 px, `no_background`): c'est l'outil des icônes et des
  plats, pas `create_1_direction_object` qui en coûte 20 à 40.
- **L'éditeur ouvert importe tout seul au retour du focus**, et un lancement
  `--headless` du jeu importe aussi ce qui manque au passage. Ne pas lancer un
  `--headless --import` concurrent. Sans import, le smoke test le dit
  franchement: « Le visuel publié « X » n'est pas chargeable ».

