For power users

Automation & API

Spiralyst Lab is scriptable. Every on-screen control has a programmatic twin, so a script, a MIDI/OSC bridge, an AI agent, or an automated QA harness can drive what the app shows and read what it hears — in real time, without faking mouse clicks.

Local only. The automation surface runs entirely on your Mac — no remote control, no telemetry, nothing leaves your machine.

Tutorial video — coming soon

This page documents the creative subset of the surface: read and set the whole scene, switch fractals and wire reactivity, inspect the live audio, run Auto-Reactivity, and export the rendered viewport to PNG.

Who it's for

  • Power users who want to script setups and batch-export art.
  • DJs & VJs bridging a MIDI or OSC controller to colors, motion, and fractal parameters.
  • AI agents that read the live audio and current look, decide what should happen next, and apply it.
  • QA & measurement: drive a known scene, render, read pixels + audio + state, and grade against a baseline.

How to drive it

Two paths into the same surface — the HTTP API for code (any language, any tool) and a set of reference Claude Code skills we publish here for anyone who wants a ready-to-install agent integration.

HTTP — http://127.0.0.1:<port>/api/*

The app's embedded localhost server. Drive it from any language — curl, a Python script, a Node process, a MIDI/OSC bridge, an AI agent. Twenty-plus endpoints across state, UI, window, audio, and export. Changes apply within one ~250 ms poll tick.

Localhost-only, with a per-launch bearer token — by design. The server binds 127.0.0.1 on an OS-assigned port, and every request needs a secret token that's regenerated every time the app launches. The port + token are written to a private file in your home folder, readable only by you — so only software running as you can find them and call the API. Same model Jupyter and VS Code use. It is not a remote-control surface — don't expose it off the machine.

Read the port + token (written to ~/.spiralyst-lab/api-port.json at launch)

# the file lives at ~/.spiralyst-lab/api-port.json — 0600, user-only:
#   { "url": "http://127.0.0.1:54321", "port": 54321, "token": "…", "version": "3.3.0", … }
P=~/.spiralyst-lab/api-port.json
BASE=$(jq -r .url "$P")
AUTH="Authorization: Bearer $(jq -r .token "$P")"

Both the port and the token rotate on every launch — re-read the file each run, don't hard-code either. The same two values are also shown in-app under About ▸ Spiralyst Lab with Copy buttons, for when a human wants to grab them without opening a file.

The Spiralyst Lab About dialog showing the Local API panel with URL and Token rows, each with a Copy button on the right.
The About dialog in v3.3.0 carries the local-API panel: URL and token, each with a one-click Copy button. The same two values are written to ~/.spiralyst-lab/api-port.json on every launch — pick whichever path your workflow prefers.

Quickstart

A complete drive-and-capture loop over HTTP: read the port + token, fetch the scene, switch fractal + enable audio, wait a tick, export a 4K still, and read where it landed.

# 1. read $BASE and $AUTH (see above) — one jq line each from ~/.spiralyst-lab/api-port.json

# 2. read the current scene
curl -s -H "$AUTH" "$BASE/api/state" | jq '{ type, hueStart: .color.hueStart }'

# 3. switch fractal + enable system audio
curl -s -H "$AUTH" -XPOST "$BASE/api/state/apply" -H 'Content-Type: application/json' \
  -d '{"type":"fractal-phyllotaxis","audio":{"enabled":true,"source":"system"}}'

# 4. wait ~0.3s for the JS poll to apply
sleep 0.3

# 5. export a 4K still
curl -s -H "$AUTH" -XPOST "$BASE/api/export/png" -H 'Content-Type: application/json' -d '{"res":"4K"}'

# 6. read where it was written
curl -s -H "$AUTH" "$BASE/api/export/png" | jq '.path'   # → ~/.spiralyst-lab/qa/<file>.png

Every request needs the Authorization: Bearer … header — a request without the right token returns 401 Unauthorized.

Reference — creative subset

Path · method · purpose · params, with the window.__spiral.* equivalent. This is the creative subset only; see Full reference for advanced/agent endpoints.

State

EndpointPurposeParamsJS equivalent
GET /api/stateLast pushed scene snapshot (or null at boot before the first push).__spiral.state.get()
POST /api/state/applyApply a full scene snapshot (within ~250 ms).snapshot blob (JSON body)__spiral.state.set(snap)
POST /api/state/undoStep back in history.__spiral.undo()
POST /api/state/redoStep forward in history.__spiral.redo()
GET /api/state/stack{ undo, redo, canUndo, canRedo }__spiral.stack()

UI

EndpointPurposeParamsJS equivalent
POST /api/state/tabSwitch the sidebar tab.{ name: "source" | "visual" | "camera" | "export" }__spiral.ui.tab(name)
POST /api/state/scrollScroll a control into view (auto-activates its tab).{ target: "color:hueStart" }__spiral.ui.scrollTo(target)

Audio

EndpointPurposeParamsJS equivalent
GET /api/audio/snapshotLatest audio-input frame: { source, active, peak, rms, spectrum[32], pitchHz, ... } — the values the artwork reacts to.__spiral.audio.snapshot()
GET /api/audio/bandsLive per-reactive-slider levels (incl. saturated / lowDynamics flags) — see whether a band is maxed out or barely moving.
POST /api/audio/healRun Auto-Reactivity (AGC). Runs in-app over a few seconds; poll GET /api/audio/heal for the report. Needs music playing.{ policy?, keys?, targetPeak? }await __spiral.audio.heal({ policy: "auto" })

