Pack Layout and Conventions

Every rule on this page applies to all file formats. Read it once before the per-format pages.

Source folder structure

Editor/<Mod Name>/
  config.json
  thumbnail.png
  Entities/
    <Entity Name>/
      spriteSettings.json
      animations.json
      logic.json
      dependencies.json
      0.png, 1.png, 2.png, ...
      portrait.png
      preview.png
      Palettes/
        palette 0.png, palette 1.png, ...
  Entity Replacements/
    Classic/
      <Classic Entity Name>/         same files as an entity
  Levels/
    level 1.json
    level 1 - art.json
    level 1 - cutscenes.json
    title.json
    presentation.json
    ending.json
    Art/
      <any image files>
  Level Replacements/
    Classic/
      level 1 - art.json
      level 1 - cutscenes.json
      title.json
      presentation.json
      ending.json
  Palettes/
    <Target Pack>/
      <Entity Name>/
        palette 0.png, palette 1.png, ...
  Sounds/
    <any audio files>
  Musics/
    <any audio files>
    <track name>.json                loop points
  Audio Replacements/
    <Target Pack>/
      music-replacements.json
      sound-replacements.json
  Scripts/
    <any .lua files>

Only the folders your mod uses need to exist. Missing folders and missing files are not errors; the loader treats them as "this mod provides nothing here".

The folder name under Editor/ is the pack name. Renaming the folder renames the pack, which changes its hash and breaks every packName reference pointing at the old name.

The three kinds of content

Understanding which of these you are authoring decides where the files go.

Own content lives under Entities/ and Levels/. It belongs to your pack and is addressed as (your pack name, entity or level name).

Replacements live under Entity Replacements/<Target Pack>/ and Level Replacements/<Target Pack>/. They substitute content of another pack, in place, keeping that pack's identity. This is how a reskin works: your Entity Replacements/Classic/Axel/ becomes what the game shows when it draws Classic's Axel. The folder name under the replacements folder must match an entity or file name that exists in the target pack.

Contributions live under Palettes/<Target Pack>/ and Audio Replacements/<Target Pack>/. They add to or redirect part of another pack without replacing whole entities.

<Target Pack> is almost always Classic, the built-in pack extracted from the original ROM.

How names resolve

Almost every cross-reference in these files is a (packName, name) pair of plain strings.

  • An empty or omitted packName means the Classic pack in loadcues and dependencies, and the current pack in editor-written sound and script references. The per-format pages state which applies.
  • Names are matched by folder or file name exactly as written, including spaces and capitalisation.
  • Internally, both names are reduced to a 32-bit hash. You never need to compute this except for allowedCharacters in config.json; see Enums and Identifiers.

A reference to a pack that is not loaded is not a load-time error. It fails at the moment the game tries to use it, which usually looks like a missing sprite or a silent sound. List every pack you reference in config.json dependencies.

File naming rules

These are matched by prefix and suffix in code, so they are exact.

Pattern Meaning
Levels/level <n>.json A level's gameplay data. The prefix is level with a trailing space.
Levels/level <n> - art.json That level's visuals. The suffix is - art.json.
Levels/level <n> - cutscenes.json That level's cutscenes. The suffix is - cutscenes.json.
Levels/title.json, presentation.json, ending.json Fixed names for the non-level screens.
Entities/<name>/<i>.png Own sprite frame i, zero-based, no padding.
Palettes/.../palette <n>.png Palette n. Sorted numerically by the trailing digits, not alphabetically.
Musics/<track>.json Loop points for Musics/<track>.<audio extension>.

Level discovery scans Levels/ for files starting with level and not ending in the art or cutscenes suffix, so a stray level notes.json would be picked up as a level. Keep the folder tidy.

Palette sorting deserves a note: files are ordered by the digits at the end of the base name, so palette 2.png comes before palette 10.png. Plain alphabetical order would get this wrong, and everything downstream — exporting, deleting, the paletteIndex a loadcue refers to — assumes the numeric order.

Assets

Asset Format Notes
Sprite frames PNG One image per frame. Transparency preserved. Frame count comes from spriteSettings.json pivots, not from how many PNGs exist.
portrait.png, preview.png PNG Optional. Character select portrait and preview.
thumbnail.png PNG Optional. Shown in mod listings.
Level art PNG or JPG Anything the engine's texture loader accepts. Referenced by file name including extension.
Palettes PNG See Palette Files.
Sounds and music .wav, .mp3, .ogg Referenced by base name without extension.

Level art images are drawn with point filtering by default, which keeps pixel art sharp. An image used only at non-integer scales is switched to bilinear filtering automatically. If the same image is used at both an integer and a non-integer scale anywhere in the pack, point filtering wins for all of its uses.

Editing safely

  • Never reorder an indexed array. animations, animationsLogic, and animationsDefinition are addressed by position. Inserting an entry in the middle silently repoints every reference past it.
  • Keep parallel arrays aligned. animations.json animations[i] and logic.json animationsLogic[i] describe the same animation. Either may be shorter, and either entry may be null.
  • Prefer omitting a field to writing a zero, especially on an entity that sets referencePackName. On a referencing entity, 0 is indistinguishable from "not set" and falls through to the reference. See Entity Files.
  • Close the editor before hand-editing. The Godot editors hold the loaded model in memory and rewrite the whole file on save, so a save after your edit will discard it.