Use when reading, parsing, writing, dumping, or debugging any Jill of the Jungle data file (DMA, SHA, JN, MAC, CFG, VCL, CMF/DDT, Crunched Screen Image) or when reasoning about its byte layout, flag bits, object iTypes, savegame structure, palette handling, or per-file quirks. Examples: "why is this DMA entry parsing wrong?", "add a SHA tile dumper", "what's the layout of the JN object record?", "is the player object always first?", "decode dan.cmf", "parse the VCL sound table", "port the Crunched Screen Image renderer".
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Use when reading, parsing, writing, dumping, or debugging any Jill of the Jungle data file (DMA, SHA, JN, MAC, CFG, VCL, CMF/DDT, Crunched Screen Image) or when reasoning about its byte layout, flag bits, object iTypes, savegame structure, palette handling, or per-file quirks. Examples: "why is this DMA entry parsing wrong?", "add a SHA tile dumper", "what's the layout of the JN object record?", "is the player object always first?", "decode dan.cmf", "parse the VCL sound table", "port the Crunched Screen Image renderer".
Jill of the Jungle Data Formats
Single source of truth for byte-level layout of every Jill of the Jungle
data file: docs/port/00-format-reference.md.
That file cites the upstream ModdingWiki pages and is updated when new
porting questions surface. This skill is a router into it plus the
quirks/gotchas that bite porters most often.
When to use
Trigger on any of:
Touching crates/openjill-data/ (or any module that reads/writes
original Jill bytes).
Adding or fixing a parser, dumper, or extractor.
Designing types that mirror an on-disk record.
Debugging why parsed data disagrees with the original game.
Answering "what does this byte mean?" / "what is the layout of …?".
Auditing endianness, offsets, masks, or string encoding for any of
DMA, SHA, JN (*.JN[123]), MAC, CFG, VCL, CMF (*.DDT), or Crunched
Screen Image streams.
Workflow
1. Open docs/port/00-format-reference.md.
2. Jump to the section for the format in question (anchors below).
3. Re-read the per-file quirks subsection — most parser bugs live there.
4. Cross-check against existing Rust code in crates/openjill-data/<format>.rs
(parser already exists for: DMA, VCL-text, CFG, SHA, JN).
5. For new behavior, prefer extending the existing parser to introducing
a parallel one. Match the wiki's field names (iType, lPointer, etc.)
so the code maps 1:1 onto the reference.
Format index → reference anchor
Format
When you hit it
Reference section in 00-format-reference.md
DMA (JILL.DMA)
Tile metadata; iMapCode → tileset+flags
## DMA — JILL.DMA
SHA (*.SHA)
Tilesets, fonts, sprites, palette override
## SHA — *.SHA
JN (*.JN[123])
Maps, screens, intro, savegames, string stack
## JN — *.JN[123]
MAC (*.MAC)
Demo playback macros
## MAC — *.MAC
CFG (JILL#.CFG)
High scores, save names, joystick/display
## CFG — JILL[1-3].CFG
VCL (*.VCL)
50 sounds + 40 texts
## VCL — *.VCL
CMF (*.DDT)
Adlib/OPL background music
## CMF — *.DDT (background music)
Crunched Screen
Hardware-detect + ordering inside loader EXE
## Crunched Screen Image (loader EXE only)
High-leverage quick-reference
These are the answers porters re-derive most often. Always confirm
against the reference doc before coding — this is a memory aid, not the
spec.
Endianness
Everything multi-byte is little-endian. Period. Strings are not
null-terminated unless explicitly noted (DMA cName is not, CMF
title/composer/remarks are).
*filename → load song from start
#filename → keep current song or play if none
&filename → Xargon: force song_33.xr1 + treat as demo macro
Jill: song unchanged
! → load previous map (no filename)
no prefix → next level filename
MAC event loop
1. Read u8 inputFlags (bit 0=X, 1=Y, 2=Btn1, 3=Btn2, 4=Key)
2. For each set bit (LSB first), read 1 byte of input state.
X/Y axis: 0xFF = neg, 0x00 = center, 0x01 = pos.
Buttons: 0x00 / 0x01.
Key: raw key value, 0x00 = none.
3. Read next-event timestamp:
- byte < 0x80 → absolute frame number
- byte >= 0x80 → low 7 bits, then read another byte and shift << 7
Determinism: max 32767 frames; RNG seed hardcoded to 12345, not in
file.
CFG layout (254 bytes total)
0..=99 char[10] x 10 high-score names
100..=119 (undocumented; PRESERVE on round-trip)
120..=159 i32le x 10 high-score values
160..=231 char[12] x 6 save names (display truncates to 7)
232.. CFG_STRUCT i16le block (joystick/display/audio)
CFG_STRUCT offset 0 is a one-shot reset flag the engine clears after
honoring. Display mode: 1=CGA, 2=EGA, 4=VGA.
Song data: raw MIDI track payload (no MTrk header). End-of-track:
FF 2F 00. Jill dan.cmf ships malformed FF 2F FE — treat any
FF 2F xx as end-of-track.
Crunched Screen Image byte codes
0x00..0x0F set foreground color
0x10..0x17 set background color (lower 4 bits)
0x18 newline
0x19 n emit (n+1) spaces
0x1A n c emit char c (n+1) times
0x1B toggle blink
0x1C..0x1F undefined; skip
0x20..0xFF emit byte verbatim
No header. Stream ends when cursor Y exceeds row 25.
Cross-cutting porting rules
Preserve unknown bytes verbatim on round-trip writes. The
background-grid upper 2 bits, the CFG 100..=119 region, and the VCL
unknown-aux block all fall here.
Treat unknown iType as no-ops, not errors — the wiki warns "not
all objects are valid" and KILLME is normal.
Keep parser types decoupled from rendering.openjill-data returns
indexed pixels and the EXE-style palette; conversion to RGBA happens
in openjill-render.
Mirror the wiki's field names in Rust types (iType, iCounter,
lPointer, numColourBits, …) so docs map 1:1 onto code. Use
doc comments (per AGENTS.md) to spell out the meaning rather than
renaming the fields.
Real-data integration tests for any new parser, gated on
OPENJILL_DATA_DIR (see AGENTS.md §"Integration tests").
When the reference is wrong
If you find a parser disagreement with the wiki that the wiki doesn't
explain (e.g. another Jill-specific quirk like dan.cmf):
Update docs/port/00-format-reference.md with the new quirk under
the relevant "Per-file quirks" / "Round-trip rules" subsection.
Cite the source (a specific shipped file, a Java OpenJill behavior,
or a wiki diff).
Make the parser tolerate the malformed data; do not "correct" the
bytes silently.