Skip to main content

Overview

Batch processing allows you to apply the same operations to multiple files automatically. This is essential for managing large projects with many sprites.

Running Batch Scripts from Command Line

Aseprite can run scripts in batch mode without opening the GUI:
aseprite -b --script batch-process.lua

Basic File Processing Loop

Here’s a template for processing multiple files:
-- List of files to process
local files = {
  "sprites/character1.aseprite",
  "sprites/character2.aseprite",
  "sprites/character3.aseprite"
}

-- Process each file
for _, filename in ipairs(files) do
  print("Processing: " .. filename)
  
  -- Open the file
  local sprite = app.open(filename)
  
  if sprite then
    -- Do processing here
    -- sprite:resize(64, 64)
    -- app.command.Flatten()
    
    -- Save the changes
    sprite:save()
    
    -- Close the sprite
    sprite:close()
    
    print("Completed: " .. filename)
  else
    print("Error opening: " .. filename)
  end
end

print("Batch processing complete!")

Discovering Files Automatically

Use the file system API to find files automatically:
local fs = app.fs

-- Get the current directory
local inputDir = fs.currentPath .. "/sprites"

if not fs.isDirectory(inputDir) then
  print("Directory not found: " .. inputDir)
  return
end

-- List all files
local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  local fullPath = fs.joinPath(inputDir, filename)
  
  -- Process only .aseprite files
  if fs.fileExtension(filename) == "aseprite" then
    print("Processing: " .. filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      -- Process sprite...
      sprite:save()
      sprite:close()
    end
  end
end

Batch Export to PNG

Convert all Aseprite files to PNG:
local fs = app.fs

local inputDir = "./input"
local outputDir = "./output"

-- Create output directory if it doesn't exist
if not fs.isDirectory(outputDir) then
  fs.makeDirectory(outputDir)
end

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local inputPath = fs.joinPath(inputDir, filename)
    local baseName = fs.fileTitle(filename)
    local outputPath = fs.joinPath(outputDir, baseName .. ".png")
    
    print("Converting: " .. filename)
    
    local sprite = app.open(inputPath)
    if sprite then
      sprite:saveCopyAs(outputPath)
      sprite:close()
      print("Saved: " .. outputPath)
    end
  end
end

print("Export complete!")

Batch Resize All Sprites

local fs = app.fs

local inputDir = "./sprites"
local targetWidth = 64
local targetHeight = 64

local files = fs.listFiles(inputDir)
local processedCount = 0

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      local oldSize = sprite.width .. "x" .. sprite.height
      
      sprite:resize(targetWidth, targetHeight)
      sprite:save()
      
      print(string.format("%s: %s -> %dx%d",
        filename, oldSize, targetWidth, targetHeight))
      
      sprite:close()
      processedCount = processedCount + 1
    end
  end
end

print("Resized " .. processedCount .. " sprites")

Batch Export Sprite Sheets

Export all animations as sprite sheets:
local fs = app.fs

local inputDir = "./animations"
local outputDir = "./spritesheets"

if not fs.isDirectory(outputDir) then
  fs.makeDirectory(outputDir)
end

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local inputPath = fs.joinPath(inputDir, filename)
    local baseName = fs.fileTitle(filename)
    local outputPath = fs.joinPath(outputDir, baseName .. ".png")
    
    print("Exporting sprite sheet: " .. filename)
    
    local sprite = app.open(inputPath)
    if sprite then
      app.sprite = sprite
      
      app.command.ExportSpriteSheet{
        type = SpriteSheetType.HORIZONTAL,
        textureFilename = outputPath,
        shapePadding = 1,
        borderPadding = 0
      }
      
      sprite:close()
      print("Saved: " .. outputPath)
    end
  end
end

print("Sprite sheet export complete!")

Batch Apply Color Adjustments

local fs = app.fs

local inputDir = "./sprites"
local brightnessAdjust = 20
local contrastAdjust = 10

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    print("Adjusting: " .. filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      app.sprite = sprite
      
      app.command.BrightnessContrast{
        brightness = brightnessAdjust,
        contrast = contrastAdjust
      }
      
      sprite:save()
      sprite:close()
    end
  end
end

print("Applied color adjustments")
Add a copyright layer to all sprites:
local fs = app.fs

local inputDir = "./sprites"
local copyrightText = "Copyright 2024"

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      -- Create copyright layer
      local layer = sprite:newLayer()
      layer.name = "Copyright"
      
      -- Lock the layer so it's not accidentally edited
      layer.isEditable = false
      
      print("Added copyright layer to: " .. filename)
      
      sprite:save()
      sprite:close()
    end
  end
end

print("Added copyright layers")

Batch Flatten Layers

local fs = app.fs

local inputDir = "./sprites"
local outputDir = "./flattened"

if not fs.isDirectory(outputDir) then
  fs.makeDirectory(outputDir)
end

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local inputPath = fs.joinPath(inputDir, filename)
    local outputPath = fs.joinPath(outputDir, filename)
    
    local sprite = app.open(inputPath)
    if sprite then
      local layerCount = #sprite.layers
      
      sprite:flatten()
      
      print(string.format("%s: flattened %d layers",
        filename, layerCount))
      
      sprite:saveAs(outputPath)
      sprite:close()
    end
  end
end

print("Flattening complete!")

Batch Convert Color Mode

Convert all sprites to indexed color:
local fs = app.fs

local inputDir = "./sprites"

local files = fs.listFiles(inputDir)
local convertedCount = 0

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      local oldMode = sprite.colorMode
      
      if oldMode ~= ColorMode.INDEXED then
        app.sprite = sprite
        app.command.ChangePixelFormat{ format="indexed" }
        
        sprite:save()
        
        print(string.format("%s: converted to indexed", filename))
        convertedCount = convertedCount + 1
      else
        print(string.format("%s: already indexed", filename))
      end
      
      sprite:close()
    end
  end
end

print("Converted " .. convertedCount .. " sprites to indexed color")

Batch Trim Transparent Pixels

local fs = app.fs

local inputDir = "./sprites"

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      local oldSize = sprite.width .. "x" .. sprite.height
      
      app.sprite = sprite
      app.command.AutocropSprite()
      
      local newSize = sprite.width .. "x" .. sprite.height
      
      if oldSize ~= newSize then
        sprite:save()
        print(string.format("%s: trimmed from %s to %s",
          filename, oldSize, newSize))
      else
        print(string.format("%s: no trim needed", filename))
      end
      
      sprite:close()
    end
  end
end

print("Trim complete!")

Batch Add Grid Overlay

local fs = app.fs

local inputDir = "./sprites"
local gridWidth = 16
local gridHeight = 16

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    local sprite = app.open(fullPath)
    if sprite then
      -- Set grid bounds
      sprite.gridBounds = Rectangle(0, 0, gridWidth, gridHeight)
      
      sprite:save()
      
      print(string.format("%s: set grid to %dx%d",
        filename, gridWidth, gridHeight))
      
      sprite:close()
    end
  end
end

print("Grid settings applied")

Batch Export at Different Scales

Export sprites at multiple scales (1x, 2x, 4x):
local fs = app.fs

local inputDir = "./sprites"
local outputDir = "./exports"
local scales = { 1, 2, 4 }

for _, scale in ipairs(scales) do
  local scaleDir = fs.joinPath(outputDir, scale .. "x")
  if not fs.isDirectory(scaleDir) then
    fs.makeAllDirectories(scaleDir)
  end
end

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local inputPath = fs.joinPath(inputDir, filename)
    local baseName = fs.fileTitle(filename)
    
    print("Exporting: " .. filename)
    
    local sprite = app.open(inputPath)
    if sprite then
      app.sprite = sprite
      
      for _, scale in ipairs(scales) do
        local outputPath = fs.joinPath(
          outputDir,
          scale .. "x",
          baseName .. ".png"
        )
        
        app.command.SaveFileCopyAs{
          filename = outputPath,
          scale = scale
        }
        
        print(string.format("  Saved %dx: %s", scale, outputPath))
      end
      
      sprite:close()
    end
  end
end

print("Multi-scale export complete!")

Command-Line Usage

You can pass arguments to your batch scripts:
# Run batch script
aseprite -b --script batch-export.lua

# Process specific file
aseprite -b sprite.aseprite --script resize.lua --save-as output.png

# Chain multiple operations
aseprite -b input.aseprite --script process.lua --scale 2 --save-as output.png

Error Handling in Batch Processing

local fs = app.fs

local inputDir = "./sprites"
local errors = {}

local files = fs.listFiles(inputDir)

for _, filename in ipairs(files) do
  if fs.fileExtension(filename) == "aseprite" then
    local fullPath = fs.joinPath(inputDir, filename)
    
    -- Use pcall for error handling
    local success, err = pcall(function()
      local sprite = app.open(fullPath)
      if not sprite then
        error("Failed to open file")
      end
      
      -- Process sprite...
      sprite:resize(64, 64)
      sprite:save()
      sprite:close()
      
      print("Processed: " .. filename)
    end)
    
    if not success then
      table.insert(errors, { file = filename, error = err })
      print("ERROR with " .. filename .. ": " .. err)
    end
  end
end

print("\nProcessing complete!")
if #errors > 0 then
  print("Errors encountered: " .. #errors)
  for _, e in ipairs(errors) do
    print("  " .. e.file .. ": " .. e.error)
  end
end

Next Steps

Automation Examples

Automate repetitive tasks

Custom Tools

Create custom drawing tools

Scripting Introduction

Learn the basics of scripting