Skip to content

Instantly share code, notes, and snippets.

@zerkz
Last active June 11, 2026 03:04
Show Gist options
  • Select an option

  • Save zerkz/ff6774c8fbe45241fb6b798c2bdd5a33 to your computer and use it in GitHub Desktop.

Select an option

Save zerkz/ff6774c8fbe45241fb6b798c2bdd5a33 to your computer and use it in GitHub Desktop.
Steam Deck: copy FANTASIAN Neo Dimension DEMO save into the full game (demo->full root.json bridge across Proton prefixes)
#!/usr/bin/env bash
# HOW TO RUN? OPEN TERMINAL (KONSOLE IN DESKTOP MODE) AND PASTE THE ONELINER BELOW, not including the pound sign:
# curl -fsSL https://gist.githubusercontent.com/zerkz/ff6774c8fbe45241fb6b798c2bdd5a33/raw/copy-fantasian-demo-save-to-full.sh | bash
#
# copy-fantasian-demo-save-to-full.sh
#
# Copies the FANTASIAN Neo Dimension *demo* save (root.json) into the
# *full* game's Proton prefix on a Steam Deck, so the demo progress
# carries over to the purchased game.
#
# Why this is needed: the demo (AppID 3347730) and the full game
# (AppID 2844850) each run in their own Proton prefix, so the full
# game never sees the demo's "My Games" save folder. This script
# bridges them.
#
# Usage:
# ./copy-fantasian-demo-save-to-full.sh # copy demo -> full
# ./copy-fantasian-demo-save-to-full.sh --dry-run # show what would happen, change nothing
#
# Safe to re-run: any existing full-game root.json is backed up first.
#
# IMPORTANT — after running this, use "Continue" in the full game, NOT "Load".
# "Continue" resumes from your most recent point (e.g. right before the demo
# ended), while "Load" only lists older manual save slots and will appear to
# put you back further. The transferred progress is there either way; just pick
# "Continue" to land on the latest state.
set -euo pipefail
DEMO_APPID=3347730
FULL_APPID=2844850
SAVE_FILE=root.json
STEAM_COMPAT="${HOME}/.steam/steam/steamapps/compatdata"
DEMO_GAME_DIR="FANTASIAN Neo Dimension DEMO"
FULL_GAME_DIR="FANTASIAN Neo Dimension"
DRY_RUN=0
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=1
err() { printf 'Error: %s\n' "$*" >&2; exit 1; }
info() { printf '%s\n' "$*"; }
# Build the path down to the _data folder for a given AppID + game dir name.
# The "prettylongnumber" (SteamID3) subfolder is discovered at runtime so the
# script works on any account, not just the one it was written on.
data_dir_for() {
local appid="$1" game_dir="$2"
local base="${STEAM_COMPAT}/${appid}/pfx/drive_c/users/steamuser/Documents/My Games/${game_dir}/Steam"
[[ -d "$base" ]] || err "Steam save folder not found for AppID ${appid}: ${base}"
# Find the SteamID subfolder that actually contains a _data directory.
local match=""
local d
for d in "$base"/*/; do
[[ -d "${d}_data" ]] || continue
if [[ -n "$match" ]]; then
err "Multiple save profiles found under ${base}; please copy manually."
fi
match="${d}_data"
done
[[ -n "$match" ]] || err "No _data folder found under ${base}"
printf '%s' "$match"
}
DEMO_DATA="$(data_dir_for "$DEMO_APPID" "$DEMO_GAME_DIR")"
FULL_DATA="$(data_dir_for "$FULL_APPID" "$FULL_GAME_DIR")"
SRC="${DEMO_DATA}/${SAVE_FILE}"
DST="${FULL_DATA}/${SAVE_FILE}"
[[ -f "$SRC" ]] || err "Demo save not found: ${SRC} (have you played the demo?)"
info "Demo save : ${SRC}"
info "Full save : ${DST}"
if [[ "$DRY_RUN" == "1" ]]; then
info "[dry-run] would copy demo save -> full save"
[[ -f "$DST" ]] && info "[dry-run] would back up existing full save first"
exit 0
fi
# Back up an existing full-game save so this is non-destructive.
if [[ -f "$DST" ]]; then
backup="${DST}.bak.$(date +%Y%m%d-%H%M%S)"
cp -p -- "$DST" "$backup"
info "Backed up existing full save -> ${backup}"
fi
cp -- "$SRC" "$DST"
info "Copied demo save into full game."
# Verify the copy matches byte-for-byte.
if cmp -s -- "$SRC" "$DST"; then
info "Verified: full save matches demo save."
else
err "Copy verification failed — files differ after copy."
fi
info "Done. Launch FANTASIAN Neo Dimension; your demo save should appear."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment