feat(website): a save scrubber page, longshot_saves.py scrub in the browser #747
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8015c9a
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!747
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:feat/website-save-scrubber"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: feat · Risk: low · Tested on: Linux, Chromium (headless) · Needs: Firefox and Safari, a real save
Why
Making a save for the repository (
assets/saves) means runningpython -I scripts/longshot_saves.py scrubfrom acopy of the source. People without Python, or without a checkout, had no way to make one. This adds a page to the
website, Development → Scrub a save (
/saves/scrub/), where you drop a save in and get the scrubbed slot back asa zip, the same files the script makes. It all runs in the browser: nothing is uploaded.
What changed
The scrub is ported to TypeScript byte for byte (the
caption.savlayout, the date keys, the grey JPEG writer and theJPEG reader that checks it), with a page that takes a slot folder, a whole save folder or the two files, by drag and
drop or file pickers, lists the slots it finds and zips the one you pick. A test runs the Python script and the port
on the same made-up saves and requires identical output.
website/src/lib/save-scrub.ts:captionLayout,captionDates,greyJpeg,jpegBlocks/jpegIsMidGreyandscrubSlot(the script'sscrub: same refusals, same change lines);findSlotsgroups thedropped files by folder (
account.sav,option.savand anything else are named and left out);zipStoredwritesthe zip, entries dated 2026-01-01 00:00 like the script's modification times.
website/src/lib/save-scrub-page.ts(the<save-scrubber>element: drop, folder walk capped at2000 entries, file size capped at the script's 4 MB, text from files shown with
textContentonly),website/src/components/SaveScrubber.astro,website/src/content/docs/saves/scrub.mdx, and the sidebar entry inwebsite/astro.config.ts. The zip holds<name>/README.md(the script's template),<name>/slot_00/progress.savand
<name>/slot_00/caption.sav, ready to unzip intoassets/saves/.follow
assets/saves/README.mdand still passcheck-repo-saves.docs/saves-script.mdpoints to the page from "Making one".AGENTS.md(its own commit) says a change that shows on screen carries screenshots in the description,taken by the agent (a website page from a local build, dark, light and phone width, with made-up data), and how
to attach them with the forge sign-in.
website/tests/save-scrub.test.ts: the port againstlongshot_saves.py(scrubbed slot, grey JPEGs at threesizes/levels, refusals for a repeated or missing date key, bad magic, short file, bad scene name), slot finding, and
the zip read back by Python's
zipfile.Measurements
Nothing to measure: a website page with its tests.
Flags and settings
None
Testing
Tested:
node --test tests/save-scrub.test.tsinwebsite/: 6/6 pass, including byte-for-byte equality withlongshot_saves.py scrubon the Python tests' made-up saves.astro buildbuilds the page (17 pages). In headless Chromium (agent-browser) on the built site: chose a made-upsave folder with
slot_01,slot_04,account.savandoption.savthrough Choose a folder: both slots listedwith scene and date, the two other files named as left out; scrubbed
slot_04, downloaded the zip, and itsprogress.savandcaption.savare identical to the script's scrub of the same slot. Choose files with aslot's two files works too.
node --test tests/*.test.ts: 81/82; the one failure (HDR Native condition accepts current prose but remains required,tests/graphics-settings.test.ts) fails the same onmain.npm run check's site check stops on three progress-feed items ("game branding remains in public copy", issues603, 615 and 715): today's issue titles from Forgejo, the same on
main, not this page.python -I -B tests/run_all.py(before the AGENTS.md commit;tests/test_switches_removed.py, which reads AGENTS.md, passes after it): 509 passed, 14 failed, 70 skipped; the same 14 fail onmain@a00c485c(test_make_game_cache,test_lift_cleanup_error,test_bake_portability,test_crash_dialog,test_cpm_discovery,test_env_on,test_linux_preflight,test_appimage_player_build,test_options_budget_once,test_pipeline_tour,test_mods_size_table,test_readback_late,test_vk_pgo,test_walk_key); none reads the files changed here.Screenshots (After: this PR @
7778a235; the page is new,mainhas none), the built site in headless Chromium,with a made-up save folder (
slot_01,slot_04,account.sav,option.sav):The page, dark:
slot_04scrubbed, dark:The same, light:
The same at phone width (390 px):
Not tested: drag and drop with a real mouse (only the file pickers were driven; the drop path walks the same
entries), Firefox, Safari, and a real save from the game (the made-up saves are the ones the script's own tests use).
Must be tested:
/saves/scrub/, drag a save folder from the file manager onto thedrop box, scrub a slot, expecting the slots listed and a zip whose files
python -I scripts/longshot_saves.py check-repo-savespasses once unzipped intoassets/saves/with its README filled in.Risks
What could break: only the new page; nothing else on the site changes except a sidebar entry under Development.
Turning it off: revert the commit.
Compatibility: Nothing changes.
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.846a7842537778a235cfAdded screenshots of the page (dark, light, phone width) to the description, and a second commit: AGENTS.md now asks agents to put screenshots in the description of any PR that changes what's on screen, with how to attach them.
7778a235cfeba1f5d99beba1f5d99bb5f04ef33a