Documentation → Étape 4
Étape 4 — Téléchargement et extraction
748 rendus, 94 secondes, zéro échec — et 374 gabarits génériques reconstruits à partir d'une API qui ne les expose pas.
1. Compter les variantes avant de tirer
Un cosmétique n'est pas une variante. Trois paramètres le démultiplient :
la morphologie (wide / slim) et, pour deux groupes,
un alignement.
| Paramètre | Valeurs | Groupes concernés |
|---|---|---|
skin_type | wide, slim | déterminé par mesure, voir ci-dessous |
eyes_alignment | high, middle, low | eyes_textures |
mouth_alignment | high, low | mouth_textures |
2. Quels groupes changent vraiment entre wide et slim ?
Doubler les 22 groupes « au cas où » aurait ajouté plusieurs centaines de requêtes inutiles. Un représentant par groupe, rendu dans les deux morphologies et comparé pixel à pixel, tranche la question pour 44 requêtes :
| Groupe | Témoin | Pixels différents | Décision |
|---|---|---|---|
top_textures | baseball_tee | 61 | wide + slim |
outerwear_textures | alien_force | 125 | wide + slim |
gloves_textures | fingerless_gloves | 82 | wide + slim |
makeup_textures | admin | 41 | wide + slim |
base_textures | bear | 0 | wide seul |
| … et 17 autres groupes à 0 différence | |||
base_textures — le corps lui-même, donc les bras — ne change pas.
Vérifié sur trois cosmétiques différents pour écarter un faux négatif. À l'inverse,
makeup_textures, qui est sur le visage, change. L'anatomie n'était pas un
bon guide : seule la mesure l'était.
3. Deux passes suffisent à tout décomposer
Chaque variante est rendue deux fois, avec des couleurs choisies pour être orthogonales :
| Passe | Zone primaire | Zone secondaire |
|---|---|---|
| A | $800000 rouge | $000080 bleu |
| B | $008000 vert | $800000 rouge |
La lecture croisée lève toute ambiguïté :
rouge puis vert → zone primaire
bleu puis rouge → zone secondaire
identique → pixel fixe
Les valeurs sont à 128 et non 255 : au-delà, le slot le plus clair dépasse la capacité d'un octet et l'information se perd dans l'écrêtage.
4. Politesse réseau
Le service appartient à un développeur solo qui sortait d'un burn-out, avec près de six mois d'indisponibilité derrière lui. Les garde-fous ne sont pas décoratifs :
Ce qui est imposé
- 3 requêtes simultanées au maximum
- 120 ms minimum entre deux départs, tous workers confondus
- 4 tentatives maximum, backoff exponentiel
Retry-Afterrespecté sur 429 et 5xx- User-Agent descriptif et identifiable
Détails d'implémentation
- Le throttle est une chaîne de promesses partagée, pas un
setTimeoutpar worker — sinon 3 workers émettraient 3 requêtes simultanées toutes les 120 ms. - Écriture en
.partpuis renommage atomique : une interruption ne laisse jamais un fichier tronqué qu'une reprise prendrait pour valide. - Un fichier non vide déjà présent est sauté.
- Les 4xx autres que 429 ne sont pas réessayés : ce sont des réponses, pas des pannes.
5. Le téléchargement
Le passage à blanc, obligatoire avant tout tir réel :
Résultat réel :
Terminé en 94 s
téléchargés : 748 sautés : 0 échecs : 0
Soit 8,0 requêtes par seconde — exactement la cadence imposée par le throttle (3 workers ÷ 120 ms). Le serveur n'a jamais renvoyé un seul 429 ni 5xx.
6. Extraction des gabarits
Les paires de passes sont ensuite fusionnées en un gabarit générique par variante.
Chaque pixel est attribué à une zone, et sa valeur comparée à la rampe de référence
[96, 105, 114, 128, 138, 143, 148, 153] lue sur la bande de calibration.
Erreur maximale d'affectation : 0. Les 94 510 pixels colorisables tombent exactement sur l'une des 8 valeurs de la rampe, sans un seul pixel inclassable. Un modèle approximatif aurait produit des dizaines de résidus.
7. Format d'archive
Chaque gabarit est un PNG 64×64 RGBA où les canaux portent des index, pas des couleurs :
| Canal | Contenu |
|---|---|
| R | zone — 0 = fixe, 1 = primaire, 2 = secondaire |
| G | index de slot d'ombrage, 0 (plus sombre) à 7 (plus clair) |
| B | inutilisé |
| A | alpha d'origine, conservé tel quel |
Les pixels fixes conservent leur couleur littérale dans _fixed.json.
L'arborescence sur disque suit la hiérarchie sémantique du manifest :
textures/<groupe>/<cosmétique>/<morphologie>[_<alignement>].png
textures/top_textures/chef_shirt/wide.png
textures/eyes_textures/big_ol_eyes/wide_middle.png
textures/outerwear_textures/alien_force/slim.png
Ces gabarits sont servis par ce site et alimentent directement la démo interactive.