Documentation → Étape 1

Étape 1 — Découverte des endpoints

Trouver les vraies URLs de l'application, sans en deviner aucune.

11 requêtes émises · toutes séquentielles · User-Agent descriptif

Objectif et règle du jeu

La règle imposée était stricte : ne deviner aucune URL. Pas de /api/layers tenté au hasard, pas d'énumération d'identifiants. Tout devait venir soit du code réellement chargé par l'application, soit de la documentation publique.

Cette contrainte est aussi ce qui a permis d'éviter une erreur : l'endpoint que j'aurais « logiquement » deviné n'existe pas, et la vraie source de données est ailleurs.

1. Le HTML de l'application

Première requête sur la webapp. J'utilise curl plutôt qu'un outil qui convertit en Markdown, car j'ai besoin des balises <script> brutes.

curl -A "starlight-layer-archiver/1.0 (…)" \
     https://starlightskins.lunareclipse.studio/apps/skin-creator

→ HTTP 200 | 80 929 octets | text/html

Les scripts chargés :

https://cdnjs.cloudflare.com/ajax/libs/lz-string/1.4.4/lz-string.min.js
./starlight-skin-maker-files/js/main.js?v=103
./starlight-skin-maker-files/js/pickr.min.js
./starlight-skin-maker-files/js/render.js?v=6
Bonne nouvelle

Ce n'est pas une application bundlée. Pas de webpack, pas de Vite, pas de minification sur main.js. 975 lignes de JavaScript lisible, commentées par l'auteur. Aucune sourcemap à reconstituer.

2. Le piège du chemin relatif

Les scripts sont référencés en ./starlight-skin-maker-files/…. Or l'URL de la page est /apps/skin-creator, sans slash final, et le document ne contient aucune balise <base>. Le ./ résout donc vers /apps/, et non vers /apps/skin-creator/.

URL testéeRéponse
/apps/starlight-skin-maker-files/js/main.js 200 — 40 639 o
/apps/skin-creator/starlight-skin-maker-files/js/main.js 404

Détail sans gloire, mais il aurait coûté un moment d'égarement si je l'avais pris à l'envers, et surtout il aurait pu être interprété à tort comme « les assets sont protégés ».

3. Grep des bundles

Recherche de tout ce qui ressemble à une route d'API dans les deux fichiers :

grep -ohE 'https?://[a-zA-Z0-9./_?&=:%-]+' main.js render.js
grep -nE 'fetch\(' main.js render.js

Résultat : un seul appel fetch() dans toute l'application.

main.js:713:  fetch("/dev-tools/skin-creator-code/" + inputValue)

Et il sert au décodage des « skin codes » partagés, pas au listing des layers. Aucune route /api/, aucun manifest.json, aucune référence à un CDN de textures.

Moment de doute

À ce stade, l'hypothèse de travail — « il existe une API publique qui liste les layers » — semblait fausse. Le code ne demande la liste à personne. La question devient donc : d'où vient la liste ?

4. Le manifest est inline

main.js lit une variable globale skinCreatorData qu'il ne déclare jamais :

// main.js:30
let data = skinCreatorData;
skinCreatorInfo = data;
definedOptions = data.definedOptions;

La variable est définie dans le HTML, ligne 494, dans un <script> inline :

skinCreatorData = {"cosmetics":{"skin_type":{"wide":{"id":1},…
Résultat

48 459 octets de JSON valide, servis directement avec la page. Il n'y a pas d'API de listing à interroger : la totalité du catalogue arrive avec le HTML. Une seule requête suffit à obtenir l'intégralité du manifest.

5. Structure du manifest

Trois clés racine :

CléContenu
cosmetics24 groupes : skin_type, colors, et 22 groupes *_textures
cosmeticOptions.referencesTable des crédits auteurs (nom affiché + couleur)
definedOptionsÉtat par défaut, et surtout la liste exhaustive des paramètres acceptés (58 clés)

Forme d'une entrée cosmétique :

"chef_shirt": {
  "uses_secondary_color": true,
  "color_template": "default",
  "created": "bret06",
  "preview_attributes": { "top_color": "white", "top_color_secondary": "red" },
  "id": 2
}

Aucune URL d'asset n'apparaît dans le manifest. Les URLs sont construites côté client à partir du nom de groupe et du nom de cosmétique — ce qui explique qu'aucun grep d'URL ne les fasse apparaître.

272
cosmétiques
22
groupes
70
à 2 zones
13
palettes

Sur les 13 palettes définies, 11 seulement sont référencées par un cosmétique. default_darker et revamped sont orphelines — vestiges d'une version antérieure, sans doute.

6. Les documentations officielles

Le site de documentation rend son contenu côté client avec marked.js. Les pages sont de simples fichiers Markdown :

https://docs.lunareclipse.studio/assets/markdown/starlight-skinapi/${page}.md

Les identifiants de page sont dans le HTML (onclick="selectPage(event)" sur des <h1 id="…">). Trois concernent le Skin Creator : skin_creator_index, getting_skin_creator_info, generating_skins.

Ils confirment deux endpoints, officiellement documentés et assumés :

https://starlightskins.lunareclipse.studio/create-skin/info
https://starlightskins.lunareclipse.studio/create-skin/:base_texture/:base_color/:skinType/?[OPTIONS]

Le premier renvoie 69 798 octets de JSON — le catalogue, dans une forme proche du manifest inline. Le second compose et renvoie le skin fini.

7. Les couleurs hex arbitraires

L'application embarque Pickr, un sélecteur de couleur libre. La valeur choisie est encodée ainsi :

// main.js:225
const hexCode = pickr._color.toHEXA().toString();
definedOptions[itemName] = (hexCode.includes("#"))
  ? "$" + hexCode.slice(1)
  : "$" + hexCode;
Convention

Un paramètre de couleur accepte soit un nom de palette (red, crimson…), soit un hex libre préfixé d'un dollar : $FF0000. Dans une URL, le $ doit être encodé en %24. Les palettes nommées sont donc des raccourcis de confort, pas une contrainte du moteur.

Bilan de l'étape

Acquis

  • Catalogue complet obtenu en une requête
  • Endpoint de composition identifié et documenté
  • Encodage des couleurs libres compris
  • Deux zones par layer confirmées structurellement

Question ouverte à ce stade

Aucun endpoint ne sert le PNG de layer brut. Les assets sources ne sont pas adressables publiquement. Comment, alors, archiver les textures ?

→ C'est l'objet de l'étape 2.

Note de périmètre

Les documentations portent une mention de copyright explicite. Le cadre retenu — archivage personnel, fork local, aucune redistribution — reste cohérent avec cette mention. Rien n'est republié ici : les images présentées sont des rendus de démonstration, produits pour illustrer le raisonnement.