Skip to content

Add save/load of full particle state (2D & 3D) - #4

Open
wiesenthal wants to merge 1 commit into
DicSo92:masterfrom
wiesenthal:feature/save-load-particle-state
Open

wiesenthal wants to merge 1 commit into
DicSo92:masterfrom
wiesenthal:feature/save-load-particle-state

Conversation

@wiesenthal

Copy link
Copy Markdown

What

Adds the ability to save and load the full state of a simulation — the position, velocity and type of every particle — for both the 2D and 3D WebGPU engines. This complements the existing preset system (which only stores rules/radii/colors/settings) by capturing the exact live snapshot, so you can freeze a run and resume it later pixel-for-pixel.

How it works

  • composables/useStateManager.ts — serializes a snapshot to a compact binary container and parses it back:

    [4]  magic "SBXS"
    [4]  version (uint32)
    [4]  header length (uint32)
    [..] JSON header (engine, counts, world size, colors, matrices)
    [..] raw Float32 particle data (x,y[,z],vx,vy[,vz],type per particle)
    

    JSON would balloon for millions of particles, so the particle data stays as raw little-endian floats. Includes downloadState() and readStateFile() helpers with toast feedback.

  • components/particle-life/StatePanel.vue — a small Save State / Load State panel (hidden file input for load), added to the left sidebar of both engines under a new "Save / Load State" collapse section.

  • ParticleLifeGpu.vue / ParticleLifeGpu3D.vue:

    • saveState() reads the live GPU particle buffer back via the existing readBufferFromGPU helper (after onSubmittedWorkDone() so the snapshot is current) and downloads it.
    • loadState(file) parses the file, applies the saved particle/species counts and world size, then rebuilds the simulation — injecting the saved matrices, colors and particle buffer instead of regenerating randomly. This reuses the existing initLife() rebuild path through a small pendingLoadedState seam, so buffer/pipeline recreation stays in one place.
    • Loading a 3D file into the 2D engine (or vice-versa) is rejected with a clear toast.

Buffer layouts handled: 2D = 5 floats/particle [x, y, vx, vy, type], 3D = 7 floats/particle [x, y, z, vx, vy, vz, type].

Testing

  • Verified the binary serialize → deserialize roundtrip preserves all particle floats and header metadata exactly, including the offset/subarray case produced by GPU buffer read-back.
  • Parsed every changed/added <script> block with oxc-parser to confirm no syntax/TS errors.

Note: a full nuxt build could not be run in my environment due to an unrelated toolchain issue (oxc-walker require()s the ESM-only oxc-parser). Changes are isolated to the feature files and follow the existing engine patterns. A quick manual smoke test (save a running sim, refresh, load it back in both 2D and 3D) is recommended before merge.

🤖 Generated with Claude Code

Adds the ability to snapshot the entire live simulation — the position,
velocity and type of every particle — to a file and restore it later,
for both the 2D and 3D WebGPU engines.

- New `useStateManager` composable: compact binary container
  (magic + version + JSON header + raw Float32 particle data) with
  download/parse helpers.
- New `StatePanel` component: Save State / Load State buttons, wired
  into the left sidebar of both engines under a "Save / Load State"
  section.
- 2D/3D engines: `saveState` reads the GPU particle buffer back via the
  existing `readBufferFromGPU` helper; `loadState` rebuilds the sim from
  the file, injecting the saved matrices/colors/particles instead of
  regenerating randomly (guarded by a `pendingLoadedState` seam in
  `initLife`). Engine mismatch (2D file in 3D, or vice versa) is rejected
  with a toast.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant