API de scripts
Les scripts Lua pilotent le même moteur que celui sur lequel tourne l'éditeur : chaque outil, calque, image, tuile et sélection avec lesquels on peut travailler est lisible et modifiable par code, avec ou sans écran. Cette référence est générée à partir du moteur lui-même, elle correspond donc toujours à ce que fait l'app : 251 fonctions (35 lectures, 158 modifications, 58 utilitaires pour les images, les nombres aléatoires, le calcul de couleurs et les boîtes de dialogue de script).
Toutes les fonctions se trouvent dans la table globale app. Les appels sont synchrones du point de vue du script. print(...) écrit dans la console du script, et app.config contient les valeurs du formulaire de configuration du script (toujours définie, vide quand il n'y a pas de formulaire). Les couleurs sont des chaînes "#rgb", "#rrggbb" / "#rrggbbaa" ou des tables { r, g, b, a }. Les coordonnées sont des pixels entiers du sprite, avec (0, 0) en haut à gauche. Les identifiants de calques, d'images, d'étiquettes et de slices sont des chaînes. Les tables Lua commencent à 1, et une liste renvoyée de nombres 0/1 ou RGBA est rangée ligne par ligne.
- Commence par app.describe(). Un seul appel renvoie toute la structure du document : calques, images, cels, étiquettes, slices, sélection et contexte d'édition.
- Une création renvoie un id. app.addLayer, app.addFrame, app.addTag et leurs semblables renvoient ce qu'ils ont créé, valide à travers les annulations et rétablissements.
- La sélection et la symétrie sont optionnelles. Si tu omets une couleur ou un pinceau, le contexte d'édition la ou le renseigne. La sélection et la symétrie sont optionnelles : passe respectSelection = true et symmetry = app.getContext().symmetry.
- Une exécution, une annulation. Tout ce qu'un script modifie forme une seule étape d'annulation. Les calques verrouillés sont refusés.
- Pas de limite de temps. Toute exécution peut être mise en pause, même en pleine boucle, reprise, arrêtée, ou arrêtée puis annulée.
- Utilise app.random, pas math.random. app.random.new(seed) est un générateur à graine : la même graine donne le même résultat à chaque exécution (et à chaque rétablissement), donc les scripts devraient prendre une graine dans app.config et la préférer à math.random. app.random.hash(x, y, seed) produit du bruit par pixel. pairs() parcourt aussi les clés d'une table dans le même ordre à chaque exécution, donc itérer sur une table de couleurs ne change pas le dessin.
- Les boucles sur les pixels passent par une Image. app.getImage, puis img:getPixel / img:setPixel autant que tu veux, puis un seul app.putImage. Chaque appel app.* est un aller-retour vers l'éditeur ; les méthodes d'une Image n'en sont pas.
- Utilise app.color, pas de l'analyse hexadécimale et du mélange faits maison. app.color.mix, adjust, ramp, shades, nearest et contrast travaillent dans un espace perceptuel (OKLab) et écrêtent vers sRGB ; analyser "#rrggbb" avec string.sub et faire la moyenne des canaux donne des résultats ternes.
- En bac à sable. Pas de réseau, de fichiers ni de chargement de code ; un script ne peut toucher que le sprite ouvert. Une exécution a un budget mémoire (ses Images, ses données Lua, ce qu'elle ajoute au document et à l'historique des annulations) : au-delà, le script est arrêté avec une erreur et ce qu'il a fait jusque-là reste en une seule étape d'annulation. app.apiVersion indique à un script sur quelle version de cette API il tourne.
Sections
- Groupes d'options: Les options de peinture et de pinceau partagées par les fonctions de dessin, définies une seule fois.
- Document: Le sprite dans son ensemble : commence ici avec app.describe(), puis la taille, le recadrage, la rotation et le mode colorimétrique. (15 fonctions)
- Dessin: Les outils de l'éditeur sous forme de commandes — les outils de l'interface appellent exactement celles-ci. La couleur, le pinceau et les options d'outil que tu omets viennent du contexte d'édition. La peinture ignore la sélection et la symétrie sauf si tu passes respectSelection = true et symmetry = app.getContext().symmetry. (24 fonctions)
- Ajustements: Les ajustements de couleur et les effets de couleur (FX) du menu Filtre, chacun en une étape d'annulation sur les cels d'un calque dans les images que tu listes. Ils ignorent la sélection sauf si tu passes respectSelection = true, et ne touchent jamais les pixels totalement transparents. Sur les sprites indexés, indexedMode choisit entre aligner les pixels recolorés sur l'entrée de palette la plus proche ("remap") et modifier les entrées de palette que les cels utilisent ("palette"). (16 fonctions)
- Images: La façon rapide de travailler pixel par pixel. app.getImage lit un cel (ou une partie) dans une Image, un tampon de pixels qui vit à l'intérieur du script : img:getPixel et img:setPixel ne quittent jamais le script, donc une boucle sur chaque pixel d'un cel de 512 x 512 prend environ un dixième de seconde. app.putImage la réécrit en une seule modification, quel que soit le nombre de pixels que tu as définis. Un pixel est un entier empaqueté (app.pixelColor.rgba(r, g, b, a), comme dans Aseprite) ; setPixel accepte aussi "#rrggbb[aa]" et { r, g, b, a } (alpha vaut 255 par défaut). Sur les sprites indexés, img:getIndex et img:setIndex travaillent avec des index de palette, donc les couleurs en double restent distinctes. Le schéma habituel : local img = app.getImage(layer, frame); for y = 0, img.height - 1 do for x = 0, img.width - 1 do img:setPixel(x, y, ...) end end; app.putImage(layer, frame, img). (17 fonctions)
- Pixels: Lecture et écriture de pixels sous forme de listes RGBA à plat (construites sur les Images ; jamais limitées par la sélection ni en miroir), remplissages et retournements de toute la sélection, et la pipette. (7 fonctions)
- Sélection: Les formes de sélection se combinent avec la sélection actuelle (remplacer, ajouter, soustraire, intersecter). Le masque de sélection est lisible et modifiable. (19 fonctions)
- Calques: Crée, organise et configure des calques. Les groupes sont des dossiers de calques : le parentId d'un calque nomme son groupe (nil au niveau supérieur) et les positions d'app.moveLayer comptent à l'intérieur d'un groupe (0 = en bas). Masquer ou verrouiller un groupe masque ou verrouille tout ce qu'il contient. Un groupe à pleine opacité avec le mode de fusion "normal" est en transparence (ses calques se fondent directement dans ce qui est dessous) sauf si son indicateur isolated est activé ; un groupe isolé, ou toute autre opacité ou mode, compose d'abord ses calques ensemble. (25 fonctions)
- Images et étiquettes: La chronologie : les images, leurs durées et les étiquettes d'animation. (25 fonctions)
- Cels: Un cel est l'image d'un calque sur une image d'animation. Déplace, efface et lie-les par blocs. (9 fonctions)
- Tilemaps: Les calques tilemap placent sur une grille des tuiles issues de leur propre tileset. Les tuiles sont numérotées à partir de 1 (0 est la tuile vide). (19 fonctions)
- Palette: La palette du sprite. (21 fonctions)
- Slices: Des rectangles nommés, par exemple pour des zones d'export ou des hitboxes. Un slice peut aussi être un 9-slice (un rectangle central) et porter un point de pivot ; les deux sont relatifs au coin supérieur gauche du slice, comme dans Aseprite, et le suivent quand le canevas est redimensionné, recadré ou pivoté. (5 fonctions)
- Pinceaux: Définis tes propres pinceaux par leur nom, puis peins avec. Ils n'existent que dans le moteur, le temps de la session : ils ne font pas partie du document, ne sont pas annulables, ne sont pas enregistrés et restent séparés de la bibliothèque de pinceaux de l'éditeur. (6 fonctions)
- Contexte d'édition: Les couleurs, le pinceau, la symétrie et les options d'outils actuels, partagés avec la barre d'outils de l'éditeur. Les commandes de dessin s'en servent pour les couleurs, le pinceau et les options d'outils qu'on ne leur donne pas ; la symétrie est une simple information et n'est appliquée que si tu la passes. (3 fonctions)
- Aléatoire: Des nombres aléatoires à graine, calculés dans le script (sans aller-retour à chaque appel). La même graine donne les mêmes résultats : un script peut donc être relancé, annulé et rétabli, ou partagé, et produire un résultat identique. Préfère-les à math.random, qui diffère à chaque exécution. Les générateurs sont des objets : appelle leurs méthodes avec deux-points (rng:int(1, 6)). (11 fonctions)
- Couleur: Du calcul de couleur sans analyse manuelle de l'hexadécimal ni mélange RGB maison. En entrée, les couleurs sont des chaînes "#rrggbb" / "#rrggbbaa" ou des tables { r, g, b, a } (0-255, a facultatif) ; en sortie, ce sont des tables { r, g, b, a }, sauf si le nom parle d'hexadécimal. Le mélange et les ajustements utilisent OKLab par défaut, un espace perceptuel où des pas égaux paraissent égaux ; `space` peut valoir "oklab", "oklch", "rgb" ou "hsl". Les résultats sont ramenés dans le gamut sRGB en réduisant la chroma, donc la teinte et la luminosité sont conservées. Les listes (ramp, shades) se construisent en un seul appel. (11 fonctions)
- Boîtes de dialogue et commandes: L'interface des scripts, sur le modèle d'Aseprite : Dialog{ title = ... } construit une fenêtre à partir de widgets (label, entry, number, slider, check, radio, combobox, color, shades, button, separator, file) et plugin:newCommand ajoute des commandes aux menus, à la palette de commandes et à l'éditeur de raccourcis clavier. La fenêtre est dessinée par l'éditeur, en texte seulement, avec une barre de titre qui nomme le script et porte la mention "script". Les callbacks (onclick, onchange, onclose) s'exécutent dans le script, un à la fois, chacun en une seule étape d'annulation ; un script dont une boîte de dialogue est ouverte reste actif, au repos, pendant que l'utilisateur continue de dessiner, et l'arrêter ferme ses boîtes de dialogue. Non pris en charge : les widgets de canevas et dlg:repaint. (18 fonctions)
- Formulaires de configuration: Le formulaire préalable à l'exécution que déclare un script : champs nombre, texte, case à cocher, liste, couleur, pinceau et palette.
- Réglages du contexte: Les couleurs, le pinceau et les options d'outil que les commandes de dessin utilisent par défaut, plus l'interrupteur de symétrie de l'interface (à titre informatif).
- Types: Chaque ensemble de valeurs nommé (FillMode, BlendMode, SymmetryAxis, ...), chaque valeur expliquée.
- Lecture du document: Comment un script lit chaque partie du modèle du document.
- Commandes internes: Les commandes du moteur que les scripts ne peuvent pas appeler, et pourquoi.
- Ce qui reste dans l'éditeur: Ce qu'un script ne peut pas atteindre : zoom, panneaux, lecture, enregistrement.
En Markdown : scripting.md ; toute la documentation en un seul fichier : llms-full.txt.