Skip to content

Authoring Manifest

EmoTracker Community edited this page Apr 8, 2026 · 1 revision

Authoring a Manifest

manifest.json is the only file EmoTracker requires at a known path inside your pack. It lives at the pack root and tells EmoTracker the pack's name, identity, version, target game, author, and any variants the user can pick from. Without it, the Package Manager and the gear-menu Installed Packages list have nothing to display.

This page is a complete reference for the manifest format — every field, their defaults, and the gotchas. Most pack authors only touch a handful of fields, but knowing the rest exists is useful when you need them.

See Developer Setup → The pack directory layout for where this file fits in the larger pack structure.

Where it lives

my_pack/
├── manifest.json     ← THIS FILE
├── scripts/
│   └── init.lua
├── items/
├── locations/
├── layouts/
└── images/

manifest.json must be at the root of the pack, not inside a subdirectory. EmoTracker reads it via GamePackage.LoadManifest immediately when the pack is loaded — before any items, locations, layouts, or scripts. If the file is missing or malformed, the pack fails to load.

A minimal manifest

The smallest legal manifest has three fields:

{
    "name": "My Pack",
    "uid": "my_pack_yourname",
    "version": "1.0.0"
}

That's enough for the pack to load and appear in the Installed Packages list. To make it useful you'll typically also want platform, game_name, and author — see Common manifests below for fuller examples.

JSON schema

The canonical JSON schema is published at EmoTracker-Service/sdk/schema/manifest.json. Wire it up in VS Code along with the other pack schemas (see Developer Setup → Configuring JSON schema validation) so you get autocomplete and validation for every field while authoring:

// .vscode/settings.json — add this entry to the json.schemas array
{
    "fileMatch": [ "manifest.json" ],
    "url": "https://raw.githubusercontent.com/EmoTracker-Community/EmoTracker-Service/main/sdk/schema/manifest.json"
}

Field reference

Parsed in EmoTracker.Data/Packages/GamePackage.cs:LoadManifest.

Required fields

Field Type Description
name string Display name of the pack, shown in the Package Manager and the gear-menu Installed Packages list.
uid string Unique identifier for the pack. Used as the local install filename (<uid>.zip) and as the pack's identity for update detection. Must be unique across every pack the user might install. Pick something namespaced and stable like alttpr_emotracker_emosaru rather than something generic like tracker.
version string Pack version in System.Version format (Major.Minor[.Build[.Revision]]). Used for update detection by the Package Manager. Examples: "1.0.0", "1.0.7.14", "2.0".

Identity (recommended)

Field Type Description
author string Display name of the pack's author. Shown in the Package Manager and the Installed Packages submenu in italics next to the pack name.
game_name string The game this pack tracks, matching a top-level key from the EmoTracker service's supported_games.json. The runtime uses this to look up the game's display info, image, and memory whitelist.
game_variant string An optional sub-variant of the game (e.g. a region, revision, or rule-set name). Free-form string used for display only.

Platform (required for autotracking)

Field Type Description
platform enum The game platform this pack targets. Required for autotracking — AutoTrackingProviderRegistry.GetProvidersForPack filters registered providers to those whose SupportedPlatforms contains this value. Without a platform, the autotracker submenu's Provider list is empty and your pack cannot autotrack. Valid values: NES, SNES, N64, Gameboy, GBA, Gamecube, Genesis.

If your pack has no autotracker, you can omit platform entirely. If you ever add autotracking later, you'll need to add it.

Layout engine version

Field Type Description
layout_engine_version string The layout engine version the pack was authored against, in System.Version format. Used for legacy compatibility shims like the itemgrid legacy margin interpretation. New packs should set this to the latest version to opt into modern behavior.

Variants

Field Type Description
variants object Map of variant identifier → variant definition. Each variant becomes a separate selectable entry in the gear menu's Installed Packages submenu, letting users switch between different views of the same pack (e.g., item-only vs full map tracker).

Each entry inside variants is keyed by a stable variant identifier (the variant UID) and has at least a display_name:

"variants": {
    "item_tracker": {
        "display_name": "Item Tracker"
    },
    "map_tracker": {
        "display_name": "Standard Map Tracker"
    },
    "keysanity_map_tracker": {
        "display_name": "Keysanity Map Tracker"
    }
}

The variant UID (item_tracker, map_tracker, etc.) is what your init.lua reads from Tracker.ActiveVariantUID to branch on which variant the user picked — see Authoring Lua — init.lua → Detecting the active variant. Each variant also gets its own user data subdirectory under the pack's override path, so user-applied overrides are kept separate per variant.

If your pack only has one logical view, omit variants entirely — EmoTracker treats the pack as a single un-named entry in the menu.

