Documentation → API
API locale de génération de skins
Un générateur compatible Starlight, servi depuis ce domaine, à partir des assets archivés. Fonctionne même si le service d'origine est hors ligne.
Principe
L'API compose les gabarits archivés dans l'ordre de superposition mesuré, applique les couleurs demandées, et renvoie un PNG 64×64 utilisable directement comme skin Minecraft. Aucune requête n'est faite vers Starlight : tout est calculé localement, sans dépendance externe — le codec PNG lui-même est écrit à la main.
Les endpoints
| Route | Réponse |
|---|---|
GET /api/health | État du service |
GET /api/info | Catalogue complet : groupes, cosmétiques, palettes, ordre des layers |
GET /api/create-skin/:base/:couleur/:morpho/?… | image/png 64×64 |
GET /api/skin?… | Idem, forme à plat |
La première forme reprend volontairement la structure d'URL d'origine
(/create-skin/:base_texture/:base_color/:skinType/) : basculer d'un service à
l'autre ne demande que de changer le nom d'hôte et de préfixer par /api.
Ajoutez &debug=1 pour obtenir, au lieu du PNG, la liste des layers
réellement composés et les avertissements éventuels. Pratique pour comprendre
pourquoi un cosmétique n'apparaît pas.
Paramètres
Pour chaque groupe, trois à quatre paramètres, nommés comme en amont :
<groupe>_texture nom du cosmétique, ou "none"
<groupe>_color couleur de la zone primaire
<groupe>_color_secondary couleur de la zone secondaire
<groupe>_alignment uniquement eyes (high|middle|low) et mouth (high|low)
Les groupes disponibles : base, makeup, gloves,
mouth, socks, top, top_designs,
bottom, footwear, middlewear,
outerwear, facial_hair, hair_style,
eyes, eyebrow, face_item,
headwear, ears.
skin_type vaut wide ou slim. Seuls quatre groupes
diffèrent réellement entre les deux morphologies ; pour les autres, la variante
wide est réutilisée automatiquement.
Une couleur omise reprend la valeur par défaut du moteur d'origine, pas celle de l'autre
zone. C'est important : les yeux ont une secondaire par défaut à white
(le blanc de l'œil). Refléter la primaire y peindrait l'œil entier d'une seule couleur.
Couleurs
Hexadécimal
$rrggbb (encodé %24rrggbb dans une URL) ou #rrggbb.
La teinte est appliquée par la rampe multiplicative à 8 niveaux. C'est le mode le plus fidèle : écart maximal de 1/255.
Nom de palette
red, crimson, tan… selon la palette du cosmétique.
Ces couleurs ne passent pas par la rampe : chacune porte un nuancier dessiné à la main, capturé depuis le moteur d'origine.
La liste des palettes et de leurs couleurs est dans /api/info, sous la clé
palettes. Chaque cosmétique indique sa palette via color_template.
Ordre de superposition
Le manifest d'origine ne contient aucun z-index. L'ordre a donc été mesuré : pour chaque paire de groupes qui se recouvrent, un rendu avec deux couleurs distinctes révèle lequel est dessiné au-dessus. 153 paires testées, zéro incohérence avec l'ordre total obtenu.
base → makeup → gloves → mouth → socks → top → top_designs → bottom
→ footwear → middlewear → outerwear → facial_hair → hair_style
→ eyes → eyebrow → face_item → headwear → ears
Il correspond à l'anatomie : le corps, puis ce qui se pose dessus, puis les vêtements du plus près au plus loin de la peau, puis le visage, puis ce qui se porte sur la tête.
Exemples
Une tenue simple
https://skins.coruitech.dev/api/create-skin/male/tan/wide/
?top_texture=basic&top_color=%243366cc
&bottom_texture=jeans&bottom_color=%234682b4
Deux zones et un motif
https://skins.coruitech.dev/api/create-skin/none/white/wide/
?top_texture=chef_shirt&top_color=white&top_color_secondary=red
&top_designs_texture=cake&top_designs_color=black
Un visage
https://skins.coruitech.dev/api/create-skin/male/tan/wide/
?eyes_texture=big_ol_eyes&eyes_color=green&eyes_alignment=middle
&mouth_texture=basic&mouth_color=tan&mouth_alignment=high
&eyebrow_texture=basic&eyebrow_color=brown
Lister ce qui existe
curl -s https://skins.coruitech.dev/api/info | jq '.groups.top.cosmetics[].name'
curl -s https://skins.coruitech.dev/api/info | jq '.palettes.default'
Fidélité mesurée
Chaque cas est composé localement, demandé en parallèle au service d'origine, et comparé pixel par pixel. Les 8 pixels de la bande de calibration sont comptés à part : ils sont une métadonnée du moteur amont, pas du contenu.
| Cas | Écart moyen | Écart max | Alpha |
|---|---|---|---|
| t-shirt + jean, couleurs hex | 0,114 | 1 | 0 |
| chef + motif, couleurs nommées | 0,000 | 0 | 0 |
| visage complet, couleurs nommées | 0,000 | 0 | 0 |
| corps + vêtements clairs | 1,273 | 17 | 0 |
| tenue empilée avec outerwear | 2,136 | 255 | 13 |
Deux cas sont identiques au bit près. Les deux derniers relèvent des limites décrites ci-dessous.
Limites connues
1. Occlusion entre vêtements superposés
Quand un outerwear est présent, le moteur d'origine supprime
quelques pixels du top dans la couche overlay (y ≥ 32) — y compris là où
l'outerwear ne dessine rien. Sur le cas testé : 13 pixels sur environ 860, soit 1,5 %.
Ce n'est pas une simple suppression en bloc : sur 16 pixels du top non recouverts, 13 disparaissent et 3 subsistent. Modéliser la règle exactement demanderait de capturer un masque d'occlusion par paire de layers. Non fait pour l'instant.
2. Compression de la rampe sur les couleurs claires
Au-delà d'environ 190 sur un canal, le niveau le plus clair (×1,348) dépasserait 255.
Le moteur d'origine comprime alors toute la rampe au lieu de simplement plafonner.
Sur $e0e0e0, le niveau le plus sombre vaut ×0,897 en amont contre ×0,823 en
local — un écart de 17/255.
Aucun modèle testé (HSL, HSV, luma pondérée, multiplication en lumière linéaire) ne rend compte de cette compression. Les couleurs dont tous les canaux restent sous 190 ne sont pas concernées.
3. Modificateurs de coiffure non archivés
hair_texture, hair_pattern_texture et
hair_extension_front/back_texture ne sont pas des layers indépendants :
ils modifient le rendu de hair_style. Le premier change son
ombrage, le deuxième repeint une zone, les extensions ajoutent de la géométrie.
Les archiver exhaustivement demanderait 29 × 7 × 6 × 4 × 8 ≈ 39 000
combinaisons. hair_style seul est donc supporté ; ces quatre groupes sont
listés dans /api/info sous unsupported.
4. Nuanciers nommés partiellement observables
Certains niveaux d'ombrage ne sont visibles sur aucun cosmétique d'une palette donnée —
et la bande de calibration, qui les révélerait, n'est émise que sur le chemin
$hex. Les niveaux manquants sont interpolés linéairement entre les nuances
observées. Les deux cas à couleurs nommées testés ressortent malgré tout exacts.
Déploiement
| Élément | Valeur |
|---|---|
| Service | starlight-local.service (systemd, redémarrage automatique) |
| Processus | Node 24, écoute sur 127.0.0.1:3110 |
| Exposition | Reverse proxy /api créé via l'API aaPanel |
| Dépendances | aucune — codec PNG écrit à la main |
| Durcissement | ProtectSystem=strict, NoNewPrivileges, utilisateur www |
Le proxy apparaît dans l'onglet « Reverse proxy » du site dans aaPanel, exactement comme s'il avait été créé depuis l'interface.