{
  "width": 500,
  "height": 500,
  "elements": {
    "bxz99ahfCnX794HHdPbfDP": {
      "type": "button",
      "buttonType": "script",
      "textColor": {
        "type": "preset",
        "color": "white"
      },
      "backgroundColor": {
        "type": "preset",
        "color": "green"
      },
      "label": "${ local(\"tapTempo\", \"--\") }",
      "font": {
        "size": 40
      },
      "width": 200,
      "height": 200,
      "x": 150,
      "y": 150,
      "zIndex": 1010,
      "scriptOnPress": "// Tap Tempo for an AbleSet Canvas Script button\n// Stores up to the 10 most recent tap timestamps in a local variable\n// Stores the calculated tempo in another local variable\n\nconst MAX_TAPS = 10;\nconst RESET_AFTER_MS = 2500; // if you wait too long, start a new tap sequence\n\nconst currentTime = now();\n\n// Get previous taps from local storage\nlet taps = local(\"tapTempoTaps\", []);\nconst lastTap = taps.length > 0 ? taps[taps.length - 1] : null;\n\n// Reset tap history if the pause between taps is too long\nif (lastTap !== null && currentTime - lastTap > RESET_AFTER_MS) {\n  taps = [];\n}\n\n// Add current tap\ntaps.push(currentTime);\n\n// Keep only the 10 most recent taps\nif (taps.length > MAX_TAPS) {\n  taps = taps.slice(-MAX_TAPS);\n}\n\n// Save updated tap array\nsetLocal(\"tapTempoTaps\", taps);\n\n// Only calculate BPM once we have at least 2 taps\nif (taps.length >= 2) {\n  const firstTap = taps[0];\n  const lastTapTime = taps[taps.length - 1];\n  const tapCount = taps.length;\n\n  // Average interval across all taps:\n  // total time / number of intervals\n  const avgIntervalMs = (lastTapTime - firstTap) / (tapCount - 1);\n\n  const bpm = 60000 / avgIntervalMs;\n  const roundedBpm = Math.round(bpm * 10) / 10; // 1 decimal place\n\n  // Save calculated tempo\n  setLocal(\"tapTempo\", roundedBpm);\n\n  log(`Tap Tempo: ${roundedBpm} BPM (${tapCount} taps)`);\n} else {\n  // Optional: clear tempo until enough taps exist\n  setLocal(\"tapTempo\", null);\n  log(\"Tap once more to calculate tempo\");\n}"
    }
  }
}
