{
  "width": 1180,
  "height": 810,
  "elements": {
    "9JDMpEMdmWkvdmka55rMAx": {
      "type": "button",
      "buttonType": "script",
      "textColor": {
        "type": "preset",
        "color": "white"
      },
      "backgroundColor": {
        "type": "dynamic",
        "template": "${shared(\"filterClosed\") ? \"indigo-400\" : \"indigo-900\"}"
      },
      "label": "${shared(\"filterClosed\") ? \"Fade In\" : \"Fade Out\"}",
      "font": {
        "size": 40
      },
      "width": 200,
      "height": 200,
      "x": 820,
      "y": 130,
      "zIndex": 1031,
      "scriptOnPress": "const track = TRACK-ID;\nconst device = 0;\nconst param = 1;\nconst fadeDuration = 8000; // ms\nconst steps = 300;\nconst stepTime = fadeDuration / steps;\nconst volFadeTime = 8; // seconds (same duration as filter sweep)\n\nconst isClosed = shared(\"filterClosed\", false);\n\nif (isClosed) {\n  // Fade in: restore volumes + sweep filter up\n  sendOsc(\"/mixer/your-track-group/fadeTo\", \"previous\", volFadeTime);\n\n  const prev = shared(\"filterPrev\", 1.0);\n  for (let i = 1; i <= steps; i++) {\n    const v = (i / steps) * prev;\n    sendOsc(\":AbletonOSC/live/device/set/parameter/value\", int(track), int(device), int(param), v);\n    await sleep(stepTime);\n  }\n  setShared(\"filterClosed\", false);\n} else {\n  // Fade out: kill volumes + sweep filter down\n  const current = osc(\":AbletonOSC/live/device/58/0/get/parameter/value\", 1) ?? 1.0;\n  setShared(\"filterPrev\", current);\n\n  sendOsc(\"/mixer/your-track-group/fadeTo\", 0, volFadeTime);\n\n  for (let i = 1; i <= steps; i++) {\n    const v = current * (1 - i / steps);\n    sendOsc(\":AbletonOSC/live/device/set/parameter/value\", int(track), int(device), int(param), v);\n    await sleep(stepTime);\n  }\n  setShared(\"filterClosed\", true);\n}"
    }
  }
}
