WP-002: TGIFILE.ART payload decoder + first image extraction

Status: 📝 Drafted Phase: 1 — Format Research Depends on: WP-001 (preferred — gives decode algorithm directly; can be started without if Ghidra path is blocked) Companion EC: EC-002 Estimated effort: Half-day if WP-001 succeeds; 1–2 days if blind-decoding


Goal

Decode at least one TGIFILE.ART entry from Showdown in Ghost Town to a recognizable PNG or BMP that visually matches in-game output. This satisfies Phase 1 exit criterion #1 and unblocks Phase 2.

Background

TGIFILE.ART structure is understood (69 groups, 453 asset entries, 8-byte (start, end) records — see docs/formats/tgifile-art.md). The remaining unknown is the per-entry payload compression. Opening bytes of entry 0 (F0 0C 25 5C 12 AE F0 08) match no standard codec.

WP-003 baseline (2026-06-02) — first-decode strategy revised. WP-003 established three facts that change how this WP should approach the first decode:

  1. Entry 0 is OBJ_DAPHNE_A, not an unnamed background. WP-003 confirmed entry[i] is the payload for OBJ id i, and the OBJ name table maps id 0 → OBJ_DAPHNE_A. The “first image” target is a character sprite (Daphne, presumably idle or one walk-cycle frame), not a full-screen background. Visual verification should look for a Daphne-shaped silhouette, not a room. WP-009’s reference screenshot library should include at least one clear Daphne sprite shot.
  2. Palette is NOT in the pre-payload region. WP-003 ran exhaustive stride-3 / stride-4 / 768-byte / 1024-byte scans on 0x0F44–0x10017E and found nothing palette-shaped. Palette discovery now has two leading candidates: (a) per-asset leading bytes inside each payload — the palette is co-located with the asset; (b) the 20-byte per-record metadata field at offsets 48–67 of name-table records — the palette index or a small per-resource palette lives there. The “blind decode-guessing” strategy should test (a) first by probing for a 256-entry RGB or RGBA block in the first 768–1024 bytes of entry 0’s payload.
  3. The 20-byte metadata field carries (6534, 6078, 6078, 0, 0) on at least one record (ANIM_BIG_HEAD_BG_P09DAPHNE at file 0xE644), plausibly (width, height_a, height_b). If the per-record metadata on OBJ_DAPHNE_A’s name-table record carries similar values, that’s a free pre-decode dimensions hint. Worth reading the metadata field of name-table records on the OBJ section before running blind decode.

WP-008 baseline (2026-06-03) — labeling rule confirmed + coverage expectations sharpened. The Showdown object.ini analysis confirmed the engine is name-driven (MODE_A), so the deterministic naming rule from WP-008 §Notes — entry_<index>_<wp003_name>.png, sanitization preserving uppercase verbatim, anything outside [A-Za-z0-9_] → _ — applies directly. Confirmed clean: every observed name (OBJ_DAPHNE_A, OBJ_P40_TO_P33, ANIM_CURSORARROW) is already filename-safe; sanitization is a no-op on every observed input. The 65 unmatched references from the WP-008 cross-check (21 scripted/engine ROOM_*, 25 invisible-hotspot OBJ_*, 19 inventory-specific ANIM_*) are not expected to resolve to decoded TGIFILE.ART entries — they’re hotspots without art payloads, scripted rooms rendered by per-room functions (see WP-001 §Background), and inventory animations that live in another store. EC-002’s probe coverage should treat their absence as expected, not as a decoder bug; verifying zero of them produce decoded output is itself a finding worth recording.

Two additional test corpus opportunities WP-003 surfaced:

Three viable strategies:

Strategy Time Confidence Trigger
Reimplement decode from Ghidra trace (WP-001 output) Half-day High WP-001 succeeded
Blind decode-guessing: opcode RLE → 8-bit palette → LZ variants 1–2 days Medium WP-001 blocked or partial
Hybrid — Ghidra gives algorithm name (e.g. “LZ77”), confirm by reimplementing standard variant Half-day High WP-001 partial

Scope

In scope:

Out of scope:

Dependencies

Exit criteria

  1. tools/probe_art.py runs and successfully extracts and decodes at least entry 0 of Showdown’s TGIFILE.ART.
  2. Output PNG/BMP is visually recognizable as a Scooby-Doo asset (background, sprite frame, or UI element). Recognizability is the test, not pixel-exact match against a specific source.
  3. docs/formats/tgifile-art.md Findings → “Per-entry payload” section populated with: compression algorithm name (or description), pixel format (palette vs. truecolor + bit depth), palette location and format, decode pseudocode or working Python.
  4. Output PNG/BMP committed to tools/samples/tgifile-art-entry0.png for visual reference.

Deliverables

Notes