Back to Provenance

Skin Catalog Contribution Guide

Scripts/SKIN_CATALOG_CONTRIBUTING.md

3.3.18.5 KB
Original Source

Skin Catalog Contribution Guide

This guide explains how to add new skins to the Provenance skin catalog so they appear in the Skin Browser (Settings → Skins → Browse Catalog).


Table of Contents

  1. Overview
  2. Catalog JSON Schema
  3. Option A: Auto-generate via Scraper
  4. Option B: Add a Skin Manually
  5. Deploying Changes
  6. PR Guidelines
  7. Supported Systems

Overview

The skin catalog is a JSON file that lists community-created .deltaskin and .manicskin files compatible with the Provenance emulator. It is stored in two locations:

FilePurpose
Scripts/catalog_seed.jsonSource of truth — edited by contributors
PVUI/Sources/PVUIBase/Resources/catalog_seed.jsonBundled copy — loaded by the app at runtime

Both files must be kept in sync (see Deploying Changes).

The scraper (Scripts/scrape_skin_catalog.py) crawls several community skin repositories and regenerates catalog_seed.json automatically. You can also add entries by hand.


Catalog JSON Schema

The top-level catalog object:

json
{
  "version": 1,
  "lastUpdated": "2026-01-01T00:00:00Z",
  "skins": [ ... ]
}

Each entry in "skins" is an object with the following fields:

FieldTypeRequiredDescription
idstringYes16-character hex identifier. Generate with sha256("source:downloadURL")[:16]. Must be unique across the catalog.
namestringYesDisplay name shown in the Skin Browser (e.g. "Dark Mode GBA").
authorstring or nullNoSkin creator's name or handle.
systemsstring arrayYesShort system codes (e.g. ["gba"]). See Supported Systems.
gameTypeIdentifierstring or nullNoDelta-compatible game type identifier (e.g. "com.rileytestut.delta.game.gba").
versionstring or nullNoSkin version string, if available.
downloadURLstringYesDirect download URL for the .deltaskin or .manicskin file. Must be publicly accessible.
thumbnailURLstring or nullNoURL to a preview image (JPEG or PNG). Displayed in the skin browser grid.
screenshotURLsstring arrayNoAdditional in-use screenshot URLs.
tagsstring arrayNoOptional tags such as "landscape", "dark", "minimal".
deviceSupportstring arrayNoDevice hints, e.g. ["iphone-x", "iphone-legacy"].
downloadCountnumber or nullNoDownload count, if known from source.
ratingnumber or nullNoRating from 0.0–5.0, if known from source.
lastUpdatedstring or nullNoISO 8601 date when the skin file was last updated.
fileSizenumber or nullNoFile size in bytes, if known.
sourcestringYesShort source identifier (e.g. "delta-skins.github.io", "manual").

Minimal valid entry

json
{
  "id": "a1b2c3d4e5f60718",
  "name": "My Awesome GBA Skin",
  "author": "yourname",
  "systems": ["gba"],
  "gameTypeIdentifier": "com.rileytestut.delta.game.gba",
  "version": null,
  "downloadURL": "https://github.com/yourname/skins/raw/main/MyAwesomeGBA.deltaskin",
  "thumbnailURL": null,
  "screenshotURLs": [],
  "tags": [],
  "deviceSupport": [],
  "downloadCount": null,
  "rating": null,
  "lastUpdated": null,
  "fileSize": null,
  "source": "manual"
}

Option A: Auto-generate via Scraper

The easiest way to refresh the catalog with all known community skins is to run the bundled scraper script.

Prerequisites

bash
pip install -r Scripts/requirements-scraper.txt

The script also works without extra packages using stdlib fallbacks (slower HTML parsing for the delta-skins source):

bash
python3 Scripts/scrape_skin_catalog.py --help

Run the scraper

bash
# Scrape all sources and write to Scripts/catalog_seed.json
python3 Scripts/scrape_skin_catalog.py \
    --source all \
    --output Scripts/catalog_seed.json

# Copy to the bundled app resources
cp Scripts/catalog_seed.json \
    PVUI/Sources/PVUIBase/Resources/catalog_seed.json

