Skip to content

Mastering Asset Packing

In Roblox, image performance is primarily a battle against draw calls. If your UI uses 50 individual images, the engine treats them as 50 separate tasks to load and render. By consolidating these into a single spritesheet, you allow the engine to process everything in a single pass—effectively slashing 50 draw calls down to just one.

In this guide, we’ll walk through how Tungsten automates the complex math of packing images and generates the code needed to use them.

To pack assets, Tungsten needs to know which files belong together. The cleanest way to do this is by organizing your assets/ folder.

Let’s say you have a set of UI icons. Arrange them like this:

  • Directoryassets/
    • Directoryicons/
      • home.png
      • settings.png
      • user.png
      • menu.png

By default, Tungsten syncs files individually. To bundle them into a spritesheet, you need to define an [inputs] entry in your tungsten.toml with packable = true.

[inputs.ui_icons]
path = "assets/icons/**/*"
output_path = "src/IconSheet.luau"
type = "image"
packable = true
  • path: A glob pattern defining which images Tungsten should combine.
  • output_path: The file path where Tungsten will generate the Luau module containing your asset references.
  • packable: A boolean flag that explicitly enables the spritesheet packing logic for this group.

If your images put together exceed 1024×1024, Tungsten automatically creates additional sheets (Sheet_001, Sheet_002, etc.) and generates code that references the correct sheet per sprite.

When sprites are packed into a sheet and scaled in Roblox, transparent edges can show dark fringes from neighboring sprites. Tungsten automatically applies alpha bleeding (color expansion into transparent pixels) to prevent this.

To disable for specific inputs (e.g., full-frame backgrounds):

[inputs.backgrounds]
path = "assets/backgrounds/**/*"
output_path = "src/Backgrounds.luau"
type = "decal"
bleed = false  # Disable alpha bleeding

Default: true for all packed and individual images.

Run your sync command:

tungsten sync cloud

When Tungsten runs, it performs the following:

  1. Locates all images matching your path glob pattern.

  2. Computes the most efficient layout using a rect-packing algorithm (max 1024×1024 per sheet).

  3. Creates the optimized spritesheet image(s) and the output_path Luau module.

  4. Pushes the spritesheet(s) to Roblox.

  5. Refreshes your code generation file with the correct coordinates.

Tungsten generates type-safe code with ImageRectOffset and ImageRectSize pre-calculated.

local Assets = game.ReplicatedStorage.Assets

-- Require the module Tungsten generated
local Icons = require(Assets.IconSheet)

local home = script.Parent

-- Apply the sprite properties automatically
home.Image = Icons.home.Image
home.ImageRectOffset = Icons.home.ImageRectOffset
home.ImageRectSize = Icons.home.ImageRectSize

Tungsten handles the “boring” math of sprite coordinates, so you can simply point your ImageLabel to the asset reference generated by the tool.