Slices and Pivots
Aseprite slices define regions within sprite frames for pivot points, collision boxes, and custom metadata. Slices can have different values per frame for animation-aware positioning.
Creating Slices in Aseprite
- Open your sprite in Aseprite
- Go to Frame > Slices or press
Ctrl+Shift+9 - Create a new slice with the slice tool
- Name the slice (e.g., "pivot", "hitbox", "feet")
- Optionally set pivot and center points
- Export with Slices enabled in JSON settings
Pivot Points
Pivot points control the origin for positioning and rotation.
Default Centering
By default, sprites are centered on the transform position:
gfx.Sprite.fromAseprite("player.png", "idle", {
centered = true -- Default: sprite center at transform
})Slice-Based Pivots
Use an Aseprite slice as the pivot point:
gfx.Sprite.fromAseprite("player.png", "attack", {
pivotSlice = "weapon_origin" -- Use this slice's pivot
})In Aseprite, set the slice's pivot point:
- Select the slice
- In the slice properties, enable Pivot
- Position the pivot within the slice bounds
Top-Left Origin
For classic sprite positioning (origin at top-left):
gfx.Sprite.fromAseprite("player.png", "idle", {
centered = false -- Origin at (0, 0)
})Fallback Behavior
When pivotSlice is specified but the slice or pivot isn't found:
centered | Fallback |
|---|---|
true | Use sprite center (0.5, 0.5) |
false | Use top-left (0, 0) |
Per-Frame Pivots
Slices can have different pivot points per frame, useful for:
- Weapon rotation points that shift during swings
- Feet positions for ground-aligned characters
- Hand positions for held items
Defining Per-Frame Pivots in Aseprite
- Create a slice
- Navigate to different frames
- Adjust the slice position/pivot for each frame
- Aseprite stores "keys" for frames where the slice changes
The animation system automatically uses the correct pivot for each frame.
Example: Rotating Sword
-- In Aseprite:
-- - Create a "sword_pivot" slice
-- - On frame 1: pivot at sword handle
-- - On frame 5: pivot shifts as sword swings
world:spawn(
tecs.builtins.Transform(100, 100, 5, 0, { rotation = 0 }),
gfx.Sprite.fromAseprite("sword.png", "swing", {
pivotSlice = "sword_pivot"
})
)
-- Rotation will occur around the current frame's pivotAccessing Slice Data
local sheet = gfx.SpriteSheet.fromFile("player.png")
local slice = sheet:getSlice("hitbox")
if slice then
-- User data from Aseprite
print(slice.data)
-- Iterate slice keys (per-frame data)
for i, key in ipairs(slice.keys) do
print("Frame:", key.frame)
print("Position:", key.x, key.y)
print("Size:", key.w, key.h)
if key.hasPivot then
print("Pivot:", key.pivotX, key.pivotY)
end
if key.hasCenter then
print("Center:", key.centerX, key.centerY)
end
end
endSlice Key Properties
| Property | Type | Description |
|---|---|---|
frame | integer | Frame number this key applies to |
x, y | number | Slice position within frame |
w, h | number | Slice dimensions |
hasCenter | boolean | Whether center point is defined |
centerX, centerY | number | Center point coordinates |
hasPivot | boolean | Whether pivot point is defined |
pivotX, pivotY | number | Pivot point coordinates |
Common Slice Patterns
Feet Position
Ground-aligned characters with feet at the bottom:
-- In Aseprite: Create "feet" slice at character's feet with pivot
world:spawn(
tecs.builtins.Transform(100, groundY), -- Transform at ground level
gfx.Sprite.fromAseprite("player.png", "idle", {
pivotSlice = "feet" -- Feet touch the ground
})
)Weapon Attach Point
Attach point for weapons or effects:
-- In Aseprite: Create "hand" slice at character's hand
-- Get hand position for spawning weapon
local sprite = world:get(playerId, gfx.Sprite)
local frame = sprite:getAbsoluteFrame()
local sheet = gfx.SpriteSheet.fromFile("player.png")
local slice = sheet:getSlice("hand")
-- Find key for current frame
for _, key in ipairs(slice.keys) do
if key.frame == frame then
-- Spawn weapon at hand position
local handX = playerX + key.x
local handY = playerY + key.y
break
end
endHit/Hurt Boxes
Collision regions for combat:
-- In Aseprite: Create "hitbox" and "hurtbox" slices
-- Read hitbox for current frame
local sprite = world:get(entityId, gfx.Sprite)
local hitbox = getSliceForFrame(sheet, "hitbox", sprite:getAbsoluteFrame())Overriding with Pivot Component
The Pivot component overrides slice-based pivots:
-- This uses the Pivot component, not pivotSlice
world:spawn(
tecs.builtins.Transform(100, 100),
gfx.Sprite.fromAseprite("player.png", "idle", {
pivotSlice = "feet" -- Ignored when Pivot component exists
}),
gfx.Pivot(0.5, 1.0) -- Bottom-center pivot
)Priority order:
Pivotcomponent (highest)pivotSliceoptioncenteredoption (default: true → center, false → top-left)