Design save/load for game state — choosing what to serialize, file formats, save slots, atomic crash-safe writes, schema versioning and migration, and autosave. Engine-neutral. Use when the user mentions save system, save/load, game state persistence, save slots, autosave, save file corruption, or migrating old saves to a new version.
This skill covers designing save/load systems for game state in an engine-neutral way. It frames the hard parts not as writing bytes but as choosing what to serialize, writing it so a crash mid-save cannot corrupt it, and reading old saves after shipping a patch. Get those three right and the rest is plumbing. The guidance targets the durability and forward-compatibility problems that break real games after updates.
The core workflow decides what state is authoritative (save the data — hp, position, seed, unlocked flags — not engine objects or live node references), defines a versioned schema with a `version` integer, picks a format (JSON for readability, binary for size/speed), writes atomically via temp-file-plus-rename with a backup for non-atomic platforms, loads defensively by reading version then migrating up then validating then instantiating, autosaves on safe boundaries to a separate slot, and verifies by full quit-and-relaunch. A detailed reference explains the non-negotiable version field, a migration chain of pure `vN -> vN+1` functions applied in order, backups and rotating autosave rings, checksums for corruption detection, format trade-offs, a load-time validation checklist, and what to store versus recompute. Examples appear in GDScript and Python.
The target users are game developers building persistence for player progress, save slots, quicksave/autosave, and crash-safe writes, and anyone whose old save files break after a content or code change. Use cases include designing a new save system and adding schema migration to an existing one.
Choosing what to serialize, writing it so a crash mid-save cannot corrupt the file, and being able to read old saves after you ship a patch.
Write atomically: serialize to a temp file, flush, then rename over the real file so a crash leaves either the old or new save. On platforms where rename isn't atomic, keep the previous file as a .bak backup for recovery.
Every save embeds a version integer. On load you read the version, refuse saves newer than the build, run a chain of pure vN-to-vN+1 migration functions in order for older saves, then validate and instantiate. Old migrations are kept forever so any version stays reachable.
Store authoritative, non-derivable state like choices, unlocked flags, RNG seed, inventory, and positions; recompute derived data such as full stat tables or procedural maps on load to avoid desync and bloat.
No, it is engine-neutral with GDScript and Python examples, and it defers to engine-specific skills for details like Godot's FileAccess/ResourceSaver or Roblox DataStores.
Quick Setup:
.claude/skills/