API de scripts

Scripts Lua controlam o mesmo engine em que o editor roda: toda ferramenta, camada, quadro, tile e seleção com que uma pessoa pode trabalhar, legíveis e graváveis por código, com ou sem tela. Esta referência é gerada a partir do próprio engine, então sempre corresponde ao que o app faz: 251 funções (35 leituras, 158 alterações, 58 auxiliares para imagens, números aleatórios, cálculo de cores e janelas de script).

Todas as funções ficam na tabela global app. As chamadas são síncronas do ponto de vista do script. print(...) escreve no console do script, e app.config guarda os valores do formulário de configuração do script (sempre definida, vazia quando não há formulário). As cores são strings "#rgb", "#rrggbb" / "#rrggbbaa" ou tabelas { r, g, b, a }. As coordenadas são pixels inteiros do sprite, com (0, 0) no canto superior esquerdo. Os ids de camadas, quadros, tags e slices são strings. As tabelas Lua começam em 1, e uma lista retornada de números 0/1 ou RGBA vem em ordem de linhas.

  • Comece com app.describe(). Uma única chamada retorna a estrutura de todo o documento: camadas, quadros, cels, tags, slices, seleção e contexto de edição.
  • Criar retorna um id. app.addLayer, app.addFrame, app.addTag e similares retornam o que criaram, válido ao desfazer e refazer.
  • Seleção e simetria são opcionais. Se você omitir uma cor ou um pincel, o contexto de edição os preenche. Seleção e simetria são opcionais: passe respectSelection = true e symmetry = app.getContext().symmetry.
  • Uma execução, um desfazer. Tudo o que um script altera é uma única etapa de desfazer. Camadas bloqueadas são recusadas.
  • Sem limite de tempo. Qualquer execução pode ser pausada, até no meio de um laço, retomada, interrompida, ou interrompida e revertida.
  • Use app.random, não math.random. app.random.new(seed) é um gerador com seed: a mesma seed dá o mesmo resultado em toda execução (e ao refazer), então os scripts devem receber uma seed de app.config e preferi-la a math.random. app.random.hash(x, y, seed) gera ruído por pixel. pairs() também percorre as chaves de uma tabela na mesma ordem em toda execução, então iterar uma tabela de cores não muda a arte.
  • Laços de pixels passam por uma Image. app.getImage, depois img:getPixel / img:setPixel quantas vezes quiser, depois um único app.putImage. Cada chamada app.* é uma ida ao editor; os métodos de uma Image não são.
  • Use app.color, não leitura e mistura de hex feitas à mão. app.color.mix, adjust, ramp, shades, nearest e contrast trabalham em um espaço perceptual (OKLab) e limitam o resultado a sRGB; ler "#rrggbb" com string.sub e tirar a média dos canais dá resultados turvos.
  • Isolado. Sem rede, arquivos nem carregamento de código; um script só pode tocar o sprite aberto. Uma execução tem um orçamento de memória (suas Images, seus dados Lua, o que ela adiciona ao documento e ao histórico de desfazer): ao ultrapassá-lo, o script é interrompido com um erro e o que ele fez até então permanece como uma única etapa de desfazer. app.apiVersion informa a um script em qual versão desta API ele está rodando.

Seções

  • Grupos de opções: As opções de pintura e de pincel compartilhadas pelas funções de desenho, definidas uma única vez.
  • Documento: O sprite como um todo: comece aqui com app.describe() e depois tamanho, recorte, rotação e modo de cor. (15 funções)
  • Desenho: As ferramentas do editor como comandos: as ferramentas da interface despacham exatamente estes. Cor, pincel e opções de ferramenta que você omitir vêm do contexto de edição. A pintura ignora a seleção e a simetria, a menos que você passe respectSelection = true e symmetry = app.getContext().symmetry. (24 funções)
  • Ajustes: Os ajustes de cor e os efeitos de cor (FX) do menu Filtro, cada um como uma etapa de desfazer sobre os cels de uma camada nos quadros que você listar. Ignoram a seleção, a menos que você passe respectSelection = true, e nunca tocam em pixels totalmente transparentes. Em sprites indexados, indexedMode escolhe entre ajustar os pixels recoloridos à entrada da paleta mais próxima ("remap") e editar as entradas da paleta que os cels usam ("palette"). (16 funções)
  • Images: O jeito rápido de trabalhar pixel a pixel. app.getImage lê um cel (ou parte dele) em uma Image, um buffer de pixels que vive dentro do script: img:getPixel e img:setPixel nunca saem do script, então um laço sobre todos os pixels de um cel de 512 x 512 leva cerca de um décimo de segundo. app.putImage a grava de volta como uma única alteração, não importa quantos pixels você defina. Um pixel é um inteiro empacotado (app.pixelColor.rgba(r, g, b, a), como no Aseprite); setPixel também aceita "#rrggbb[aa]" e { r, g, b, a } (alfa padrão 255). Em sprites indexados, img:getIndex e img:setIndex trabalham com índices da paleta, então cores duplicadas continuam distintas. O padrão de uso: 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 funções)
  • Pixels: Leitura e escrita de pixels como listas RGBA planas (construídas sobre Images; nunca recortadas pela seleção nem espelhadas), preenchimentos e inversões da seleção inteira, e o conta-gotas. (7 funções)
  • Seleção: As formas de seleção se combinam com a seleção atual (substituir, adicionar, subtrair, intersectar). A máscara de seleção pode ser lida e escrita. (19 funções)
  • Camadas: Crie, organize e configure camadas. Grupos são pastas de camadas: o parentId de uma camada nomeia o grupo dela (nil no nível superior) e as posições de app.moveLayer contam dentro de um grupo (0 = base). Ocultar ou bloquear um grupo oculta ou bloqueia tudo o que está dentro dele. Um grupo com opacidade total e modo de mesclagem "normal" é pass-through (as camadas dele se mesclam direto no que está abaixo), a menos que a flag isolated esteja definida; um grupo isolado, ou com qualquer outra opacidade ou modo, compõe primeiro as camadas dele entre si. (25 funções)
  • Quadros e tags: A linha do tempo: quadros, suas durações e as tags de animação. (25 funções)
  • Cels: Um cel é a imagem de uma camada em um quadro. Mova, limpe e vincule cels em blocos. (9 funções)
  • Tilemaps: As camadas de tilemap colocam em uma grade tiles do seu próprio tileset. Os tiles são numerados a partir de 1 (0 é o tile vazio). (19 funções)
  • Paleta: A paleta do sprite. (21 funções)
  • Slices: Retângulos nomeados, p. ex. para regiões de exportação ou hitboxes. Um slice também pode ser um 9-slice (um retângulo central) e ter um ponto de pivô; ambos são relativos ao canto superior esquerdo do slice, como no Aseprite, e se movem com ele quando a tela é redimensionada, cortada ou girada. (5 funções)
  • Pincéis: Defina seus próprios pincéis por nome e pinte com eles. Eles existem apenas no engine durante a sessão: não ficam no documento, não podem ser desfeitos, não são salvos e são separados da biblioteca de pincéis do editor. (6 funções)
  • Contexto de edição: As cores, o pincel, a simetria e as opções de ferramenta atuais, compartilhados com a barra de ferramentas do editor. Os comandos de desenho os usam para as cores, o pincel e as opções de ferramenta que não recebem; a simetria é apenas informativa e só é aplicada quando você a passa. (3 funções)
  • Aleatório: Números aleatórios com seed, calculados dentro do script (sem ida e volta a cada chamada). A mesma seed dá os mesmos resultados, então um script pode ser executado de novo, desfeito e refeito, ou compartilhado, e ter sempre a mesma aparência. Prefira estas funções a math.random, que muda a cada execução. Os geradores são objetos: chame seus métodos com dois-pontos (rng:int(1, 6)). (11 funções)
  • Cor: Cálculos de cor sem precisar interpretar hex à mão nem misturar RGB manualmente. Cores de entrada são strings "#rrggbb" / "#rrggbbaa" ou tabelas { r, g, b, a } (0-255, a opcional); cores de saída são tabelas { r, g, b, a }, a menos que o nome indique hex. Misturar e ajustar usam OKLab por padrão, um espaço perceptual em que passos iguais parecem iguais; `space` pode ser "oklab", "oklch", "rgb" ou "hsl". Os resultados são limitados ao sRGB reduzindo o croma, então matiz e luminosidade se mantêm. Listas (ramp, shades) são geradas em uma única chamada. (11 funções)
  • Diálogos e comandos: Interface de script, nos moldes do Aseprite: Dialog{ title = ... } monta uma janela a partir de widgets (label, entry, number, slider, check, radio, combobox, color, shades, button, separator, file) e plugin:newCommand adiciona comandos aos menus, à paleta de comandos e ao editor de Atalhos de teclado. A janela é desenhada pelo editor, somente com texto, com uma barra de título que nomeia o script e a marca como "script". Os callbacks (onclick, onchange, onclose) rodam no script, um de cada vez, cada um como um único passo de desfazer; um script com um diálogo aberto continua vivo, ocioso, enquanto o usuário segue desenhando, e interrompê-lo fecha os diálogos dele. Não há suporte para widgets de canvas nem para dlg:repaint. (18 funções)
  • Formulários de configuração: O formulário que um script declara antes de rodar: campos de número, texto, caixa de seleção, escolha, cor, pincel e paleta.
  • Configurações de contexto: As cores, o pincel e as opções de ferramenta que os comandos de desenho usam por padrão, mais o botão de simetria da interface (apenas informativo).
  • Tipos: Cada conjunto nomeado de valores (FillMode, BlendMode, SymmetryAxis, ...), com cada valor explicado.
  • Leitura do documento: Como um script lê cada parte do modelo do documento.
  • Comandos internos: Comandos do motor que os scripts não podem chamar, e por quê.
  • Fica no editor: O que um script não alcança: zoom, painéis, reprodução, salvamento.

Em Markdown: scripting.md; toda a documentação em um só arquivo: llms-full.txt.