Firestaff Artpack Studio 0.2

scripts/firestaff_artpack_studio.py is a cross-platform graphical tool for creating and editing modern artpacks for:

The tool uses Python, Tkinter, and Pillow. It writes the same modern_asset_manifest.json format used by the runtime and can write finish_receipt.json after required slots validate.

Run

python3 scripts/firestaff_artpack_studio.py --game dm1
python3 scripts/firestaff_artpack_studio.py --game dm2 --pack-dir "$HOME/.firestaff/assets/dm2/modern"

Install Pillow if needed:

python3 -m pip install Pillow

Features

.fsart Format

.fsart is the portable Firestaff artpack container. It is a ZIP archive with the .fsart extension. The archive root contains modern_asset_manifest.json and one subdirectory per manifest category, for example:

modern_asset_manifest.json
finish_receipt.json
wall_shapes/wall_d3_carved_hero_01.png
champion_portraits/champion_warrior_hero_01.png
title_frames/title_0001.png

The studio rejects unsafe archive paths and verifies that the archive game matches the selected game before saving the imported manifest.

The archive may also contain v22_inplace_cache.bin. Use Build Runtime Cache after changing art (or --build-runtime-cache in the CLI) before selecting V2.2 in Firestaff. The cache is a bounded native RGBA representation of the manifest PNGs; it does not add or synthesize any image content.

The Firestaff startup menu can store a selected .fsart file under Settings / Controls / V2.2 Artpack. The launcher persists that path in startup-menu.toml as artpack_path; runtime unpacking/manifest-cache promotion remains a separate loader step and must continue to verify the archive contents before using them.

The startup menu also stores an optional broad Unicode font path under Settings / Controls / Unicode Font. Use a TTF/OTF/TTC family with broad language coverage, such as Noto Sans. The path is persisted as unicode_font_path.

Reference Assets

The V1 root defaults to:

$HOME/.firestaff/data/<game>

The studio recursively scans common image formats under that directory. Category names are taken from matching path components when possible and inferred from filenames otherwise. Rows marked OK have a matching V2.2 target in the open pack; rows marked -- still need a V2.2 replacement.

Original Game Data Import

Use Import game data to select a local original file, for example GRAPHICS.DAT. The studio hashes the file and compares it with docs/VERIFIED_HASHES.md. Known hashes select the exact game/variant; unknown files are marked with a warning and only get a filename/size-based game guess.

For DM1/CSB-style GRAPHICS.DAT, the importer reads the same new/old header shape used by Firestaff’s ReDMCSB-compatible F0479 path:

Records that can be decoded by the DM1/CSB IMG3 expander or the DM2 GDAT preview decoder are shown as original graphics. DM2 preview currently supports skproject-style IMG3 C4 plus uncompressed U4/U8 records. Unsupported records, including IMG9 C8, are still listed with dimensions, offsets, hashes, and a decode warning; the studio does not invent replacement pixels for them.

The status line reports imported asset count, warning count, and byte size. The Warnings button shows file-level and per-record warnings.

Headless Original-Record Export

The same source inspection path is available without starting Tk. This is useful for reviewing a locally supplied, original CSB graphics record on a build machine. CSB has no original PC/DOS edition: select an admitted Amiga, Atari ST or FM Towns source and never use a PC-shaped reference fixture as runtime media:

python3 scripts/firestaff_artpack_studio.py \
  --import-game-data /path/to/original/CSBGRAPHICS.DAT \
  --export-original-previews "$HOME/.firestaff/review/csb-original-previews"

This writes every successfully decoded original record as a PNG and records the source SHA-256, record offsets, dimensions, byte counts and decode warnings in original_graphics_preview_manifest.json. It deliberately does not write an .fsart or assign V2.2 material IDs: an operator must review and map source records to the CSB 29-slot runtime contract before a pack can pass the finished-art gate.

AI Generation Hook

The studio does not hard-code a specific cloud AI API. Instead it runs an operator-provided command template. This keeps the GUI portable and avoids locking artpack creation to one provider.

Set:

export FIRESTAFF_ARTPACK_AI_COMMAND='my-generator --prompt {prompt_file} --ref {source} --out {output}'

Available placeholders:

The command must write a PNG to {output}. The studio then loads that image as the V2.2 target so the operator can inspect, edit, and import it.

The first AI field is optional custom prompt text. AI selected generates only the selected asset. AI missing/all walks missing V2.2 targets first and falls back to all listed reference/original assets when nothing is missing.

Validation

The self-test is registered in CTest:

python3 scripts/firestaff_artpack_studio.py --self-test
python3 scripts/firestaff_artpack_studio.py --screenshot .codex-scratch/firestaff-artpack-studio.png
ctest --test-dir build-local-ninja -R firestaff_artpack_studio_self_test --output-on-failure

The self-test creates a scratch DM1 pack, imports all required DM1 V2.2 slots, validates them, and writes a receipt.