{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "gallery-spectral-knob",
  "type": "registry:ui",
  "title": "Orbital graphite dial",
  "description": "Reusable controlled graphite knob with scoped material artwork.",
  "dependencies": [
    "maruaudio@>=0.0.3 <0.1.0"
  ],
  "registryDependencies": [
    "https://pluginui.com/r/core-knob.json",
    "https://pluginui.com/r/gallery-spectral-control-styles.json"
  ],
  "files": [
    {
      "path": "components/ui/spectral-knob.tsx",
      "content": "/**\n * Source: https://maru.audio/ui-kit/spectral-knob\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 \"@/components/ui/spectral-controls.css\"\nimport {\n  Knob,\n  type KnobProps,\n  type KnobDesignState,\n} from \"@/components/ui/knob\"\n\nexport interface SpectralKnobProps extends KnobProps {\n  accent?: string\n  bands?: readonly number[]\n  readout?: string\n  ribbed?: boolean\n}\n\n/** Pure artwork. The shared Knob owns values, gestures, formatting and reset. */\nexport function SpectralKnobDesign({\n  value01,\n  size,\n  disabled,\n  formattedValue,\n  accent = \"#64c8c4\",\n  bands,\n  ribbed = false,\n}: KnobDesignState & Pick<SpectralKnobProps, \"accent\" | \"bands\" | \"ribbed\">) {\n  return (\n    <div\n      className=\"spectral-knob\"\n      style={\n        {\n          width: size,\n          height: size,\n          \"--spectral-accent\": accent,\n        } as CSSProperties\n      }\n      aria-disabled={disabled || undefined}\n    >\n      <svg\n        viewBox=\"0 0 200 200\"\n        className=\"spectral-knob__scale\"\n        aria-hidden=\"true\"\n      >\n        {!bands &&\n          Array.from({ length: ribbed ? 101 : 13 }, (_, i) => {\n            const count = ribbed ? 100 : 12\n            const a = ((135 + (i / count) * 270) * Math.PI) / 180\n            return ribbed ? (\n              <line\n                key={i}\n                x1={100 + Math.cos(a) * 88}\n                y1={100 + Math.sin(a) * 88}\n                x2={100 + Math.cos(a) * 98}\n                y2={100 + Math.sin(a) * 98}\n                stroke={i / count < value01 ? accent : \"#535558\"}\n                strokeWidth=\"1.4\"\n              />\n            ) : (\n              <circle\n                key={i}\n                cx={100 + Math.cos(a) * 97}\n                cy={100 + Math.sin(a) * 97}\n                r=\"1.4\"\n                fill=\"#c7c9ca\"\n              />\n            )\n          })}\n        {bands ? (\n          bands.map((v, i) => {\n            const a = 100 + i * 90\n            const color = [\"#ffad77\", \"#f45c89\", \"#b977ed\", \"#58bbee\"][i]\n            const end =\n              ((a + (((Math.max(0.02, v) * 160) / 91) * 180) / Math.PI) *\n                Math.PI) /\n              180\n            return (\n              <g key={i}>\n                <circle\n                  cx=\"100\"\n                  cy=\"100\"\n                  r=\"91\"\n                  fill=\"none\"\n                  stroke={[\"#ffad77\", \"#f45c89\", \"#b977ed\", \"#58bbee\"][i]}\n                  strokeWidth=\"5.5\"\n                  strokeDasharray={`${Math.max(0.02, v) * 160} 572`}\n                  transform={`rotate(${a} 100 100)`}\n                />\n                <circle\n                  cx={100 + Math.cos(end) * 91}\n                  cy={100 + Math.sin(end) * 91}\n                  r=\"3\"\n                  fill={color}\n                  stroke=\"#25282a\"\n                  strokeWidth=\"1.5\"\n                />\n              </g>\n            )\n          })\n        ) : (\n          <circle\n            cx=\"100\"\n            cy=\"100\"\n            r=\"88\"\n            fill=\"none\"\n            stroke={accent}\n            strokeWidth=\"1.2\"\n            strokeDasharray={`${value01 * 414} 553`}\n            transform=\"rotate(135 100 100)\"\n          />\n        )}\n      </svg>\n      <span className=\"spectral-knob__rim\" />\n      <span className=\"spectral-knob__cap\">\n        <i style={{ transform: `rotate(${-135 + value01 * 270}deg)` }} />\n        <span className=\"spectral-knob__readout\">{formattedValue}</span>\n      </span>\n    </div>\n  )\n}\n\n/** Convenience visual preset with the ordinary Knob contract. */\nexport function SpectralKnob({\n  label = \"Amount\",\n  size = 112,\n  accent = \"#64c8c4\",\n  bands,\n  readout,\n  ribbed = false,\n  unit,\n  ...control\n}: SpectralKnobProps) {\n  return (\n    <Knob\n      {...control}\n      size={size}\n      label={label}\n      hideLabel\n      hideValue\n      display={readout ?? control.display}\n      unit={unit}\n      renderDesign={(state) => (\n        <SpectralKnobDesign\n          {...state}\n          accent={accent}\n          bands={bands}\n          ribbed={ribbed}\n        />\n      )}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "@ui/spectral-knob.tsx"
    }
  ]
}
