SaveFlow Lite is a comfort-first save workflow plugin for Godot 4.
It is built for developers who do not just need to write save files, but need a cleaner way to organize save logic as projects grow.
- Godot:
4.6 - Plugin version:
1.0.1 - Documentation: SaveFlow Lite Docs
- License: MIT
- Tests: runtime suite passing locally
Start with the smallest ownership model that matches what you are saving:
| You Need To Save | Typical Example | Recommended Path |
|---|---|---|
| One authored or prefab-owned object | player, chest, NPC, door, lever |
SaveFlowNodeSource |
| One system, model, table, or queue | quest log, inventory backend, world progression table | SaveFlowTypedDataSource or custom SaveFlowDataSource |
| A changing set of runtime entities | room enemies, dropped loot, summoned units | SaveFlowEntityCollectionSource + SaveFlowPrefabEntityFactory |
If your save must restore several domains in order, add SaveFlowScope as a domain boundary and put the right leaf sources inside it.
For a normal project, install only the addon folders:
- Download
saveflow-lite-vX.Y.Z-addons.zipfrom the latest release, or install the plugin from the Godot Asset Library. - Extract or copy
addons/saveflow_coreandaddons/saveflow_liteinto your projectaddons/folder. - Enable
SaveFlow LiteinProject > Project Settings > Plugins. - Godot will register the
SaveFlowautoload for you.
Use saveflow-lite-vX.Y.Z-addons-demo.zip only when you want a runnable demo project with the recommended template and example scenes included.
Release package shapes are intentionally narrow:
| Package | Intended use | Archive root |
|---|---|---|
Godot Asset Library / saveflow-lite-vX.Y.Z-addons.zip |
Install into an existing game project. | addons/ only. |
saveflow-lite-vX.Y.Z-addons-demo.zip |
Open the demo project directly or study example scenes. | addons/, demo/, project.godot, and this README. |
| GitHub repository clone | Inspect docs source, release automation, or public history. | Full source mirror, including docs-site. |
Do not copy docs-site, tmp, .github, tests, or release tooling into a
game project. Those paths are for the public repository and automation, not the
runtime addon package.
SaveFlow Lite now adds a SaveFlow Settings dock in the editor.
Use it for project-wide defaults such as:
- save format
- save root and slot index path
- JSON and binary file extensions
- project title, game version, save schema, and data version
- safe write, last-known-good backup, auto-create directories, slot-index metadata, and log level
- compatibility enforcement for
save_schema,data_version, and scene/scope restore targets
This panel configures the SaveFlow runtime singleton itself. It is the right
place for project-level defaults.
It is not the place for object-owned or system-owned save behavior. Keep those decisions on:
SaveFlowNodeSourceSaveFlowTypedDataSource/SaveFlowDataSourceSaveFlowEntityCollectionSourceSaveFlowScope
SaveFlow Lite also includes DevSaveManager for editor-side slot inspection.
Read its badges in this order:
Compatibility: can the slot load under the current schema/data-version policy?Restore Contract: is the current scene the expected restore target?Slot Safety: is the primary file healthy, and is backup recovery available?
If you need more than the headline state, expand Slot Details to inspect the
slot path, primary file state, backup state, schema, versions, and saved scene path.
The 2D/3D editor menu also shows a small SaveFlow validator badge. Use it to
preflight the current scene for obvious authoring mistakes such as duplicate
source keys, invalid Source/Scope/Factory plans, and misplaced pipeline signal
bridges before running the game.
- Start with one object:
SaveFlowNodeSource - Start with one system:
SaveFlowTypedDataSourceif exported typed fields are enough, customSaveFlowDataSourceif gather/apply logic is project-specific - Start with one runtime set:
SaveFlowEntityCollectionSource+SaveFlowPrefabEntityFactory - Quick component choice: saveflow-quick-selection-map.md
- Recommended integration path: saveflow-recommended-integration.md
- Public docs site source: docs-site/README.md
- Recommended template:
res://demo/saveflow_lite/recommended_template/scenes/project_workflow/recommended_project_workflow_main.tscn - Pipeline signals demo:
res://demo/saveflow_lite/recommended_template/scenes/pipeline_notifications/pipeline_notification_demo.tscn - Common authoring mistakes: saveflow-common-authoring-mistakes.md
- Commercial-project guide: saveflow-commercial-project-guide.md
- Concept relationship map: saveflow-concept-map.md
- Source tree map: saveflow-source-map.md
- C# quickstart: saveflow-csharp-quickstart.md
- Release notes: CHANGELOG.md
Use SaveFlowNodeSource when the mental model is "save this Godot object".
Examples:
- player state
- a chest that can be opened
- a door or lever with built-in node state
- an NPC with exported gameplay fields and an
AnimationPlayer
Use SaveFlowTypedDataSource when the state belongs to a typed data object
rather than one scene node.
Examples:
- quest log
- inventory model
- world progression table
- event queue
Use a custom SaveFlowDataSource when the source itself must translate tables,
registries, caches, or external manager state during gather/apply.
Use SaveFlowEntityCollectionSource when the set of entities changes over time.
Examples:
- current room enemies
- dropped loot
- summoned units
- temporary spawned world actors
Start with SaveFlowPrefabEntityFactory if one type_key maps cleanly to one prefab scene. Move to a custom SaveFlowEntityFactory only when you need pooling, authored spawn points, or custom lookup rules.
Most save plugins help you serialize data. SaveFlow Lite is aimed at an earlier pain point: structuring save/load code without ending up with glue-code spaghetti.
SaveFlow Lite focuses on:
- clean slot-based save/load APIs
- a scene and node workflow through
save_scene()andload_scene() - a hierarchical save graph workflow through
save_scope()andload_scope() - a node-centric workflow through
SaveFlowNodeSourcefor built-in Godot node state - exported-field persistence by default, instead of hand-written serializer glue
- system and table persistence through typed data resources or custom
SaveFlowDataSource - readable JSON in editor and binary output in exported builds
- lighter boilerplate for multi-system saves
- integration seams for runtime entity factories through
SaveFlowEntityCollectionSource,SaveFlowPrefabEntityFactory, andSaveFlowEntityFactory - a path that can grow into commercial project needs
SaveFlow.save_data()andSaveFlow.load_data()for direct payload savesSaveFlow.read_slot_summary(),SaveFlow.read_slot_metadata(), andSaveFlow.list_slot_summaries()for lightweight save-list UI readsSaveFlow.save_scene()andSaveFlow.load_scene()for scene/node workflowsSaveFlow.save_scope()andSaveFlow.load_scope()for hierarchical save graphsSaveFlow.inspect_scope()for graph diagnosticsSaveFlowPipelineControl,SaveFlowPipelineSignals, callback/signal events, andpipeline_tracemetadata for local save/load lifecycle controlSaveFlow.save_nodes()andSaveFlow.load_nodes()for custom saveable-node workflowsSaveFlowNodeSourcefor target-node built-ins and selected child participantsSaveFlowTypedDataandSaveFlowTypedDataSourcefor typed manager/model-style stateSaveFlowDataSourcefor custom manager, table, queue, and registry adaptersSaveFlowEntityCollectionSourceandSaveFlow.restore_entities()as the runtime-entity seamSaveFlowPrefabEntityFactoryas the default low-boilerplate runtime factory- slot operations: save, load, delete, copy, rename, list
- typed slot metadata helpers through
SaveFlowSlotMetadata - active-slot and save-card UI helpers through
SaveFlowSlotWorkflowandSaveFlowSlotCard - safe-write pipeline with temp file replacement
- optional last-known-good slot backup beside each slot file
- compatibility inspection and baseline load blocking for schema/data-version mismatches
- scene/scope restore target verification through saved scene-path metadata
- JSON in editor, binary in export through
AUTOformat - demo sandbox scene
- GdUnit4 runtime tests
Enable the SaveFlow Lite plugin in the Godot editor.
It registers an autoload named SaveFlow.
var game_data := {
"player": {
"hp": 100,
"coins": 42,
},
"settings": {
"language": "zh_CN",
},
}
var save_result: SaveResult = SaveFlow.save_data(
"slot_1",
game_data,
"Slot 1",
"manual"
)
if not save_result.ok:
push_error(save_result.error_message)
var load_result: SaveResult = SaveFlow.load_data("slot_1")
if load_result.ok:
var loaded_data: Dictionary = load_result.data
print(loaded_data)When game UI only needs save-list rows, read slot summaries instead of loading full gameplay payload:
var summaries_result: SaveResult = SaveFlow.list_slot_summaries()
if summaries_result.ok:
for summary in summaries_result.data:
print(
"%s | %s | %s" % [
summary["display_name"],
summary["save_type"],
summary["location_name"],
]
)Each summary keeps the common save-list fields at the top level:
display_namesave_typechapter_namelocation_nameplaytime_secondsdifficultythumbnail_path
and exposes compatibility_report plus custom_metadata for project-specific
UI needs.
Keep the three slot identity concepts separate:
slot_index: integer UI/session identity for sorting and active-slot stateslot_id: stable SaveFlow storage key such asslot_1display_name: player-facing metadata such asForest Gate
Recommended save-card rule:
- the game owns
active_slot_index - SaveFlow writes exactly one
slot_idper save request - manual save, autosave, and checkpoint events write the active card unless the game intentionally selected a different slot
display_nameis metadata for the row/card UI, not the storage key
Use SaveFlowSlotWorkflow when your game follows the common pattern of
integer slot selection plus stable storage keys:
const SlotWorkflowScript := preload("res://addons/saveflow_core/runtime/types/saveflow_slot_workflow.gd")
var slot_workflow: Resource = SlotWorkflowScript.new()
func _ready() -> void:
slot_workflow.slot_id_template = "slot_{index}"
slot_workflow.empty_display_name_template = "Manual Slot {index}"
slot_workflow.select_slot_index(1)
func manual_save(slot_index: int) -> void:
slot_workflow.select_slot_index(slot_index)
var meta: SaveFlowSlotMetadata = slot_workflow.build_active_slot_metadata(
"Manual Slot %d" % slot_index,
"manual",
"Chapter 1",
current_location_name(),
current_playtime_seconds()
)
SaveFlow.save_data(slot_workflow.active_slot_id(), build_payload(), meta)
func build_save_cards() -> Array:
var summaries := SaveFlow.list_slot_summaries()
if not summaries.ok:
return []
return slot_workflow.build_cards_for_indices(PackedInt32Array([1, 2, 3]), summaries.data)SaveFlowSlotWorkflow does not save automatically and does not own your
session. It only centralizes active slot index, storage-key mapping, metadata
construction, and save-card summary data.
To keep save-list metadata consistent, start from typed slot metadata. Extend
SaveFlowSlotMetadata when your project needs more save-list fields:
# my_slot_metadata.gd
class_name MySlotMetadata
extends SaveFlowSlotMetadata
@export var slot_index := 0
@export var storage_key := ""
# Save call
func save_game(game_data: Dictionary) -> void:
var meta := MySlotMetadata.new()
meta.display_name = "Forest Gate"
meta.save_type = "autosave"
meta.chapter_name = "Chapter 2"
meta.location_name = "Forest Gate"
meta.playtime_seconds = 1320
meta.slot_index = 1
meta.storage_key = "slot_1"
SaveFlow.save_data("slot_1", game_data, meta)If several save-list fields belong together, group them in a nested
SaveFlowTypedData object instead of hand-writing a dictionary:
class_name MySlotRowData
extends SaveFlowTypedData
@export var slot_index := 0
@export var storage_key := ""
@export var tags: PackedStringArray = PackedStringArray()
class_name MyGroupedSlotMetadata
extends SaveFlowSlotMetadata
@export var row_data := MySlotRowData.new()SaveFlow still writes metadata as a dictionary on disk, but gameplay code should prefer typed fields and inherited metadata classes over string-key dictionaries. If metadata contains runtime objects, raw Resources, or too many custom fields, SaveFlow emits an authoring warning. Keep metadata focused on save-list summary UI; move real gameplay state into the save payload or SaveFlow sources.
For the common path, you should not need to hand-write custom source classes for every gameplay node.
Instead, add a SaveFlowNodeSource as a child and mark the business fields you want persisted with @export or @export_storage.
SaveFlowNodeSource will persist exported fields by default, can include extra target properties, and can also include built-in transform/layout state plus selected child participants such as AnimationPlayer.
Example target node:
extends Node
@export var hp := 100
@export var coins := 42
var runtime_only_cache := {}Then add a SaveFlowNodeSource under it and configure:
save_key = "player"- leave
property_selection_modeatExported Fields + Additional Properties - use
additional_propertiesonly for extra target properties you want beyond exported fields - use
ignored_propertieswhen a target property should not be saved - optionally include child participants like
AnimationPlayer
When the node source is selected in the editor, the Inspector now shows a compact SaveFlow panel so you can verify target fields, toggle built-ins, pick child participants, and catch missing paths before writing a slot.
Save and load the scene root:
var save_result: SaveResult = SaveFlow.save_scene(
"slot_1",
$StateRoot,
"Slot 1"
)
var load_result: SaveResult = SaveFlow.load_scene("slot_1", $StateRoot)This is the main SaveFlow Lite workflow. It is meant to reduce both:
- manual payload assembly
- repeated hand-written save/load glue on every stateful node
- separate "business fields" and "built-ins" save nodes for the same object
If you want full control, save_nodes() and load_nodes() support custom SaveFlowSource subclasses.
When the user mental model is "save this Godot object", the recommended path is now SaveFlowNodeSource.
Use it when:
- the target node has built-in Godot state that should be saved by type
- selected child nodes such as
AnimationPlayershould travel with the same object - you want less hand-written source code for common engine types
Example:
Player
|- AnimationPlayer
|- SaveFlowNodeSource # exported fields + built-ins + selected child participants
SaveFlowNodeSource binds to one target node and:
- gathers exported target fields by default
- gathers supported built-ins from the target type
- lets you include selected child relative paths such as
AnimationPlayer - stores a structured payload for the target and its included participants
When selected in the editor, SaveFlowNodeSource now shows an inspector panel that lets you:
- verify which target fields will be persisted
- toggle target built-ins on and off
- pick discovered child participants from the target subtree
- verify missing paths before saving
Current first-wave built-ins:
Node2DNode3DControlAnimationPlayerTimerAudioStreamPlayer/AudioStreamPlayer2D/AudioStreamPlayer3DPathFollow2D/PathFollow3DCamera2D/Camera3DSprite2D/AnimatedSprite2DCharacterBody2D/CharacterBody3DRigidBody2D/RigidBody3DArea2DNavigationAgent2DTileMapLayer/TileMap(cell payload)
You can also inspect what SaveFlow will collect before writing a slot:
var inspect_result: SaveResult = SaveFlow.inspect_scene($StateRoot)
if inspect_result.ok:
print(inspect_result.data)Once a project grows beyond a flat scene save, the main path should move to SaveFlowScope and SaveFlowSource.
SaveFlowScopeorganizes a logical domain such asplayer,world,settings, orspawned_enemiesSaveFlowSourceis a leaf source inside that graphSaveFlowNodeSourcealready works as aSaveFlowSource, so you can reuse the same node-first workflow while changing how systems are organized
Treat SaveFlowScope as a domain boundary, not as a payload serializer.
It answers:
- which systems belong to one gameplay domain
- what order sibling domains should restore in
- how that domain should react to restore errors
It does not replace object ownership and it should not be used as a generic "container that saves things by itself".
Example graph:
SaveGraphRoot
|- PlayerScope
| |- PlayerCoreSource
| |- PartyScope
| |- AriaSource
| |- BramSource
|- WorldScope
| |- WorldStateSource
| |- QuestStateSource
| |- EnemyScope
| |- WolfAlphaSource
| |- SlimeBetaSource
|- SettingsScope
|- SettingsStateSource
Save and load the graph root:
var save_result: SaveResult = SaveFlow.save_scope(
"slot_1",
$StateRoot/SaveGraphRoot,
"Slot 1"
)
var load_result: SaveResult = SaveFlow.load_scope(
"slot_1",
$StateRoot/SaveGraphRoot,
true
)Use this path when:
- one gameplay domain spans multiple nodes
- restore order matters
- you want an explicit save hierarchy instead of one flat
save_keynamespace - runtime entities should eventually be delegated into an entity-factory-driven runtime workflow
You can inspect the graph before saving:
var inspect_result: SaveResult = SaveFlow.inspect_scope($StateRoot/SaveGraphRoot)
if inspect_result.ok:
print(inspect_result.data)For runtime entities, SaveFlow should orchestrate and your game systems should create the entities. The recommended seam is now:
SaveFlowEntityCollectionSourcefor the runtime setSaveFlowPrefabEntityFactorywhen onetype_keymaps directly to one prefab sceneSaveFlowEntityFactorywhen the project already owns pooling, authored spawning, or custom lookup logic
That keeps the save graph explicit in the scene while still letting the project own runtime spawning.
Custom factories receive the saved descriptor as the stable wire-format
dictionary, but factory code should immediately convert it to
SaveFlowEntityDescriptor so it does not depend on handwritten string keys:
extends SaveFlowEntityFactory
func can_handle_type(type_key: String) -> bool:
return type_key == "enemy"
func spawn_entity_from_save(descriptor: Dictionary, _context: Dictionary = {}) -> Node:
var entity_descriptor := resolve_entity_descriptor(descriptor)
var enemy := EnemyScene.instantiate()
enemy.name = entity_descriptor.persistent_id
return enemy
func apply_saved_data(node: Node, payload: Variant, _context: Dictionary = {}) -> void:
node.apply_runtime_payload(payload)SaveFlowEntityCollectionSource now exposes three restore policies:
Apply ExistingOnly update entities the factory can already find.Create MissingUpdate existing entities and spawn missing ones through the factory. This is the default.Clear And RestoreClear the target container first, then rebuild the saved set through the factory.
failure_policy controls failure behavior:
Report Only: SaveFlow restores what it can and reports the failures in the resultFail On Missing Or Invalid: the load fails if any entity is missing or cannot be restored
Entity descriptors have a fixed core shape: persistent_id, type_key, and
payload. Use SaveFlowIdentity.descriptor_extra only for small spawn/routing
data the factory needs before payload application, such as a spawn point or pool
id. Normal gameplay state still belongs in the entity payload.
$Enemy/Identity.descriptor_extra = {
"spawn_point": "north_gate",
"pool_id": "forest_enemies",
}For local lifecycle control, pass a SaveFlowPipelineControl to scope save/load.
The control owns callbacks; its context.values dictionary is still passed to
existing scope/source hooks.
var control := SaveFlowPipelineControl.new()
control.context.values["restore_reason"] = "continue_latest"
control.before_load = func(event: SaveFlowPipelineEvent) -> void:
print("Load slot: ", event.slot_id)
control.before_apply_source = func(event: SaveFlowPipelineEvent) -> void:
if event.key == "inventory" and not _inventory_ready():
event.cancel("Inventory is not ready.")
control.after_load = func(_event: SaveFlowPipelineEvent) -> void:
_refresh_hud()
var result := SaveFlow.load_scope("slot_1", $SaveGraphRoot, true, control)
if result.ok:
print(result.meta["pipeline_trace"])This trace reports local scope/source stages such as scope.before_load,
source.apply, and scope.after_load, plus callback stages such as
before_apply_source. It is not a scene/resource scheduler.
If the reaction belongs in a scene rather than the caller script, add a
SaveFlowPipelineSignals node under a SaveFlowScope or SaveFlowSource and
connect its signals in Godot's Node > Signals panel. The signal bridge is a
pipeline helper, so it is not written into the save payload and is ignored by
NodeSource child-participant collection.
Not every commercial save problem lives on scene nodes. Some state belongs to:
- quest managers
- inventory backends
- region tables
- event queues
- profile registries
That is what SaveFlowTypedDataSource is for.
The recommended first path is SaveFlowTypedData, a typed Resource convenience
base. Gameplay code edits fields; SaveFlow converts those fields to the normal
Variant/Dictionary payload at the graph boundary.
Recommended data object:
# world_state_data.gd
class_name WorldStateData
extends SaveFlowTypedData
@export var chapter := 1
@export var unlocked_regions: PackedStringArray = []
@export var quest_flags := {}Recommended scene workflow:
WorldState
|- SaveFlowTypedDataSource
Prefer assigning the SaveFlowTypedData resource directly to
SaveFlowTypedDataSource when the scene owns that data.
The source itself is contract-based, not Resource-only. It accepts any object that implements:
func to_saveflow_payload() -> Dictionary
func apply_saveflow_payload(payload: Dictionary) -> voidThat means a target Node, a target property holding RefCounted data, or a
custom Resource can be used without extending SaveFlowTypedData. Use this
when gameplay code creates or swaps the data at runtime.
Use a custom SaveFlowDataSource only when the source itself needs bespoke
translation logic or your project already owns a dictionary/table payload:
extends SaveFlowDataSource
func gather_data() -> Dictionary:
return export_payload_from_my_registry()
func apply_data(data: Dictionary) -> void:
import_payload_into_my_registry(data)SaveFlowTypedDataSource and custom SaveFlowDataSource can both provide
editor preview metadata through describe_data_plan().
That preview uses a fixed top-level schema:
validreasonsource_keydata_versionphaseenabledsave_enabledload_enabledsummarysectionsdetails
Only those top-level fields are rendered by the built-in preview.
If you want custom preview content, put it inside details instead of adding
new top-level keys.
Then wire it into the graph like any other source:
SaveGraphRoot
|- WorldScope
|- WorldDataSource
This is the preferred path when the state is:
- not naturally represented by exported node fields
- owned by a manager or service
- stored in typed data, a table, queue, or registry
Start with SaveFlowTypedDataSource when one object can provide a coherent
payload through the payload-provider contract. Move to a custom
SaveFlowDataSource when the source itself needs broader adapter logic rather
than just field persistence.
Start with:
res://demo/saveflow_lite/recommended_template/scenes/project_workflow/recommended_project_workflow_main.tscnres://demo/saveflow_lite/recommended_template/scenes/pipeline_notifications/pipeline_notification_demo.tscnres://demo/saveflow_lite/recommended_template/scenes/csharp_workflow/csharp_workflow_demo.tscn
Use the older sandboxes as QA and historical references:
res://demo/saveflow_lite/plugin_sandbox/plugin_sandbox.tscnres://demo/saveflow_lite/complex_sandbox/complex_sandbox.tscnres://demo/saveflow_lite/zelda_like/scenes/zelda_like_sandbox.tscn
The recommended project workflow demonstrates:
- a project-style hub scene and authored room subscenes
- active slot selection with manual save/load/delete
- autosave and checkpoint writes
- typed room data, player node state, and runtime entity collections
- scene-authored UI that reads save state instead of owning gameplay data
The focused public demos demonstrate:
- pipeline signals for source-level and final save/load feedback
- the C# path through
SaveFlowTypedStateSource,SaveFlowSlotWorkflow,SaveFlowSlotCard, andSaveFlowClient.SaveScope()
The plugin sandbox demonstrates:
- mutate local state
- save into a slot
- load the slot back
- list slots
- delete the slot
- node-source-driven persistence using exported fields
The complex sandbox demonstrates:
- a
SaveScopegraph over player, world, settings, party, and enemy domains - how a larger save hierarchy can stay readable
- how one explicit
SaveGraphRootcan own the save graph without duplicate Source children on target nodes - the current limitation around missing runtime entities
- why entity collections need an entity factory integration seam
Related files:
Import the project headlessly:
.\tools\import_project.ps1Run runtime tests:
.\tools\run_gdunit.ps1 -ContinueOnFailureCurrent runtime coverage includes:
- JSON save/load
- binary save/load
- slot copy/rename/delete
- source collection and restore
- node-source-driven scene save/load
- scene inspection and exported-field collection
- hierarchical save graph gather/apply
- strict graph failure when a source target disappears
- data-source graph save/load
- entity collection restoration delegation
C# now has a shipped baseline wrapper layer in:
addons/saveflow_core/runtime/dotnet/client/SaveFlowClient.csaddons/saveflow_core/runtime/dotnet/client/SaveFlowCallResult.csaddons/saveflow_core/runtime/dotnet/slots/SaveFlowSlotMetadata.csaddons/saveflow_core/runtime/dotnet/entities/SaveFlowEntityDescriptor.cs
Current entrypoints include:
SaveFlowClient.SaveData(...)SaveFlowClient.LoadData(...)SaveFlowClient.SaveNodes(...)SaveFlowClient.LoadNodes(...)SaveFlowClient.SaveScope(...)SaveFlowClient.LoadScope(...)SaveFlowClient.SaveCurrent(...)SaveFlowClient.LoadCurrent(...)SaveFlowClient.InspectSlotCompatibility(...)SaveFlowClient.SaveDevNamedEntry(...)SaveFlowClient.LoadDevNamedEntry(...)
In C#, use SaveFlow.DotNet.SaveFlowClient for these calls.
The goal is not just "call the GDScript autoload from C#". The goal is a wrapper that feels idiomatic for Godot C# users and supports stronger typing over time.
SaveFlow Lite should solve:
- clean save architecture for jam and lightweight projects
- slot handling without boilerplate
- practical node/system save workflow
- explicit save graphs for multi-system authored state
- manager and table state through a first-class data-source path
- baseline trust features such as scene-restore contracts, version compatibility reporting, and last-backup safety
SaveFlow Pro should solve:
- migration and version tooling
- multi-scene restore orchestration and resource-loading coordination
- storage profiles, cold-backup recovery helpers, and cloud-save transport
- reference repair across authored/runtime objects
- seamless/background save workflows for larger commercial projects
For a deeper explanation of why those problems appear and how they map back to Godot workflows, see:
Current status:
- brand renamed to
SaveFlow Lite - main runtime entry is
SaveFlow - demo scene is working
- runtime tests are passing
- C# wrapper baseline is shipped in
saveflow_core/runtime/dotnet

