{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-shove-1",
  "type": "registry:block",
  "title": "Card Shove 1",
  "author": "Kenney <https://kenney.nl>",
  "description": "A quick, decisive sound of a virtual card being shoved or pushed, suitable for repositioning or discarding.",
  "files": [
    {
      "path": "registry/soundcn/sounds/card-shove-1/card-shove-1.ts",
      "content": "import type { SoundAsset } from \"@/lib/sound-types\";\n\nexport const cardShove1Sound: SoundAsset = {\n  name: \"card-shove-1\",\n  dataUri: \"data:audio/mpeg;base64,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\",\n  duration: 0.766,\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.766,
    "format": "mp3",
    "sizeKb": 7,
    "license": "CC0",
    "tags": [
      "card",
      "shove",
      "1"
    ],
    "keywords": [
      "card",
      "shove",
      "push",
      "move",
      "reposition",
      "discard",
      "game",
      "ui",
      "quick",
      "decisive",
      "short",
      "paper",
      "interaction",
      "feedback",
      "slide",
      "reorder",
      "flick",
      "action",
      "confident",
      "firm",
      "snappy"
    ]
  },
  "categories": [
    "card"
  ]
}