Documentation
¶
Overview ¶
Package sff defines the pure-data model for MUGEN/Ikemen GO sprite (.sff) files: Sprite and SpriteGroup.
This is the read-path surface — the stable vocabulary a library consumer (editor, engine) works with. It carries no binary decoding, file I/O, or write-only (format-preservation) logic; per CLAUDE.md's read/write separation constraint, that lives elsewhere so importing this data model alone never pulls in write-only dependencies.
The model is version-agnostic: MUGEN's .sff format has two on-disk versions (v1 and v2) with different header/table layouts and pixel encodings, but both describe the same logical sprite metadata. No v1/v2-specific field lives here — each version's parser (added separately) is responsible for populating this shared shape. Sprite pixel data itself is also out of scope here; only the metadata needed to reference and place a sprite is modeled.
Package sff reads and writes MUGEN/Ikemen GO sprite sheet (.sff) files, v1 and v2, and resolves sprite palettes (including external .act overrides). It has no rendering dependency and compiles to WebAssembly.
Index ¶
- Constants
- func EncodeExternalPalette(p Palette) []byte
- func EncodePCX(img *PCXImage) ([]byte, error)
- func EncodeV1Palette(p Palette) []byte
- func EncodeV2Palette(p Palette, colorCount int) ([]byte, error)
- func EncodeV2Sprite(format int, img *V2Image) ([]byte, error)
- func ResolvePixels(indices []byte, palette Palette, rule AlphaRule) []color.RGBA
- func ResolveSpritePixels(r io.ReaderAt, group, image int, override *Palette) ([]color.RGBA, int, int, error)
- func SerializeV1(w io.Writer, version [4]byte, sharedPalette bool, sprites []V1WriteSprite) error
- func SerializeV2(w io.Writer, version [4]byte, sprites []V2WriteSprite, ...) error
- type AlphaRule
- type PCXImage
- type Palette
- func DecodeExternalPalette(data []byte) (Palette, error)
- func DecodeV1Palette(data []byte) (Palette, error)
- func DecodeV2Palette(data []byte) (Palette, error)
- func ResolveV1Palette(table *V1SpriteTable, r io.ReaderAt, i int, override *Palette) (Palette, error)
- func ResolveV2Palette(table *V2SpriteTable, r io.ReaderAt, index int, override *Palette) (Palette, error)
- type Sprite
- type SpriteGroup
- type V1Header
- type V1SpriteEntry
- type V1SpriteTable
- type V1WriteSprite
- type V2Header
- type V2Image
- type V2PaletteEntry
- type V2SpriteEntry
- type V2SpriteTable
- type V2WritePalette
- type V2WriteSprite
Constants ¶
const ( V2FormatRaw = 0 V2FormatRLE8 = 2 V2FormatRLE5 = 3 V2FormatLZ5 = 4 V2FormatPNG8 = 10 V2FormatPNG24 = 11 V2FormatPNG32 = 12 )
Pixel-data format codes, as stored in each V2SpriteEntry's Format field. The v2 pixel decoder (a later, separate piece of work) is responsible for interpreting these; ParseV2 only records them.
const SpritePixelDimensionLimit = 4096
SpritePixelDimensionLimit guards ResolveSpritePixels against a corrupt or adversarial .sff file declaring an implausibly large sprite: unlike the rest of this package's decode path, ResolveSpritePixels is reachable directly from untrusted caller-supplied bytes (the WASM boundary, see cmd/wasm and .vibe/decisions/013-wasm-sprite-pixel-resolution-batched-stateless-contract.md). 4096 per axis comfortably exceeds every known real MUGEN/Ikemen sprite (typically well under 1024x1024).
const V1PaletteBlockSize = 768
V1PaletteBlockSize is the fixed size, in bytes, of a .sff v1 sprite's embedded 256-color RGB palette block.
const Version = "0.3.0"
Version is the library version.
Variables ¶
This section is empty.
Functions ¶
func EncodeExternalPalette ¶
EncodeExternalPalette encodes p into a standalone externalPaletteSize-byte (768) MUGEN/Ikemen .act palette file buffer — the exact inverse of DecodeExternalPalette's index reversal. Alpha is ignored: like v1's embedded palette, an .act file has no on-disk alpha channel and always stores opaque triplets, so p's own alpha values (including the forced- transparent index 0 DecodeExternalPalette produces) are not written back.
func EncodePCX ¶
EncodePCX encodes a pure pixel buffer into RLE-compressed, 8-bit indexed PCX image data — the pixel encoding used by MUGEN/Ikemen GO .sff v1 sprites — so it can be written into a .sff v1 file (see SerializeV1). It is the write-path counterpart of DecodePCX.
EncodePCX always emits run-length units (never a bare literal byte), even for a run of a single pixel: this keeps the output unambiguous and the encoder simple, at the cost of not matching the byte-for-byte output an original MUGEN-authored file might use for the same pixels — see .vibe/decisions/005-sff-v1-serialize-is-semantic-not-byte-exact-round-trip.md. Every unit produced is guaranteed decodable by DecodePCX.
func EncodeV1Palette ¶
EncodeV1Palette encodes p into a V1PaletteBlockSize-byte (768) v1 embedded palette block — 256 RGB triplets, 3 bytes/color — the exact inverse of DecodeV1Palette. Alpha is ignored: a v1 embedded palette has no on-disk alpha channel (DecodeV1Palette always resolves it to opaque), so encoding two palettes that differ only in alpha produces identical bytes.
func EncodeV2Palette ¶
EncodeV2Palette encodes the first colorCount colors of p into v2 palette bank color data — RGBA, 4 bytes/color — the exact inverse of DecodeV2Palette. colorCount must be between 0 and 256 inclusive; entries of p beyond colorCount are not written, mirroring how DecodeV2Palette leaves entries beyond its own declared count at their zero value.
func EncodeV2Sprite ¶
EncodeV2Sprite is the exact inverse of DecodeV2Sprite: it encodes a decoded pixel buffer back into the on-disk byte representation for format. V2FormatRaw, V2FormatRLE8, V2FormatRLE5, V2FormatLZ5, and the PNG formats (V2FormatPNG8/24/32) are supported; see .vibe/decisions/001-v2-rle8-lz5-encode-scope-and-rle5-deferred.md and, for V2FormatRLE5 specifically (implemented later, without a real fixture — a deliberate departure from that decision), .vibe/decisions/014-v2-rle5-decode-and-encode-implemented-without-a-real-fixture.md.
func ResolvePixels ¶
ResolvePixels resolves a row-major palette-index pixel buffer — as decoded by DecodePCX or DecodeV2Sprite for an indexed pixel format (BytesPerPixel: 1) — against palette into a row-major buffer of final RGBA colors, one per index, applying rule to determine index 0's alpha.
func ResolveSpritePixels ¶
func ResolveSpritePixels(r io.ReaderAt, group, image int, override *Palette) ([]color.RGBA, int, int, error)
ResolveSpritePixels resolves the sprite identified by (group, image) within a .sff file — version 1 or 2, auto-detected the same way Load is — to its final on-screen RGBA pixels: decoding its pixel data, resolving its palette (or using override in its place, if non-nil), and applying that palette. override is ignored for a v2 direct-color sprite (PNG24/PNG32), which has no palette of its own to replace.
Returns a descriptive error, prefixed "sprite not found: " specifically when no sprite matches (group, image) — distinct from every other failure (malformed file, corrupt pixel/palette data, an implausibly large declared size) — so a caller iterating candidate sprites (e.g. browsing a sheet) can tell "doesn't exist" apart from "something is broken" without parsing the rest of the message. See .vibe/decisions/013-wasm-sprite-pixel-resolution-batched-stateless-contract.md.
A v2 sprite that shares (rather than owns) its pixel data is not yet supported and returns a descriptive error: no v2 linked-sprite decode path has been validated against real files anywhere in this package yet (see .vibe/backlog/029-fixture-driven-v2-sprite-test-suite.md, still open) — reporting a clear error here is preferred over guessing at the linking rule the way v1's own rule needed correcting once real-file testing (item 028) checked it.
func SerializeV1 ¶
SerializeV1 writes a .sff v1 file to w: the fixed 512-byte header followed by one 32-byte subheader plus pixel data blob per sprite, in order, chained via each subheader's "next subfile" offset — the layout ParseV1 reads back.
version is written verbatim as the file's four raw version bytes. sharedPalette sets the header's file-level palette-sharing flag (SPRPALTYPE_SHARED); it is independent of each V1WriteSprite's own SharedPalette field, which governs whether that individual sprite reuses the previous sprite's palette. The header's group/image counts are derived from sprites rather than taken from the caller, so they can never disagree with what is actually written: ImageCount is len(sprites), and GroupCount is the number of distinct Group values present.
SerializeV1 always produces a fresh, valid layout — it does not attempt to reproduce any original file's exact byte layout or PCX encoding choices; see .vibe/decisions/005-sff-v1-serialize-is-semantic-not-byte-exact-round-trip.md.
func SerializeV2 ¶
func SerializeV2(w io.Writer, version [4]byte, sprites []V2WriteSprite, palettes []V2WritePalette) error
SerializeV2 writes a .sff v2 file to w: the v2HeaderSize-byte header portion ParseV2 reads, followed by the sprite table, the palette table, and finally a single data section holding every sprite's pixel data and every palette bank's color data, in that order.
version is written verbatim as the file's four raw version bytes. SerializeV2 always writes every sprite's/palette's data into the file's literal data section (the on-disk "translated" flag bit is always 0) and only writes the v2HeaderSize header bytes ParseV2 itself understands — see .vibe/decisions/007-sff-v2-serialize-shape-and-scope.md for why.
Types ¶
type AlphaRule ¶
type AlphaRule int
AlphaRule selects how ResolvePixels determines a resolved pixel's alpha channel at palette index 0. The reference decoders this package tracks apply one of two rules depending on the sprite's own encoding, not a single universal rule.
const ( // AlphaForceTransparentAtIndexZero forces palette index 0 to resolve to // fully transparent ((0,0,0,0)), regardless of the palette's own stored // value there. Used by PCX (v1) and PNG8 (v2) decoded pixel data. AlphaForceTransparentAtIndexZero AlphaRule = iota // AlphaLiteral uses the palette's own stored alpha value unmodified, // including at index 0. Used by RLE8/LZ5 (v2) decoded pixel data. AlphaLiteral )
type PCXImage ¶
type PCXImage struct {
// Width is the image width in pixels.
Width int
// Height is the image height in pixels.
Height int
// Pixels is the row-major buffer of palette index values, of length
// Width*Height.
Pixels []byte
}
PCXImage is a decoded PCX-encoded sprite: its pixel dimensions and a row-major buffer of palette index values (one byte per pixel). It carries no palette (RGB) data — a PCX-encoded .sff v1 sprite's actual colors are resolved separately against the sprite's (possibly shared) palette.
func DecodePCX ¶
DecodePCX decodes RLE-compressed, 8-bit indexed PCX image data — the pixel encoding used by MUGEN/Ikemen GO .sff v1 sprites — into a pure pixel buffer. It reads the standard 128-byte PCX header embedded in data to recover the image's own width and height, then RLE-decodes the scanline data that follows.
Only single-plane, 8-bit, RLE-encoded PCX data is supported, which is what .sff v1 sprites use; anything else returns a descriptive error, as does corrupted or truncated data, rather than panicking.
func ResolveV1Pixels ¶
ResolveV1Pixels resolves sprite index i's actual decoded PCX pixel data — following v1's sprite-linking rule so a caller (e.g. a future editor wanting a sprite's real image, not just its dimensions the way loadV1 uses this internally) gets the same result Load itself would derive dimensions from, without having to reimplement the linking rule. Mirrors ResolveV1Palette's public shape.
type Palette ¶
Palette is a resolved 256-entry RGBA color table, indexed by a decoded sprite's palette index bytes (PCXImage.Pixels / V2Image.Pixels with BytesPerPixel: 1).
It is kept separate from PCXImage/V2Image/Sprite — the read-path pure-data types — as an explicit opt-in helper, mirroring how DecodePCX and DecodeV2Sprite are already separate from Load; see .vibe/decisions/008-palette-resolution-api-shape.md.
func DecodeExternalPalette ¶
DecodeExternalPalette decodes an external MUGEN/Ikemen .act palette file (256 RGB triplets, always opaque on disk) into a Palette, reproducing convertExternalPaletteToRGBA.mjs's two quirks: the file stores its 256 triplets in reverse index order — the first triplet becomes palette index 255, the last becomes index 0 — and only the resulting index 0 is forced to fully transparent (alpha 0); every other entry stays opaque. data must be exactly externalPaletteSize (768) bytes.
func DecodeV1Palette ¶
DecodeV1Palette decodes a .sff v1 sprite's embedded palette block — 256 RGB triplets (3 bytes/color), always opaque — into a Palette. data must be exactly V1PaletteBlockSize (768) bytes: the palette block itself, not the sprite's pixel data it follows (see ResolveV1Palette, which locates it within a sprite's raw file bytes).
func DecodeV2Palette ¶
DecodeV2Palette decodes a .sff v2 palette bank's raw color data — already stored as RGBA on disk, 4 bytes/color, unlike v1's opaque-only RGB triplets — into a Palette. data's length must be a multiple of 4 and declare at most 256 colors; any entries beyond the declared color count are left at their zero value (fully transparent black).
func ResolveV1Palette ¶
func ResolveV1Palette(table *V1SpriteTable, r io.ReaderAt, i int, override *Palette) (Palette, error)
ResolveV1Palette resolves the palette used by sprite index i in table, replicating the reference decoder's exact inheritance rule (see .vibe/decisions/011-v1-sprite-linking-and-palette-inheritance-rules.md): a sprite that does not share (SharedPalette == false) decodes its own embedded block; one that does share inherits table index 0's own resolved palette when it is itself (Group 0, Image 0), or the immediately preceding sprite's resolved palette otherwise. Table index 0 always decodes its own block regardless of its own SharedPalette bit — there is no earlier sprite for it to inherit from.
A zero-length entry (Length == 0 — a "copy" sprite with no pixel data of its own either, see resolveV1Pixels) always inherits the immediately preceding sprite's resolved palette instead, regardless of its own SharedPalette bit or (Group, Image): confirmed against the reference decoder's own source, which never reads a palette block for a zero-length entry — real corpus files carry zero-length entries not explicitly marked SharedPalette, which the SharedPalette-only rule above would wrongly treat as required to own a full embedded block.
An owning sprite's embedded block is read via r from the last V1PaletteBlockSize bytes of its own declared [Offset, Offset+Length) span, not a suffix starting right after it: a v1 sprite's declared Length includes its own trailing palette block when it owns one, confirmed against real, unmodified .sff v1 files — see .vibe/decisions/012-v1-palette-block-lives-inside-declared-length.md.
If override is non-nil, it is returned immediately instead — a caller- supplied external palette (see DecodeExternalPalette) used in place of the sprite's own, bypassing the table lookup entirely. See .vibe/decisions/010-external-palette-override-api-shape.md.
func ResolveV2Palette ¶
func ResolveV2Palette(table *V2SpriteTable, r io.ReaderAt, index int, override *Palette) (Palette, error)
ResolveV2Palette resolves the palette bank at index within table.Palettes to its final Palette: its own RGBA color data (read via r) when it stores one (Length > 0), or the colors of the bank its LinkedIndex points to otherwise — following the chain across further zero-length banks if needed. A link chain that is out of range or cycles back on itself returns a descriptive error instead of looping or panicking, mirroring v1 linked-sprite resolution (ResolveV1Pixels).
If override is non-nil, it is returned immediately instead — a caller- supplied external palette (see DecodeExternalPalette) used in place of the bank's own, bypassing the table lookup entirely. See .vibe/decisions/010-external-palette-override-api-shape.md.
func (*Palette) SetColor ¶
SetColor edits p's color at index to (r, g, b, a). index and every color component must be in [0, 255]; SetColor returns a descriptive error and leaves p unchanged instead of silently wrapping or clamping an out-of-range value the way a direct uint8(v) conversion would (e.g. uint8(300) silently becomes 44). This is the validated entry point for editing a Palette from caller-supplied integers — e.g. a UI or the eventual WASM/JS bridge — where values arrive as plain ints, not already-safe uint8s.
type Sprite ¶
type Sprite struct {
// Group is the sprite group index this sprite belongs to.
Group int `json:"group"`
// Image is this sprite's image index within its Group.
Image int `json:"image"`
// Width is the sprite's width in pixels.
Width int `json:"width"`
// Height is the sprite's height in pixels.
Height int `json:"height"`
// AxisX is the horizontal offset from the sprite's top-left corner to
// its axis (pivot) point, used when positioning the sprite.
AxisX int `json:"axisX"`
// AxisY is the vertical offset from the sprite's top-left corner to
// its axis (pivot) point, used when positioning the sprite.
AxisY int `json:"axisY"`
// Palette is a reference to the palette this sprite is drawn with. Its
// exact meaning (e.g. a shared palette table index) is defined by the
// .sff version that populates it.
Palette int `json:"palette"`
}
Sprite is a single MUGEN/Ikemen sprite's metadata: which group and image index identify it, its pixel dimensions, the offset from its top-left corner to its axis (pivot) point, and which palette it uses.
type SpriteGroup ¶
type SpriteGroup struct {
// Index is the sprite group index shared by every Sprite in Sprites.
Index int `json:"index"`
// Sprites is the ordered collection of sprites belonging to this group.
Sprites []Sprite `json:"sprites"`
}
SpriteGroup is a collection of Sprites that share the same group index — e.g. the frames of a single stance or attack, addressed by their Image index within the group.
func Load ¶
func Load(r io.ReaderAt) ([]SpriteGroup, error)
Load reads a full MUGEN/Ikemen GO .sff file from r — version 1 or version 2, auto-detected from the file's own signature and version bytes — and assembles it into the shared read-path SpriteGroup model, decoding whatever pixel data is needed to do so.
v1's sprite table carries no width/height (see .vibe/decisions/004-sff-v1-table-is-a-separate-low-level-type.md): Load decodes each sprite's PCX pixel data to recover them, resolving a linked sprite (one with no pixel data of its own) to its link target first. A link chain that is out of range or cycles back on itself returns a descriptive error instead of looping or panicking. v1's table also only records whether a sprite reuses the previous sprite's palette, not a numeric reference, so Sprite.Palette is derived by incrementing a counter on every sprite that does not share, and having sharing sprites inherit the current value.
v2's sprite table already carries width/height and an explicit palette bank index, so each V2SpriteEntry maps directly to a Sprite without decoding any pixel data.
type V1Header ¶
type V1Header struct {
// Version holds the four raw version bytes as stored in the file
// (verhi, verlo1, verlo2, verlo3).
Version [4]byte
// GroupCount is the number of sprite groups declared in the header.
GroupCount int
// ImageCount is the total number of sprites declared in the header.
ImageCount int
// (SPRPALTYPE_SHARED in the MUGEN spec), false when each sprite
// carries its own individual palette (SPRPALTYPE_INDIV).
SharedPalette bool
}
V1Header is the parsed MUGEN/Ikemen GO .sff v1 file header.
type V1SpriteEntry ¶
type V1SpriteEntry struct {
// Group is the sprite group index.
Group int
// Image is the sprite's image index within Group.
Image int
// AxisX is the horizontal offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisX int
// AxisY is the vertical offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisY int
// Offset is the absolute file offset of this sprite's pixel data,
// immediately following its own subheader.
Offset int64
// Length is the pixel data length in bytes. Zero means this sprite
// does not store pixel data of its own: it links to a previous
// sprite's data, identified by LinkedIndex.
Length int
// LinkedIndex is the index, within the sprite table's Sprites slice,
// of the sprite this one shares pixel data with. Only meaningful
// when Length is 0.
LinkedIndex int
// sprite's palette instead of carrying its own.
SharedPalette bool
}
V1SpriteEntry is one sprite's entry in a .sff v1 sprite index table: its (group, image) key, its axis (pivot) point, and where its pixel data lives in the file. Pixel data itself is not decoded here — see the v1 pixel decoder.
type V1SpriteTable ¶
type V1SpriteTable struct {
Header V1Header
Sprites []V1SpriteEntry
}
V1SpriteTable is a parsed .sff v1 file header plus its sprite index table, as produced by ParseV1.
func ParseV1 ¶
func ParseV1(r io.ReaderAt) (*V1SpriteTable, error)
ParseV1 reads a MUGEN/Ikemen GO .sff v1 file header and its sprite index table from r. Sprite pixel data is located (offset and length) but not decoded.
func (*V1SpriteTable) Index ¶
func (t *V1SpriteTable) Index(group, image int) (int, bool)
Index resolves the (group, image) pair to its position within t.Sprites — the index ResolveV1Pixels/ResolveV1Palette take. The second return value is false if no sprite with that (group, image) exists in the table.
type V1WriteSprite ¶
type V1WriteSprite struct {
// Group is the sprite group index.
Group int
// Image is the sprite's image index within Group.
Image int
// AxisX is the horizontal offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisX int
// AxisY is the vertical offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisY int
// palette instead of carrying its own.
SharedPalette bool
// PixelData is this sprite's PCX-encoded pixel data, e.g. produced by
// EncodePCX. Leave it nil/empty to write this sprite as a linked
// sprite that reuses another sprite's pixel data instead — see
// LinkedIndex.
PixelData []byte
// Palette is this sprite's own embedded 768-byte RGB palette block
// (256 triplets, 3 bytes/color, matching DecodeV1Palette's input
// shape). Required whenever SharedPalette is false: real .sff v1 files
// always embed an owning sprite's palette immediately after its own
// pixel data, folded into the subheader's declared Length rather than
// following it — see
// .vibe/decisions/012-v1-palette-block-lives-inside-declared-length.md.
// Ignored when SharedPalette is true.
Palette []byte
// LinkedIndex is the index, within the Sprites slice passed to
// SerializeV1, of the sprite this one shares pixel data with. Only
// meaningful when PixelData is empty.
LinkedIndex int
}
V1WriteSprite describes one sprite to serialize into a .sff v1 file via SerializeV1: its (group, image) key, its axis (pivot) point, and either its own PCX-encoded pixel data or a link to another sprite already in the same call's Sprites slice.
This is a write-only counterpart to V1SpriteEntry, not that same type reused: V1SpriteEntry carries Offset/Length, facts ParseV1 computes while reading a file, not values a caller should be trusted to supply when writing one — see .vibe/decisions/005-sff-v1-serialize-is-semantic-not-byte-exact-round-trip.md.
type V2Header ¶
type V2Header struct {
// Version holds the four raw version bytes as stored in the file
// (verlo3, verlo2, verlo1, verhi). verhi (Version[3]) is 2 for a v2
// file.
Version [4]byte
// SpriteCount is the total number of sprites declared in the header.
SpriteCount int
// PaletteCount is the total number of palette banks declared in the
// header.
PaletteCount int
}
V2Header is the parsed MUGEN/Ikemen GO .sff v2 file header.
type V2Image ¶
type V2Image struct {
// Width is the image width in pixels.
Width int
// Height is the image height in pixels.
Height int
// BytesPerPixel is the number of bytes each pixel occupies in Pixels:
// 1 for indexed data, 3 for RGB, 4 for RGBA.
BytesPerPixel int
// Pixels is the row-major pixel buffer, of length
// Width*Height*BytesPerPixel.
Pixels []byte
}
V2Image is a decoded .sff v2 sprite: its pixel dimensions and a row-major pixel buffer.
For indexed pixel data (V2FormatRaw, V2FormatRLE8, V2FormatPNG8), BytesPerPixel is 1 and each byte in Pixels is a palette index — no RGB/palette resolution performed, mirroring PCXImage. For direct-color pixel data (V2FormatPNG24, V2FormatPNG32), BytesPerPixel is 3 (RGB) or 4 (RGBA, straight alpha) and each pixel's actual color channels are stored directly, since no palette is involved for those formats.
func DecodeV2Sprite ¶
DecodeV2Sprite decodes a .sff v2 sprite's stored pixel data into a pure pixel buffer. format is the sprite table entry's Format code (V2Format* constant); width, height, and colorDepth are the entry's own declared dimensions and color depth, since not every encoding self-describes them the way PCX/PNG headers do.
Only V2FormatRaw (uncompressed indexed data), V2FormatRLE8, V2FormatRLE5, V2FormatLZ5, and the PNG formats (V2FormatPNG8/24/32, decoded via the standard library) are supported. Any other format code returns a descriptive error rather than panicking or silently misinterpreting the data; see .vibe/decisions/006-sff-v2-pixel-decode-shape-and-scope.md and, for V2FormatRLE5 specifically, .vibe/decisions/014-v2-rle5-decode-and-encode-implemented-without-a-real-fixture.md.
type V2PaletteEntry ¶
type V2PaletteEntry struct {
// Group is the palette bank's group index.
Group int
// Number is the palette bank's index within Group.
Number int
// ColorCount is the number of colors declared for this palette bank.
ColorCount int
// Offset is the absolute file offset of this palette bank's RGBA color
// data.
Offset int64
// Length is the color data length in bytes. Zero means this palette
// bank does not store color data of its own: it links to a previous
// bank's data, identified by LinkedIndex.
Length int
// LinkedIndex is the index, within the sprite table's Palettes slice,
// of the palette bank this one shares color data with. Only meaningful
// when Length is 0.
LinkedIndex int
}
V2PaletteEntry is one palette bank's entry in a .sff v2 palette table: its (group, number) key, its color count, and where its color data lives in the file.
type V2SpriteEntry ¶
type V2SpriteEntry struct {
// Group is the sprite group index.
Group int
// Image is the sprite's image index within Group.
Image int
// Width is the sprite's width in pixels, as declared in the table
// (independent of its encoded pixel data).
Width int
// Height is the sprite's height in pixels, as declared in the table.
Height int
// AxisX is the horizontal offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisX int
// AxisY is the vertical offset from the sprite's top-left corner to its
// axis (pivot) point.
AxisY int
// Offset is the absolute file offset of this sprite's encoded pixel
// data, already resolved against the file's literal or translated data
// section as indicated by the sprite's on-disk flag.
Offset int64
// Length is the encoded pixel data length in bytes. Zero means this
// sprite does not store pixel data of its own: it links to a previous
// sprite's data, identified by LinkedIndex.
Length int
// LinkedIndex is the index, within the sprite table's Sprites slice, of
// the sprite this one shares pixel data with. Only meaningful when
// Length is 0.
LinkedIndex int
// Format identifies how the pixel data at Offset is encoded (see the
// V2Format* constants). Only meaningful when Length is non-zero.
Format int
// ColorDepth is the color depth, in bits, of the encoded pixel data.
ColorDepth int
// PaletteIndex is the index, within the sprite table's Palettes slice,
// of the palette bank this sprite is drawn with.
PaletteIndex int
}
V2SpriteEntry is one sprite's entry in a .sff v2 sprite index table: its (group, image) key, its pixel dimensions, its axis (pivot) point, which palette bank it uses, and where its pixel data lives in the file. Pixel data itself is not decoded here — see the v2 pixel decoder.
type V2SpriteTable ¶
type V2SpriteTable struct {
Header V2Header
Sprites []V2SpriteEntry
Palettes []V2PaletteEntry
}
V2SpriteTable is a parsed .sff v2 file header plus its sprite and palette index tables, as produced by ParseV2.
func ParseV2 ¶
func ParseV2(r io.ReaderAt) (*V2SpriteTable, error)
ParseV2 reads a MUGEN/Ikemen GO .sff v2 file header and its sprite and palette index tables from r. Sprite and palette color data is located (offset and length) but not decoded.
func (*V2SpriteTable) Index ¶
func (t *V2SpriteTable) Index(group, image int) (int, bool)
Index resolves the (group, image) pair to its position within t.Sprites. The second return value is false if no sprite with that (group, image) exists in the table.
func (*V2SpriteTable) Offset ¶
func (t *V2SpriteTable) Offset(group, image int) (int64, bool)
Offset resolves the (group, image) pair to the absolute file offset of that sprite's encoded pixel data. The second return value is false if no sprite with that (group, image) exists in the table.
func (*V2SpriteTable) PaletteOffset ¶
func (t *V2SpriteTable) PaletteOffset(group, number int) (int64, bool)
PaletteOffset resolves the (group, number) pair to the absolute file offset of that palette bank's RGBA color data. The second return value is false if no palette bank with that (group, number) exists in the table.
type V2WritePalette ¶
type V2WritePalette struct {
// Group is the palette bank's group index.
Group int
// Number is the palette bank's index within Group.
Number int
// ColorCount is the number of colors in this palette bank.
ColorCount int
// ColorData is this palette bank's own RGBA color data. Leave it
// nil/empty to write this bank as linked, reusing another bank's color
// data instead — see LinkedIndex.
ColorData []byte
// LinkedIndex is the index, within the Palettes slice passed to
// SerializeV2, of the palette bank this one shares color data with.
// Only meaningful when ColorData is empty.
LinkedIndex int
}
V2WritePalette describes one palette bank to serialize into a .sff v2 file via SerializeV2: its (group, number) key, color count, and either its own RGBA color data or a link to another palette bank already in the same call's Palettes slice.
This is a write-only counterpart to V2PaletteEntry, for the same reason V2WriteSprite is a write-only counterpart to V2SpriteEntry.
type V2WriteSprite ¶
type V2WriteSprite struct {
// Group is the sprite group index.
Group int
// Image is the sprite's image index within Group.
Image int
// Width is the sprite's width in pixels.
Width int
// Height is the sprite's height in pixels.
Height int
// AxisX is the horizontal offset from the sprite's top-left corner to
// its axis (pivot) point.
AxisX int
// AxisY is the vertical offset from the sprite's top-left corner to its
// axis (pivot) point.
AxisY int
// Format identifies how PixelData is encoded (see the V2Format*
// constants). Only meaningful when PixelData is non-empty.
Format int
// ColorDepth is the color depth, in bits, of PixelData.
ColorDepth int
// PaletteIndex is the index, within the Palettes slice passed to
// SerializeV2, of the palette bank this sprite is drawn with.
PaletteIndex int
// PixelData is this sprite's already-encoded pixel data, e.g. produced
// by EncodeV2Sprite. Leave it nil/empty to write this sprite as a
// linked sprite that reuses another sprite's pixel data instead — see
// LinkedIndex.
PixelData []byte
// LinkedIndex is the index, within the Sprites slice passed to
// SerializeV2, of the sprite this one shares pixel data with. Only
// meaningful when PixelData is empty.
LinkedIndex int
}
V2WriteSprite describes one sprite to serialize into a .sff v2 file via SerializeV2: its (group, image) key, declared dimensions, axis (pivot) point, palette bank reference, and either its own encoded pixel data (e.g. produced by EncodeV2Sprite) or a link to another sprite already in the same call's Sprites slice.
This is a write-only counterpart to V2SpriteEntry, not that same type reused: V2SpriteEntry carries Offset/Length, facts ParseV2 computes while reading a file, not values a caller should be trusted to supply when writing one — see .vibe/decisions/007-sff-v2-serialize-shape-and-scope.md.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
wasm
command
Command wasm is the WASM entrypoint for the sff library: thin syscall/js glue exposing this package's Load and ResolveSpritePixels to a browser (or any JS host) as global functions, so a consumer (stage, lifebar apps) can load and decode MUGEN/Ikemen .sff sprite sheets without a Go toolchain of its own — independent of character's own WASM build, which consumes this same package internally but publishes its own artifact.
|
Command wasm is the WASM entrypoint for the sff library: thin syscall/js glue exposing this package's Load and ResolveSpritePixels to a browser (or any JS host) as global functions, so a consumer (stage, lifebar apps) can load and decode MUGEN/Ikemen .sff sprite sheets without a Go toolchain of its own — independent of character's own WASM build, which consumes this same package internally but publishes its own artifact. |