diff --git a/docs/RollbackImplementationPlan.md b/docs/RollbackImplementationPlan.md index 2c838228..742e97ef 100644 --- a/docs/RollbackImplementationPlan.md +++ b/docs/RollbackImplementationPlan.md @@ -433,8 +433,8 @@ Rollback restores: Rollback does not restore: -- global-device variables -- global-account variables +- device variables +- account variables - seen registries Implementation rule: diff --git a/docs/SaveLoad.md b/docs/SaveLoad.md index 60a87cbd..86c224ea 100644 --- a/docs/SaveLoad.md +++ b/docs/SaveLoad.md @@ -57,8 +57,8 @@ Rollback data lives inside context state and is therefore part of saved story st Persistent global variables are variables with scope: -- `global-device` -- `global-account` +- `device` +- `account` These are not story-local and should not be stored inside save slot state. @@ -161,7 +161,7 @@ This is a product decision, not an implementation detail. ### Persistent globals stay outside save slots -`global-device` and `global-account` variables are intentionally not saved into slots. +`device` and `account` variables are intentionally not saved into slots. Load should not roll them back or replace them from slot data. diff --git a/docs/StorySessionReset.md b/docs/StorySessionReset.md index 3030ac4b..30dff4a2 100644 --- a/docs/StorySessionReset.md +++ b/docs/StorySessionReset.md @@ -18,7 +18,7 @@ where the engine should: - clear rollback/session-local history - clear seen/viewed state - clear transient runtime UI/playback state -- preserve `global-device` and `global-account` variables +- preserve `device` and `account` variables without introducing dedicated `startGame` / `exitGame` engine actions. @@ -58,7 +58,7 @@ When `resetStorySession` runs, the engine should: ### Preserve - current context read pointer -- `global.variables` for `global-device` and `global-account` +- `global.variables` for `device` and `account` - `projectData` - `global.saveSlots` @@ -233,7 +233,7 @@ actions: - resets rollback to a single checkpoint anchored at the current read pointer - clears `viewedRegistry.sections` - clears `viewedRegistry.resources` -- preserves `global-device` and `global-account` variables +- preserves `device` and `account` variables - clears transient globals and queues timer-clear effects - appends effects instead of replacing the pending queue - when ordered after `sectionTransition` in the same batch, anchors rollback at diff --git a/package.json b/package.json index f02e43e6..4e0d7f10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "route-engine-js", - "version": "0.7.6", + "version": "0.8.0", "description": "A lightweight Visual Novel engine built in JavaScript for creating interactive narrative games with branching storylines", "repository": { "type": "git", diff --git a/spec/system/actions/resetStorySession.spec.yaml b/spec/system/actions/resetStorySession.spec.yaml index 4dff9890..a84f542c 100644 --- a/spec/system/actions/resetStorySession.spec.yaml +++ b/spec/system/actions/resetStorySession.spec.yaml @@ -21,11 +21,11 @@ in: default: false volume: type: number - scope: global-device + scope: device default: 80 unlockedEnding: type: boolean - scope: global-account + scope: account default: false story: initialSceneId: scene1 @@ -132,11 +132,11 @@ out: default: false volume: type: number - scope: global-device + scope: device default: 80 unlockedEnding: type: boolean - scope: global-account + scope: account default: false story: initialSceneId: scene1 diff --git a/spec/system/actions/rollbackToLine.spec.yaml b/spec/system/actions/rollbackToLine.spec.yaml index 9de91da6..495776a5 100644 --- a/spec/system/actions/rollbackToLine.spec.yaml +++ b/spec/system/actions/rollbackToLine.spec.yaml @@ -667,7 +667,7 @@ in: variables: volume: type: number - scope: global-device + scope: device default: 50 global: variables: @@ -720,7 +720,7 @@ out: variables: volume: type: number - scope: global-device + scope: device default: 50 global: variables: diff --git a/spec/system/actions/updateVariable.spec.yaml b/spec/system/actions/updateVariable.spec.yaml index d438fcaf..65328f7c 100644 --- a/spec/system/actions/updateVariable.spec.yaml +++ b/spec/system/actions/updateVariable.spec.yaml @@ -42,7 +42,7 @@ out: - variables: playerName: "Alice" --- -case: set global-device variable +case: set device variable in: - state: projectData: @@ -50,7 +50,7 @@ in: variables: volume: type: number - scope: global-device + scope: device default: 50 global: variables: @@ -69,7 +69,7 @@ out: variables: volume: type: number - scope: global-device + scope: device default: 50 global: variables: @@ -83,7 +83,7 @@ out: contexts: - variables: {} --- -case: set global-account variable +case: set account variable in: - state: projectData: @@ -91,7 +91,7 @@ in: variables: achievement1: type: boolean - scope: global-account + scope: account default: false global: variables: @@ -110,7 +110,7 @@ out: variables: achievement1: type: boolean - scope: global-account + scope: account default: false global: variables: @@ -196,7 +196,7 @@ out: - variables: soundEnabled: false --- -case: toggle global-device boolean +case: toggle device boolean in: - state: projectData: @@ -204,7 +204,7 @@ in: variables: notificationsOn: type: boolean - scope: global-device + scope: device default: false global: variables: @@ -222,7 +222,7 @@ out: variables: notificationsOn: type: boolean - scope: global-device + scope: device default: false global: variables: @@ -248,11 +248,11 @@ in: default: 0 volume: type: number - scope: global-device + scope: device default: 50 achievement1: type: boolean - scope: global-account + scope: account default: false global: variables: @@ -282,11 +282,11 @@ out: default: 0 volume: type: number - scope: global-device + scope: device default: 50 achievement1: type: boolean - scope: global-account + scope: account default: false global: variables: @@ -564,7 +564,7 @@ in: - variableId: badVar op: set value: 10 -throws: "Invalid variable scope: invalid for variable badVar. Expected one of: context, global-device, global-account" +throws: "Invalid variable scope: invalid for variable badVar. Expected one of: context, device, account" --- case: error - unknown variable type in: @@ -723,7 +723,7 @@ out: - id: sword name: Steel Sword --- -case: set global-device object variable +case: set device object variable in: - state: projectData: @@ -731,7 +731,7 @@ in: variables: pageButtons: type: object - scope: global-device + scope: device default: items: [] global: @@ -757,7 +757,7 @@ out: variables: pageButtons: type: object - scope: global-device + scope: device default: items: [] global: diff --git a/spec/system/createInitialState.spec.yaml b/spec/system/createInitialState.spec.yaml index a383e7c6..2c68f48d 100644 --- a/spec/system/createInitialState.spec.yaml +++ b/spec/system/createInitialState.spec.yaml @@ -90,7 +90,7 @@ in: name: Steel Sword pageButtons: type: object - scope: global-device + scope: device default: items: - label: A @@ -142,7 +142,7 @@ out: name: Steel Sword pageButtons: type: object - scope: global-device + scope: device default: items: - label: A @@ -277,15 +277,15 @@ in: variables: volume: type: number - scope: global-device + scope: device default: 50 achievement1: type: boolean - scope: global-account + scope: account default: false newVariable: type: string - scope: global-device + scope: device default: "default" story: initialSceneId: "scene1" @@ -326,15 +326,15 @@ out: variables: volume: type: number - scope: global-device + scope: device default: 50 achievement1: type: boolean - scope: global-account + scope: account default: false newVariable: type: string - scope: global-device + scope: device default: "default" story: initialSceneId: "scene1" diff --git a/src/schemas/projectData/resources.yaml b/src/schemas/projectData/resources.yaml index 2e654016..6e9c15ca 100644 --- a/src/schemas/projectData/resources.yaml +++ b/src/schemas/projectData/resources.yaml @@ -309,7 +309,7 @@ properties: enum: [string, boolean, number, object] scope: type: string - enum: [context, global-device, global-account] + enum: [context, device, account] default: description: Default initial value for the variable. Runtime accepts any YAML value and uses it as-is additionalProperties: true diff --git a/src/schemas/systemState/effects.yaml b/src/schemas/systemState/effects.yaml index dc002d44..af4563f7 100644 --- a/src/schemas/systemState/effects.yaml +++ b/src/schemas/systemState/effects.yaml @@ -35,7 +35,7 @@ anyOf: required: [name, payload] additionalProperties: false - - title: Save global-device variables effect + - title: Save device variables effect type: object properties: name: @@ -51,7 +51,7 @@ anyOf: required: [name, payload] additionalProperties: false - - title: Save global-account variables effect + - title: Save account variables effect type: object properties: name: diff --git a/src/schemas/systemState/systemState.yaml b/src/schemas/systemState/systemState.yaml index 181fab5a..30ccee7c 100644 --- a/src/schemas/systemState/systemState.yaml +++ b/src/schemas/systemState/systemState.yaml @@ -210,7 +210,7 @@ properties: $ref: "./effects.yaml" variables: type: object - description: Global-device and global-account variables + description: Device- and account-scoped variables additionalProperties: true saveSlots: type: object diff --git a/src/stores/system.store.js b/src/stores/system.store.js index 0834f5a9..742f250c 100644 --- a/src/stores/system.store.js +++ b/src/stores/system.store.js @@ -2688,9 +2688,9 @@ export const updateVariable = ({ state }, payload) => { if (scope === "context") { contextVariableModified = true; contextOperations.push({ variableId, op, value }); - } else if (scope === "global-device") { + } else if (scope === "device") { globalDeviceModified = true; - } else if (scope === "global-account") { + } else if (scope === "account") { globalAccountModified = true; } @@ -2705,12 +2705,12 @@ export const updateVariable = ({ state }, payload) => { }); } - // Save global-device variables if any were modified + // Save device-scoped variables if any were modified if (globalDeviceModified) { const globalDeviceVars = filterVariablesByScope( state.global.variables, state.projectData.resources?.variables, - "global-device", + "device", ); state.global.pendingEffects.push({ name: "saveGlobalDeviceVariables", @@ -2720,12 +2720,12 @@ export const updateVariable = ({ state }, payload) => { }); } - // Save global-account variables if any were modified + // Save account-scoped variables if any were modified if (globalAccountModified) { const globalAccountVars = filterVariablesByScope( state.global.variables, state.projectData.resources?.variables, - "global-account", + "account", ); state.global.pendingEffects.push({ name: "saveGlobalAccountVariables", diff --git a/src/util.js b/src/util.js index 31025380..52d42c10 100644 --- a/src/util.js +++ b/src/util.js @@ -347,7 +347,7 @@ export const getVariableDefaultValue = (config, variableId) => { * resources: { * variables: { * playerName: { type: 'string', scope: 'context', default: 'Player' }, - * volume: { type: 'number', scope: 'global-device', default: 50 } + * volume: { type: 'number', scope: 'device', default: 50 } * } * } * }; @@ -370,7 +370,7 @@ export const getDefaultVariablesFromProjectData = (projectData) => { if (config.scope === "context") { contextVariableDefaultValues[variableId] = value; } else { - // global-device and global-account scopes both go to globalVariablesDefaultValues + // device and account scopes both go to globalVariablesDefaultValues globalVariablesDefaultValues[variableId] = value; } }, @@ -388,12 +388,12 @@ export const getDefaultVariablesFromProjectData = (projectData) => { * @throws {Error} If scope is missing or invalid * * @example - * validateVariableScope('runtime', 'score') // No error + * validateVariableScope('device', 'score') // No error * validateVariableScope('invalid', 'score') // Throws Error * validateVariableScope(undefined, 'score') // Throws Error */ export const validateVariableScope = (scope, variableId) => { - const VALID_SCOPES = ["context", "global-device", "global-account"]; + const VALID_SCOPES = ["context", "device", "account"]; if (!scope) { throw new Error(`Variable scope is required for variable: ${variableId}`); @@ -491,17 +491,17 @@ export const applyVariableOperation = (currentValue, op, value) => { * * @param {Object} variables - Object containing variable values * @param {Object} variableConfigs - Variable configuration objects with scope information - * @param {string} targetScope - Scope to filter by (context, global-device, or global-account) + * @param {string} targetScope - Scope to filter by (context, device, or account) * @returns {Object} New object containing only variables matching the target scope * * @example * const vars = { score: 100, volume: 80, achievement: true }; * const configs = { * score: { scope: 'context' }, - * volume: { scope: 'global-device' }, - * achievement: { scope: 'global-account' } + * volume: { scope: 'device' }, + * achievement: { scope: 'account' } * }; - * filterVariablesByScope(vars, configs, 'global-device') // { volume: 80 } + * filterVariablesByScope(vars, configs, 'device') // { volume: 80 } * filterVariablesByScope(vars, configs, 'context') // { score: 100 } */ export const filterVariablesByScope = ( diff --git a/tasks/TASK/000/TASK-013.md b/tasks/TASK/000/TASK-013.md index cc4ff8aa..f9e67ba0 100644 --- a/tasks/TASK/000/TASK-013.md +++ b/tasks/TASK/000/TASK-013.md @@ -20,7 +20,7 @@ context: - in game point systems -global-device +device - stored per device, saved globally in device - will persist over restarts - not saved in save data @@ -28,9 +28,9 @@ global-device - audio volume - text display speed -global-account +account - persists across game/story starts -- unlike global-device, should be tied to the user in cloud systems. +- unlike device, should be tied to the user in cloud systems. - example: - show extra section only when user has completed a specifc route or entire story @@ -43,4 +43,3 @@ boolean, string, number/integer, object, array, enum, etc... need action to edit/mutate variable values. currently I think we have only basic increment - diff --git a/vt/specs/choice/interaction-guards.yaml b/vt/specs/choice/interaction-guards.yaml index 3a057b96..206d974c 100644 --- a/vt/specs/choice/interaction-guards.yaml +++ b/vt/specs/choice/interaction-guards.yaml @@ -61,7 +61,7 @@ resources: variables: _autoForwardTime: type: number - scope: global-device + scope: device default: 5000 controls: guardControls: diff --git a/vt/specs/choice/skip-stops-on-choice.yaml b/vt/specs/choice/skip-stops-on-choice.yaml index af5980ac..68023e07 100644 --- a/vt/specs/choice/skip-stops-on-choice.yaml +++ b/vt/specs/choice/skip-stops-on-choice.yaml @@ -41,7 +41,7 @@ resources: variables: _skipUnseenText: type: boolean - scope: global-device + scope: device default: true controls: guardControls: diff --git a/vt/specs/complete/one.yaml b/vt/specs/complete/one.yaml index bb69e92e..a9daafe2 100644 --- a/vt/specs/complete/one.yaml +++ b/vt/specs/complete/one.yaml @@ -57,7 +57,7 @@ resources: textSpeed: type: number default: 50 - persistence: global-device + persistence: device controls: base1: elements: diff --git a/vt/specs/dialogue/skip-revealing.yaml b/vt/specs/dialogue/skip-revealing.yaml index 2ac3d86e..db496b0c 100644 --- a/vt/specs/dialogue/skip-revealing.yaml +++ b/vt/specs/dialogue/skip-revealing.yaml @@ -22,7 +22,7 @@ resources: variables: _skipUnseenText: type: boolean - scope: global-device + scope: device default: true characters: narrator: diff --git a/vt/specs/dialogue/skip-timing.yaml b/vt/specs/dialogue/skip-timing.yaml index 39eba1df..001df180 100644 --- a/vt/specs/dialogue/skip-timing.yaml +++ b/vt/specs/dialogue/skip-timing.yaml @@ -22,7 +22,7 @@ resources: variables: _skipUnseenText: type: boolean - scope: global-device + scope: device default: true characters: narrator: diff --git a/vt/specs/save/dynamic-slot-selector-test.yaml b/vt/specs/save/dynamic-slot-selector-test.yaml index 2d4a58f9..4c068708 100644 --- a/vt/specs/save/dynamic-slot-selector-test.yaml +++ b/vt/specs/save/dynamic-slot-selector-test.yaml @@ -14,7 +14,7 @@ resources: variables: loadPage: type: number - scope: global-device + scope: device default: 1 previewFrame: type: string diff --git a/vt/specs/sfx/sound-volume.yaml b/vt/specs/sfx/sound-volume.yaml index 7bcbf4d2..9c044679 100644 --- a/vt/specs/sfx/sound-volume.yaml +++ b/vt/specs/sfx/sound-volume.yaml @@ -9,11 +9,11 @@ resources: variables: _soundVolume: type: number - scope: global-device + scope: device default: 500 _muteAll: type: boolean - scope: global-device + scope: device default: false layouts: main: diff --git a/vt/specs/slider/slider-variable-binding.yaml b/vt/specs/slider/slider-variable-binding.yaml index 08ad49eb..5df6b2f3 100644 --- a/vt/specs/slider/slider-variable-binding.yaml +++ b/vt/specs/slider/slider-variable-binding.yaml @@ -9,7 +9,7 @@ resources: variables: sliderValue: type: number - scope: global-device + scope: device default: 50 images: horizontal_idle_thumb: diff --git a/vt/specs/variables/boolean-test.yaml b/vt/specs/variables/boolean-test.yaml index 0ad1cd38..b3086f5b 100644 --- a/vt/specs/variables/boolean-test.yaml +++ b/vt/specs/variables/boolean-test.yaml @@ -13,11 +13,11 @@ resources: default: true notificationsOn: type: boolean - scope: global-device + scope: device default: false tutorialCompleted: type: boolean - scope: global-account + scope: account default: false controls: base1: diff --git a/vt/specs/variables/counter.yaml b/vt/specs/variables/counter.yaml index 8c9d0bf8..3a21ebe2 100644 --- a/vt/specs/variables/counter.yaml +++ b/vt/specs/variables/counter.yaml @@ -9,7 +9,7 @@ resources: variables: count: type: number - scope: global-account + scope: account default: 0 images: dmni32: diff --git a/vt/specs/variables/scope-comparison.yaml b/vt/specs/variables/scope-comparison.yaml index 98abee05..822fb512 100644 --- a/vt/specs/variables/scope-comparison.yaml +++ b/vt/specs/variables/scope-comparison.yaml @@ -1,6 +1,6 @@ --- title: Variable Scopes Comparison -description: Demonstrates context, global-device, and global-account variable scopes +description: Demonstrates context, device, and account variable scopes --- screen: width: 1920 @@ -18,19 +18,19 @@ resources: default: Town Square textSpeed: type: number - scope: global-device + scope: device default: 50 volume: type: number - scope: global-device + scope: device default: 80 totalPlaythroughs: type: number - scope: global-account + scope: account default: 0 secretUnlocked: type: boolean - scope: global-account + scope: account default: false controls: base1: @@ -176,30 +176,30 @@ resources: op: set value: Dark Forest textStyleId: textStyle9 - - id: global-deviceSection + - id: deviceSection type: container x: 100 y: 450 children: - - id: global-deviceTitle + - id: deviceTitle type: text content: GLOBAL-DEVICE SCOPE x: 0 y: 0 textStyleId: textStyle2 - - id: global-deviceDesc + - id: deviceDesc type: text content: Settings stored on this device x: 0 y: 40 textStyleId: textStyle3 - - id: global-deviceDesc2 + - id: deviceDesc2 type: text content: ✓ Persists across sessions x: 0 y: 70 textStyleId: textStyle4 - - id: global-deviceDesc3 + - id: deviceDesc3 type: text content: ✗ NOT in save slots x: 0 @@ -314,30 +314,30 @@ resources: op: decrement value: 10 textStyleId: textStyle7 - - id: global-accountSection + - id: accountSection type: container x: 100 y: 750 children: - - id: global-accountTitle + - id: accountTitle type: text content: GLOBAL-ACCOUNT SCOPE x: 0 y: 0 textStyleId: textStyle2 - - id: global-accountDesc + - id: accountDesc type: text content: Achievements across all playthroughs x: 0 y: 40 textStyleId: textStyle3 - - id: global-accountDesc2 + - id: accountDesc2 type: text content: ✓ Persists forever x: 0 y: 70 textStyleId: textStyle4 - - id: global-accountDesc3 + - id: accountDesc3 type: text content: ✓ Shared across saves x: 0 @@ -447,43 +447,43 @@ resources: x: 350 y: 100 textStyleId: textStyle4 - - id: global-deviceRow + - id: deviceRow type: text content: Device x: 0 y: 140 textStyleId: textStyle4 - - id: global-deviceSaved + - id: deviceSaved type: text content: ✗ No x: 200 y: 140 textStyleId: textStyle4 - - id: global-devicePersist + - id: devicePersist type: text content: ✓ Yes x: 350 y: 140 textStyleId: textStyle4 - - id: global-accountRow + - id: accountRow type: text content: Global x: 0 y: 180 textStyleId: textStyle4 - - id: global-accountSaved + - id: accountSaved type: text content: ✗ No* x: 200 y: 180 textStyleId: textStyle4 - - id: global-accountPersist + - id: accountPersist type: text content: ✓ Yes x: 350 y: 180 textStyleId: textStyle4 - - id: global-accountNote + - id: accountNote type: text content: "* Shared across all saves" x: 0 diff --git a/vt/specs/variables/string-test.yaml b/vt/specs/variables/string-test.yaml index c8b81935..348e4fff 100644 --- a/vt/specs/variables/string-test.yaml +++ b/vt/specs/variables/string-test.yaml @@ -13,7 +13,7 @@ resources: default: Guest currentStatus: type: string - scope: global-account + scope: account default: Idle controls: base1: