Skript-API
Lua-Skripte steuern dieselbe Engine, auf der der Editor läuft – jedes Werkzeug, jede Ebene, jeden Frame, jedes Tile und jede Auswahl, mit denen man arbeiten kann, lesbar und schreibbar aus Code, mit oder ohne Bildschirm. Diese Referenz wird aus der Engine selbst erzeugt und stimmt deshalb immer mit dem überein, was die App tut: 251 Funktionen (35 Abfragen, 158 Änderungen, 58 Helfer für Bilder, Zufallszahlen, Farbmathematik und Skript-Dialoge).
Alle Funktionen liegen in der globalen Tabelle app. Aus Sicht des Skripts sind Aufrufe synchron. print(...) schreibt in die Skriptkonsole, und app.config enthält die Werte des Konfigurationsformulars des Skripts (immer definiert, leer, wenn es kein Formular gibt). Farben sind Strings wie "#rgb", "#rrggbb" / "#rrggbbaa" oder Tabellen { r, g, b, a }. Koordinaten sind ganzzahlige Sprite-Pixel mit (0, 0) oben links. IDs von Ebenen, Frames, Tags und Slices sind Strings. Lua-Tabellen beginnen bei 1, und eine zurückgegebene Liste aus 0/1- oder RGBA-Zahlen ist zeilenweise geordnet.
- Fang mit app.describe() an. Ein Aufruf liefert die gesamte Struktur des Dokuments: Ebenen, Frames, Cels, Tags, Slices, Auswahl und Bearbeitungskontext.
- Erstellen liefert eine ID. app.addLayer, app.addFrame, app.addTag und Verwandte geben zurück, was sie erstellt haben – gültig über Rückgängig und Wiederholen hinweg.
- Auswahl und Symmetrie sind optional. Lässt du eine Farbe oder einen Pinsel weg, setzt der Bearbeitungskontext sie ein. Auswahl und Symmetrie musst du ausdrücklich einschalten: Übergib respectSelection = true und symmetry = app.getContext().symmetry.
- Ein Lauf, ein Rückgängig-Schritt. Alles, was ein Skript ändert, ist ein einziger Rückgängig-Schritt. Gesperrte Ebenen werden abgelehnt.
- Kein Zeitlimit. Jeder Lauf lässt sich anhalten – auch mitten in einer Schleife –, fortsetzen, stoppen oder stoppen und zurücksetzen.
- Nimm app.random, nicht math.random. app.random.new(seed) ist ein Generator mit Seed: Derselbe Seed liefert bei jedem Lauf (und bei Wiederholen) dasselbe Ergebnis. Skripte sollten deshalb einen Seed aus app.config nehmen und ihn math.random vorziehen. app.random.hash(x, y, seed) liefert Rauschen pro Pixel. Auch pairs() durchläuft die Schlüssel einer Tabelle bei jedem Lauf in derselben Reihenfolge, sodass das Durchlaufen einer Tabelle mit Farben die Grafik nicht verändert.
- Pixelschleifen laufen über ein Image. app.getImage, dann img:getPixel / img:setPixel so oft du willst, dann ein app.putImage. Jeder app.*-Aufruf ist eine Fahrt zum Editor; die Methoden eines Images sind es nicht.
- Nimm app.color, kein selbstgebautes Hex-Parsen und Mischen. app.color.mix, adjust, ramp, shades, nearest und contrast arbeiten in einem Wahrnehmungsraum (OKLab) und begrenzen auf sRGB; "#rrggbb" mit string.sub zu parsen und Kanäle zu mitteln, liefert trübe Ergebnisse.
- Abgeschottet. Kein Netzwerk, keine Dateien, kein Nachladen von Code; ein Skript kann nur den geöffneten Sprite anfassen. Ein Lauf hat ein Speicherbudget (seine Images, seine Lua-Daten, was er dem Dokument und dem Änderungsverlauf hinzufügt): Wird es überschritten, stoppt das Skript mit einem Fehler, und was es bis dahin getan hat, bleibt als ein Rückgängig-Schritt erhalten. app.apiVersion verrät einem Skript, auf welcher Version dieser API es läuft.
Abschnitte
- Optionsgruppen: Die Mal- und Pinseloptionen, die die Zeichenfunktionen gemeinsam haben, einmal definiert.
- Dokument: Der Sprite als Ganzes: Fang hier mit app.describe() an, dann Größe, Zuschneiden, Drehen und Farbmodus. (15 Funktionen)
- Zeichnen: Die Werkzeuge des Editors als Befehle – die Werkzeuge der Oberfläche rufen genau diese auf. Farb-, Pinsel- und Werkzeugoptionen, die du weglässt, kommen aus dem Bearbeitungskontext. Malen ignoriert Auswahl und Symmetrie, solange du nicht respectSelection = true und symmetry = app.getContext().symmetry übergibst. (24 Funktionen)
- Anpassungen: Die Farbanpassungen und Farb-FX des Filter-Menüs, jede ein Rückgängig-Schritt über die Cels einer Ebene in den Frames, die du auflistest. Sie ignorieren die Auswahl, solange du nicht respectSelection = true übergibst, und berühren nie vollständig transparente Pixel. Auf indizierten Sprites wählt indexedMode zwischen dem Einrasten der umgefärbten Pixel auf den nächsten Paletteneintrag ("remap") und dem Bearbeiten der Paletteneinträge, die die Cels nutzen ("palette"). (16 Funktionen)
- Images: Der schnelle Weg, Pixel für Pixel zu arbeiten. app.getImage liest ein Cel (oder einen Teil davon) in ein Image, einen Pixelpuffer, der im Skript lebt: img:getPixel und img:setPixel verlassen das Skript nie, sodass eine Schleife über jedes Pixel eines 512 x 512 großen Cels etwa eine Zehntelsekunde dauert. app.putImage schreibt es als eine einzige Änderung zurück, egal wie viele Pixel du setzt. Ein Pixel ist eine gepackte ganze Zahl (app.pixelColor.rgba(r, g, b, a), wie in Aseprite); setPixel nimmt auch "#rrggbb[aa]" und { r, g, b, a } (Alpha ist standardmäßig 255). Auf indizierten Sprites arbeiten img:getIndex und img:setIndex mit Palettenindizes, sodass doppelte Farben getrennt bleiben. Das übliche Muster: 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 Funktionen)
- Pixel: Pixel lesen und schreiben als flache RGBA-Listen (auf Images aufgebaut; nie von der Auswahl beschnitten oder gespiegelt), Füllungen und Spiegelungen der ganzen Auswahl und die Pipette. (7 Funktionen)
- Auswahl: Auswahlformen verbinden sich mit der aktuellen Auswahl (ersetzen, hinzufügen, abziehen, schneiden). Die Auswahlmaske ist les- und schreibbar. (19 Funktionen)
- Ebenen: Ebenen erstellen, anordnen und konfigurieren. Gruppen sind Ordner für Ebenen: Die parentId einer Ebene nennt ihre Gruppe (nil auf oberster Ebene), und die Positionen von app.moveLayer zählen innerhalb einer Gruppe (0 = unten). Eine Gruppe auszublenden oder zu sperren blendet alles darin aus oder sperrt es. Eine Gruppe mit voller Deckkraft und dem Mischmodus "normal" ist Pass-through (ihre Ebenen mischen sich direkt in das, was darunter liegt), solange ihr Flag isolated nicht gesetzt ist; eine isolierte Gruppe oder jede andere Deckkraft oder jeder andere Modus setzt ihre Ebenen zuerst zusammen. (25 Funktionen)
- Frames & Tags: Die Zeitleiste: Frames, ihre Dauer und Animations-Tags. (25 Funktionen)
- Cels: Ein Cel ist das Bild einer Ebene in einem Frame. Verschiebe, leere und verknüpfe sie blockweise. (9 Funktionen)
- Tilemaps: Tilemap-Ebenen platzieren Tiles aus ihrem eigenen Tileset auf einem Raster. Tiles werden ab 1 nummeriert (0 ist das leere Tile). (19 Funktionen)
- Palette: Die Palette des Sprites. (21 Funktionen)
- Slices: Benannte Rechtecke, z. B. für Exportbereiche oder Hitboxen. Ein Slice kann auch ein 9-Slice (ein mittleres Rechteck) sein und einen Pivotpunkt tragen; beide beziehen sich wie in Aseprite auf die obere linke Ecke des Slices und wandern mit, wenn die Leinwand skaliert, zugeschnitten oder gedreht wird. (5 Funktionen)
- Pinsel: Definiere eigene Pinsel mit einem Namen und mal dann mit ihnen. Sie existieren nur in der Engine für die Dauer der Sitzung: nicht im Dokument, nicht rückgängig zu machen, nicht gespeichert und getrennt von der Pinselbibliothek des Editors. (6 Funktionen)
- Bearbeitungskontext: Die aktuellen Farben, der Pinsel, die Symmetrie und die Werkzeugoptionen – geteilt mit der Werkzeugleiste des Editors. Zeichenbefehle nutzen sie für Farben, Pinsel und Werkzeugoptionen, die ihnen nicht übergeben werden; die Symmetrie ist nur eine Information und wird nur angewendet, wenn du sie übergibst. (3 Funktionen)
- Zufall: Zufallszahlen mit Seed, berechnet innerhalb des Skripts (kein Roundtrip pro Aufruf). Derselbe Seed liefert dieselben Ergebnisse, sodass ein Skript erneut ausgeführt, rückgängig gemacht und wiederholt oder geteilt werden kann und identisch aussieht. Bevorzuge diese Funktionen gegenüber math.random, das bei jedem Lauf anders ist. Generatoren sind Objekte: Ruf ihre Methoden mit einem Doppelpunkt auf (rng:int(1, 6)). (11 Funktionen)
- Farbe: Farbberechnung ohne selbstgebautes Hex-Parsing und RGB-Mischen. Farben als Eingabe sind Strings der Form "#rrggbb" / "#rrggbbaa" oder { r, g, b, a }-Tabellen (0-255, a optional); Farben als Ausgabe sind { r, g, b, a }-Tabellen, außer der Name sagt Hex. Mischen und Anpassen verwenden standardmäßig OKLab, einen wahrnehmungsbasierten Raum, in dem gleiche Schritte gleich aussehen; `space` kann "oklab", "oklch", "rgb" oder "hsl" sein. Die Ergebnisse werden durch Verringern der Chroma auf sRGB begrenzt, sodass Farbton und Helligkeit erhalten bleiben. Listen (ramp, shades) entstehen in einem einzigen Aufruf. (11 Funktionen)
- Dialoge und Befehle: Skript-Oberfläche nach dem Vorbild von Aseprite: Dialog{ title = ... } baut ein Fenster aus Widgets (label, entry, number, slider, check, radio, combobox, color, shades, button, separator, file), und plugin:newCommand fügt den Menüs, der Befehlspalette und dem Editor für Tastenkürzel Befehle hinzu. Das Fenster wird vom Editor gezeichnet, nur als Text, mit einer Titelleiste, die das Skript nennt und als "script" markiert. Callbacks (onclick, onchange, onclose) laufen im Skript, einer nach dem anderen, jeder als ein einzelner Rückgängig-Schritt; ein Skript mit offenem Dialog bleibt am Leben, im Leerlauf, während du weiterzeichnest, und wird es angehalten, schließt das seine Dialoge. Nicht unterstützt: Canvas-Widgets und dlg:repaint. (18 Funktionen)
- Konfigurationsformulare: Das Formular vor dem Start, das ein Skript deklariert: Felder für Zahl, Text, Kontrollkästchen, Auswahl, Farbe, Pinsel und Palette.
- Kontexteinstellungen: Die Farben, der Pinsel und die Werkzeugoptionen, die Zeichenbefehle standardmäßig verwenden, plus der Symmetrie-Schalter der Oberfläche (nur zur Information).
- Typen: Jede benannte Wertemenge (FillMode, BlendMode, SymmetryAxis, ...), jeder Wert erklärt.
- Dokument lesen: Wie ein Skript jeden Teil des Dokumentmodells liest.
- Interne Befehle: Engine-Befehle, die Skripte nicht aufrufen können, und warum.
- Bleibt im Editor: Was ein Skript nicht erreicht: Zoom, Bedienfelder, Wiedergabe, Speichern.
Als Markdown: scripting.md; die gesamte Dokumentation in einer Datei: llms-full.txt.