{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-shove-4",
  "type": "registry:block",
  "title": "Card Shove 4",
  "author": "Kenney <https://kenney.nl>",
  "description": "A slightly extended and crisp sound of a card being shoved, perfect for a deliberate and audible card movement.",
  "files": [
    {
      "path": "registry/soundcn/sounds/card-shove-4/card-shove-4.ts",
      "content": "import type { SoundAsset } from \"@/lib/sound-types\";\n\nexport const cardShove4Sound: SoundAsset = {\n  name: \"card-shove-4\",\n  dataUri: \"data:audio/mpeg;base64,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\",\n  duration: 0.809,\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.809,
    "format": "mp3",
    "sizeKb": 7,
    "license": "CC0",
    "tags": [
      "card",
      "shove",
      "4"
    ],
    "keywords": [
      "card",
      "shove",
      "push",
      "move",
      "reposition",
      "discard",
      "game",
      "ui",
      "extended",
      "crisp",
      "deliberate",
      "paper",
      "interaction",
      "feedback",
      "slide",
      "reorder",
      "flick",
      "action",
      "audible",
      "smooth",
      "controlled",
      "distinct"
    ]
  },
  "categories": [
    "card"
  ]
}