{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "level-meter",
  "type": "registry:ui",
  "title": "LevelMeter",
  "description": "Live audio level in dBFS with warning and clip zones and a peak hold, painted without React renders.",
  "dependencies": [
    "@base-ui/react@^1.8.0"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/range-knobs.ts",
      "target": "@components/control-ui/knob-contracts/range-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/range.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const rangeKnobs = [\n  \"--cui-range-level-warning-background\",\n  \"--cui-range-level-clip-background\",\n  \"--cui-range-indeterminate-size\",\n  \"--cui-range-track-radius\",\n  \"--cui-range-track-background\",\n  \"--cui-range-indicator-radius\",\n  \"--cui-range-indicator-background\",\n  \"--cui-range-thumb-radius\",\n  \"--cui-range-thumb-background\",\n  \"--cui-range-thumb-border-color\",\n  \"--cui-range-thumb-shadow\",\n] as const;\nexport type RangeKnobStyle = Partial<Record<(typeof rangeKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/lib/level-meter-ballistics.ts",
      "target": "@components/control-ui/lib/level-meter-ballistics.ts",
      "type": "registry:lib",
      "content": "export const LEVEL_METER_RELEASE_DB_PER_SECOND = 24;\nexport const LEVEL_METER_PEAK_HOLD_MS = 1000;\n\nexport type LevelMeterScale = { minDb: number; maxDb: number };\n\nexport type LevelMeterReading = { levelDb: number; peakDb: number; peakHeldUntilMs: number };\n\nexport function clampLevelDb(levelDb: number, { minDb, maxDb }: LevelMeterScale) {\n  if (Number.isNaN(levelDb)) return minDb;\n  return Math.min(maxDb, Math.max(minDb, levelDb));\n}\n\nexport function levelMeterFraction(levelDb: number, scale: LevelMeterScale) {\n  const span = scale.maxDb - scale.minDb;\n  if (!(span > 0)) return 0;\n  return (clampLevelDb(levelDb, scale) - scale.minDb) / span;\n}\n\nexport function advanceLevelMeterReading(\n  reading: LevelMeterReading,\n  targetDb: number,\n  elapsedMs: number,\n  nowMs: number,\n  scale: LevelMeterScale,\n): LevelMeterReading {\n  const target = clampLevelDb(targetDb, scale);\n  const fallDb = (LEVEL_METER_RELEASE_DB_PER_SECOND * Math.max(0, elapsedMs)) / 1000;\n  const levelDb = Math.max(target, reading.levelDb - fallDb);\n  if (levelDb >= reading.peakDb) return { levelDb, peakDb: levelDb, peakHeldUntilMs: nowMs + LEVEL_METER_PEAK_HOLD_MS };\n  const peakDb = nowMs < reading.peakHeldUntilMs ? reading.peakDb : Math.max(levelDb, reading.peakDb - fallDb);\n  return { levelDb, peakDb, peakHeldUntilMs: reading.peakHeldUntilMs };\n}\n\nexport function levelMeterReadingSettled(reading: LevelMeterReading, targetDb: number, scale: LevelMeterScale) {\n  return reading.levelDb === clampLevelDb(targetDb, scale) && reading.peakDb === reading.levelDb;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/range-level-meter.css",
      "target": "@components/control-ui/styles/recipes/range-level-meter.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"root\"]) {\n    --cui-range-level-warning-background: var(--warning);\n    --cui-range-level-clip-background: var(--destructive);\n    --_range-level-peak-size: 2px;\n    --_range-level-zone-angle: 90deg;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"root\"][data-orientation=\"horizontal\"]) {\n    block-size: calc(var(--spacing) * 2);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"root\"][data-orientation=\"horizontal\"]:dir(rtl)) {\n    --_range-level-zone-angle: 270deg;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"root\"][data-orientation=\"vertical\"]) {\n    --_range-level-zone-angle: 0deg;\n    flex-direction: column;\n    inline-size: calc(var(--spacing) * 2);\n    min-block-size: calc(var(--spacing) * 16);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"track\"]) {\n    flex: 1;\n    border-radius: var(--cui-range-track-radius);\n    background: var(--cui-range-track-background);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"bar\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"peak\"]) {\n    background-image: linear-gradient(\n      var(--_range-level-zone-angle),\n      var(--cui-range-indicator-background) calc(var(--_range-level-warning-start, 1) * 100%),\n      var(--cui-range-level-warning-background) 0 calc(var(--_range-level-clip-start, 1) * 100%),\n      var(--cui-range-level-clip-background) 0\n    );\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"bar\"]) {\n    clip-path: inset(0 calc((1 - var(--_range-level, 0)) * 100%) 0 0 round var(--cui-range-indicator-radius));\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"peak\"]) {\n    clip-path: inset(\n      0 calc((1 - var(--_range-level-peak, 0)) * 100%) 0 calc(var(--_range-level-peak, 0) * 100% - var(--_range-level-peak-size))\n    );\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"bar\"]:dir(rtl)) {\n    clip-path: inset(0 0 0 calc((1 - var(--_range-level, 0)) * 100%) round var(--cui-range-indicator-radius));\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"peak\"]:dir(rtl)) {\n    clip-path: inset(\n      0 calc(var(--_range-level-peak, 0) * 100% - var(--_range-level-peak-size)) 0 calc((1 - var(--_range-level-peak, 0)) * 100%)\n    );\n  }\n\n  :where(\n    [data-range-kind=\"level-meter\"][data-slot=\"root\"][data-orientation=\"vertical\"]\n      [data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"bar\"]\n  ) {\n    clip-path: inset(calc((1 - var(--_range-level, 0)) * 100%) 0 0 0 round var(--cui-range-indicator-radius));\n  }\n\n  :where(\n    [data-range-kind=\"level-meter\"][data-slot=\"root\"][data-orientation=\"vertical\"]\n      [data-control-family=\"range\"][data-range-kind=\"level-meter\"][data-slot=\"peak\"]\n  ) {\n    clip-path: inset(\n      calc((1 - var(--_range-level-peak, 0)) * 100%) 0 calc(var(--_range-level-peak, 0) * 100% - var(--_range-level-peak-size)) 0\n    );\n  }\n}\n\n@property --cui-range-level-warning-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-range-level-clip-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/range.css",
      "target": "@components/control-ui/styles/recipes/range.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"range\"][data-slot=\"root\"]) {\n    --cui-range-track-radius: 9999px;\n    --cui-range-track-background: var(--muted);\n    --cui-range-indicator-radius: 9999px;\n    --cui-range-indicator-background: var(--primary);\n    --cui-range-thumb-radius: 9999px;\n    --cui-range-thumb-background: var(--background);\n    --cui-range-thumb-border-color: var(--control-rim);\n    --cui-range-thumb-shadow: var(--shadow-sm);\n    --cui-range-indeterminate-size: 40%;\n    --_range-thumb-border-width: var(--control-rim-width);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"root\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"root\"]) {\n    gap: calc(var(--spacing) * 2);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"track\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"track\"]) {\n    block-size: calc(var(--spacing) * 2);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"label-overlay\"]) {\n    padding-inline: calc(var(--spacing) * 3);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"track\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"track\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"track\"]) {\n    border-radius: var(--cui-range-track-radius);\n    background: var(--cui-range-track-background);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"track\"]) {\n    block-size: calc(var(--spacing) * 1.5);\n    touch-action: pan-y;\n    transition: background-color var(--duration-fast) var(--ease-standard);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"root\"][data-variant=\"plain\"]) {\n    --cui-range-track-radius: 3px;\n    --cui-range-track-background: var(--hover-fill);\n    --cui-range-indicator-radius: var(--cui-range-track-radius);\n    --cui-range-indicator-background: oklch(from var(--foreground) l c h / 0.14);\n    --cui-range-thumb-radius: 1px;\n    --cui-range-thumb-background: oklch(from var(--foreground) l c h / 0.3);\n    --cui-range-thumb-shadow: none;\n    --_range-thumb-border-width: 0px;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"track\"][data-dragging]) {\n    --cui-range-track-background: oklch(from var(--foreground) l c h / 0.1);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"indicator\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"indicator\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"indicator\"]) {\n    height: 100%;\n    border-radius: var(--cui-range-indicator-radius);\n    background: var(--cui-range-indicator-background);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"indicator\"]) {\n    transition: background-color var(--duration-fast) var(--ease-standard);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"indicator\"][data-dragging]) {\n    --cui-range-indicator-background: var(--primary);\n    background: var(--cui-range-indicator-background);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"control\"]) {\n    padding-block: calc(var(--spacing) * 1.5);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"control\"][data-labeled]) {\n    block-size: calc(var(--spacing) * 7.5);\n    padding-block: 0;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"track\"][data-labeled]) {\n    block-size: 100%;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"][data-variant=\"default\"]) {\n    inline-size: calc(var(--spacing) * 3.5);\n    block-size: calc(var(--spacing) * 3.5);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"]) {\n    position: relative;\n    border: var(--_range-thumb-border-width) solid var(--cui-range-thumb-border-color);\n    border-radius: var(--cui-range-thumb-radius);\n    background: var(--cui-range-thumb-background);\n    box-shadow: var(--cui-range-thumb-shadow);\n    touch-action: pan-y;\n    transition-property: scale, box-shadow, height, width;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  @media (hover: hover) and (pointer: fine) {\n    :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"]:hover:not([data-disabled])) {\n      scale: 1.1;\n    }\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"][data-dragging]) {\n    scale: 1.1;\n    --cui-range-thumb-shadow: var(--shadow-md);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"][data-variant=\"plain\"]) {\n    height: 1rem;\n    width: 0.125rem;\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"][data-variant=\"plain\"]:hover:not([data-disabled])) {\n      --cui-range-thumb-background: oklch(from var(--foreground) l c h / 0.5);\n      scale: 1;\n    }\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"][data-variant=\"plain\"][data-dragging]) {\n    --cui-range-thumb-background: oklch(from var(--foreground) l c h / 0.7);\n    scale: 1;\n    height: 1.25rem;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"tick\"]) {\n    inline-size: 1px;\n    block-size: calc(var(--spacing) * 1.5);\n    background: oklch(from var(--foreground) l c h / 0.15);\n    transition-property: height, background-color;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"root\"][data-dragging] [data-slot=\"tick\"]) {\n    height: 0.75rem;\n    background: oklch(from var(--foreground) l c h / 0.25);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"]:is([data-slot=\"label\"], [data-slot=\"value\"])) {\n    color: var(--muted-foreground);\n    transition-property: color, scale, translate;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"root\"][data-dragging] [data-slot=\"label\"]) {\n    translate: calc(var(--spacing) * -1) calc(var(--spacing) * -1.5);\n    scale: 0.9;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"root\"][data-dragging] [data-slot=\"value\"]) {\n    translate: calc(var(--spacing) * 0.5) calc(var(--spacing) * -1.5);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"value\"]) {\n    font-size: var(--text-caption);\n    line-height: calc(var(--spacing) * 3.5);\n    letter-spacing: var(--tracking-tight);\n    font-variant-numeric: tabular-nums;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"label\"]) {\n    font-size: var(--text-caption);\n    line-height: calc(var(--spacing) * 3.5);\n    letter-spacing: var(--tracking-tight);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"root\"][data-disabled]) {\n    opacity: var(--disabled-opacity);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"control\"]) {\n    padding-inline: calc(var(--spacing) * 1.5);\n    padding-block: 0;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"control\"][data-labeled]) {\n    inline-size: calc(var(--spacing) * 7.5);\n    block-size: 100%;\n    padding-inline: 0;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"track\"]),\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"thumb\"]) {\n    touch-action: pan-x;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"track\"]) {\n    inline-size: calc(var(--spacing) * 1.5);\n    block-size: 100%;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"track\"][data-labeled]) {\n    inline-size: 100%;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"indicator\"]) {\n    width: 100%;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"thumb\"][data-variant=\"plain\"]) {\n    height: 0.125rem;\n    width: 1rem;\n  }\n\n  :where(\n    [data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"thumb\"][data-variant=\"plain\"][data-dragging]\n  ) {\n    width: 1.25rem;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"root\"] [data-slot=\"tick\"]) {\n    inline-size: calc(var(--spacing) * 1.5);\n    block-size: 1px;\n    inset-inline-start: 0;\n  }\n\n  :where(\n    [data-control-family=\"range\"][data-range-kind=\"slider\"][data-orientation=\"vertical\"][data-slot=\"root\"] [data-slot=\"label-overlay\"]\n  ) {\n    flex-direction: column;\n    padding-inline: 0;\n    padding-block: calc(var(--spacing) * 2);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"indicator\"]) {\n    transition-property: width;\n    transition-duration: var(--duration-slow);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"indicator\"][data-indeterminate]) {\n    inline-size: var(--cui-range-indeterminate-size);\n    animation: cui-range-indeterminate calc(var(--duration-loop) * 1.5) var(--ease-standard) infinite;\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"indicator\"][data-indeterminate]) {\n      animation: none;\n      opacity: 0.6;\n    }\n  }\n\n  :where([data-motion=\"reduced\"] [data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"indicator\"][data-indeterminate]) {\n    animation: none;\n    opacity: 0.6;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"value\"]) {\n    font-size: var(--text-label);\n    color: var(--muted-foreground);\n    font-variant-numeric: tabular-nums;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"progress\"][data-slot=\"label\"]) {\n    font-size: var(--text-label);\n    font-weight: var(--font-weight-medium);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"indicator\"]) {\n    transition-property: width;\n    transition-duration: var(--duration-slow);\n    transition-timing-function: var(--ease-emphasized);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"value\"]) {\n    font-size: var(--text-label);\n    color: var(--muted-foreground);\n    font-variant-numeric: tabular-nums;\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"meter\"][data-slot=\"label\"]) {\n    font-size: var(--text-label);\n    font-weight: var(--font-weight-medium);\n    color: var(--foreground);\n  }\n\n  :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"])::after {\n    content: \"\";\n    position: absolute;\n    inset: 50%;\n    translate: -50% -50%;\n    inline-size: max(100%, var(--target-min));\n    block-size: max(100%, var(--target-min));\n  }\n\n  @media (pointer: coarse) {\n    :where([data-control-family=\"range\"][data-range-kind=\"slider\"][data-slot=\"thumb\"])::after {\n      inline-size: max(100%, var(--touch-target));\n      block-size: max(100%, var(--touch-target));\n    }\n  }\n}\n\n@keyframes cui-range-indeterminate {\n  from {\n    margin-inline-start: calc(var(--cui-range-indeterminate-size) * -1);\n  }\n  to {\n    margin-inline-start: 100%;\n  }\n}\n\n@property --cui-range-indeterminate-size {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-range-track-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-range-track-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-range-indicator-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-range-indicator-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-range-thumb-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-range-thumb-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-range-thumb-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-range-thumb-shadow {\n  syntax: \"*\";\n  inherits: true;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/level-meter.tsx",
      "target": "@components/control-ui/ui/level-meter.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, CSSProperties } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RangeKnobStyle } from \"@/components/control-ui/knob-contracts/range-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport {\n  advanceLevelMeterReading,\n  type LevelMeterReading,\n  type LevelMeterScale,\n  levelMeterFraction,\n  levelMeterReadingSettled,\n} from \"@/components/control-ui/lib/level-meter-ballistics\";\n\nexport type LevelMeterSource = {\n  subscribe: (listener: (levelDb: number) => void) => () => void;\n};\n\nexport type LevelMeterOrientation = \"horizontal\" | \"vertical\";\n\nexport type LevelMeterProps = Omit<ComponentProps<\"div\">, \"style\"> & {\n  value?: number;\n  source?: LevelMeterSource | null;\n  minDb?: number;\n  maxDb?: number;\n  warningDb?: number;\n  clipDb?: number;\n  orientation?: LevelMeterOrientation;\n  style?: CSSProperties & RangeKnobStyle;\n};\n\nexport type LevelMeterTrackProps = Omit<ComponentProps<\"div\">, \"style\"> & { style?: CSSProperties & RangeKnobStyle };\n\nexport type LevelMeterBarProps = Omit<ComponentProps<\"div\">, \"style\" | \"children\"> & {\n  style?: CSSProperties & RangeKnobStyle;\n};\n\nexport type LevelMeterPeakProps = Omit<ComponentProps<\"div\">, \"style\" | \"children\"> & { style?: CSSProperties & RangeKnobStyle };\n\ntype LevelMeterZoneStyle = CSSProperties & Record<\"--_range-level-warning-start\" | \"--_range-level-clip-start\", string>;\n\nconst ARIA_UPDATE_INTERVAL_MS = 250;\n\nfunction createLevelMeterPainter() {\n  let root: HTMLElement | null = null;\n  let scale: LevelMeterScale = { minDb: -60, maxDb: 0 };\n  let announcesValue = false;\n  let targetDb = Number.NEGATIVE_INFINITY;\n  let reading: LevelMeterReading = { levelDb: scale.minDb, peakDb: scale.minDb, peakHeldUntilMs: 0 };\n  let frame = 0;\n  let lastFrameMs = 0;\n  let lastAnnouncedMs = Number.NEGATIVE_INFINITY;\n\n  const paint = (element: HTMLElement, nowMs: number, settled: boolean) => {\n    element.style.setProperty(\"--_range-level\", `${levelMeterFraction(reading.levelDb, scale)}`);\n    element.style.setProperty(\"--_range-level-peak\", `${levelMeterFraction(reading.peakDb, scale)}`);\n    if (!announcesValue || (!settled && nowMs - lastAnnouncedMs < ARIA_UPDATE_INTERVAL_MS)) return;\n    lastAnnouncedMs = nowMs;\n    const roundedDb = Math.round(reading.levelDb);\n    element.setAttribute(\"aria-valuenow\", `${roundedDb}`);\n    element.setAttribute(\"aria-valuetext\", `${roundedDb} dB`);\n  };\n\n  const step = (nowMs: number) => {\n    frame = 0;\n    if (!root) return;\n    reading = advanceLevelMeterReading(reading, targetDb, nowMs - lastFrameMs, nowMs, scale);\n    lastFrameMs = nowMs;\n    const settled = levelMeterReadingSettled(reading, targetDb, scale);\n    paint(root, nowMs, settled);\n    if (!settled) frame = requestAnimationFrame(step);\n  };\n\n  const wake = () => {\n    if (frame !== 0 || !root) return;\n    lastFrameMs = performance.now();\n    frame = requestAnimationFrame(step);\n  };\n\n  return {\n    attach(element: HTMLElement, nextScale: LevelMeterScale, nextAnnouncesValue: boolean) {\n      root = element;\n      scale = nextScale;\n      announcesValue = nextAnnouncesValue;\n      wake();\n      return () => {\n        cancelAnimationFrame(frame);\n        frame = 0;\n        root = null;\n      };\n    },\n    setTarget(levelDb: number) {\n      targetDb = levelDb;\n      wake();\n    },\n  };\n}\n\nexport function LevelMeter({\n  value,\n  source,\n  minDb = -60,\n  maxDb = 0,\n  warningDb = -18,\n  clipDb = -6,\n  orientation = \"horizontal\",\n  className,\n  style,\n  children,\n  ref,\n  ...props\n}: LevelMeterProps) {\n  const [painter] = useState(createLevelMeterPainter);\n  const rootRef = useRef<HTMLDivElement>(null);\n  const labelled = Boolean(props[\"aria-label\"] || props[\"aria-labelledby\"]);\n  const scale = { minDb, maxDb };\n  const zoneStyle: LevelMeterZoneStyle = {\n    \"--_range-level-warning-start\": `${levelMeterFraction(warningDb, scale)}`,\n    \"--_range-level-clip-start\": `${levelMeterFraction(clipDb, scale)}`,\n    ...style,\n  };\n\n  useEffect(() => {\n    const root = rootRef.current;\n    if (!root) return;\n    return painter.attach(root, { minDb, maxDb }, labelled);\n  }, [painter, minDb, maxDb, labelled]);\n\n  useEffect(() => {\n    if (source) return source.subscribe(painter.setTarget);\n    painter.setTarget(value ?? Number.NEGATIVE_INFINITY);\n  }, [painter, source, value]);\n\n  return useRender({\n    defaultTagName: \"div\",\n    ref: [ref ?? null, rootRef],\n    props: {\n      ...props,\n      role: labelled ? \"meter\" : undefined,\n      \"aria-hidden\": labelled ? undefined : true,\n      \"aria-valuemin\": labelled ? minDb : undefined,\n      \"aria-valuemax\": labelled ? maxDb : undefined,\n      \"aria-valuenow\": labelled ? minDb : undefined,\n      \"data-control-ui\": \"level-meter\",\n      \"data-control-family\": \"range\",\n      \"data-range-kind\": \"level-meter\",\n      \"data-slot\": \"root\",\n      \"data-orientation\": orientation,\n      className: cn(\"flex\", className),\n      style: zoneStyle,\n      children: children ?? (\n        <LevelMeterTrack>\n          <LevelMeterBar />\n        </LevelMeterTrack>\n      ),\n    },\n  });\n}\n\nexport function LevelMeterTrack({ className, ...props }: LevelMeterTrackProps) {\n  return (\n    <div\n      data-control-ui=\"level-meter\"\n      data-control-family=\"range\"\n      data-range-kind=\"level-meter\"\n      data-slot=\"track\"\n      className={cn(\"relative overflow-hidden\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function LevelMeterBar({ className, ...props }: LevelMeterBarProps) {\n  return (\n    <div\n      data-control-ui=\"level-meter\"\n      data-control-family=\"range\"\n      data-range-kind=\"level-meter\"\n      data-slot=\"bar\"\n      className={cn(\"absolute inset-0\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function LevelMeterPeak({ className, ...props }: LevelMeterPeakProps) {\n  return (\n    <div\n      data-control-ui=\"level-meter\"\n      data-control-family=\"range\"\n      data-range-kind=\"level-meter\"\n      data-slot=\"peak\"\n      className={cn(\"absolute inset-0\", className)}\n      {...props}\n    />\n  );\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/range.css\"": {},
    "@import \"../components/control-ui/styles/recipes/range-level-meter.css\"": {}
  }
}
