Files
gen1recomp/docs/new-features.md
T
bryanthaboi ebf44f20d3 Add custom carts: named, version-pinned mod sets that play as their own game
A custom cart pairs an identity (title, shell colour, label art) with a base
game, a list of mods pinned to exact builds with their option values frozen,
a load order, and a seal. It ships no code of its own: every mod it names is
a separately published mod, which is what keeps a cart auditable before it
runs and reproducible after an author's repo disappears.

Format and storage:
- src/carts/CartManifest.lua parses and validates cart.json, canonicalises it
  for hashing and reads/writes the .g1rcart bundle. The bundle is a data-only
  serialised table read through SaveSerializer, so an imported cart can never
  execute code. Canonical strings are length-prefixed because option keys and
  values are author-controlled and could otherwise forge a record boundary and
  collide two different carts onto one hash.
- Pins name a public source: a GitHub release with its sha256, a GameBanana
  file id with its md5, or "local" for a capture that only exists on this
  install. A local pin is unpublishable by construction, which is what makes
  "build it here, publish later" possible without inventing a hash.
- Label art rides alongside the manifest rather than inside its identity, so
  re-arting a cart does not tell every player their run is out of date.
  src/core/Base64.lua decodes it; strict, with no whitespace tolerance.

Saves:
- Cart playthroughs live in the cart's own slot namespace (saves/cart_<id>/),
  so a cart's file never sits beside a vanilla one and uninstalling a cart
  never orphans a save. Every save records the cart build it was made under.

The seal:
- A sealed cart loads its pinned list, in its order, with its options, and
  nothing else. A pinned mod with no frozen options gets an empty bucket so
  unfrozen keys fall to schema defaults, identical for everyone; otherwise two
  players on one cart quietly run different games.
- A sealed cart refuses to load when a pin is missing or installed at another
  version. Playing a subset of the cart is the exact dishonesty the seal
  exists to prevent, so the refusal loads nothing at all.
- Breaking the seal is permanent, marked per save slot, and downgrades that
  playthrough to open behaviour. It cannot be cleared through any public API.

Launcher:
- A game's page carries a Custom Carts control and a picker; choosing a cart
  turns the page into that cart's page, with its own cartridge, title and save
  slots. The rail of five games never grows and a cart id never reaches
  imp.tab or imp.panelVersion.
- Loader.planCart runs before boot so a refusal is visible on the page instead
  of being discovered as an error after launch.
- Save as cart captures the enabled mods for a game and names, before the
  player confirms, every mod that could only be pinned to this install and
  whether the result can be shared at all.

Authoring:
- tools/cartkit.py scaffolds, validates, pins and packs a cart, and installs a
  release workflow. Its writer is byte-identical to the engine's serialiser.
2026-08-23 12:18:29 -04:00

1.7 KiB

New Features

Features intentionally added beyond the original Pokémon Red, Blue, and Yellow games:

  • Survey zoom with connected-map rendering and configurable void fill
  • Perspective tilt mode for an HD-2D-style overworld
  • Multiple color modes, including original, SGB, advanced GBC, monochrome, and classic green
  • Optional GBC screen effects, including pixel grids, shadows, glare, and transparency
  • Performance presets and configurable FPS limits
  • Peer-to-peer link play for trades and battles between Red, Blue, and Yellow
  • Persistent custom options stored separately from game saves
  • Optional widescreen battle layout
  • Mobile touch controls with editable layouts, vibration, and orientation settings
  • Screen position setting (center, upper, top) shared across all games, for clamp-on controllers that cover the lower screen
  • Touch skins in RetroArch overlay format and Delta .deltaskin (including PDF-wrapped bezel art), with per-button press states and Super Game Boy borders
  • Pokédex diploma and printer image exports
  • Shareable mod lists over save sync, optionally carrying the options set for those mods, which the receiving device is asked about before anything is changed
  • Custom carts, a named mod set saved from the mods tab and picked from a game's page, with its own shell colour, label art, save slots and export file

Gen 2 Specifics

  • Pokémon Silver as an importable, launcher-selectable version alongside Gold
  • Pokémon Crystal as an importable, launcher-selectable version alongside Gold and Silver
  • Mod manager with Gen 1 mod adapters, per-game targeting, and modkit gen2check
  • Followers for mods, plus Gen 2-only registries and hooks