Cartdata with Hot Reload

This recipe explains how to use your own cartdata() for save data while keeping the CLI's hot reload functionality working.

The Problem

The CLI uses PICO-8's cartdata() mechanism to signal hot reloads. However, PICO-8 only allows one cartdata() call per cart. If you call cartdata() in your game for saving high scores or progress, you'll get a conflict.

Solution

Configure the CLI to use the same cartdata ID as your game:

// jspicl.config.ts
import type {Config} from "@jspicl/cli/types";

const config: Config = {
spritesheetImagePath: "assets/sprites.png",
jsOutput: "build/game.js",
picoOptions: {
cartDataId: "mygame_save" // Use your game's cartdata ID
}
// ...
};

export default config;

In your game code, use the same ID:

function _init() {
cartdata("mygame_save");
highscore = dget(0); // Load high score from slot 0
}

function saveHighscore(score) {
if (score > highscore) {
highscore = score;
dset(0, highscore); // Save to slot 0
}
}

Important: Reserved Slot

The CLI reserves slot 63 (dget(63) / dset(63)) for hot reload signals. Do not use this slot in your game.

Available slots: 0-62 (63 slots total)

// Safe to use
dset(0, highscore);
dset(1, playerLevel);
dset(2, unlockedStages);
// ...
dset(62, lastSetting);

// DO NOT USE - reserved for hot reload
// dset(63, anything);

Complete Example

const SLOT_HIGHSCORE = 0;
const SLOT_SOUND_ON = 1;
const SLOT_MUSIC_ON = 2;

function _init() {
cartdata("mygame_save");

// Load saved data
highscore = dget(SLOT_HIGHSCORE);
soundOn = dget(SLOT_SOUND_ON) != 0;
musicOn = dget(SLOT_MUSIC_ON) != 0;
}

function saveGame() {
dset(SLOT_HIGHSCORE, highscore);
dset(SLOT_SOUND_ON, soundOn ? 1 : 0);
dset(SLOT_MUSIC_ON, musicOn ? 1 : 0);
}