State Persistence

Oscilla persists various state data so that positions, visibility, and presets survive page reloads. This document provides an overview of what gets saved and where.


Summary

State Type Storage Location Auto-save Scope
Drag positions localStorage Yes Per project
Visibility state Server (JSON) Yes (1s debounce) Per project
O2P Presets localStorage + Server Manual Per project
Configurations localStorage + Server Manual Per project
Launchers localStorage + Server Yes Per project

Drag Positions

What: X/Y positions of draggable overlays (drag(1), drag-click:1)

Storage: localStorage under key oscilla-drag-positions

Structure:

{
  "project-name": {
    "uid1": { "x": 100, "y": 200 },
    "uid2": { "x": 150, "y": 300 }
  }
}

Behavior:

Source: button.js — saveDragPosition(), loadDragPositions()


Visibility State

What: Hidden/visible state of elements controlled by ui(uid:..., action:toggle)

Storage: Server-side JSON via /api/ui-state/{project}

Structure:

{
  "rot_triangle": { "visible": false },
  "synth_panel": { "visible": true }
}

Behavior:

Source: animShared.js — saveVisibilityState(), loadVisibilityState()

See also: ui() documentation


O2P Presets

What: Saved fader/control positions for O2P animations, plus visibility state

Storage: Dual — localStorage (fast backup) + Server (project file)

Structure:

{
  "kind": "o2pPreset",
  "name": "warm_mix",
  "data": {
    "fader_uid_1": 0.75,
    "fader_uid_2": 0.5,
    "_meta": { "savedAt": 1234567890, "filter": "groupA" },
    "_visibility": {
      "rot_triangle": { "visible": false }
    }
  }
}

Behavior:

Source: o2pPresets.js — savePreset(), recallPreset()


Configurations

What: Complete launcher state snapshots plus visibility

Storage: Same dual system as presets

Structure:

{
  "kind": "configuration",
  "name": "opening_state",
  "data": {
    "launchers": {
      "launcher_uid": { /* launcher data */ }
    },
    "visibility": {
      "rot_triangle": { "visible": true }
    }
  }
}

Behavior:

Source: controlShared.js — saveConfiguration(), recallConfiguration()


Launchers

What: Individual O2P launcher states (fader positions, active state)

Storage: Same dual system as presets

Behavior:

Source: controlShared.js — saveLauncher()


Storage Priority

When restoring state, the system checks sources in this order:

  1. Server — Authoritative source, synced across clients
  2. localStorage — Fast fallback if server unavailable
  3. SVG/cue defaults — Initial values from score definition

For visibility specifically (in toggle indicators):

  1. Saved JSON state — From loadVisibilityState()
  2. visible: parameter — From cue definition
  3. Default — Visible (true)

Clearing State

Drag positions: Clear localStorage key oscilla-drag-positions

Visibility: Delete server file or clear via API

Presets/Configurations: Use GUI delete or clear localStorage + server

Full reset: Clear localStorage and restart server to regenerate defaults


Events

Event Dispatched When
oscilla:visibility-state-loaded Visibility state restored from server or preset

Listen for this event to update UI that depends on visibility state:

window.addEventListener("oscilla:visibility-state-loaded", () => {
  // Update toggle indicators, refresh UI, etc.
});

Global Functions

These are exposed on window for cross-module access:

window._loadVisibilityState()        // Load and apply visibility from server
window._getVisibilitySnapshot()      // Get current visibility state object
window._applyVisibilitySnapshot(obj) // Apply visibility state with optional dur

Tip: use ← → or ↑ ↓ to navigate the docs