# `tecs.gfx.sheet`
A sprite sheet divides one image into frames, tags, and slices.
Aseprite supplies the model: each frame carries its own duration, tags play
inclusive spans in a direction, and slices carry rectangles, nine-slice
centers, and pivots that may move between frames. `fromAseprite` reads its JSON
export into the same interface `grid`, `rects`, and `build` produce.
```nupp
const hero = tecs.gfx.sheet.grid({
name = "game.hero",
imageWidth = 256,
imageHeight = 32,
frameWidth = 32,
frameHeight = 32,
tags = {idle = {from = 1, to = 4}, run = {from = 5, to = 8}},
})
hero:bind(tecs.gfx.images.id("sprites/hero"))
world:spawn(
tecs.ecs.Transform2D(64, 64, 0, 1, 0, 32, 32),
tecs.gfx.Tint(1, 1, 1, 1),
hero:sprite(),
tecs.gfx.Renderable2D
)
```
Frames count from one in sheet order. Tag zero is the whole sheet playing
forward, which is what an animation naming no tag plays.
`bind` resolves the sheet's pixel rectangles against a `tecs.gfx.images` id, so
`sprite` and `uv` then answer the region a
[`Sprite`](tecs.gfx.Sprite) samples. A sheet is usable before that:
until it is bound, a frame's region is its plain fraction of the image.
A sheet name is a snapshot compatibility surface. Every entity playing the
sheet shares its registered frame, tag, slice, and timing data.
# Pivots
`pivotOf` answers a slice's pivot as a fraction of its frame, which is what an
attachment point on a hand, a muzzle, or a pair of feet is measured in. No
component carries one: a frame packet places a quad by its center, so a pivot
is a number a game reads rather than something the renderer applies. The render
lane owns adding a quad origin, and a pivot becomes a component when it does.
## Types
### `AsepriteOptions` _type_
```nupp
type AsepriteOptions = {
name: string?,
json: any
}
```
Configures a sheet read from an Aseprite JSON export.
### `Builder` _record_
```nupp
record Builder
frame: function(self: Builder, x: number, y: number, w: number, h: number, duration: number?): Builder
tag: function(self: Builder, name: string, from: integer, to: integer, direction: Direction?): Builder
slice: function(
self: Builder,
name: string,
x: number,
y: number,
w: number,
h: number,
pivotX: number?,
pivotY: number?
): Builder
sliceKeys: function(self: Builder, name: string, data: string?, keys: {SliceKey}): Builder
finish: function(self: Builder): Sheet
end
```
Builds a sheet one frame, tag, and slice at a time.
What every constructor here goes through, and what an importer for a format
nothing else reads writes into.
#### Methods
##### `frame`
```nupp
frame: function(self: Builder, x: number, y: number, w: number, h: number, duration: number?): Builder
```
Appends a frame to the sheet under construction.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Builder` | |
| `x` | `number` | |
| `y` | `number` | |
| `w` | `number` | |
| `h` | `number` | |
| `duration` | `number?` | |
###### Returns
| Type | Description |
| --- | --- |
| `Builder` | |
###### Raises
- when the frame has no positive size
##### `tag`
```nupp
tag: function(self: Builder, name: string, from: integer, to: integer, direction: Direction?): Builder
```
Names an inclusive frame span and its playback direction.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Builder` | |
| `name` | `string` | |
| `from` | `integer` | |
| `to` | `integer` | |
| `direction` | `Direction?` | |
###### Returns
| Type | Description |
| --- | --- |
| `Builder` | |
###### Raises
- when the name is empty
##### `slice`
```nupp
slice: function(
self: Builder,
name: string,
x: number,
y: number,
w: number,
h: number,
pivotX: number?,
pivotY: number?
): Builder
```
Adds a fixed slice carrying one pivot.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Builder` | |
| `name` | `string` | |
| `x` | `number` | |
| `y` | `number` | |
| `w` | `number` | |
| `h` | `number` | |
| `pivotX` | `number?` | |
| `pivotY` | `number?` | |
###### Returns
| Type | Description |
| --- | --- |
| `Builder` | |
##### `sliceKeys`
```nupp
sliceKeys: function(self: Builder, name: string, data: string?, keys: {SliceKey}): Builder
```
Adds a slice from explicit keys, which is what an importer writes.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Builder` | |
| `name` | `string` | |
| `data` | `string?` | |
| `keys` | `{SliceKey}` | |
###### Returns
| Type | Description |
| --- | --- |
| `Builder` | |
##### `finish`
```nupp
finish: function(self: Builder): Sheet
```
Registers and returns the finished sheet.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Builder` | |
###### Returns
| Type | Description |
| --- | --- |
| `Sheet` | |
###### Raises
- when the sheet has no frames, when a tag's span falls outside them, or when a slice has no name or no keys
### `Direction` _type_
```nupp
type Direction = "forward" | "reverse" | "pingpong"
```
Selects how a tag walks its span.
`pingpong` plays forward and then back without repeating either end, so a
three-frame tag is 1, 2, 3, 2 and then round again.
These identifiers reach an Aseprite export and configuration a developer
writes, so they are a compatibility surface.
### `GridOptions` _type_
```nupp
type GridOptions = {
name: string,
imageWidth: number,
imageHeight: number,
frameWidth: number,
frameHeight: number,
margin: number?,
spacing: number?,
columns: integer?,
rows: integer?,
count: integer?,
duration: number?,
tags: {[string]: Tag}?,
slices: {Slice}?
}
```
Configures a sheet cut into a uniform grid.
### `PivotValue` _struct_
```nupp
struct PivotValue
x: number
y: number
sheet: integer
slice: integer
end
```
`@derive(nupp.derive.Debug, nupp.derive.Serde)`
A sprite's anchor as fractions of its frame. A bound slice follows its
authored keys during GPU animation without updating the component.
#### Fields
##### `x`
```nupp
x: number
```
Caller-writable horizontal anchor; one half selects the center.
##### `y`
```nupp
y: number
```
Caller-writable vertical anchor; one half selects the center.
##### `sheet`
```nupp
sheet: integer
```
Caller-writable sheet id, or zero for a direct anchor.
##### `slice`
```nupp
slice: integer
```
Caller-writable slice id, or zero for a direct anchor.
### `Rect` _type_
```nupp
type Rect = {
x: number?,
y: number?,
w: number,
h: number,
duration: number?
}
```
Defines one frame's pixel rectangle and duration.
`x` and `y` default to zero, and `duration` to `DEFAULT_DURATION`
milliseconds. These keys are the sheet format's own and are a compatibility
surface.
### `RectsOptions` _type_
```nupp
type RectsOptions = {
name: string,
imageWidth: number,
imageHeight: number,
frames: {Rect},
tags: {[string]: Tag}?,
slices: {Slice}?
}
```
Configures a sheet cut into explicitly listed rectangles.
### `Sheet` _record_
```nupp
record Sheet
name: string
id: integer
count: integer
imageWidth: number
imageHeight: number
rect: function(self: Sheet, frame: integer): (number, number, number, number)
duration: function(self: Sheet, frame: integer): number
uv: function(self: Sheet, frame: integer): (number, number, number, number)
hasTag: function(self: Sheet, name: string): boolean
tag: function(self: Sheet, name: string): (integer, integer, Direction)
tagId: function(self: Sheet, name: string?): integer
tagName: function(self: Sheet, id: integer): string
tagCount: function(self: Sheet): integer
cycle: function(self: Sheet, id: integer): number
frameAt: function(self: Sheet, id: integer, time: number): integer
pivot: function(
self: Sheet,
name: string,
frame: integer?
): components.FFIInstance>
slice: function(self: Sheet, name: string): Slice?
sliceId: function(self: Sheet, name: string?): integer
sliceName: function(self: Sheet, id: integer): string
sliceKeyAt: function(self: Sheet, id: integer, frame: integer): SliceKey?
pivotOf: function(self: Sheet, id: integer, frame: integer): (number, number)
boundImage: function(self: Sheet): integer
bind: function(self: Sheet, image: integer, u0: number?, v0: number?, u1: number?, v1: number?): Sheet
sprite: function(
self: Sheet,
frame: integer?
): components.FFIInstance>
end
```
Represents an image divided into frames.
#### Methods
##### `rect`
```nupp
rect: function(self: Sheet, frame: integer): (number, number, number, number)
```
Returns a frame's pixel rectangle.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `frame` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `number` | |
| `number` | |
| `number` | |
| `number` | |
###### Raises
- when the frame is outside the sheet, because that is a sheet and an animation disagreeing rather than something to paper over
##### `duration`
```nupp
duration: function(self: Sheet, frame: integer): number
```
Returns how long a frame stays visible.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `frame` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `number` | |
###### Raises
- when the frame is outside the sheet
##### `uv`
```nupp
uv: function(self: Sheet, frame: integer): (number, number, number, number)
```
Returns a frame's region.
Fractions of the image before `bind`, and of the bound image's region after
it, which is what a [`Sprite`](tecs.gfx.Sprite) samples.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `frame` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `number` | |
| `number` | |
| `number` | |
| `number` | |
###### Raises
- when the frame is outside the sheet
##### `hasTag`
```nupp
hasTag: function(self: Sheet, name: string): boolean
```
Returns whether the sheet carries a tag.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `boolean` | |
##### `tag`
```nupp
tag: function(self: Sheet, name: string): (integer, integer, Direction)
```
Returns a named tag's span and direction.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
| `integer` | |
| `Direction` | |
###### Raises
- when the sheet carries no such tag, because the alternative is an animation silently playing the whole sheet on a typo
##### `tagId`
```nupp
tagId: function(self: Sheet, name: string?): integer
```
Returns the index a tag name represents, or zero when the sheet has none.
Zero reads as the whole sheet rather than as nothing, so an animation
naming no tag plays every frame in order.
A name the sheet does not carry is reported at error level under the
`tecs.gfx` logger and then treated as the whole sheet, because zero is a
plausible wrong answer rather than a visible failure. The report names the
sheet, the name asked for, and the tags the sheet does carry, once per sheet
and name however often the name is asked. Call `hasTag` instead when a
name's absence is expected and ordinary.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string?` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `tagName`
```nupp
tagName: function(self: Sheet, id: integer): string
```
Returns the name a tag index represents.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
##### `tagCount`
```nupp
tagCount: function(self: Sheet): integer
```
Returns how many named tags the sheet carries.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `cycle`
```nupp
cycle: function(self: Sheet, id: integer): number
```
Returns the duration of one tag cycle.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `number` | |
##### `frameAt`
```nupp
frameAt: function(self: Sheet, id: integer, time: number): integer
```
Returns the frame a tag shows at a point in its cycle.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
| `time` | `number` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `pivot`
```nupp
pivot: function(
self: Sheet,
name: string,
frame: integer?
): components.FFIInstance>
```
Creates an anchor that follows a named slice.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string` | |
| `frame` | `integer?` | |
###### Returns
| Type | Description |
| --- | --- |
| `components.FFIInstance\\>` | |
##### `slice`
```nupp
slice: function(self: Sheet, name: string): Slice?
```
Returns a slice by name.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string` | |
###### Returns
| Type | Description |
| --- | --- |
| `Slice?` | |
##### `sliceId`
```nupp
sliceId: function(self: Sheet, name: string?): integer
```
Returns the index a slice name represents, or zero when the sheet has none.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `name` | `string?` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `sliceName`
```nupp
sliceName: function(self: Sheet, id: integer): string
```
Returns the name a slice index represents.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `string` | |
##### `sliceKeyAt`
```nupp
sliceKeyAt: function(self: Sheet, id: integer, frame: integer): SliceKey?
```
Returns the slice key in effect on a frame.
A slice holds a key until the next one, so this answers the last key at or
before the frame rather than only an exact match.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
| `frame` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `SliceKey?` | |
##### `pivotOf`
```nupp
pivotOf: function(self: Sheet, id: integer, frame: integer): (number, number)
```
Returns a slice's pivot as a fraction of its frame.
Aseprite writes a pivot in the slice's own pixels, so this adds the slice's
origin and divides by the frame, which is the number a quad wants: nothing
downstream has to know the sheet's pixel sizes.
A slice with a center but no pivot answers the center's middle, and a slice
with neither answers the middle of its own rectangle. Zero, a slice the
sheet does not carry, and a frame it has no key for all answer the middle of
the frame, which is where a quad sits with no pivot at all.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `id` | `integer` | |
| `frame` | `integer` | |
###### Returns
| Type | Description |
| --- | --- |
| `number` | |
| `number` | |
##### `boundImage`
```nupp
boundImage: function(self: Sheet): integer
```
Returns the image this sheet was last bound to.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
###### Returns
| Type | Description |
| --- | --- |
| `integer` | |
##### `bind`
```nupp
bind: function(self: Sheet, image: integer, u0: number?, v0: number?, u1: number?, v1: number?): Sheet
```
Resolves the sheet's frames against an image.
The optional region names the part of the image the sheet occupies, which
is what an atlas packer places it at, and defaults to the whole image. Frame
rectangles are scaled into it, so passing a region smaller than the sheet
describes places the frames inside that region rather than across the image.
Binding again rescales from the pixel rectangles rather than from the
previous result, so re-registering an image accumulates no scaling error.
Entities already carrying regions from an earlier bind keep them: a rebind
updates no existing [`Sprite`](tecs.gfx.Sprite).
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `image` | `integer` | |
| `u0` | `number?` | |
| `v0` | `number?` | |
| `u1` | `number?` | |
| `v1` | `number?` | |
###### Returns
| Type | Description |
| --- | --- |
| `Sheet` | |
##### `sprite`
```nupp
sprite: function(
self: Sheet,
frame: integer?
): components.FFIInstance>
```
Creates a sprite showing one frame, ready to spawn.
Meaningful after `bind`, since before it the sheet names no image and the
quad samples the backend's white fallback.
###### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `self` | `Sheet` | |
| `frame` | `integer?` | |
###### Returns
| Type | Description |
| --- | --- |
| `components.FFIInstance\\>` | |
###### Raises
- when the frame is outside the sheet
#### Fields
##### `name`
```nupp
name: string
```
Read-only. Reports the registered name a snapshot stores.
##### `id`
```nupp
id: integer
```
Read-only. Reports the registration index an `Animation` carries.
Construction assigns an id once and never reuses it.
##### `count`
```nupp
count: integer
```
Read-only. Reports the number of frames, which is the largest index
`rect`, `uv`, and `sprite` accept.
##### `imageWidth`
```nupp
imageWidth: number
```
Read-only. Reports the source image width in pixels. Frame rectangles
are measured in it, so binding to an image of another size places
frames wrongly.
##### `imageHeight`
```nupp
imageHeight: number
```
Read-only. Reports the source image height in pixels.
### `Slice` _type_
```nupp
type Slice = {
name: string,
data: string?,
keys: {SliceKey}
}
```
Represents a named region that moves across frames.
Aseprite's slices carry hitboxes, attachment points, and nine-patch
borders. Tecs reads pivots out of them; everything else is the game's to
use. These keys are the sheet format's own and are a compatibility surface.
### `SliceKey` _type_
```nupp
type SliceKey = {
frame: integer?,
x: number?,
y: number?,
w: number?,
h: number?,
centerX: number?,
centerY: number?,
centerW: number?,
centerH: number?,
pivotX: number?,
pivotY: number?
}
```
Defines where a slice sits from one frame onward and which points it
carries.
A slice holds a key until the next one, so a slice that never moves is one
key at frame one. A nil `centerX` means the slice names no nine-slice
center, and a nil `pivotX` means it names no pivot. These keys are the
sheet format's own and are a compatibility surface.
### `Tag` _type_
```nupp
type Tag = {
from: integer,
to: integer,
direction: Direction?
}
```
Defines an inclusive frame span and its playback direction.
Aseprite calls this a frame tag, and a tag's name is what an animation asks
for. `direction` defaults to `"forward"`. These keys are the sheet format's
own and are a compatibility surface.
## Functions
### `build` _function_
```nupp
function build(name: string, imageWidth: number, imageHeight: number): Builder
```
Creates a builder for a sheet the other constructors cannot describe.
The model is what the builder writes, so an atlas from any tool reaches the
same sheet an Aseprite export does. Frames, tags, and slices are added in
any order, and `finish` registers the result.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | the name to register the finished sheet under |
| `imageWidth` | `number` | the width in pixels of the image the frames are cut from |
| `imageHeight` | `number` | the height in pixels of that image |
#### Returns
| Type | Description |
| --- | --- |
| `Builder` | a builder whose methods chain |
#### Raises
- when the name is empty or either dimension is not positive
### `byId` _function_
```nupp
function byId(id: integer): Sheet?
```
Returns the sheet a registration index names.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `id` | `integer` | an `id` from a sheet this process built; ids are assigned in build order, so one is meaningful only within a run |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet?` | the sheet, or nil when nothing was built under the id |
### `byName` _function_
```nupp
function byName(name: string): Sheet?
```
Returns the sheet a name names.
Building a second sheet under a taken name replaces what this returns, so a
reload points new entities at the new sheet. Entities already carrying the
old id keep drawing the old one, which is what stops a reload pulling a
frame out from under them.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `name` | `string` | the name a sheet was built under |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet?` | the sheet most recently registered under the name, or nil |
### `fromAseprite` _function_
```nupp
function fromAseprite(options: AsepriteOptions): Sheet
```
Creates a sheet from an Aseprite JSON export.
One reader in front of the model rather than a second model: frames, their
durations, frame tags with their directions, and slices with their keys all
land in the sheet the builder writes.
The reader accepts Aseprite's array layout and its object layout, sorting
the latter by frame name. It ignores `spriteSourceSize`, so export with
trimming off.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `AsepriteOptions` | the export as JSON text or an already-decoded table, and the name to register it under; the name defaults to the export's image name |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet` | the finished sheet, already registered |
#### Raises
- when the export is not readable, when it names no image and the caller supplied no name, or when a frame carries no rectangle
### `grid` _function_
```nupp
function grid(options: GridOptions): Sheet
```
Creates a sheet whose frames form a uniform grid.
Margin surrounds the grid and spacing separates the cells, so a cell's left
edge is `margin + column * (frameWidth + spacing)`. Both default to zero,
which is an image cut with nothing between its cells. Frames come out in
row-major order.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `GridOptions` | the image size, the cell size, and the optional grid shape, tags, and slices |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet` | the finished sheet, already registered under its name and carrying an `id` |
#### Raises
- on a missing name, a non-positive image or frame size, a grid that fits no cells, or a `count` past what the grid holds
### `rects` _function_
```nupp
function rects(options: RectsOptions): Sheet
```
Creates a sheet from explicitly listed frame rectangles.
For an image no grid describes: frames of differing sizes, or an atlas whose
cells a packing tool placed. Rectangles are not checked against the image, so
one running off the edge samples whatever the image holds there.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `options` | `RectsOptions` | the image size, the frame list, and the optional tags and slices |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet` | the finished sheet, already registered under its name and carrying an `id` |
#### Raises
- on a missing name, a non-positive image size, an empty frame list, or a frame with no positive size
### `replace` _function_
```nupp
function replace(built: Sheet): Sheet?, string?
```
Folds a freshly built sheet into the one already registered under its name,
keeping the old sheet's id.
The reverse of what building under a taken name does, and it exists because
a reload wants the reverse. Building again answers new entities with the new
sheet and leaves every entity already playing on the old one, which is right
for two sheets that happen to share a name and wrong for one file that was
re-exported. This overwrites in place instead, so an `Animation` holding the
id continues and shows the new frames on its next step without the world
changing.
The refusals exist because a component holds an index into this sheet, so
anything this refuses is a change that would renumber one. Tag ids follow
the tag names in sorted order and slice ids follow the slices, so adding,
removing, or renaming either is a restart. Frames are free to change: an
entity carries a tag and a time, and each step resolves its frame from the
cycle.
Replacement keeps the live sheet's bind and rescales the new frames against
it, so a caller need not bind again.
The sheet handed in is spent. Its id resolves to the live sheet rather than
to itself, because the two share their frame tables once the fold is done
and only one of them may be bound.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `built` | `Sheet` | a sheet from any constructor here, registered moments ago under a name something else already held |
#### Returns
| Type | Description |
| --- | --- |
| `Sheet?` | the live sheet, or nil and the refusal reason |
| `string?` | |
### `revision` _function_
```nupp
function revision(): integer
```
Returns how many times any sheet's frames have changed.
Bumped by registration and by `bind`, both of which move where a frame's
region points. Anything holding a copy of those regions compares this
against what it copied at rather than being told, which keeps the dependency
running one way: a sheet knows nothing about who read it.
#### Returns
| Type | Description |
| --- | --- |
| `integer` | a count that only ever rises |
## Values
### `DEFAULT_DURATION` _variable_
```nupp
const DEFAULT_DURATION: number
```
The milliseconds a frame is held when nothing says otherwise, which is what
Aseprite writes for a frame nobody retimed.
### `Pivot` _variable_
```nupp
const Pivot
```
Anchors a sprite directly, or follows a sheet slice. Snapshots store names.