{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "book-flip-1",
  "type": "registry:block",
  "title": "Book Flip 1",
  "author": "Kenney <https://kenney.nl>",
  "description": "A gentle, quick page-turning sound, ideal for navigating through virtual book pages or scrolling content.",
  "files": [
    {
      "path": "registry/soundcn/sounds/book-flip-1/book-flip-1.ts",
      "content": "import type { SoundAsset } from \"@/lib/sound-types\";\n\nexport const bookFlip1Sound: SoundAsset = {\n  name: \"book-flip-1\",\n  dataUri: \"data:audio/mpeg;base64,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znVxCBiMo3ziXSTOdjLJ8u6kGFEQMdBBjwAgeefUGZv/eyd38iGIbWXXiMbI+7e0R0Rad/3qrECWZ4gEGIwQyUPmemv39PTT6rdXrv/7UsRegAzdP2HHjLGBlSztfPMJuKzOqJ3fJS7IjGQ4ZxhSNSppuniNYjmQB46uw2sEpgapiO9rMolBUtgyUt3U0srkbGeAzB5xpRI/LhFJKyq/aJCzAlCBwFePWuKhm1qxukzeVUv25P4svuMFARIEwY1BNrEN+WBojFsSwMSXgu4O1AZNBEMoPEk8jSh0RcMzwpBnI1rhwBtgBRCsOQdB6YhyOwmlQ7CWzzq73TpepYNYymsKn7HDoowop0DYUUbaRyOQybJ5Shc+9U7stHqV//tSxFYADTTNY8wYbsGQmeq4wYpo1GFBQyAjzCquCtgEFgqY5Y9LPuei+4JmVB0GrpltURFWIli5eIhUIgFBJRMFi2IRAZtQRVohDWgRl66d7GzgDoYyJVWNn39tFjOGWxmm3l+Mav0iIUbQVnDL/843HnNprFhDndymjlMWhZMt/0HkluDQ69dx02JUXtsJ2d6h0NIABd5OJlqIyDqHsXEo/ZTnbl+uhV5l0ThobiVWefhYhZGahV4uZ/S/D1RiU2Pq5/zci1wREaZMediBiK//+1LETQALCNVL4LBhwV4aaDhmDSAwm7QRxvq+o5SJWiBh6SCRcnMSAva+N23+zkAhs2GI6dtmwxmApruC2cTPYokadmbHtLdlmqpS0FfzpHZVPOKAkre35Ll9UurAoVBRMqw004MI7cVI0J2Sx46JH88Vc4C9m8q0s97WJQI5bdE4gCCmCrCnumxzJAZjBg2FvQgot4rK2HoxV0VfwyWTrkRkVOqnnLbIbCRYgkZLTCIjUwGE6YgiALf+hl8X/36tXqiKPHBMUF9avNNVEErEAP/7UsRTAApMvT2DGGzBOyfm9DCX0QjHDymf2fnqUeUGoNVYaMZaz8v1Iw7xOVZxxgjnrIxLD1AXCtow4CUCtDMmBgILYo3CiBmMekyqs1dVLpFP62lf9tU79//4ICB1rE//WAcIA45NVhHDZUhqVowrBoTOCPlphRm+qikA9TUCoLpOIlJzQCfISYnKtLnkOyPerGPJwUyeCSEGpHXzt//FizdyF/Yd5Jy9CgYAAAERCZNmvIWTDicUOzWabhqarsfVqw1JjAQYlmNRMAgQpSh0//tSxGAAijU7JwQMWsEfGOPUMIyAmJuGFRrSAnAUFVddqrOJEodOoZR5Fv61Tv/1jDPKiLlcrUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+1LEcQPI9McLBIRl0AAANIAAAARVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==\",\n  duration: 0.769,\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.769,
    "format": "mp3",
    "sizeKb": 7,
    "license": "CC0",
    "tags": [
      "book",
      "flip",
      "1"
    ],
    "keywords": [
      "book",
      "flip",
      "page",
      "turn",
      "scroll",
      "navigate",
      "ui",
      "document",
      "content",
      "read",
      "subtle",
      "gentle",
      "quick",
      "paper",
      "interaction",
      "progress",
      "next",
      "browse",
      "slide",
      "light"
    ]
  },
  "categories": [
    "book"
  ]
}