Skip to content

State and settings

State follows the reader through the story. It’s saved in bookmarks, and it rewinds and replays with the reader.

Settings aren’t tied to the reader’s place in the story. They aren’t saved in bookmarks, and they don’t change when the reader steps backward or forward. Use them for things like preferences, unlocked galleries, and achievements.

Scripts loaded from your project.json’s main script share one state object and one settings object. Screenplay expressions can read that state too.

Each plugin has its own private state and settings. To share data with other plugins, a plugin provides selectors.

State and settings are plain objects. State starts as an empty object, {}, unless you set its starting value with onInitState. Settings get their starting values from onInitSettings.

Returns the current state.

getState<T>(): T
Example
const trust = getState().trust;

Replaces the current state.

setState<T>(newState: T | ((currentState: T) => T)): void

Pass the new state, or a function that takes the current state and returns the new one. Use the function form when the new state depends on the current state.

setState replaces the whole object. To change only part of it, use updateState.

Example
setState({
trust: 1,
achievements: ["first-blood"],
});
setState((current) => ({
...current,
trust: current.trust + 1,
}));

Merges a value into the current state.

updateState<T>(newState: T | ((currentState: T) => T)): void

Pass the values to merge, or a function that takes the current state and returns them.

The merge is shallow. Each top-level key you pass replaces the existing value, so spread nested objects to keep their other values.

Example
updateState({ trust: 8 });
updateState((current) => ({ trust: current.trust + 1 }));

Returns the current settings.

getSettings<T>(): T
Example
const { volume } = getSettings();

Replaces the current settings.

setSettings<T>(newSettings: T | ((currentSettings: T) => T)): void

Pass the new settings, or a function that takes the current settings and returns the new ones. Use the function form when the new settings depend on the current settings.

Example
setSettings({
volume: 0.8,
unlocked: { "prologue-gallery": true },
});
setSettings((current) => ({
...current,
volume: 0.8,
}));

Merges a value into the current settings.

updateSettings<T>(newSettings: T | ((currentSettings: T) => T)): void

Pass the values to merge, or a function that takes the current settings and returns them.

The merge is shallow. Each top-level key you pass replaces the existing value, so spread nested objects to keep their other values.

Example
updateSettings({ volume: 0.8 });
updateSettings((current) => ({
unlocked: { ...current.unlocked, "act-1-gallery": true },
}));

Sets the starting value of your state, and migrates saved state from older versions.

onInitState<T>(versions: Versions<T>): void
type Versions<T> = {
default: T;
[version: string]: T | ((oldState: T) => T);
};
KeyValue
defaultThe state a new story starts with.
A version, like "2.0.0"A function that takes state saved by the previous version and returns it in this version’s shape.

Inkweaver runs only the versions newer than the one that saved the data, in order. Your default is merged underneath the result, so any value a migration doesn’t set falls back to the default.

The saving version is the version in your plugin.json at the time, or in project.json for your novel’s own scripts.

If you don’t call onInitState, your state starts as {}.

Example
const DEFAULTS = { reputation: 0 };
// Before v2, `reputation` was called `trust`.
function toV2(oldState) {
const { trust, ...rest } = oldState;
return {
...rest,
reputation: trust,
};
}
onInitState({
default: DEFAULTS,
"2.0.0": toV2,
});

Sets the starting value of your settings, and migrates saved settings from older versions.

onInitSettings<T>(versions: Versions<T>): void

Works the same way as onInitState, except that settings are loaded once, at startup.

Example
const DEFAULTS = {
masterVolume: 1,
musicVolume: 1,
voiceVolume: 1,
};
// V2 splits volume into three channels.
function toV2(oldSettings) {
const { volume, ...rest } = oldSettings;
return {
...rest,
masterVolume: volume,
musicVolume: volume,
voiceVolume: volume,
};
}
onInitSettings({
default: DEFAULTS,
"2.0.0": toV2,
});