Autotracker provider override

Field Type Description
auto_tracker_providers array of strings Optional explicit list of autotracking provider UIDs the pack supports. When set, only providers with one of these UIDs are offered for the pack, regardless of platform. When unset (the typical case), providers are matched against the pack's platform instead.

Known provider UIDs:

  • sni — SNI (SNES via FxPak Pro / snes9x / retroarch / BizHawk)
  • nwa — NWA (BizHawk and other NWA-capable hosts; multi-platform)

Use this only if you want to restrict which providers are offered — for example, "this pack only works with NWA on BizHawk, do not offer SNI". For the typical case (any provider that supports the platform is fine), leave the field out and let platform do the matching.

Unsafe scripting

Field Type Default Description
enable_unsafe_scripting boolean false If true, the Lua sandbox grants this pack additional os / io access for filesystem reads and writes. Packs flagged unsafe show a warning icon in the Package Manager and discourage installation.

The default Lua sandbox removes io entirely and locks down most of the os table — see Authoring Lua Scripts → The Lua sandbox. Setting enable_unsafe_scripting: true lifts those restrictions for this pack only. Almost no pack genuinely needs this; only enable it if you have a real reason and you've thought through the implications.

Legacy aliases

EmoTracker still reads two legacy field names for backwards compatibility with very old packs. New packs should use the new names instead.

Legacy field New field
package_uid uid
package_version version

The legacy fields are only consulted as a fallback when the new field is missing or unparseable. Don't set both — use one or the other.

Common manifests

A minimal pack with author info

{
    "name": "My Cool Tracker",
    "uid": "my_cool_tracker_yourname",
    "version": "1.0.0",
    "author": "Your Name",
    "game_name": "A Link to the Past Randomizer"
}

Enough to ship a non-autotracker pack — appears in the Package Manager with author info and game association.

A pack with autotracker and a single variant

{
    "name": "My ALttPR Tracker",
    "uid": "my_alttpr_tracker_yourname",
    "version": "1.0.0",
    "author": "Your Name",
    "game_name": "A Link to the Past Randomizer",
    "platform": "SNES",
    "layout_engine_version": "1.0"
}

The platform field unlocks autotracking. SNI and NWA are both offered when the user opens the autotracker menu, since both support SNES.

A pack with multiple variants

{
    "name": "Full ALttPR Tracker",
    "uid": "alttpr_full_tracker_yourname",
    "version": "1.0.0",
    "author": "Your Name",
    "game_name": "A Link to the Past Randomizer",
    "platform": "SNES",
    "layout_engine_version": "1.0",
    "variants": {
        "item_tracker": {
            "display_name": "Item Tracker"
        },
        "map_tracker": {
            "display_name": "Standard Map Tracker"
        },
        "keysanity_map_tracker": {
            "display_name": "Keysanity Map Tracker"
        }
    }
}

Three variants appear in the gear menu under the pack name. Your scripts/init.lua branches on Tracker.ActiveVariantUID to load the right layout for whichever variant the user selected.

A pack restricted to BizHawk via NWA

{
    "name": "BizHawk-only Tracker",
    "uid": "bizhawk_only_yourname",
    "version": "0.1.0",
    "platform": "GBA",
    "auto_tracker_providers": [ "nwa" ]
}

Even though SNI doesn't support GBA anyway, the explicit auto_tracker_providers list makes it clear that only NWA is offered. This is mostly useful when the platform has multiple providers and you want to pin to one of them.

Tips and pitfalls

  • uid is forever. Once a pack is published with a uid, changing it produces a "different" pack from the user's perspective — they'll see two installed entries and won't get update notifications between them. Pick something unique and stable on day one and never change it.
  • Version updates require bumping version. The Package Manager compares version strings to detect updates. If you ship a new pack zip without bumping version, users who already have the old version won't be offered the update.
  • platform is usually required. The only packs that can safely omit it are non-autotracker packs. If you're not sure, set it.
  • Variant UIDs become part of user data paths. Each variant gets its own override directory. Avoid changing variant UIDs after publication for the same reason as the pack uid — users' overrides are tied to them.
  • game_name matches the service. The string must be a top-level key in supported_games.json. If your game isn't there, open a PR against the service repo adding it.
  • Don't enable enable_unsafe_scripting casually. It triggers warning UI for users and undermines trust in your pack. Only set it if your pack genuinely needs io access and you've documented why in your pack's docs.
  • Validate the JSON. EmoTracker silently fails to load packs with malformed manifests. A JSON linter (or VS Code's built-in validation, with the schema wired up) catches these before you ship.

See also

Clone this wiki locally