Export

EndpointPurposeParamsJS equivalent
POST /api/export/pngRender the active viewport to a PNG (exact pixels, not a screen grab). Writes to ~/.spiralyst-lab/qa/.{ res: "4K" | "1440p" | "1080p" | "720p" } or { w, h, ppi }await __spiral.export.png({ res: "4K" })
GET /api/export/pngThe last export report: { path, w, h, ppi, bytes } — poll after the POST.

Output location. Exported PNGs are written to ~/.spiralyst-lab/qa/. POST /api/export/png enqueues the render; GET /api/export/png returns the report with the path once it lands.

Examples

From the WebView devtools console — window.__spiral (instant)

__spiral.state.patch({ type: "fractal-phyllotaxis", audio: { enabled: true, source: "system" } });
__spiral.state.patch({ color: { hueStart: 0.9 } });   // set one field → re-renders
await __spiral.audio.heal({ policy: "auto" });        // tune reactivity to the music
await __spiral.export.png({ res: "4K" });             // → ~/.spiralyst-lab/qa/

Switch a fractal + tune reactivity over HTTP

# enable system audio + phyllotaxis
curl -s -H "$AUTH" -XPOST "$BASE/api/state/apply" -H 'Content-Type: application/json' \
  -d '{"type":"fractal-phyllotaxis","audio":{"enabled":true,"source":"system"}}'

# auto-tune, then poll the report (music must be playing)
curl -s -H "$AUTH" -XPOST "$BASE/api/audio/heal" -H 'Content-Type: application/json' -d '{"policy":"auto"}'
sleep 4
curl -s -H "$AUTH" "$BASE/api/audio/heal" | jq '.healed'

Inspect the live audio (what the artwork hears)

curl -s -H "$AUTH" "$BASE/api/audio/snapshot" | jq '{ peak, rms, pitchHz }'
curl -s -H "$AUTH" "$BASE/api/audio/bands"    | jq '.bands[] | { key, level, saturated, lowDynamics }'

Full reference

This page covers the creative subset only. The complete contract — file read/write, save/open dialogs, the calibration suite, and the full 50+ endpoint list for advanced and agent use — lives in the agent-control reference, hosted here for direct read access from agents, scripts, and integrations.

Reference — Claude Code skills

Four reference skills exist for Claude Code (Anthropic's CLI agent). Claude Code resolves slash commands like /spiral-observe to a local skill folder under ~/.claude/skills/<name>/; the skill's SKILL.md tells Claude what the command does and how to drive it.

Not bundled. Spiralyst Lab does not ship these skills, and they are not installed by Claude Code. They are reference examples, published here, demonstrating how to drive the API above. Install them yourself with the steps below, or read them as worked examples and write your own. Nothing about the API is Claude-specific — any agent that can speak HTTP can drive Spiralyst Lab.

  1. /spiral-observe — read the live audio (snapshot, per-band reactivity, full-rate frames), read the scene state, capture a PNG of the rendered viewport, and report what the app is currently doing. [SKILL.md]
  2. /spiral-scene — build a scene programmatically from a natural-language description: fractal type + params, effects, layers, background, and wire sliders to audio bands or sine animation, then verify with a screenshot. [SKILL.md]
  3. /spiral-calibrate — run the calibration suite (audible by design): play ground-truth tones, grade pitch / gain / beat timing / settings round-trip / visual render against a baseline. [SKILL.md]
  4. /spiral-heal — auto-tune (AGC) the audio-reactive bands so sliders stop pinning at max or sitting at zero. Tunes gain, squelch, and signal together. [SKILL.md]

Setup

  1. Install Claude Code and sign in.
  2. Create the skills directory if it doesn't exist:
    mkdir -p ~/.claude/skills
  3. For each skill, create a folder and drop in a SKILL.md. With curl:
    for name in spiral-observe spiral-scene spiral-calibrate spiral-heal; do
      mkdir -p ~/.claude/skills/$name
      curl -fsSL "https://spiralyst.com/skills/$name/SKILL.md" \
        -o ~/.claude/skills/$name/SKILL.md
    done
    Each SKILL.md is the literal file the agent reads — open the [SKILL.md] links above to inspect the source before you install.
  4. Restart Claude Code. The four slash commands resolve on next session start.
  5. Launch Spiralyst Lab (the skills drive the app's local HTTP server documented above; if the app isn't running there's nothing to talk to).

Inspect before you install. Each skill is a single Markdown file with a YAML frontmatter (name, description) and a body of plain instructions plus shell snippets that call the public HTTP API documented above. Read the source from the SKILL.md links next to each skill name — nothing is obfuscated, and there are no hidden binaries or daemons.

Caveats

  • Localhost only. The HTTP server binds 127.0.0.1 — it is not a remote-control surface. Don't expose it off the machine.
  • Latency. HTTP changes apply within one ~250 ms poll tick. The window.__spiral object (accessible via the app's WebView devtools console — Develop → Web Inspector → Console) is synchronous and instant; it's documented in the reference table above for developers who want zero-latency control without leaving the app's runtime.
  • One instance. Drive a single running app instance at a time; the port is per-launch and OS-assigned.

Get Spiralyst Lab — $24.99/yr Back to Support