Providing a GitHub token avoids the 60 req/hr anonymous API rate limit when scraping GitHub-hosted sources:

bash
export GITHUB_TOKEN="YOUR_GITHUB_TOKEN"
python3 Scripts/scrape_skin_catalog.py --source all --output Scripts/catalog_seed.json

Dry-run (no network requests)

bash
python3 Scripts/scrape_skin_catalog.py --dry-run --source all

Validate an existing catalog

bash
# Validate schema and check for broken download URLs
python3 Scripts/scrape_skin_catalog.py --validate Scripts/catalog_seed.json

Scrape a specific source only

bash
# Supported: delta-skins, broank, litritt
python3 Scripts/scrape_skin_catalog.py --source delta-skins --output Scripts/catalog_seed.json

Adding a new scraper source

To add support for a new community skin host, add a new scraper function to Scripts/scrape_skin_catalog.py and register it in the SOURCE_SCRAPERS dictionary at the bottom of the file.


Option B: Add a Skin Manually

Use this approach to add a single skin from any publicly accessible URL.

Step 1: Generate a unique ID

Python (recommended):

python
import hashlib
source = "manual"
download_url = "https://example.com/MySkin.deltaskin"
skin_id = hashlib.sha256(f"{source}:{download_url}".encode()).hexdigest()[:16]
print(skin_id)

Shell:

bash
printf 'manual:https://example.com/MySkin.deltaskin' | shasum -a 256 | cut -c1-16

Step 2: Edit catalog_seed.json

Open Scripts/catalog_seed.json and add a new entry to the "skins" array. Required fields are id, name, systems, downloadURL, and source.

Make sure to place a comma between entries and keep the JSON valid. Avoid reordering existing entries; just insert your new skin near similar systems to minimize diff noise. A strict global sort order is not required.

Step 3: Validate JSON

bash
python3 -m json.tool Scripts/catalog_seed.json > /dev/null && echo "Valid JSON"

Step 4: Sync to app resources

bash
cp Scripts/catalog_seed.json \
    PVUI/Sources/PVUIBase/Resources/catalog_seed.json

Deploying Changes

After updating either file (via scraper or manual edit), always sync both:

bash
cp Scripts/catalog_seed.json \
    PVUI/Sources/PVUIBase/Resources/catalog_seed.json

Commit both files together in your PR.


PR Guidelines

  1. Target the develop branch.
  2. Commit both files: Scripts/catalog_seed.json and PVUI/Sources/PVUIBase/Resources/catalog_seed.json.
  3. PR title format:
    • Single skin: feat(skins): add "Skin Name" to catalog
    • Bulk refresh: chore(skins): refresh skin catalog from scraper
  4. Verify the download URL is publicly accessible before submitting — paste the URL into a browser and confirm the file downloads.
  5. Include a thumbnail URL when possible so users can preview the skin in the browser grid.
  6. One skin per PR for manual additions. Bulk scraper refreshes are fine in a single PR.
  7. Check for duplicates: search Scripts/catalog_seed.json for the skin's downloadURL before adding.

Supported Systems

The following system short codes are currently scraped/populated by the skin catalog and recognised by the Provenance skin browser:

Short CodeSystemgameTypeIdentifier
gbaGame Boy Advancecom.rileytestut.delta.game.gba
gbcGame Boy Color / Game Boycom.rileytestut.delta.game.gbc
nesNintendo Entertainment Systemcom.rileytestut.delta.game.nes
snesSuper Nintendocom.rileytestut.delta.game.snes
n64Nintendo 64com.rileytestut.delta.game.n64
ndsNintendo DScom.rileytestut.delta.game.ds
genesisSega Genesis / Mega Drivecom.rileytestut.delta.game.genesis
unofficialMulti-system / other(none)

Note: The app's system mapping supports additional codes (for example: vb, pm, 3ds, psx, etc.). For the full, authoritative list of recognised system codes, see the SYSTEM_MAP dictionary in Scripts/scrape_skin_catalog.py.

To add support for a new system (or adjust an existing one), update the SYSTEM_MAP dictionary in Scripts/scrape_skin_catalog.py.


Questions?

Open a GitHub issue in the Provenance-Emu/Provenance repository.