{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gallery-knob-gallery-core",
  "type": "registry:ui",
  "title": "Knob Gallery Core",
  "description": "Shared Knob presets, pure artwork exports and scoped motion CSS for custom knob designs.",
  "dependencies": [
    "maruaudio@>=0.0.3 <0.1.0"
  ],
  "registryDependencies": [
    "https://pluginui.com/r/core-knob.json"
  ],
  "files": [
    {
      "path": "components/ui/gallery-knob.tsx",
      "content": "/**\n * Source: https://pluginui.com/controls\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\nimport type { CSSProperties } from \"react\"\nimport { Knob, type KnobProps } from \"@/components/ui/knob\"\nimport \"@/components/ui/knob-gallery.css\"\nimport type {\n  GalleryLight,\n  KnobOption,\n} from \"maruaudio/ui/shared/knob-gallery-types\"\n\nexport type MotionMode = \"still\" | \"press\" | \"sway\" | \"spark\"\nexport interface GalleryKnobProps extends KnobProps {\n  option: KnobOption\n  size?: KnobProps[\"size\"]\n  accent: string\n  light: GalleryLight\n  motion?: MotionMode\n}\n\n/** Only artwork is experimental. All gestures remain UI-kit-owned. */\nexport function GalleryKnob({\n  option,\n  value,\n  size = 72,\n  accent,\n  light,\n  motion = \"still\",\n  label,\n  onChange,\n  ...control\n}: GalleryKnobProps) {\n  const { Design } = option\n  return (\n    <Knob\n      {...control}\n      className=\"gallery-knob\"\n      style={{ \"--knob-accent\": accent } as CSSProperties}\n      size={size}\n      value={value}\n      onChange={onChange}\n      label={label ?? option.name}\n      hideLabel\n      hideValue\n      renderDesign={({ value01, size: pixels }) => (\n        <div\n          className=\"artwork\"\n          data-motion={motion}\n          style={{ width: pixels, height: pixels }}\n        >\n          <Design value={value01} size={pixels} accent={accent} light={light} />\n          <span className=\"knob-spark\" aria-hidden>\n            ✦\n          </span>\n        </div>\n      )}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "@ui/gallery-knob.tsx"
    },
    {
      "path": "components/ui/create-gallery-knob.tsx",
      "content": "/**\n * Source: https://pluginui.com/controls\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\nimport type { KnobDesignState } from \"@/components/ui/knob\"\nimport {\n  GalleryKnob,\n  type GalleryKnobProps,\n} from \"@/components/ui/gallery-knob\"\nimport type { KnobOption } from \"maruaudio/ui/shared/knob-gallery-types\"\n\nexport type CustomKnobProps = Omit<\n  GalleryKnobProps,\n  \"option\" | \"size\" | \"accent\" | \"light\"\n> &\n  Partial<Pick<GalleryKnobProps, \"size\" | \"accent\" | \"light\">>\n\n/** Bind one authored design without importing the full option collection. */\nexport function createGalleryKnob(option: KnobOption) {\n  return function CustomKnob({\n    size = 72,\n    accent = \"#bd4f84\",\n    light = { azimuth: 235, elevation: 55, intensity: 1 },\n    ...props\n  }: CustomKnobProps) {\n    return (\n      <GalleryKnob\n        {...props}\n        option={option}\n        size={size}\n        accent={accent}\n        light={light}\n      />\n    )\n  }\n}\n\n/** Bind the same design as pure artwork for standard or parameter-bound Knob. */\nexport function createGalleryKnobDesign(option: KnobOption) {\n  const Design = option.Design\n  return function GalleryKnobDesign({\n    value01,\n    size,\n    accent = \"#bd4f84\",\n    light = { azimuth: 235, elevation: 55, intensity: 1 },\n  }: KnobDesignState & Partial<Pick<GalleryKnobProps, \"accent\" | \"light\">>) {\n    return <Design value={value01} size={size} accent={accent} light={light} />\n  }\n}\n",
      "type": "registry:component",
      "target": "@ui/create-gallery-knob.tsx"
    },
    {
      "path": "components/ui/knob-gallery.css",
      "content": "/**\n * Source: https://pluginui.com/controls\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\n.gallery-knob {\n  position: relative;\n  cursor: ns-resize;\n  touch-action: none;\n  outline: none;\n  flex-shrink: 0;\n}\n.gallery-knob:focus-visible {\n  outline: 2px solid var(--knob-accent);\n  outline-offset: 6px;\n  border-radius: 50%;\n}\n.gallery-knob .artwork {\n  pointer-events: none;\n  transition: transform 190ms cubic-bezier(0.2, 0.8, 0.2, 1);\n  transform-origin: 50% 65%;\n}\n.gallery-knob:active .artwork[data-motion=\"press\"] {\n  transform: translateY(2px) scale(0.96);\n}\n.gallery-knob:hover .artwork[data-motion=\"sway\"] {\n  animation: knob-gallery-sway 1.8s ease-in-out infinite;\n}\n.knob-spark {\n  position: absolute;\n  top: 4%;\n  right: 7%;\n  pointer-events: none;\n  color: var(--knob-accent);\n  font-size: 22px;\n  opacity: 0;\n  transform: scale(0.1);\n}\n.gallery-knob:active .artwork[data-motion=\"spark\"] .knob-spark {\n  animation: knob-gallery-spark 550ms ease-out both;\n}\n.gallery-knob:active .artwork[data-motion=\"spark\"] {\n  transform: scale(0.97);\n}\n.knob-static {\n  display: inline-flex;\n  flex-shrink: 0;\n}\n.gallery-knob .artwork canvas,\n.gallery-knob .artwork svg,\n.knob-static .artwork canvas,\n.knob-static .artwork svg {\n  display: block;\n}\n\n@keyframes knob-gallery-sway {\n  0%,\n  100% {\n    transform: translateX(-2px) translateY(0);\n  }\n  50% {\n    transform: translateX(2px) translateY(-2px);\n  }\n}\n@keyframes knob-gallery-spark {\n  0% {\n    opacity: 0;\n    transform: scale(0.1) rotate(-25deg);\n  }\n  35% {\n    opacity: 1;\n    transform: scale(1.1) rotate(8deg);\n  }\n  100% {\n    opacity: 0;\n    transform: scale(0.5) translateY(-14px) rotate(30deg);\n  }\n}\n@media (prefers-reduced-motion: reduce) {\n  .gallery-knob .artwork {\n    animation: none !important;\n    transition: none !important;\n    transform: none !important;\n  }\n  .gallery-knob .knob-spark {\n    display: none;\n  }\n}\n",
      "type": "registry:file",
      "target": "@ui/knob-gallery.css"
    }
  ]
}
