Appearance
Save & Undo
Save and Push are separate operations with separate snapshots.
- Save persists the full config (all themes) to
figma.root.pluginData("systema_config")— file-level storage, shared across all users of the file. Does not touch Figma variables. The shortcut is ⌥S (Alt+S). - Push Vars is described in the previous section. It always saves the config as step 1, but the inverse isn't true — saving doesn't push. The shortcut is ⌥P (Alt+P).
- Autosave is an optional Settings dialog setting, off by default. When enabled it calls Save on a timer (interval 10–600 s, default 60 s) while the current theme is dirty — another save trigger.
- Undo/Redo operates on per-theme stacks, each capped at the last 4 checkpoints (
.slice(-4)). The controls appear in the status bar as buttons labeled "Prev save" and "Next save" (not "Undo"/"Redo"). Each Save (and each Push Vars, which saves first) pushes the previous saved state onto the undo stack and clears the redo stack; Undo restores the previous saved state, Redo moves forward. Switching themes swaps stacks, so each theme's history is independent. (Reset to defaultsalso pushes a checkpoint, so it's undoable.) isDirty= current theme JSON ≠lastSavedJsons[themeId]. Disables Save when clean.isPushNeeded= current theme JSON ≠lastPushedJsons[themeId]. Disables Push Vars when clean. Re-evaluated on every theme switch (per-theme), so flipping between themes reflects each one's own push state.- Optimistic push snapshot — when Push Vars is clicked, the UI stores
pendingPushSnapshot = { themeId, themeJson }and sendsapply-paletteto the backend.lastPushedJsonsandisPushNeededare NOT updated at this moment. The backend'spush-complete { success }message decides: on success → promote the snapshot intolastPushedJsons; on cancel/abort → discard. This is why cancelling the replace-theme dialog leaves Push Vars active instead of looking like the push succeeded. - Plugin-load reconcile — on startup
handleLoadConfigposts the list of existing Figma collection names alongsideconfig-loaded. The UI checks for any Systema-shape collection name (meta,color,color/meta,color/...,…/meta(legacy prefixed meta collections — names ending in/meta) or legacy{prefix}/color/...). If none are present, everylastPushedJsonsentry is dropped andisPushNeededflips totrue. The backend also emits alast-pushedmessage read fromsystema_pushed; that narrows the reconcile to just the theme currently in the file. - Config is also auto-saved to pluginData at the start of every Push Vars.