Skip to content

Saves and settings

Feather 2 games have built-in save slots and a per-player settings menu. A save records everything a running game changed, and settings record each player’s preferences. Both live in the player’s Feather data folder, separate from the game’s read-only files.

Part Contents
Metadata Slot, label, real save time, in-game day and minute, play time, and whether a thumbnail exists
Level and clock The current level and game clock
Script state World-script state
Objects Objects spawned at runtime, authored objects that scripts moved or hid, and broken destructibles
Terrain Runtime terrain edits such as craters and digging
Player Position and facing
Story Quest progress and dialogue memory
Sections State that individual systems register, such as inventory, interaction, felled trees, fire, grass, season, fluids and player health

When a save loads, each system restores its own section. A section missing from an older save resets that system, and sections the game no longer uses are ignored, so saves stay loadable as a project grows.

  • Saves are written atomically, so a crash never leaves a half-written file.
  • Each save carries a SHA-256 checksum, so damage is detected on load.
  • The previous save of a slot is kept as <slot>.bak.json and loaded automatically if the current one is damaged.
  • Autosaves rotate through auto, auto-2, auto-3 and so on, so one bad autosave never loses the whole history.
  • The save format is versioned; older saves are migrated on load.

Saving is configured per project in Project settings → Saves & autosave, or with the saves object of project.game.

Setting Default Range
autosave_minutes 5 0 to 240 real minutes between autosaves; 0 turns timed autosave off
autosave_each_day Off Autosave at every in-game dawn
autosave_slots 3 1 to 10 rotating autosaves
manual_slots 6 1 to 50 slots in the save menu
quicksave_key, quickload_key F5, F9 Empty disables
thumbnails On Capture a small screenshot with each save
pause_menu On Offer Save game and Load game in the pause menu

Slot names are 1 to 32 letters, digits, _ or -. The name profile is reserved for permanent player progress.

Function Description
save_game(slot), save_game(slot, label) Save to a slot
load_game(slot), has_save(slot) Load a slot, or check that it exists
autosave(), delete_save(slot), latest_save(), save_slots() Manage slots
open_save_menu(mode), close_save_menu() Show or hide the built-in save menu
profile_get(key, default), profile_set(key, value), profile_has(key) Progress that persists across runs and saves
on_load() A hook that runs after a save has loaded

See Scripting.

Players change settings from the pause menu (Escape, or the gamepad’s pause button) under Settings:

Setting Values
Graphics quality Low, Medium, High (default). Controls terrain view distance, shadow map size (1024, 2048, 4096), ambient occlusion (High only), bloom (Medium and High) and foliage distance
Fullscreen Borderless fullscreen or windowed
Vertical sync On by default
Volume, Music, Effects, Voices 0 to 2; 1 is the default
Mouse sensitivity 0.1 to 4
Camera shake 0 to 1
Motion blur On or off, where the project uses it
Language One of the project’s languages
Controls Rebind any input action to a key or gamepad button

Out-of-range values in a settings file are clamped when it loads.

A game can replace the engine’s pause menu with its own title and pause screens, and build its own options screen on the same player settings.

Function Description
use_game_menu(on) The game draws its own title and pause menus: Escape reaches on_key instead of opening the engine’s menu
open_system_menu() Opens the engine’s menu, with its settings and key bindings
pause_game(on), game_paused() Freeze or resume game time: physics, timers and the player stop, while hooks keep running with dt 0
user_settings() The player’s settings as a map
set_user_setting(key, value) Changes one setting. It is saved like a change in the pause menu’s Settings
quit_game() Quits to the desktop. In the editor it stops Play

user_settings() and set_user_setting use these keys:

Key Value
quality "Low", "Medium" or "High"
fullscreen, vsync, motion_blur true or false
master_volume, music_volume, sfx_volume, voice_volume 0 to 2
mouse_sensitivity 0.1 to 4
camera_shake 0 to 1

Numbers outside the range are clamped. An unknown key, or a value of the wrong type, is a script error, so a typo shows up at once.

// A world script that runs its own pause menu.
fn start() {
use_game_menu(true);
}
fn on_key(key) {
if key == "ESCAPE" {
pause_game(!game_paused()); // show or hide your pause screen here too
}
if game_paused() && key == "M" {
let music = user_settings().music_volume;
set_user_setting("music_volume", if music > 0.0 { 0.0 } else { 1.0 });
}
if game_paused() && key == "Q" {
quit_game();
}
}

The engine’s own menu opens only in a standalone game, not during Play in the editor’s viewport.

File Contents
settings.json Player settings
bindings.json Rebound controls
language.json The chosen language
saves/<game>/<slot>.json Save slots, with .bak.json backups and .png thumbnails

While you play in the editor, these files are written to the Feather data folder itself. An exported or packaged game writes them to its own folder inside the Feather data folder, named after the project: games/<project-slug>-<hash>/. On macOS that is under ~/Library/Application Support/Feather v2/. Moving or replacing the game files does not touch this data. Set FEATHER_DATA_ROOT to an absolute path to redirect it, for example for testing.

Agents can inspect saves made while playing in the editor, which are stored under saves/<project-slug>/ in the editor’s data folder:

Terminal window
feather-cli --workspace ./my-game --project project.feather.json command save.list
feather-cli --workspace ./my-game --project project.feather.json command save.inspect \
--json '{"slot":"auto"}'

save.delete removes a slot together with its backup and thumbnail. Save behaviour is set with project.game:

Terminal window
feather-cli --workspace ./my-game --project project.feather.json command project.game \
--json '{"saves":{"autosave_minutes":10,"manual_slots":12}}' --save project.feather.json