{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-fan-1",
  "type": "registry:block",
  "title": "Card Fan 1",
  "author": "Kenney <https://kenney.nl>",
  "description": "A gentle, quick fanning sound of virtual cards, suitable for showing a hand of cards or quick selection.",
  "files": [
    {
      "path": "registry/soundcn/sounds/card-fan-1/card-fan-1.ts",
      "content": "import type { SoundAsset } from \"@/lib/sound-types\";\n\nexport const cardFan1Sound: SoundAsset = {\n  name: \"card-fan-1\",\n  dataUri: \"data:audio/mpeg;base64,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\",\n  duration: 0.721,\n  format: \"mp3\",\n  license: \"CC0\",\n  author: \"Kenney\",\n};\n",
      "type": "registry:lib"
    },
    {
      "path": "registry/soundcn/lib/sound-types.ts",
      "content": "export interface SoundAsset {\r\n  /** Unique identifier for the sound */\r\n  name: string;\r\n  /** Base64-encoded data URI (data:audio/mpeg;base64,...) */\r\n  dataUri: string;\r\n  /** Duration in seconds */\r\n  duration: number;\r\n  /** Audio format */\r\n  format: \"mp3\" | \"wav\" | \"ogg\";\r\n  /** License identifier */\r\n  license: \"CC0\" | \"OGA-BY\" | \"MIT\";\r\n  /** Original author/creator */\r\n  author: string;\r\n}\r\n\r\nexport interface UseSoundOptions {\r\n  /** Volume level from 0 to 1. Default: 1 */\r\n  volume?: number;\r\n  /** Playback speed multiplier. Default: 1 */\r\n  playbackRate?: number;\r\n  /** If true, calling play() stops current playback first. Default: false */\r\n  interrupt?: boolean;\r\n  /** If false, play() does nothing. Useful for user preferences. Default: true */\r\n  soundEnabled?: boolean;\r\n  /** Called when playback starts */\r\n  onPlay?: () => void;\r\n  /** Called when playback ends naturally */\r\n  onEnd?: () => void;\r\n  /** Called when pause() is called */\r\n  onPause?: () => void;\r\n  /** Called when stop() is called */\r\n  onStop?: () => void;\r\n}\r\n\r\nexport type PlayFunction = (overrides?: {\r\n  volume?: number;\r\n  playbackRate?: number;\r\n}) => void;\r\n\r\nexport interface SoundControls {\r\n  stop: () => void;\r\n  pause: () => void;\r\n  isPlaying: boolean;\r\n  duration: number | null;\r\n  sound: SoundAsset;\r\n}\r\n\r\nexport type UseSoundReturn = readonly [PlayFunction, SoundControls];\r\n",
      "type": "registry:lib"
    },
    {
      "path": "registry/soundcn/lib/sound-engine.ts",
      "content": "let audioContext: AudioContext | null = null;\nconst bufferCache = new Map<string, AudioBuffer>();\n\nexport function getAudioContext(): AudioContext {\n  if (!audioContext) {\n    audioContext = new AudioContext();\n  }\n  return audioContext;\n}\n\nexport async function decodeAudioData(dataUri: string): Promise<AudioBuffer> {\n  const cached = bufferCache.get(dataUri);\n  if (cached) return cached;\n\n  const ctx = getAudioContext();\n  const base64 = dataUri.split(\",\")[1];\n  const binaryString = atob(base64);\n  const bytes = new Uint8Array(binaryString.length);\n  for (let i = 0; i < binaryString.length; i++) {\n    bytes[i] = binaryString.charCodeAt(i);\n  }\n\n  const audioBuffer = await ctx.decodeAudioData(bytes.buffer.slice(0));\n  bufferCache.set(dataUri, audioBuffer);\n  return audioBuffer;\n}\n\nexport interface PlaySoundOptions {\n  volume?: number;\n  playbackRate?: number;\n  onEnd?: () => void;\n}\n\nexport interface SoundPlayback {\n  stop: () => void;\n}\n\nexport async function playSound(\n  dataUri: string,\n  options: PlaySoundOptions = {}\n): Promise<SoundPlayback> {\n  const { volume = 1, playbackRate = 1, onEnd } = options;\n  const ctx = getAudioContext();\n  if (ctx.state === \"suspended\") {\n    await ctx.resume();\n  }\n\n  const buffer = await decodeAudioData(dataUri);\n  const source = ctx.createBufferSource();\n  const gain = ctx.createGain();\n\n  source.buffer = buffer;\n  source.playbackRate.value = playbackRate;\n  gain.gain.value = volume;\n\n  source.connect(gain);\n  gain.connect(ctx.destination);\n\n  source.onended = () => {\n    onEnd?.();\n  };\n\n  source.start(0);\n\n  return {\n    stop: () => {\n      try {\n        source.stop();\n      } catch {\n        // No-op if already stopped.\n      }\n    },\n  };\n}\n",
      "type": "registry:lib"
    }
  ],
  "meta": {
    "duration": 0.721,
    "format": "mp3",
    "sizeKb": 6,
    "license": "CC0",
    "tags": [
      "card",
      "fan",
      "1"
    ],
    "keywords": [
      "card",
      "fan",
      "spread",
      "deal",
      "hand",
      "game",
      "ui",
      "selection",
      "quick",
      "gentle",
      "soft",
      "paper",
      "interaction",
      "display",
      "inventory",
      "menu",
      "browse",
      "slide",
      "reveal",
      "shuffle"
    ]
  },
  "categories": [
    "card"
  ]
}