{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "visant",
  "homepage": "https://ui.visantlabs.com",
  "items": [
    {
      "name": "vintage-theme",
      "type": "registry:theme",
      "title": "Vintage Theme",
      "description": "O tema do kit de áudio, em claro e escuro: as chapas saem dos tokens do projeto e a luz sai da marca.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "cssVars": {
        "theme": {
          "font-vintage-display": "'Orbitron', sans-serif",
          "font-vintage-mono": "'Red Hat Mono', monospace",
          "font-vintage-body": "'Helvetica Neue', Helvetica, sans-serif"
        },
        "light": {
          "vintage-meter-green": "#22c55e",
          "vintage-meter-yellow": "#eab308",
          "vintage-meter-orange": "#f97316",
          "vintage-meter-red": "#ef4444",
          "vintage-needle": "#ef2b2b",
          "vintage-needle-glow": "color-mix(in srgb, var(--vintage-needle) 50%, transparent)",
          "vintage-accent": "var(--vintage-light)",
          "vintage-accent-deep": "color-mix(in oklab, var(--vintage-light) 82%, var(--foreground))",
          "vintage-accent-glow": "color-mix(in srgb, var(--vintage-light) 60%, transparent)",
          "vintage-label": "var(--foreground)",
          "vintage-value": "var(--foreground)",
          "vintage-tube": "#0c0e0b",
          "vintage-tube-hi": "#1e201d",
          "vintage-face-ink": "#2a2014",
          "vintage-light": "var(--brand, #ffd700)",
          "vintage-brushed": "conic-gradient(from 90deg, #969aa0 0deg, #5d636c 9deg, #555b69 22deg, #dfdfdf 41deg, #71798a 63deg, #a9abb3 83deg, #cbd2d6 120deg, #ffffff 149deg, #5e646a 186deg, #8e959d 219deg, #ffffff 245deg, #7e8691 269deg, #575d6b 284deg, #6c747f 301deg, #f1f1f3 337deg, #979aa3 349deg, #b1b3b9 356deg, #969aa0 360deg)",
          "vintage-surface-1": "color-mix(in oklab, var(--foreground) 14%, var(--background))",
          "vintage-surface-2": "color-mix(in oklab, var(--foreground) 8%, var(--background))",
          "vintage-surface-3": "color-mix(in oklab, var(--foreground) 4%, var(--background))",
          "vintage-surface-3a": "color-mix(in oklab, var(--foreground) 2%, var(--background))",
          "vintage-surface-4": "var(--background)",
          "vintage-border": "color-mix(in oklab, var(--foreground) 18%, var(--background))",
          "vintage-text-muted": "color-mix(in oklab, var(--foreground) 62%, var(--background))",
          "vintage-text-dim": "color-mix(in oklab, var(--foreground) 44%, var(--background))",
          "vintage-metal-light": "color-mix(in oklab, var(--foreground) 24%, var(--background))",
          "vintage-metal-dark": "color-mix(in oklab, var(--foreground) 46%, var(--background))",
          "vintage-metal-mid": "color-mix(in oklab, var(--foreground) 34%, var(--background))",
          "vintage-metal-channel-light": "color-mix(in oklab, var(--foreground) 10%, var(--background))",
          "vintage-metal-channel-dark": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-toggle-track": "color-mix(in oklab, var(--foreground) 24%, var(--background))",
          "vintage-grid": "color-mix(in oklab, var(--foreground) 70%, var(--background))",
          "vintage-cap-hi": "color-mix(in oklab, var(--foreground) 2%, var(--background))",
          "vintage-cap-lo": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-base-hi": "color-mix(in oklab, var(--foreground) 12%, var(--background))",
          "vintage-base-lo": "color-mix(in oklab, var(--foreground) 36%, var(--background))",
          "vintage-depth-edge": "color-mix(in oklab, var(--foreground) 38%, var(--background))",
          "vintage-depth-mid": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-depth-core": "color-mix(in oklab, var(--foreground) 8%, var(--background))",
          "vintage-ring-hi": "var(--background)",
          "vintage-ring-lo": "color-mix(in oklab, var(--foreground) 40%, var(--background))",
          "vintage-face-hi": "color-mix(in oklab, var(--vintage-light) 12%, #fdf6e0)",
          "vintage-face-mid": "color-mix(in oklab, var(--vintage-light) 14%, #f3e3b4)",
          "vintage-face-lo": "color-mix(in oklab, var(--vintage-light) 16%, #d9b970)",
          "vintage-panel-shadow": "inset 0 1px 0 rgb(255 255 255 / 0.7), 0 1px 1px rgb(0 0 0 / 0.12), 0 10px 24px -8px rgb(0 0 0 / 0.2)",
          "vintage-well-shadow": "inset 0 2px 5px rgb(0 0 0 / 0.22), inset 0 0 0 1px rgb(0 0 0 / 0.14), 0 1px 0 rgb(255 255 255 / 0.7)",
          "vintage-engrave": "0 1px 0 rgb(255 255 255 / 0.7)",
          "vintage-edge": "rgb(0 0 0 / 0.2)",
          "vintage-lip": "rgb(255 255 255 / 0.7)",
          "vintage-tv-body-hi": "#c6beb6",
          "vintage-tv-body-lo": "#8c8782",
          "vintage-tv-console": "#cdc4bb",
          "vintage-tv-edge": "#4d4946",
          "vintage-tv-foot-hi": "#ccc3bb",
          "vintage-tv-foot-lo": "#9a938d",
          "vintage-tv-bezel": "#bfb7ab",
          "vintage-tv-dial-hi": "#ccc4b7",
          "vintage-tv-dial-lo": "#736d68",
          "vintage-tv-ink": "#4a4540",
          "background": "#f4f2ee",
          "foreground": "#1a1a1a",
          "card": "#fbfaf7",
          "card-foreground": "#1a1a1a",
          "primary": "#1a1a1a",
          "primary-foreground": "#f4f2ee",
          "secondary": "#e6e3dc",
          "secondary-foreground": "#1a1a1a",
          "muted": "#e6e3dc",
          "muted-foreground": "#66635d",
          "accent": "#e6e3dc",
          "accent-foreground": "#1a1a1a",
          "destructive": "#d92d20",
          "destructive-foreground": "#ffffff",
          "border": "#cfccc4",
          "input": "#cfccc4",
          "ring": "#1a1a1a"
        },
        "dark": {
          "vintage-meter-green": "#22c55e",
          "vintage-meter-yellow": "#eab308",
          "vintage-meter-orange": "#f97316",
          "vintage-meter-red": "#ef4444",
          "vintage-needle": "#ef2b2b",
          "vintage-needle-glow": "color-mix(in srgb, var(--vintage-needle) 50%, transparent)",
          "vintage-accent": "var(--vintage-light)",
          "vintage-accent-deep": "color-mix(in oklab, var(--vintage-light) 82%, var(--foreground))",
          "vintage-accent-glow": "color-mix(in srgb, var(--vintage-light) 60%, transparent)",
          "vintage-label": "var(--foreground)",
          "vintage-value": "var(--foreground)",
          "vintage-tube": "#0c0e0b",
          "vintage-tube-hi": "#1e201d",
          "vintage-face-ink": "#2a2014",
          "vintage-light": "var(--brand, #ffd700)",
          "vintage-brushed": "conic-gradient(from 90deg, #969aa0 0deg, #5d636c 9deg, #555b69 22deg, #dfdfdf 41deg, #71798a 63deg, #a9abb3 83deg, #cbd2d6 120deg, #ffffff 149deg, #5e646a 186deg, #8e959d 219deg, #ffffff 245deg, #7e8691 269deg, #575d6b 284deg, #6c747f 301deg, #f1f1f3 337deg, #979aa3 349deg, #b1b3b9 356deg, #969aa0 360deg)",
          "vintage-surface-1": "color-mix(in oklab, var(--background) 55%, black)",
          "vintage-surface-2": "var(--background)",
          "vintage-surface-3": "color-mix(in oklab, var(--foreground) 8%, var(--background))",
          "vintage-surface-3a": "color-mix(in oklab, var(--foreground) 14%, var(--background))",
          "vintage-surface-4": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-border": "color-mix(in oklab, var(--foreground) 14%, var(--background))",
          "vintage-text-muted": "color-mix(in oklab, var(--foreground) 55%, var(--background))",
          "vintage-text-dim": "color-mix(in oklab, var(--foreground) 34%, var(--background))",
          "vintage-metal-light": "color-mix(in oklab, var(--foreground) 38%, var(--background))",
          "vintage-metal-dark": "color-mix(in oklab, var(--foreground) 16%, var(--background))",
          "vintage-metal-mid": "color-mix(in oklab, var(--foreground) 60%, var(--background))",
          "vintage-metal-channel-light": "color-mix(in oklab, var(--foreground) 72%, var(--background))",
          "vintage-metal-channel-dark": "color-mix(in oklab, var(--foreground) 62%, var(--background))",
          "vintage-toggle-track": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-grid": "color-mix(in oklab, var(--foreground) 72%, var(--background))",
          "vintage-cap-hi": "color-mix(in oklab, var(--foreground) 50%, var(--background))",
          "vintage-cap-lo": "color-mix(in oklab, var(--foreground) 14%, var(--background))",
          "vintage-base-hi": "color-mix(in oklab, var(--foreground) 22%, var(--background))",
          "vintage-base-lo": "color-mix(in oklab, var(--background) 55%, black)",
          "vintage-depth-edge": "color-mix(in oklab, var(--foreground) 8%, var(--background))",
          "vintage-depth-mid": "color-mix(in oklab, var(--foreground) 26%, var(--background))",
          "vintage-depth-core": "color-mix(in oklab, var(--foreground) 38%, var(--background))",
          "vintage-ring-hi": "color-mix(in oklab, var(--foreground) 90%, var(--background))",
          "vintage-ring-lo": "color-mix(in oklab, var(--foreground) 18%, var(--background))",
          "vintage-face-hi": "color-mix(in oklab, var(--vintage-light) 14%, #f7e2a4)",
          "vintage-face-mid": "color-mix(in oklab, var(--vintage-light) 16%, #ecc86f)",
          "vintage-face-lo": "color-mix(in oklab, var(--vintage-light) 18%, #b98a33)",
          "vintage-panel-shadow": "inset 0 1px 0 rgb(255 255 255 / 0.07), 0 1px 1px rgb(0 0 0 / 0.5), 0 10px 24px -8px rgb(0 0 0 / 0.6)",
          "vintage-well-shadow": "inset 0 2px 6px rgb(0 0 0 / 0.75), inset 0 0 0 1px rgb(0 0 0 / 0.6), 0 1px 0 rgb(255 255 255 / 0.06)",
          "vintage-engrave": "0 -1px 0 rgb(0 0 0 / 0.55), 0 1px 0 rgb(255 255 255 / 0.06)",
          "vintage-edge": "rgb(0 0 0 / 0.6)",
          "vintage-lip": "rgb(255 255 255 / 0.06)",
          "vintage-tv-body-hi": "color-mix(in oklab, var(--foreground) 24%, var(--background))",
          "vintage-tv-body-lo": "color-mix(in oklab, var(--foreground) 8%, var(--background))",
          "vintage-tv-console": "color-mix(in oklab, var(--foreground) 18%, var(--background))",
          "vintage-tv-edge": "color-mix(in oklab, var(--background) 55%, black)",
          "vintage-tv-foot-hi": "color-mix(in oklab, var(--foreground) 26%, var(--background))",
          "vintage-tv-foot-lo": "color-mix(in oklab, var(--foreground) 12%, var(--background))",
          "vintage-tv-bezel": "color-mix(in oklab, var(--foreground) 16%, var(--background))",
          "vintage-tv-dial-hi": "color-mix(in oklab, var(--foreground) 52%, var(--background))",
          "vintage-tv-dial-lo": "color-mix(in oklab, var(--foreground) 20%, var(--background))",
          "vintage-tv-ink": "color-mix(in oklab, var(--foreground) 72%, var(--background))",
          "background": "#0f0f0f",
          "foreground": "#e8e8e8",
          "card": "#1a1a1a",
          "card-foreground": "#e8e8e8",
          "primary": "#ffd700",
          "primary-foreground": "#0f0f0f",
          "secondary": "#2a2a2a",
          "secondary-foreground": "#e8e8e8",
          "muted": "#2a2a2a",
          "muted-foreground": "#888888",
          "accent": "#ff6b35",
          "accent-foreground": "#ffffff",
          "destructive": "#ef4444",
          "destructive-foreground": "#ffffff",
          "border": "#333333",
          "input": "#2a2a2a",
          "ring": "#ffd700"
        }
      },
      "categories": [
        "fundacao",
        "tema",
        "css"
      ],
      "meta": {
        "uso": {
          "quando": "Montar app ou ferramenta de áudio com o kit vintage: é o tema escuro de painel que as peças vintage-* pressupõem",
          "evite": "Projeto de marca de cliente: use o tema da marca via brand-theme e deixe o kit vintage de fora"
        }
      },
      "css": {
        "@supports (color: oklch(from red l c h))": {
          ":root": {
            "--vintage-light": "oklch(from var(--brand, #b8860b) min(l, 0.62) max(c, 0.06) h)",
            "--vintage-label": "oklch(from var(--brand, #b8860b) min(l, 0.38) min(c, 0.1) h)",
            "--vintage-value": "oklch(from var(--brand, #b8860b) min(l, 0.42) c h)"
          },
          ".dark": {
            "--vintage-light": "oklch(from var(--brand, #ffd700) max(l, 0.72) c h)",
            "--vintage-label": "oklch(from var(--brand, #ffd700) max(l, 0.86) min(c, 0.12) h)",
            "--vintage-value": "oklch(from var(--brand, #ffd700) max(l, 0.86) c h)"
          }
        }
      }
    },
    {
      "name": "vintage-base",
      "type": "registry:base",
      "title": "Vintage Base",
      "description": "A fundação do kit: variáveis de painel, texturas e as regras em @layer.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme"
      ],
      "cssVars": {
        "theme": {
          "font-vintage-display": "'Orbitron', sans-serif",
          "font-vintage-mono": "'Red Hat Mono', monospace",
          "font-vintage-body": "'Helvetica Neue', Helvetica, sans-serif",
          "radius": "0.5rem"
        },
        "light": {
          "background": "#0f0f0f",
          "foreground": "#e8e8e8",
          "primary": "#ffd700",
          "primary-foreground": "#0f0f0f",
          "radius": "0.5rem"
        },
        "dark": {
          "background": "#0f0f0f",
          "foreground": "#e8e8e8",
          "primary": "#ffd700",
          "primary-foreground": "#0f0f0f"
        }
      },
      "css": {
        "@import \"https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Red+Hat+Mono:wght@400;500;600;700&display=swap\"": {}
      },
      "categories": [
        "fundacao",
        "css",
        "base"
      ],
      "meta": {
        "uso": {
          "quando": "Instalar qualquer peça vintage-*: traz as variáveis de painel, texturas e regras em @layer que elas leem",
          "evite": "Interface fora do kit vintage: não precisa, as peças @visant leem os tokens do tema da marca"
        }
      }
    },
    {
      "name": "use-knob-drag",
      "type": "registry:hook",
      "title": "useKnobDrag",
      "description": "O gesto de arrastar um knob isolado do desenho: pointer capture, trava de curso e passo fino com shift.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/vintage/hooks/use-knob-drag.ts",
          "type": "registry:hook",
          "target": "@hooks/use-knob-drag.ts"
        }
      ],
      "registryDependencies": [
        "@visant/sfx-bus"
      ],
      "categories": [
        "fundacao",
        "hook",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Criar um controle giratório próprio com arraste vertical, trava de curso e passo fino no shift",
          "evite": "Se um knob pronto serve, use vintage-knob ou vintage-large-knob; número em campo de editor, scrub-input"
        }
      }
    },
    {
      "name": "use-media-query",
      "type": "registry:hook",
      "title": "useMediaQuery",
      "description": "Media query como estado de React, via useSyncExternalStore: leitura síncrona no primeiro render, sem piscar, e segura em SSR.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-media-query.ts",
          "type": "registry:hook",
          "target": "@hooks/use-media-query.ts"
        }
      ],
      "categories": [
        "fundacao",
        "hook",
        "responsivo",
        "ssr"
      ],
      "meta": {
        "uso": {
          "quando": "Trocar layout ou comportamento por breakpoint em React, sem piscar no primeiro render e seguro em SSR",
          "evite": "Mudança só visual por largura: resolva com media query no CSS, sem hook nem re-render"
        }
      }
    },
    {
      "name": "vintage-button",
      "type": "registry:ui",
      "title": "Vintage Button",
      "description": "Botão de painel que afunda no clique.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-button.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "botao"
      ],
      "meta": {
        "uso": {
          "quando": "Botão de painel que afunda no clique, em app de áudio, synth ou ferramenta com cara de hardware",
          "evite": "Botão comum de produto ou landing: use o botão do tema; CTA de conversão, magnetic-cta"
        }
      }
    },
    {
      "name": "vintage-slider",
      "type": "registry:ui",
      "title": "Vintage Slider",
      "description": "Fader de console com curso e trilho gravados.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "fader"
      ],
      "meta": {
        "uso": {
          "quando": "Fader de console pra volume ou mix em interface de áudio do kit vintage",
          "evite": "Slider de formulário ou produto: elastic-slider ou slosh-slider; simular conta, sim-slider"
        }
      }
    },
    {
      "name": "vintage-meter",
      "type": "registry:ui",
      "title": "Vintage Meter",
      "description": "VU analógico com balística de ponteiro.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-meter.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "audio",
        "medidor"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar nível de sinal ao vivo com ponteiro de VU num painel de áudio",
          "evite": "Métrica de dashboard ou cota: gauge; número com régua e evidência, measure-bar"
        }
      }
    },
    {
      "name": "vintage-knob",
      "type": "registry:ui",
      "title": "Vintage Knob",
      "description": "Potenciômetro com arraste vertical e trava de curso.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "@visant/use-knob-drag",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-knob.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "knob"
      ],
      "meta": {
        "uso": {
          "quando": "Ajustar parâmetro contínuo num painel de áudio onde vários knobs dividem pouco espaço",
          "evite": "Parâmetro principal com escala e leitura: vintage-large-knob; número em editor, scrub-input"
        }
      }
    },
    {
      "name": "vintage-large-knob",
      "type": "registry:ui",
      "title": "Vintage Large Knob",
      "description": "O irmão grande: marcação de escala e leitura de valor.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "@visant/use-knob-drag",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-large-knob.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "knob"
      ],
      "meta": {
        "uso": {
          "quando": "Parâmetro principal do painel que pede escala marcada e leitura do valor, como ganho ou master",
          "evite": "Vários parâmetros secundários lado a lado: use vintage-knob, que ocupa menos"
        }
      }
    },
    {
      "name": "vintage-toggle",
      "type": "registry:ui",
      "title": "Vintage Toggle",
      "description": "Chave de duas posições com estalo visual.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-toggle.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "chave"
      ],
      "meta": {
        "uso": {
          "quando": "Ligar e desligar função num painel de áudio, como bypass ou phantom, com cara de chave física",
          "evite": "Switch de configuração em produto comum: liquid-toggle; tema claro e escuro, eclipse-switch"
        }
      }
    },
    {
      "name": "vintage-eq",
      "type": "registry:ui",
      "title": "Vintage EQ",
      "description": "Banco de faders com curva desenhada.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-eq.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "eq",
        "faders",
        "grafico"
      ],
      "meta": {
        "uso": {
          "quando": "Equalizador gráfico de bandas fixas em app de áudio, cada banda um fader com a curva desenhada",
          "evite": "Precisa de sino, Q e frequência livre por banda: use vintage-parametric-eq"
        }
      }
    },
    {
      "name": "vintage-parametric-eq",
      "type": "registry:ui",
      "title": "Vintage Parametric EQ",
      "description": "O EQ paramétrico: cada banda é um sino, e a curva grossa é a soma em dB. Arraste um ponto, roda muda o Q, e o BYPASS achata sem perder os valores.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-parametric-eq.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "eq",
        "curva",
        "parametrico",
        "filtro"
      ],
      "meta": {
        "uso": {
          "quando": "Editar curva de EQ com bandas móveis, Q na roda e bypass, em DAW ou plugin web",
          "evite": "Ajuste simples de graves e agudos em bandas fixas: vintage-eq resolve com menos curva de aprendizado"
        }
      }
    },
    {
      "name": "vintage-led",
      "type": "registry:ui",
      "title": "Vintage LED",
      "description": "LED de painel com halo. Quatro cores, estado on/off.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-led.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "feedback",
        "audio",
        "estado"
      ],
      "meta": {
        "uso": {
          "quando": "Indicar estado on/off num painel do kit vintage, como clip, gravando ou ligado",
          "evite": "Status de sistema em produto comum: store-status ou um ponto do tema, não o LED com halo"
        }
      }
    },
    {
      "name": "vintage-command-palette",
      "type": "registry:ui",
      "title": "Vintage Command Palette",
      "description": "Paleta de comandos no vocabulário do painel.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-command-palette.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "comando",
        "teclado"
      ],
      "meta": {
        "uso": {
          "quando": "Paleta de comandos por teclado dentro de app no kit vintage, como lista de efeitos ou presets",
          "evite": "App de produto comum: use o command menu do tema; só buscar no cabeçalho, expanding-search"
        }
      }
    },
    {
      "name": "vintage-tv-frame",
      "type": "registry:ui",
      "title": "Vintage TV Frame",
      "description": "Moldura de tubo com curvatura e brilho de varredura.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "https://visant-ui.vercel.app/r/vintage-oscilloscope.json",
        "@visant/vintage-oscilloscope",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-tv-frame.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "moldura",
        "crt"
      ],
      "meta": {
        "uso": {
          "quando": "Emoldurar vídeo, preview ou tela em interface retrô com cara de tubo CRT",
          "evite": "Moldura de foto em landing ou editorial: use photo-frame"
        }
      }
    },
    {
      "name": "vintage-soundboard-pad",
      "type": "registry:ui",
      "title": "Vintage Soundboard Pad",
      "description": "Pad de disparo com estado aceso e retorno tátil.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "https://visant-ui.vercel.app/r/sfx-bus.json",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-soundboard-pad.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "pad"
      ],
      "meta": {
        "uso": {
          "quando": "Disparar sample ou efeito sonoro com toque, numa grade de pads tipo MPC",
          "evite": "Botão de ação comum: vintage-button dentro do kit, ou o botão do tema fora dele"
        }
      }
    },
    {
      "name": "vintage-xy-pad",
      "type": "registry:ui",
      "title": "Vintage XY Pad",
      "description": "Campo de dois eixos para controlar dois parâmetros num gesto só.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-xy-pad.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "audio",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Controlar dois parâmetros juntos num gesto só, como filtro e ressonância, em app de áudio",
          "evite": "Um parâmetro só: vintage-knob ou vintage-slider"
        }
      }
    },
    {
      "name": "vintage-oscilloscope",
      "type": "registry:ui",
      "title": "Vintage Oscilloscope",
      "description": "Traço de osciloscópio alimentado por um buffer de amostras.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/vintage-theme",
        "utils"
      ],
      "files": [
        {
          "path": "registry/vintage/ui/vintage-oscilloscope.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "audio",
        "canvas"
      ],
      "meta": {
        "uso": {
          "quando": "Desenhar forma de onda ao vivo a partir de um buffer de áudio, em synth ou analisador",
          "evite": "Áudio gravado com play e busca: voice-note; série de dados no tempo, streamgraph"
        }
      }
    },
    {
      "name": "marquee",
      "type": "registry:ui",
      "title": "Marquee",
      "description": "Faixa infinita em GSAP com três modos de scroll: empurrar o ritmo, virar esteira do scroll ou amarrar a posição à rolagem.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "dependencies": [
        "gsap"
      ],
      "files": [
        {
          "path": "registry/visant/ui/marquee.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@media (prefers-reduced-motion: reduce)": {
          ".marquee-track": {
            "transform": "none",
            "flex-wrap": "wrap",
            "width": "auto"
          },
          ".marquee-track > [aria-hidden=\"true\"]": {
            "display": "none"
          }
        }
      },
      "categories": [
        "conteudo",
        "faixa",
        "loop",
        "scroll",
        "gsap",
        "vitrine"
      ],
      "meta": {
        "uso": {
          "quando": "Faixa infinita de texto ou itens numa landing, com ritmo empurrado ou amarrado ao scroll",
          "evite": "Faixa de logos de clientes: use logo-wall, que já normaliza tamanho e cor"
        }
      }
    },
    {
      "name": "logo-wall",
      "type": "registry:ui",
      "title": "Logo Wall",
      "description": "A faixa de \"confiam na gente\" com os logos normalizados: altura óptica por item, teto de largura pro wordmark comprido e dessaturação em repouso que vira cor no hover.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/marquee.json",
        "@visant/marquee"
      ],
      "files": [
        {
          "path": "registry/visant/ui/logo-wall.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "logos",
        "clientes",
        "prova-social",
        "faixa",
        "marquee",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Seção de clientes ou parceiros numa landing, com logos de proporções diferentes normalizados",
          "evite": "Texto ou itens que não são logo: marquee; prova social com citação, testimonial-wall"
        }
      }
    },
    {
      "name": "rail",
      "type": "registry:ui",
      "title": "Rail",
      "description": "Trilho horizontal com snap: anda por arrasto, Shift + roda, setas e teclado. As setas somem nas pontas.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/rail.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "carrossel",
        "snap"
      ],
      "meta": {
        "uso": {
          "quando": "Trilho horizontal de cards ou produtos com snap, arrasto e teclado, em loja ou catálogo",
          "evite": "Vídeos verticais: reels-rail; capas em perspectiva, cover-flow; fotos em mosaico, masonry-gallery"
        }
      }
    },
    {
      "name": "reels-rail",
      "type": "registry:ui",
      "title": "Reels Rail",
      "description": "O trilho de vídeo vertical: cartões 9:16 com encaixe, tocando o do meio ou o que está sob o cursor. Som opcional, um card por vez, e fora da tela pausa tudo.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/rail.json",
        "@visant/rail"
      ],
      "files": [
        {
          "path": "registry/visant/ui/reels-rail.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "lucide-react"
      ],
      "categories": [
        "conteudo",
        "video",
        "reels",
        "shorts",
        "vertical",
        "carrossel",
        "trilho"
      ],
      "meta": {
        "uso": {
          "quando": "Trilho de vídeos 9:16 em landing ou loja, tocando um por vez como reels",
          "evite": "Cards estáticos ou produtos: use rail; vídeo de abertura em tela cheia, fog-hero"
        }
      }
    },
    {
      "name": "plate",
      "type": "registry:ui",
      "title": "Plate",
      "description": "A placa onde a foto de catálogo senta. Resolve o recorte branco sobre fundo colorido.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/plate.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "produto",
        "foto"
      ],
      "meta": {
        "uso": {
          "quando": "Assentar foto de produto recortada sobre branco num fundo colorido de loja, sem o retângulo branco",
          "evite": "Foto com fundo próprio ou editorial: photo-frame; item sem foto nenhuma, cover-art"
        }
      }
    },
    {
      "name": "chip",
      "type": "registry:ui",
      "title": "Chip",
      "description": "Pastilha de filtro com contagem. A faceta sem resultado apaga em vez de mostrar zero. Com onRemove vira o chip do filtro já aplicado, sem aria-pressed.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/chip.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "filtro",
        "loja"
      ],
      "meta": {
        "uso": {
          "quando": "Filtro de loja ou catálogo com contagem por faceta, apagando a que não tem resultado",
          "evite": "Escolha única entre poucas opções: segmented-control; tag só de leitura, badge do tema"
        }
      }
    },
    {
      "name": "sticky-filterbar",
      "type": "registry:ui",
      "title": "Sticky Filterbar",
      "description": "Barra de filtro que gruda abaixo do cabeçalho sem medir altura na mão e sem pular no scroll.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/sticky-filterbar.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "filtro",
        "scroll"
      ],
      "meta": {
        "uso": {
          "quando": "Barra de filtros que gruda sob o cabeçalho numa listagem longa de loja ou catálogo",
          "evite": "Navegação principal do app: side-nav; poucos filtros no topo de página curta, chip sem grudar"
        }
      }
    },
    {
      "name": "store-status",
      "type": "registry:ui",
      "title": "Store Status",
      "description": "Aberto/fechado calculado no fuso da loja, não no do visitante. Quem está do outro lado do mundo vê a resposta certa.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/store-status.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "loja",
        "fuso"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar aberto ou fechado de loja física calculado no fuso dela, em site de varejo ou restaurante",
          "evite": "Status de processo ou sistema: status-ticker; contagem até um horário, countdown"
        }
      }
    },
    {
      "name": "measure-picker",
      "type": "registry:ui",
      "title": "Measure Picker",
      "description": "Escolher por medida e receber a recomendação. A faixa traduz o número em produto.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/measure-picker.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".measure-range::-webkit-slider-runnable-track": {
            "height": "4px",
            "background": "var(--foreground)",
            "border-radius": "999px"
          },
          ".measure-range::-webkit-slider-thumb": {
            "-webkit-appearance": "none",
            "appearance": "none",
            "width": "46px",
            "height": "46px",
            "margin-top": "-21px",
            "border-radius": "999px",
            "border": "3px solid var(--foreground)",
            "background": "var(--background)",
            "box-shadow": "3px 3px 0 0 var(--foreground)",
            "transition": "transform var(--dur-press,120ms) var(--ease-out,ease)"
          },
          ".measure-range:active::-webkit-slider-thumb": {
            "transform": "scale(0.94)",
            "box-shadow": "0 0 0 0 var(--foreground)"
          },
          ".measure-range::-moz-range-track": {
            "height": "4px",
            "background": "var(--foreground)",
            "border-radius": "999px"
          },
          ".measure-range::-moz-range-thumb": {
            "width": "46px",
            "height": "46px",
            "border-radius": "999px",
            "border": "3px solid var(--foreground)",
            "background": "var(--background)"
          }
        }
      },
      "categories": [
        "controles",
        "slider",
        "recomendacao"
      ],
      "meta": {
        "uso": {
          "quando": "Loja que recomenda tamanho ou modelo a partir de uma medida que o cliente sabe, como a altura",
          "evite": "Valor livre sem recomendação: elastic-slider; projeção de ROI com premissa, sim-slider"
        }
      }
    },
    {
      "name": "motion",
      "type": "registry:lib",
      "title": "Motion Tokens",
      "description": "Curvas e durações da casa em JS, espelho de --ease-* e --dur-*: Motion, GSAP e Web Animations API importam daqui em vez de escrever o número na peça.",
      "files": [
        {
          "path": "registry/visant/lib/motion.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "tokens",
        "motion",
        "easing",
        "duracao"
      ]
    },
    {
      "name": "motion-layer",
      "type": "registry:lib",
      "title": "Motion Layer",
      "description": "O ciclo de scroll do editor Shopify em GSAP/ScrollTrigger, com limpeza de instância.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "files": [
        {
          "path": "registry/visant/lib/motion-layer.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "gsap",
        "scroll"
      ],
      "meta": {
        "uso": {
          "quando": "Ligar reveal, parallax e magnético por data-attribute em tema Shopify ou página montada em builder",
          "evite": "App React com componentes: use fold-motion, line-reveal e magnetic-cta direto, sem camada global"
        }
      }
    },
    {
      "name": "kanban",
      "type": "registry:block",
      "title": "Kanban",
      "description": "Quadro de tarefas por etapa: arraste o cartão de uma coluna para outra. No celular as colunas empilham.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "dependencies": [
        "@dnd-kit/core",
        "@dnd-kit/sortable",
        "@dnd-kit/utilities",
        "@air/react-drag-to-select",
        "framer-motion",
        "motion"
      ],
      "files": [
        {
          "path": "registry/visant/blocks/kanban/Kanban.tsx",
          "type": "registry:component",
          "target": "~/components/kanban/Kanban.tsx"
        },
        {
          "path": "registry/visant/blocks/kanban/KanbanColumn.tsx",
          "type": "registry:component",
          "target": "~/components/kanban/KanbanColumn.tsx"
        },
        {
          "path": "registry/visant/blocks/kanban/KanbanCard.tsx",
          "type": "registry:component",
          "target": "~/components/kanban/KanbanCard.tsx"
        },
        {
          "path": "registry/visant/blocks/kanban/types.ts",
          "type": "registry:component",
          "target": "~/components/kanban/types.ts"
        },
        {
          "path": "registry/visant/blocks/kanban/index.ts",
          "type": "registry:component",
          "target": "~/components/kanban/index.ts"
        },
        {
          "path": "registry/visant/blocks/kanban/kanban.css",
          "type": "registry:file",
          "target": "~/styles/kanban.css"
        }
      ],
      "categories": [
        "conteudo",
        "board",
        "dnd",
        "selecao"
      ],
      "meta": {
        "uso": {
          "quando": "Board de tarefas ou pipeline com arrastar entre colunas e multi-seleção, em ferramenta interna",
          "evite": "Lista densa pra ordenar e editar: data-table; triagem rápida no celular, swipe-actions"
        }
      }
    },
    {
      "name": "data-table",
      "type": "registry:ui",
      "title": "Data Table",
      "description": "Tabela densa: ordenação, seleção, edição inline e menu de contexto, em qualquer app React. Sessão e URL ficam com você: canEdit libera a edição e onSortingChange avisa a ordenação. Quem já instalou precisa passar essas props.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "button",
        "checkbox",
        "context-menu",
        "input",
        "skeleton",
        "table",
        "@visant/inline-edit",
        "@visant/use-media-query"
      ],
      "files": [
        {
          "path": "registry/visant/ui/data-table.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "@tanstack/react-table@^8.21.3",
        "class-variance-authority",
        "lucide-react"
      ],
      "categories": [
        "conteudo",
        "tabela",
        "fila",
        "tanstack"
      ],
      "meta": {
        "uso": {
          "quando": "Tabela densa de admin ou dashboard com ordenação, seleção e edição inline",
          "evite": "Fluxo por etapas visível: kanban; lista curta sem ordenar nem editar, table"
        }
      }
    },
    {
      "name": "segmented-control",
      "type": "registry:ui",
      "title": "Segmented Control",
      "description": "Alternador de poucas opções. Substitui um select quando as opções cabem na tela.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/segmented-control.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "lucide-react"
      ],
      "categories": [
        "controles",
        "controle",
        "apple"
      ],
      "meta": {
        "uso": {
          "quando": "Alternar entre 2 a 5 opções que cabem na tela, como lista ou grade, ou o período de um gráfico",
          "evite": "Mensal e anual com desconto: billing-toggle; muitas opções, morph-select; liga e desliga, liquid-toggle"
        }
      }
    },
    {
      "name": "inline-edit",
      "type": "registry:ui",
      "title": "Inline Edit",
      "description": "Editar onde se lê. Enter salva, Esc cancela, o valor só troca depois que a promessa resolve.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/inline-edit.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "lucide-react"
      ],
      "categories": [
        "controles",
        "edicao",
        "formulario"
      ],
      "meta": {
        "uso": {
          "quando": "Editar nome ou campo curto onde ele aparece, em tabela, card ou cabeçalho de página",
          "evite": "Vários campos com validação: profile-form; número arrastável, scrub-input"
        }
      }
    },
    {
      "name": "auth-button",
      "type": "registry:ui",
      "title": "Auth Button",
      "description": "O canto da conta nos três estados. Enquanto a sessão não responde ele não escreve “Entrar”, e não muda de tamanho quando ela chega.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "avatar"
      ],
      "files": [
        {
          "path": "registry/visant/ui/auth-button.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "conta",
        "sessao",
        "menu"
      ],
      "meta": {
        "uso": {
          "quando": "Canto da conta no cabeçalho do app: entrar, carregando e avatar com menu, sem pular de tamanho",
          "evite": "Tela de cadastro ou edição dos dados da conta: profile-form"
        }
      }
    },
    {
      "name": "profile-form",
      "type": "registry:ui",
      "title": "Profile Form",
      "description": "Editar o perfil com foto, nome e e-mail verificado. Quando não dá pra salvar, o motivo aparece no campo, não num toast.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "avatar"
      ],
      "files": [
        {
          "path": "registry/visant/ui/profile-form.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "conta",
        "formulario",
        "validacao"
      ],
      "meta": {
        "uso": {
          "quando": "Página de configurações da conta com foto, nome e e-mail verificado, erro no próprio campo",
          "evite": "Editar um campo solto no lugar: inline-edit; só o acesso à conta no cabeçalho, auth-button"
        }
      }
    },
    {
      "name": "timeline",
      "type": "registry:ui",
      "title": "Timeline",
      "description": "Linha do tempo com progresso amarrado ao scroll.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/timeline.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "framer-motion"
      ],
      "categories": [
        "conteudo",
        "scroll",
        "narrativa"
      ],
      "meta": {
        "uso": {
          "quando": "Changelog, história da empresa ou processo longo com progresso amarrado ao scroll",
          "evite": "Poucos passos de como funciona: step-cards; arte presa avançando por passos, pinned-scene"
        }
      }
    },
    {
      "name": "assignee-stack",
      "type": "registry:ui",
      "title": "Assignee Stack",
      "description": "Pilha de responsáveis com excedente contado. Iniciais quando não há avatar.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "avatar"
      ],
      "files": [
        {
          "path": "registry/visant/ui/assignee-stack.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "avatar",
        "equipe"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar responsáveis de tarefa ou projeto em pilha de avatares com excedente contado",
          "evite": "Lista de pessoas com detalhe e ação: lista do tema; contagem de reações, reactions"
        }
      }
    },
    {
      "name": "repulsive-hover",
      "type": "registry:ui",
      "title": "Repulsive Hover",
      "description": "O elemento foge do cursor com mola. Gesto de hero, fora de formulário.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/repulsive-hover.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "framer-motion"
      ],
      "categories": [
        "efeitos",
        "hover",
        "mola"
      ],
      "meta": {
        "uso": {
          "quando": "Decoração viva de hero que foge do cursor, como selo ou peça de colagem",
          "evite": "Qualquer coisa clicável ou formulário; pra atrair o cursor pro botão, use magnetic-cta"
        }
      }
    },
    {
      "name": "smooth-scroll-provider",
      "type": "registry:lib",
      "title": "Smooth Scroll Provider",
      "description": "Lenis + GSAP num relógio só, com bail-out em prefers-reduced-motion. A instância sai por callback.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "lenis",
        "gsap"
      ],
      "files": [
        {
          "path": "registry/visant/lib/smooth-scroll-provider.tsx",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "lenis",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Landing ou editorial com rolagem suave Lenis sincronizada ao GSAP ScrollTrigger",
          "evite": "App de produto, dashboard ou formulário longo: deixe a rolagem nativa, scroll suave atrapalha ali"
        }
      }
    },
    {
      "name": "glitch-chars",
      "type": "registry:ui",
      "title": "Glitch Chars",
      "description": "Caracteres que trocam sozinhos, em cinco sotaques (símbolos, blocos, braille, binário, hex), ou decodificando até virar uma palavra.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glitch-chars.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "texto",
        "textura",
        "mono"
      ],
      "meta": {
        "uso": {
          "quando": "Textura de caracteres trocando ou palavra decodificando, em hero tech, terminal ou espera curta",
          "evite": "Título que precisa ser lido de primeira: line-reveal ou mist-text; rótulo trocando, text-morph"
        }
      }
    },
    {
      "name": "status-ticker",
      "type": "registry:ui",
      "title": "Status Ticker",
      "description": "O texto que segura a pessoa durante uma espera longa, em quatro desenhos: linha com cronômetro, barra que varre, etapas e pulso.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/glitch-chars.json",
        "@visant/glitch-chars",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/status-ticker.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "feedback",
        "espera",
        "ia",
        "estado"
      ],
      "meta": {
        "uso": {
          "quando": "Espera longa de IA ou processamento, segurando a pessoa com texto, etapas ou cronômetro",
          "evite": "Mover arquivo: paper-shuttle; layout carregando, skeleton-rail; espera curta ao lado do rótulo, working-glyph"
        }
      }
    },
    {
      "name": "turbulence-field",
      "type": "registry:ui",
      "title": "Turbulence Field",
      "description": "Ruído animado em SVG para dar vida a uma superfície parada.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/turbulence-field.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "efeitos",
        "ruido",
        "svg"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de névoa leve em tile de espera, inclusive vários na mesma grade, sem WebGL",
          "evite": "Fundo de hero que reage ao ponteiro: spring-dots ou um shader-*; malha parada, grid-dots"
        }
      }
    },
    {
      "name": "working-glyph",
      "type": "registry:ui",
      "title": "Working Glyph",
      "description": "Ícone que trabalha enquanto o sistema trabalha: picareta, martelo, engrenagem, pincel ou faísca, e o brilho corre só no traço.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/glitch-chars.json",
        "@visant/glitch-chars",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/working-glyph.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "feedback",
        "espera",
        "icone"
      ],
      "meta": {
        "uso": {
          "quando": "Ícone pequeno mostrando que algo trabalha, ao lado de rótulo ou botão, numa espera curta",
          "evite": "Espera longa que pede explicação: status-ticker; transferência de arquivo, paper-shuttle"
        }
      }
    },
    {
      "name": "paper-shuttle",
      "type": "registry:ui",
      "title": "Paper Shuttle",
      "description": "Progresso com narrativa de papel passando pela máquina.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/paper-shuttle.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "feedback",
        "progresso",
        "export"
      ],
      "meta": {
        "uso": {
          "quando": "Espera de operação que move dados: importar, exportar, converter ou sincronizar",
          "evite": "Espera de IA com etapas: status-ticker; conteúdo da tela carregando, skeleton-rail"
        }
      }
    },
    {
      "name": "masonry-gallery",
      "type": "registry:ui",
      "title": "Masonry Gallery",
      "description": "Mosaico por round-robin: anexar página nova não reordena o que já estava na tela.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/masonry-gallery.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "galeria",
        "grid"
      ],
      "meta": {
        "uso": {
          "quando": "Galeria de fotos de alturas diferentes com rolagem infinita, sem reordenar o que já carregou",
          "evite": "Abrir foto em tela cheia: photo-flip; trilho horizontal, rail; poucas capas em destaque, cover-flow"
        }
      }
    },
    {
      "name": "scrub-input",
      "type": "registry:ui",
      "title": "Scrub Input",
      "description": "Número que se arrasta na horizontal, como nos editores gráficos. Teclado continua funcionando.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/scrub-input.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "numero",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Campo numérico arrastável em editor ou ferramenta de design, como tamanho, opacidade ou ângulo",
          "evite": "Valor numa faixa visível pro público geral: elastic-slider ou slosh-slider"
        }
      }
    },
    {
      "name": "tempo-clock",
      "type": "registry:lib",
      "title": "Tempo Clock",
      "description": "Relógio de BPM sem interface: passo na divisão, envelope de bumbo, tap tempo e troca de BPM sem pular o compasso.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/lib/tempo-clock.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "bpm",
        "ritmo",
        "musica",
        "tempo",
        "vanilla"
      ],
      "meta": {
        "uso": {
          "quando": "Visual, animação ou sequenciador que precisa andar no tempo de uma música, inclusive em export quadro a quadro",
          "evite": "Sincronizar com áudio real tocando: aí a batida vem de um analisador de áudio, não de um relógio"
        }
      }
    },
    {
      "name": "fader",
      "type": "registry:lib",
      "title": "Fader",
      "description": "Slider de console em web component, sem framework: marca a cada 10%, tampa quadrada, arrastar o nome muda o valor e duplo clique volta pro padrão.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/lib/fader.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "controles",
        "slider",
        "vanilla",
        "web-component",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Coluna de parâmetros numa ferramenta (efeito, edição, áudio), em projeto vanilla ou React",
          "evite": "Valor pro público geral em landing: elastic-slider ou slosh-slider"
        }
      }
    },
    {
      "name": "tempo-bar",
      "type": "registry:lib",
      "title": "Tempo Bar",
      "description": "Controle de BPM em web component, sem framework: LED na batida, número que se arrasta, luzes de compasso, divisão e tap.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/tempo-clock"
      ],
      "files": [
        {
          "path": "registry/visant/lib/tempo-bar.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "controles",
        "bpm",
        "ritmo",
        "musica",
        "vanilla",
        "web-component"
      ],
      "meta": {
        "uso": {
          "quando": "Ferramenta ou visual de festa em que o tempo da música manda: VJ, gerador de efeito, sequenciador",
          "evite": "Player de música comum: o BPM ali é informação, não controle"
        }
      }
    },
    {
      "name": "grid-dots",
      "type": "registry:ui",
      "title": "Grid Dots",
      "description": "Malha de pontos de fundo, o papel milimetrado que dá profundidade sem competir.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/grid-dots.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "efeitos",
        "fundo",
        "grid"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo parado de malha de pontos que dá profundidade sem competir com o conteúdo",
          "evite": "Fundo que reage ao ponteiro: spring-dots; textura animada, turbulence-field ou shader-voronoi"
        }
      }
    },
    {
      "name": "drop-overlay",
      "type": "registry:ui",
      "title": "Drop Overlay",
      "description": "A camada que aparece quando um arquivo está sendo arrastado sobre a área.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/drop-overlay.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "lucide-react"
      ],
      "categories": [
        "feedback",
        "upload",
        "dnd"
      ],
      "meta": {
        "uso": {
          "quando": "Área de upload que mostra a camada de soltar quando um arquivo é arrastado por cima",
          "evite": "Upload só por botão, sem arrasto; a área vazia antes do primeiro upload, empty-state"
        }
      }
    },
    {
      "name": "brand-theme",
      "type": "registry:lib",
      "title": "Brand Theme Runtime",
      "description": "Provider e hook que aplicam em runtime o tema compilado de uma brand guideline. Uma folha de estilo só, trocada sem recarregar a página.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/lib/brand-theme.tsx",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "marca",
        "tokens",
        "runtime",
        "provider"
      ],
      "meta": {
        "uso": {
          "quando": "App que troca de marca em runtime, como multi-cliente ou white-label, aplicando o tema compilado",
          "evite": "Projeto de uma marca só: importe o CSS do tema da marca direto, sem provider"
        }
      }
    },
    {
      "name": "brand-selector",
      "type": "registry:ui",
      "title": "Brand Selector",
      "description": "Escolha uma marca e o produto inteiro veste: cor, fonte e logo. Passar o mouse pela lista já mostra como fica.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/brand-theme.json",
        "@visant/brand-theme"
      ],
      "dependencies": [
        "cmdk",
        "lucide-react"
      ],
      "files": [
        {
          "path": "registry/visant/ui/brand-selector.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "marca",
        "tema",
        "cmdk",
        "vault"
      ],
      "meta": {
        "uso": {
          "quando": "Ferramenta interna ou vitrine multi-marca em que a pessoa escolhe a marca e vê o tema aplicado",
          "evite": "Site de uma marca só; pra alternar claro e escuro, use eclipse-switch"
        }
      }
    },
    {
      "name": "section-intro",
      "type": "registry:ui",
      "title": "Section Intro",
      "description": "Abertura de dobra: rótulo, título grande e linha de contexto, com duas medidas de linha em vez de uma.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/section-intro.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "dobra",
        "titulo",
        "landing"
      ],
      "meta": {
        "uso": {
          "quando": "Abrir uma dobra de landing com rótulo, título grande e linha de contexto",
          "evite": "Título de hero animado: line-reveal ou mist-text; chamada com ação de conversão, cta-surface"
        }
      }
    },
    {
      "name": "cta-surface",
      "type": "registry:ui",
      "title": "CTA Surface",
      "description": "A superfície de conversão em três proporções (barra, painel, card). O botão herda o contraste do tom em vez de receber cor.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/cta-surface.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "cta",
        "conversao",
        "dobra"
      ],
      "meta": {
        "uso": {
          "quando": "Bloco de conversão no fim de dobra ou página: barra, painel ou card com a ação principal",
          "evite": "Só o botão ganhar presença: magnetic-cta; abertura de seção sem ação, section-intro"
        }
      }
    },
    {
      "name": "showcase-card",
      "type": "registry:ui",
      "title": "Showcase Card",
      "description": "Card de serviço: mídia com selo de seta, título que cobre o card inteiro e a lista do que está incluso como texto, não como filtro.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/showcase-card.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "servico",
        "card",
        "vitrine"
      ],
      "meta": {
        "uso": {
          "quando": "Card de serviço ou pacote com mídia, título clicável e lista do que está incluso, em site de agência",
          "evite": "Produto com cara de objeto: spine-card; card que abre detalhe no lugar, expandable-card"
        }
      }
    },
    {
      "name": "step-cards",
      "type": "registry:block",
      "title": "Step Cards",
      "description": "Como funciona, em passos numerados. Sai como lista ordenada no HTML, e a arte de cada passo entra por slot.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/blocks/step-cards/StepCards.tsx",
          "type": "registry:component",
          "target": "~/components/step-cards/StepCards.tsx"
        },
        {
          "path": "registry/visant/blocks/step-cards/index.ts",
          "type": "registry:component",
          "target": "~/components/step-cards/index.ts"
        }
      ],
      "categories": [
        "conteudo",
        "passos",
        "como-funciona",
        "onboarding"
      ],
      "meta": {
        "uso": {
          "quando": "Seção de como funciona em passos numerados com arte por passo, em landing ou onboarding",
          "evite": "História longa ou changelog: timeline; passos com a arte presa no scroll, pinned-scene"
        }
      }
    },
    {
      "name": "testimonial-wall",
      "type": "registry:block",
      "title": "Testimonial Wall",
      "description": "Parede de prova social com tipos misturados: citação, número, retrato e depoimento em vídeo na mesma malha, em colunas ou em grade que ocupa a altura, com faixa de fechamento.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/blocks/testimonial-wall/TestimonialWall.tsx",
          "type": "registry:component",
          "target": "~/components/testimonial-wall/TestimonialWall.tsx"
        },
        {
          "path": "registry/visant/blocks/testimonial-wall/index.ts",
          "type": "registry:component",
          "target": "~/components/testimonial-wall/index.ts"
        }
      ],
      "css": {
        ".no-hover": {
          "opacity": "0",
          "transition": "opacity var(--dur-fast, 160ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1))"
        },
        ".group:hover .no-hover, .no-hover:focus-within, .no-hover:has(:focus-visible)": {
          "opacity": "1"
        },
        "@media (pointer: coarse)": {
          ".no-hover": {
            "opacity": "1"
          }
        }
      },
      "categories": [
        "conteudo",
        "depoimento",
        "prova-social",
        "masonry"
      ],
      "meta": {
        "uso": {
          "quando": "Parede de prova social com citação, número, retrato e vídeo misturados numa landing",
          "evite": "Um depoimento forte só: quote-block; logos de clientes, logo-wall"
        }
      }
    },
    {
      "name": "quote-block",
      "type": "registry:ui",
      "title": "Quote Block",
      "description": "O depoimento único, em tamanho de dobra: a citação vem primeiro e em corpo de manchete, a atribuição entra depois como assinatura.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/quote-block.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "depoimento",
        "prova-social",
        "citacao",
        "cliente",
        "retrato"
      ],
      "meta": {
        "uso": {
          "quando": "Um depoimento só em tamanho de dobra, citação em corpo de manchete e assinatura depois",
          "evite": "Vários depoimentos de tipos diferentes: testimonial-wall; pilha arrastável, card-stack"
        }
      }
    },
    {
      "name": "erase-field",
      "type": "registry:ui",
      "title": "Erase Field",
      "description": "Fundo em canvas que a mão raspa pra revelar a luz por baixo, com acabamento líquido, poeira que volta em deriva e passeio ocioso pra quem não mexe o ponteiro.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/erase-field.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "fundo",
        "canvas",
        "ponteiro",
        "cta",
        "revelar",
        "raspar"
      ],
      "meta": {
        "uso": {
          "quando": "Hero ou CTA com fundo em canvas que a pessoa raspa pra revelar a luz, convidando a mexer",
          "evite": "Malha que só reage ao ponteiro: spring-dots; fundo calmo atrás de texto longo, grid-dots"
        }
      }
    },
    {
      "name": "spring-dots",
      "type": "registry:ui",
      "title": "Spring Dots",
      "description": "Malha de pontos com mola: o ponteiro empurra, o atrito segura, e quem sai de casa acende na cor da marca.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/spring-dots.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "fundo",
        "canvas",
        "ponteiro",
        "fisica",
        "mola"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero com malha de pontos que o ponteiro empurra e acende na cor da marca",
          "evite": "Fundo parado: grid-dots; revelar raspando, erase-field; textura mais densa em WebGL, shader-voronoi"
        }
      }
    },
    {
      "name": "sfx-bus",
      "type": "registry:lib",
      "title": "SFX Bus",
      "description": "Cliques de objeto analógico em WebAudio puro, sem arquivo: botão de câmera, dente de knob, alavanca e agulha pousando, com throttle, contexto armado no primeiro gesto e mudo sob prefers-reduced-motion.",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/lib/sfx-bus.ts",
          "type": "registry:lib"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "fundacao",
        "som",
        "audio",
        "webaudio",
        "feedback",
        "tato",
        "clique",
        "analogico"
      ],
      "meta": {
        "uso": {
          "quando": "Dar som de clique analógico a botões, knobs e alavancas sem arquivo de áudio, em site com tato",
          "evite": "Produto de uso diário ou ambiente de trabalho: sem som; e nunca sem sfx-toggle pra desligar"
        }
      }
    },
    {
      "name": "sfx-toggle",
      "type": "registry:ui",
      "title": "SFX Toggle",
      "description": "Liga e desliga o som da casa em um ícone só: as ondas recolhem pro alto-falante, e o estado nulo antes da hidratação fica desenhado em vez de chutado.",
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/sfx-toggle.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".sfx-toggle .sfx-wave": {
            "transform-origin": "6px 12px",
            "transition": "opacity var(--dur-base, 240ms) var(--ease-out), transform var(--dur-base, 240ms) var(--ease-out)"
          },
          ".sfx-toggle[data-state=\"off\"] .sfx-wave": {
            "opacity": "0",
            "transform": "scale(0.4)"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".sfx-toggle .sfx-wave": {
            "transition": "none"
          }
        }
      },
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "som",
        "toggle",
        "preferencia",
        "acessibilidade"
      ],
      "meta": {
        "uso": {
          "quando": "Botão de ligar e desligar o som da interface, obrigatório quando o site usa sfx-bus",
          "evite": "Site sem som de interface; mute de vídeo ou música fica no controle do próprio player"
        }
      }
    },
    {
      "name": "count-up",
      "type": "registry:ui",
      "title": "Count Up",
      "description": "O número que se apura em vez de aparecer pronto: lê o valor final do próprio texto, trava a largura antes do primeiro quadro e não anima o que não dá pra parsear.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/count-up.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "numero",
        "contagem",
        "prova",
        "estatistica",
        "animar"
      ],
      "meta": {
        "uso": {
          "quando": "Estatística de landing que apura até o valor ao entrar na tela, como 120 projetos entregues",
          "evite": "Número que muda ao vivo: slot-text; contagem até data, countdown; número com régua, measure-bar"
        }
      }
    },
    {
      "name": "use-pointer-parallax",
      "type": "registry:hook",
      "title": "usePointerParallax",
      "description": "Escreve --px e --py uma vez por quadro e deixa o CSS decidir a profundidade de cada objeto. Só em ponteiro fino, volta ao repouso ao sair da janela.",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-pointer-parallax.ts",
          "type": "registry:hook",
          "target": "@hooks/use-pointer-parallax.ts"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "fundacao",
        "paralaxe",
        "ponteiro",
        "profundidade",
        "colagem",
        "hero"
      ],
      "meta": {
        "uso": {
          "quando": "Hero de colagem em que várias camadas se movem com o ponteiro, profundidade decidida no CSS",
          "evite": "Luz por card numa grade: gleam; um card que inclina sozinho, tilt-card"
        }
      }
    },
    {
      "name": "fold-motion",
      "type": "registry:lib",
      "title": "Fold Motion",
      "description": "Hierarquia de entradas por dobra: rise, drift, mask, settle, climax, invert e mist em vez de trinta entradas iguais. O esconderijo é aplicado pelo componente, nunca por CSS estático.",
      "dependencies": [
        "react"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/lib/fold-motion.tsx",
          "type": "registry:lib"
        }
      ],
      "css": {
        "@layer components": {
          ".visant-fold[data-armed]": {
            "opacity": "0",
            "transform": "translateY(14px)",
            "transition": "opacity var(--dur-slow, 700ms) var(--ease-out), transform var(--dur-slow, 700ms) var(--ease-out)"
          },
          ".visant-fold[data-armed][data-in]": {
            "opacity": "1",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"drift-l\"][data-armed], .visant-fold[data-fold=\"drift-r\"][data-armed]": {
            "opacity": "1",
            "transform": "none",
            "overflow-x": "clip"
          },
          ".visant-fold[data-fold=\"drift-l\"][data-armed] > [data-fold-part], .visant-fold[data-fold=\"drift-r\"][data-armed] > [data-fold-part]": {
            "opacity": "0",
            "transition": "opacity var(--dur-slow, 700ms) var(--ease-out), transform var(--dur-slow, 700ms) var(--ease-drawer)"
          },
          ".visant-fold[data-fold=\"drift-l\"][data-armed] > [data-fold-part]": {
            "transform": "translateX(-22px)"
          },
          ".visant-fold[data-fold=\"drift-r\"][data-armed] > [data-fold-part]": {
            "transform": "translateX(22px)"
          },
          ".visant-fold[data-fold=\"drift-l\"][data-armed][data-in] > [data-fold-part], .visant-fold[data-fold=\"drift-r\"][data-armed][data-in] > [data-fold-part]": {
            "opacity": "1",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"mask\"][data-armed]": {
            "opacity": "1",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"mask\"][data-armed] :is(h1, h2, h3)": {
            "clip-path": "inset(0 0 100% 0)",
            "transform": "translateY(0.24em)",
            "transition": "clip-path var(--dur-slow, 700ms) var(--ease-out), transform var(--dur-slow, 700ms) var(--ease-out)"
          },
          ".visant-fold[data-fold=\"mask\"][data-armed][data-in] :is(h1, h2, h3)": {
            "clip-path": "inset(0 0 -0.2em 0)",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"settle\"][data-armed]": {
            "opacity": "1",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"settle\"][data-armed] > *": {
            "opacity": "0",
            "transform": "scale(1.03)",
            "transition": "opacity var(--dur-slow, 700ms) var(--ease-out), transform var(--dur-slow, 700ms) var(--ease-out)"
          },
          ".visant-fold[data-fold=\"settle\"][data-armed][data-in] > *": {
            "opacity": "1",
            "transform": "none"
          },
          ".visant-fold[data-fold=\"climax\"][data-armed]": {
            "transform": "translateY(8px) scale(0.994)",
            "transition-duration": "var(--dur-climax, 1100ms)"
          },
          ".visant-fold[data-fold=\"invert\"][data-armed]": {
            "opacity": "1",
            "transform": "none",
            "background": "var(--background)",
            "color": "var(--foreground)",
            "transition": "background-color var(--dur-climax, 1100ms) var(--ease-in-out), color var(--dur-climax, 1100ms) var(--ease-in-out)"
          },
          ".visant-fold[data-fold=\"invert\"][data-armed][data-in]": {
            "background": "var(--foreground)",
            "color": "var(--background)"
          },
          ".visant-fold[data-fold=\"mist\"][data-armed]": {
            "opacity": "0",
            "filter": "blur(12px)",
            "transform": "translateY(12px)",
            "transition": "opacity var(--dur-slow, 700ms) var(--ease-out), filter var(--dur-slow, 700ms) var(--ease-out), transform var(--dur-slow, 700ms) var(--ease-out)"
          },
          ".visant-fold[data-fold=\"mist\"][data-armed][data-in]": {
            "opacity": "1",
            "filter": "none",
            "transform": "none"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".visant-fold[data-armed], .visant-fold[data-armed] > [data-fold-part], .visant-fold[data-armed] > *": {
            "opacity": "1",
            "transform": "none",
            "transition": "none"
          },
          ".visant-fold[data-armed] :is(h1, h2, h3)": {
            "clip-path": "none",
            "transform": "none",
            "transition": "none"
          },
          ".visant-fold[data-fold=\"mist\"][data-armed]": {
            "opacity": "1",
            "filter": "none",
            "transform": "none",
            "transition": "none"
          }
        }
      },
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "fundacao",
        "scroll",
        "entrada",
        "reveal",
        "dobra",
        "hierarquia"
      ],
      "meta": {
        "uso": {
          "quando": "Dar hierarquia às entradas de uma landing, cada dobra com seu tipo de entrada ao rolar",
          "evite": "Só um título: line-reveal ou mist-text; app ou dashboard não pede entrada por scroll"
        }
      }
    },
    {
      "name": "measure-bar",
      "type": "registry:ui",
      "title": "Measure Bar",
      "description": "Nenhum número sem régua: valor, qualificador, evidência e rótulo nessa ordem. Sem denominador a barra não desenha, e o estado desconhecido fica tracejado em vez de zerado.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/measure-bar.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".measure-bar-fill": {
            "width": "100%",
            "transform": "scaleX(var(--v, 1))",
            "transition": "transform var(--dur-slow, 700ms) var(--ease-out)"
          },
          ".visant-fold[data-armed]:not([data-in]) .measure-bar-fill": {
            "transform": "scaleX(0)"
          },
          ".measure-bar-track[data-state=\"unknown\"]": {
            "background": "repeating-linear-gradient(90deg, var(--border) 0 6px, transparent 6px 12px)"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".measure-bar-fill": {
            "transition": "none"
          }
        }
      },
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "numero",
        "regua",
        "evidencia",
        "prova",
        "metrica"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar métrica com régua, qualificador e evidência, em landing de prova ou relatório",
          "evite": "Medidor de cota em arco: gauge; número que só apura ao entrar, count-up"
        }
      }
    },
    {
      "name": "spine-card",
      "type": "registry:ui",
      "title": "Spine Card",
      "description": "O retângulo que lê como objeto: lombada de luz na borda, tombo apoiado na base que endireita no hover, e capa em duotone que só ganha cor onde a atenção está.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/spine-card.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".spine-card": {
            "--tilt": "-5deg",
            "--lift": "0px",
            "transform": "rotate(var(--tilt)) translateY(var(--lift))",
            "transform-origin": "bottom center",
            "transition": "transform var(--dur-slow, 700ms) var(--ease-out), border-color var(--dur-slow, 700ms) ease"
          },
          ".spine-card::before": {
            "content": "\"\"",
            "position": "absolute",
            "z-index": "1",
            "top": "0",
            "bottom": "0",
            "left": "0",
            "width": "12px",
            "border-right": "1px solid var(--border)",
            "background": "linear-gradient(90deg, color-mix(in oklch, var(--foreground) 7%, transparent), transparent)",
            "pointer-events": "none"
          },
          ".spine-card:hover, .spine-card:focus-visible": {
            "--tilt": "0deg",
            "--lift": "-10px"
          },
          ".spine-card-cover :is(img, svg, video)": {
            "display": "block",
            "width": "100%",
            "height": "auto",
            "object-fit": "cover",
            "filter": "grayscale(1) sepia(0.5) hue-rotate(155deg) saturate(1.3) brightness(0.92) contrast(1.06)",
            "transition": "filter var(--dur-slow, 700ms) ease"
          },
          ".spine-card:hover .spine-card-cover :is(img, svg, video), .spine-card:focus-visible .spine-card-cover :is(img, svg, video), .spine-card[data-full-color] .spine-card-cover :is(img, svg, video)": {
            "filter": "none"
          }
        },
        "@media (hover: none)": {
          ".spine-card-cover :is(img, svg, video)": {
            "filter": "none"
          },
          ".spine-card": {
            "--tilt": "0deg"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".spine-card": {
            "transition": "none"
          }
        }
      },
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "card",
        "livro",
        "estante",
        "produto",
        "lombada"
      ],
      "meta": {
        "uso": {
          "quando": "Card de livro, disco ou produto que lê como objeto na estante, com lombada e tombo no hover",
          "evite": "Livro em 3D de verdade: book-3d; card de serviço com lista, showcase-card"
        }
      }
    },
    {
      "name": "cover-art",
      "type": "registry:ui",
      "title": "Cover Art",
      "description": "Capa determinística em CSS pra item sem arte: três famílias (livro, app, placa), monograma, e rampa tonal derivada da marca por color-mix. Zero byte de imagem, SSR igual ao cliente.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/lib/cover-look.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/ui/cover-art.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "capa",
        "placeholder",
        "catalogo",
        "deterministico",
        "sem-imagem"
      ],
      "meta": {
        "uso": {
          "quando": "Gerar capa de livro, app ou placa para item sem imagem, a partir do nome e da cor da marca",
          "evite": "Item com foto real: plate ou photo-frame; imagem ainda carregando, skeleton-rail"
        }
      }
    },
    {
      "name": "empty-state",
      "type": "registry:ui",
      "title": "Empty State",
      "description": "O estado vazio canônico: arte por slot, frase do que vai aparecer ali e no máximo uma ação. Com ou sem caixa.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/empty-state.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "vazio",
        "empty",
        "onboarding",
        "primeiro-uso"
      ],
      "meta": {
        "uso": {
          "quando": "Lista, painel ou busca sem conteúdo ainda: frase do que vai aparecer ali e no máximo uma ação",
          "evite": "Conteúdo carregando: skeleton-rail; vazio com personalidade, ponha eye-tracker no slot da arte"
        }
      }
    },
    {
      "name": "skeleton-rail",
      "type": "registry:ui",
      "title": "Skeleton Rail",
      "description": "Esqueletos com as medidas do que substituem (trilho, card, lista, texto, mídia), em quatro movimentos: pulse, shimmer, wave ou parado.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/skeleton-rail.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "skeleton",
        "carregando",
        "trilho",
        "espera"
      ],
      "meta": {
        "uso": {
          "quando": "Placeholder com a medida exata de cards, listas ou mídia enquanto o conteúdo carrega",
          "evite": "Lista que voltou vazia: empty-state; operação longa em segundo plano, status-ticker"
        }
      }
    },
    {
      "name": "skeleton-medido",
      "type": "registry:ui",
      "title": "Skeleton Medido",
      "description": "Esqueleto medido do próprio conteúdo, sem escrever as medidas à mão. Experimental: usa o Skullet 0.0.x.",
      "dependencies": [
        "skullet@0.0.3"
      ],
      "files": [
        {
          "path": "registry/visant/ui/skeleton-medido.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "skeleton",
        "carregando",
        "espera",
        "experimental"
      ],
      "meta": {
        "uso": {
          "quando": "Conteúdo que muda de forma e cujo esqueleto não vale manter à mão",
          "evite": "Projeto que não aceita dependência 0.0.x: skeleton-rail"
        }
      }
    },
    {
      "name": "use-local-search",
      "type": "registry:hook",
      "title": "useLocalSearch",
      "description": "Busca em memória tolerante a acento: índice montado uma vez por lista, todos os termos batendo em qualquer ordem, e termo vazio devolvendo a lista inteira.",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-local-search.ts",
          "type": "registry:hook",
          "target": "@hooks/use-local-search.ts"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "fundacao",
        "busca",
        "filtro",
        "acento",
        "catalogo"
      ],
      "meta": {
        "uso": {
          "quando": "Filtrar lista em memória tolerando acento e termos em qualquer ordem, como catálogo ou menu",
          "evite": "Base grande ou paginada no servidor: busque na API; o campo visual da busca, expanding-search"
        }
      }
    },
    {
      "name": "line-reveal",
      "type": "registry:ui",
      "title": "Line Reveal",
      "description": "O título que sobe de dentro do próprio corte de linha: mede a quebra depois da fonte carregar, re-quebra ao redimensionar, e o esconderijo é aplicado por JS pra página nunca sumir sem script.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/line-reveal.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".line-reveal-line, .line-reveal-word": {
            "will-change": "transform"
          }
        }
      },
      "categories": [
        "texto",
        "titulo",
        "reveal",
        "linha",
        "split",
        "gsap",
        "heroi",
        "tipografia"
      ],
      "meta": {
        "uso": {
          "quando": "Título de hero ou dobra que sobe linha por linha de dentro do próprio corte",
          "evite": "Texto saindo do desfoque por palavra: mist-text; rótulo curto trocando, text-morph"
        }
      }
    },
    {
      "name": "gleam",
      "type": "registry:ui",
      "title": "Gleam",
      "description": "A superfície que sabe onde o cursor está: luz sob o ponteiro, borda acesa do lado da luz e inclinação de 5 graus. Quatro números por quadro no JS, o desenho inteiro no CSS. Nasce inclinado e aceso (rest).",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/gleam.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".gleam-stage": {
            "perspective": "900px"
          },
          ".gleam": {
            "position": "relative",
            "isolation": "isolate",
            "border-radius": "var(--r-surface, 16px)",
            "border": "1px solid var(--border)",
            "background": "var(--card)",
            "transform-style": "preserve-3d",
            "transform": "rotateX(calc(var(--rx, 0) * 1deg)) rotateY(calc(var(--ry, 0) * 1deg))",
            "transition": "transform 120ms var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), box-shadow var(--dur-base, 200ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1))"
          },
          ".gleam:not([data-lit=\"1\"])": {
            "transition-duration": "320ms"
          },
          ".gleam:focus-visible": {
            "outline": "none",
            "box-shadow": "var(--focus, 0 0 0 2px var(--ring))"
          },
          ".gleam-light": {
            "position": "absolute",
            "inset": "0",
            "border-radius": "inherit",
            "pointer-events": "none",
            "z-index": "0",
            "opacity": "0",
            "transition": "opacity var(--dur-base, 200ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1))",
            "background": "radial-gradient(circle at calc(var(--gx, 0.5) * 100%) calc(var(--gy, 0.5) * 100%), color-mix(in oklab, var(--brand) 26%, transparent), transparent 55%)"
          },
          ".gleam[data-lit=\"1\"] .gleam-light": {
            "opacity": "var(--glow, 1)"
          },
          ".gleam-edge": {
            "position": "absolute",
            "inset": "0",
            "border-radius": "inherit",
            "pointer-events": "none",
            "z-index": "1",
            "padding": "1px",
            "background": "radial-gradient(circle at calc(var(--gx, 0.5) * 100%) calc(var(--gy, 0.5) * 100%), color-mix(in oklab, var(--brand) 65%, transparent), transparent 45%)",
            "-webkit-mask": "linear-gradient(black 0 0) content-box, linear-gradient(black 0 0)",
            "mask": "linear-gradient(black 0 0) content-box, linear-gradient(black 0 0)",
            "-webkit-mask-composite": "xor",
            "mask-composite": "exclude",
            "opacity": "0",
            "transition": "opacity var(--dur-base, 200ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1))"
          },
          ".gleam[data-lit=\"1\"] .gleam-edge": {
            "opacity": "1"
          },
          ".gleam > :not(.gleam-light):not(.gleam-edge)": {
            "position": "relative",
            "z-index": "2"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".gleam": {
            "transform": "none",
            "transition": "none"
          }
        }
      },
      "categories": [
        "efeitos",
        "hover",
        "card",
        "ponteiro",
        "tilt",
        "luz",
        "spotlight",
        "magnetico"
      ],
      "meta": {
        "uso": {
          "quando": "Grade de cards em que cada um acende luz sob o cursor e inclina leve, em vitrine ou pricing",
          "evite": "Card único que inclina forte em 3D: tilt-card; profundidade da cena inteira, use-pointer-parallax"
        }
      }
    },
    {
      "name": "sim-slider",
      "type": "registry:ui",
      "title": "Sim Slider",
      "description": "A dobra que deixa o visitante fazer a conta: controle acessível, projeção derivada do próprio valor, curva sem transição (pra não discordar do número) e premissa obrigatória por escrito.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "slider",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/sim-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".sim-slider-line": {
            "fill": "none",
            "stroke": "var(--brand)",
            "stroke-width": "2",
            "stroke-linejoin": "round",
            "stroke-linecap": "round",
            "animation": "sim-slider-fade var(--dur-slow, 300ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both"
          },
          ".sim-slider-ceiling": {
            "stroke": "var(--border)",
            "stroke-width": "1",
            "stroke-dasharray": "3 4"
          },
          ".sim-slider-area": {
            "fill": "color-mix(in oklab, var(--brand) 14%, transparent)",
            "animation": "sim-slider-fade var(--dur-slow, 300ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) 400ms both"
          }
        },
        "@keyframes sim-slider-fade": {
          "from": {
            "opacity": "0"
          },
          "to": {
            "opacity": "1"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".sim-slider-line, .sim-slider-area": {
            "animation": "none"
          }
        }
      },
      "categories": [
        "controles",
        "simulador",
        "calculadora",
        "slider",
        "projecao",
        "roi",
        "curva",
        "premissa"
      ],
      "meta": {
        "uso": {
          "quando": "Simulador de ROI ou economia numa landing: o visitante move o valor e vê a projeção com premissa",
          "evite": "Escolher valor sem projeção: elastic-slider; recomendar produto por medida, measure-picker"
        }
      }
    },
    {
      "name": "magnetic-cta",
      "type": "registry:ui",
      "title": "Magnetic CTA",
      "description": "O botão principal que vem buscar o ponteiro: campo de atração com medida lida uma vez, rótulo com inércia própria e volta com mola. No toque e sob reduced-motion é um botão comum.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "dependencies": [
        "@radix-ui/react-slot"
      ],
      "files": [
        {
          "path": "registry/visant/ui/magnetic-cta.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        ".magnet-body": {
          "transition": "transform var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1)), scale var(--dur-fast, 140ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1)), background-color var(--dur-fast, 140ms) linear"
        },
        ".magnet-field[data-magnet=hold] .magnet-body": {
          "will-change": "transform"
        },
        ".magnet-field[data-magnet=rest] .magnet-body, .magnet-field[data-magnet=rest] .magnet-label": {
          "transition-duration": "620ms",
          "transition-timing-function": "cubic-bezier(0.22, 1.35, 0.36, 1)"
        },
        ".magnet-label": {
          "transform": "translate3d(calc(var(--mx, 0px) * var(--lag, 0.35) * -1), calc(var(--my, 0px) * var(--lag, 0.35) * -1), 0)",
          "transition": "transform var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1))"
        },
        ".magnet-sheen": {
          "background": "radial-gradient(130px 130px at var(--sx, 50%) var(--sy, 50%), color-mix(in oklab, var(--brand-foreground, var(--background)) 24%, transparent), transparent 72%)",
          "opacity": "0",
          "transition": "opacity var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1))"
        },
        ".magnet-field[data-magnet=hold] .magnet-sheen": {
          "opacity": "1"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".magnet-body, .magnet-label": {
            "transform": "none",
            "transition": "none"
          },
          ".magnet-sheen": {
            "display": "none"
          }
        },
        ".magnet-field[data-magnet=rest] .magnet-sheen": {
          "transition-duration": "var(--dur-fast, 140ms)"
        }
      },
      "categories": [
        "controles",
        "cta",
        "botao",
        "ima",
        "hover",
        "conversao"
      ],
      "meta": {
        "uso": {
          "quando": "Botão principal de landing que vem buscar o ponteiro, numa dobra de conversão com espaço em volta",
          "evite": "Botão em formulário ou lista densa: botão do tema; bloco completo de conversão, cta-surface"
        }
      }
    },
    {
      "name": "nav-drawer",
      "type": "registry:ui",
      "title": "Nav Drawer",
      "description": "O menu mobile feito uma vez direito, em dois desenhos: gaveta lateral ou página inteira brutalista com imagem. Foco preso, Escape, retorno do foco e trava de rolagem vindos do Radix Dialog.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "dependencies": [
        "@radix-ui/react-dialog"
      ],
      "files": [
        {
          "path": "registry/visant/ui/nav-drawer.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@keyframes nav-drawer-veil-in": {
          "from": {
            "opacity": "0"
          },
          "to": {
            "opacity": "1"
          }
        },
        "@keyframes nav-drawer-veil-out": {
          "from": {
            "opacity": "1"
          },
          "to": {
            "opacity": "0"
          }
        },
        "@keyframes nav-drawer-from-right": {
          "from": {
            "transform": "translate3d(100%, 0, 0)"
          },
          "to": {
            "transform": "translate3d(0, 0, 0)"
          }
        },
        "@keyframes nav-drawer-to-right": {
          "from": {
            "transform": "translate3d(0, 0, 0)"
          },
          "to": {
            "transform": "translate3d(100%, 0, 0)"
          }
        },
        "@keyframes nav-drawer-from-left": {
          "from": {
            "transform": "translate3d(-100%, 0, 0)"
          },
          "to": {
            "transform": "translate3d(0, 0, 0)"
          }
        },
        "@keyframes nav-drawer-to-left": {
          "from": {
            "transform": "translate3d(0, 0, 0)"
          },
          "to": {
            "transform": "translate3d(-100%, 0, 0)"
          }
        },
        "@keyframes nav-drawer-from-top": {
          "from": {
            "transform": "translate3d(0, -100%, 0)"
          },
          "to": {
            "transform": "translate3d(0, 0, 0)"
          }
        },
        "@keyframes nav-drawer-to-top": {
          "from": {
            "transform": "translate3d(0, 0, 0)"
          },
          "to": {
            "transform": "translate3d(0, -100%, 0)"
          }
        },
        "@keyframes nav-drawer-item-in": {
          "from": {
            "opacity": "0",
            "transform": "translate3d(0, 14px, 0)"
          },
          "to": {
            "opacity": "1",
            "transform": "translate3d(0, 0, 0)"
          }
        },
        "@keyframes nav-drawer-item-out": {
          "from": {
            "opacity": "1",
            "transform": "translate3d(0, 0, 0)"
          },
          "to": {
            "opacity": "0",
            "transform": "translate3d(0, 8px, 0)"
          }
        },
        ".nav-drawer-overlay[data-state=open]": {
          "animation": "nav-drawer-veil-in var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1)) both"
        },
        ".nav-drawer-overlay[data-state=closed]": {
          "animation": "nav-drawer-veil-out var(--dur-fast, 140ms) cubic-bezier(0.5, 0, 0.9, 0.4) both"
        },
        ".nav-drawer-panel[data-side=right][data-state=open]": {
          "animation": "nav-drawer-from-right var(--dur-slow, 420ms) var(--ease-drawer, cubic-bezier(0.32, 0.72, 0, 1)) both"
        },
        ".nav-drawer-panel[data-side=right][data-state=closed]": {
          "animation": "nav-drawer-to-right var(--dur-base, 240ms) cubic-bezier(0.5, 0, 0.9, 0.4) both"
        },
        ".nav-drawer-panel[data-side=left][data-state=open]": {
          "animation": "nav-drawer-from-left var(--dur-slow, 420ms) var(--ease-drawer, cubic-bezier(0.32, 0.72, 0, 1)) both"
        },
        ".nav-drawer-panel[data-side=left][data-state=closed]": {
          "animation": "nav-drawer-to-left var(--dur-base, 240ms) cubic-bezier(0.5, 0, 0.9, 0.4) both"
        },
        ".nav-drawer-panel[data-side=top][data-state=open]": {
          "animation": "nav-drawer-from-top var(--dur-slow, 420ms) var(--ease-drawer, cubic-bezier(0.32, 0.72, 0, 1)) both"
        },
        ".nav-drawer-panel[data-side=top][data-state=closed]": {
          "animation": "nav-drawer-to-top var(--dur-base, 240ms) cubic-bezier(0.5, 0, 0.9, 0.4) both"
        },
        ".nav-drawer-panel[data-state=open] .nav-drawer-list > li": {
          "animation": "nav-drawer-item-in 460ms var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1)) both",
          "animation-delay": "calc(120ms + var(--i, 0) * 45ms)"
        },
        ".nav-drawer-panel[data-state=closed] .nav-drawer-list > li": {
          "animation": "nav-drawer-item-out calc(var(--dur-base, 240ms) * 0.6) cubic-bezier(0.5, 0, 0.9, 0.4) both",
          "animation-delay": "calc(var(--io, 0) * var(--dur-base, 240ms) * 0.1)"
        },
        ".nav-drawer-rule": {
          "transform": "scaleX(0)",
          "transition": "transform var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1))"
        },
        ".nav-drawer-item:hover .nav-drawer-rule, .nav-drawer-item:focus-visible .nav-drawer-rule, .nav-drawer-item[data-active] .nav-drawer-rule": {
          "transform": "scaleX(1)"
        },
        ".nav-drawer-label": {
          "transition": "transform var(--dur-base, 240ms) var(--ease-out, cubic-bezier(0.22, 0.61, 0.36, 1))"
        },
        ".nav-drawer-item:hover .nav-drawer-label, .nav-drawer-item:focus-visible .nav-drawer-label": {
          "transform": "translate3d(6px, 0, 0)"
        },
        ".nav-drawer-burger .burger-bar": {
          "transition": "transform var(--dur-base, 240ms) var(--ease-drawer, cubic-bezier(0.32, 0.72, 0, 1))"
        },
        ".nav-drawer-burger[data-state=open] .burger-bar:first-child": {
          "transform": "translateY(4.25px) rotate(45deg)"
        },
        ".nav-drawer-burger[data-state=open] .burger-bar:last-child": {
          "transform": "translateY(-4.25px) rotate(-45deg)"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".nav-drawer-overlay, .nav-drawer-panel, .nav-drawer-panel[data-state=open] .nav-drawer-list > li, .nav-drawer-panel[data-state=closed] .nav-drawer-list > li": {
            "animation-duration": "1ms",
            "animation-delay": "0ms"
          },
          ".nav-drawer-rule, .nav-drawer-label, .nav-drawer-burger .burger-bar": {
            "transition": "none"
          }
        }
      },
      "categories": [
        "controles",
        "menu",
        "mobile",
        "drawer",
        "navegacao",
        "acessibilidade"
      ],
      "meta": {
        "uso": {
          "quando": "Menu mobile de site ou landing, em gaveta lateral ou página inteira com imagem",
          "evite": "Navegação lateral fixa de app no desktop: side-nav; atalhos de ícone, magnify-dock"
        }
      }
    },
    {
      "name": "side-nav",
      "type": "registry:ui",
      "title": "Side Nav",
      "description": "A navegação lateral de aplicação: colapsa por clique ou por ⌘/Ctrl+B, agrupa, marca a rota ativa e lembra o estado. O rótulo vira sr-only quando fecha, nunca some do DOM.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/side-nav.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "controles",
        "sidebar",
        "navegacao",
        "app",
        "colapsar",
        "atalho",
        "teclado"
      ],
      "meta": {
        "uso": {
          "quando": "Navegação lateral de app ou dashboard, colapsável por atalho e com a rota ativa marcada",
          "evite": "Menu de site no celular: nav-drawer; poucas ações num botão flutuante, orbit-menu"
        }
      }
    },
    {
      "name": "pinned-scene",
      "type": "registry:ui",
      "title": "Pinned Scene",
      "description": "A dobra que prende a arte e avança em passos. O pin é position:sticky, não ScrollTrigger.pin — o GSAP entra só pra relatar progresso em --p, --sp e --near, sem tocar no DOM.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "dependencies": [
        "gsap"
      ],
      "files": [
        {
          "path": "registry/visant/ui/pinned-scene.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "scroll",
        "sticky",
        "passos",
        "storytelling",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Dobra de storytelling que prende a arte e avança em passos enquanto o texto rola",
          "evite": "Passos sem prender a tela: step-cards; caminhada 3D na névoa, fog-garden"
        }
      }
    },
    {
      "name": "photo-frame",
      "type": "registry:ui",
      "title": "Photo Frame",
      "description": "A moldura que revela a foto: a máscara abre, a foto assenta mais devagar que a máscara, e opcionalmente deriva na rolagem. Proporção declarada pra não haver salto de layout, e mídia por slot.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/photo-frame.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".photo-frame": {
            "display": "block",
            "margin": "0"
          },
          ".photo-frame-window": {
            "position": "relative",
            "overflow": "hidden",
            "aspect-ratio": "var(--ratio, 4/5)",
            "border-radius": "var(--r-surface, 16px)",
            "background": "var(--muted)"
          },
          ".photo-frame-media": {
            "position": "absolute",
            "inset": "0"
          },
          ".photo-frame-caption": {
            "margin-top": "0.75rem",
            "font-size": "13px",
            "line-height": "1.5",
            "color": "var(--muted-foreground)"
          },
          ".photo-frame-media > *": {
            "width": "100%",
            "height": "100%",
            "display": "block"
          },
          ".photo-frame-media img, .photo-frame-media video": {
            "width": "100%",
            "height": "100%",
            "object-fit": "cover",
            "display": "block"
          }
        }
      },
      "categories": [
        "transicoes",
        "foto",
        "moldura",
        "imagem",
        "reveal",
        "paralaxe",
        "scroll",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Foto editorial ou de case que se revela por máscara ao entrar na tela, com proporção fixa",
          "evite": "Foto ao lado de texto alternando lados: photo-split; foto de produto recortada, plate"
        }
      }
    },
    {
      "name": "photo-split",
      "type": "registry:ui",
      "title": "Photo Split",
      "description": "A dobra alternada de foto e texto: a moldura revela a imagem, o texto entra deslizando da borda externa e o lado inverte a cada dobra sem ninguém escrever nada.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "registryDependencies": [
        "utils",
        "https://visant-ui.vercel.app/r/photo-frame.json",
        "https://visant-ui.vercel.app/r/section-intro.json",
        "https://visant-ui.vercel.app/r/fold-motion.json",
        "@visant/photo-frame",
        "@visant/section-intro",
        "@visant/fold-motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/photo-split.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "dobra",
        "secao",
        "foto",
        "texto",
        "alternado",
        "scroll",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Seções alternadas de foto e texto em landing ou case, invertendo o lado a cada dobra",
          "evite": "Foto sozinha com reveal: photo-frame; arte presa avançando em passos, pinned-scene"
        }
      }
    },
    {
      "name": "photo-flip",
      "type": "registry:ui",
      "title": "Photo Flip",
      "description": "A foto atravessa da grade para a tela cheia — mesmo nó do DOM, reparentado e animado por GSAP Flip com ease-in-out. A vaga segura a proporção pra grade não desabar, e o foco volta pra foto que abriu.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/photo-flip.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        ".photo-flip-stage .photo-flip-media img, .photo-flip-stage .photo-flip-media video": {
          "object-fit": "contain"
        },
        "@layer components": {
          ".photo-flip-grid": {
            "display": "grid",
            "grid-template-columns": "repeat(3, 1fr)",
            "gap": "0.75rem"
          },
          ".photo-flip-tile": {
            "position": "relative",
            "display": "block",
            "padding": "0",
            "border": "0",
            "background": "none",
            "cursor": "zoom-in",
            "border-radius": "var(--r-surface, 16px)"
          },
          ".photo-flip-tile:focus-visible": {
            "outline": "none",
            "box-shadow": "var(--focus, 0 0 0 2px var(--ring))"
          },
          ".photo-flip-slot": {
            "position": "relative",
            "display": "block",
            "aspect-ratio": "var(--ratio, 1)",
            "overflow": "hidden",
            "border-radius": "inherit",
            "background": "var(--muted)"
          },
          ".photo-flip-media": {
            "position": "absolute",
            "inset": "0",
            "display": "block"
          },
          ".photo-flip-overlay": {
            "position": "fixed",
            "inset": "0",
            "z-index": "60",
            "display": "grid",
            "place-items": "center",
            "padding": "clamp(1rem, 4vw, 4rem)",
            "background": "color-mix(in oklab, var(--background) 88%, transparent)",
            "backdrop-filter": "blur(6px)",
            "cursor": "zoom-out"
          },
          ".photo-flip-stage": {
            "position": "relative",
            "width": "min(92vw, 1100px)",
            "height": "min(84vh, 900px)"
          },
          ".photo-flip-close": {
            "position": "absolute",
            "top": "clamp(1rem, 3vw, 2rem)",
            "right": "clamp(1rem, 3vw, 2rem)",
            "border-radius": "var(--r-pill, 9999px)",
            "border": "1px solid var(--border)",
            "background": "var(--card)",
            "color": "var(--foreground)",
            "padding": "0.5rem 1rem",
            "font-size": "13px",
            "cursor": "pointer"
          },
          ".photo-flip-close:focus-visible": {
            "outline": "none",
            "box-shadow": "var(--focus, 0 0 0 2px var(--ring))"
          },
          ".photo-flip-overlay[data-open=\"1\"]": {
            "animation": "photo-flip-veu var(--dur-base, 200ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)) both"
          },
          ".photo-flip-media > *": {
            "width": "100%",
            "height": "100%",
            "display": "block"
          },
          ".photo-flip-media img, .photo-flip-media video": {
            "width": "100%",
            "height": "100%",
            "object-fit": "cover",
            "display": "block"
          }
        },
        "@keyframes photo-flip-veu": {
          "from": {
            "opacity": "0"
          },
          "to": {
            "opacity": "1"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".photo-flip-overlay[data-open=\"1\"]": {
            "animation": "none"
          }
        }
      },
      "categories": [
        "transicoes",
        "foto",
        "galeria",
        "lightbox",
        "flip",
        "morph",
        "grade",
        "gsap"
      ],
      "meta": {
        "uso": {
          "quando": "Abrir foto da grade em tela cheia com transição contínua, como lightbox de portfólio",
          "evite": "Só exibir a grade: masonry-gallery; comparar duas versões, photo-compare"
        }
      }
    },
    {
      "name": "photo-compare",
      "type": "registry:ui",
      "title": "Photo Compare",
      "description": "A cortina entre o antes e o depois: a camada de cima é RECORTADA, nunca redimensionada, então as duas fotos ficam na mesma escala. O arrasto, o teclado e o leitor de tela vêm de um input range invisível.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "gsap",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/photo-compare.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".photo-compare": {
            "position": "relative",
            "aspect-ratio": "var(--ratio, 3/2)",
            "overflow": "hidden",
            "border-radius": "var(--r-surface, 16px)",
            "background": "var(--muted)",
            "user-select": "none"
          },
          ".photo-compare-layer": {
            "position": "absolute",
            "inset": "0"
          },
          ".photo-compare-layer img, .photo-compare-layer video": {
            "width": "100%",
            "height": "100%",
            "object-fit": "cover",
            "display": "block"
          },
          ".photo-compare-after": {
            "clip-path": "inset(0 calc(100% - var(--p, 50%)) 0 0)"
          },
          ".photo-compare-seam": {
            "position": "absolute",
            "top": "0",
            "bottom": "0",
            "left": "var(--p, 50%)",
            "width": "2px",
            "margin-left": "-1px",
            "background": "var(--brand)",
            "pointer-events": "none",
            "display": "grid",
            "place-items": "center"
          },
          ".photo-compare-grip": {
            "width": "2.25rem",
            "height": "2.25rem",
            "border-radius": "var(--r-pill, 9999px)",
            "background": "var(--brand)",
            "box-shadow": "var(--e-raised, 0 2px 8px rgb(0 0 0 / 0.18))"
          },
          ".photo-compare-label": {
            "position": "absolute",
            "bottom": "0.75rem",
            "border-radius": "var(--r-pill, 9999px)",
            "background": "color-mix(in oklab, var(--background) 82%, transparent)",
            "color": "var(--foreground)",
            "padding": "0.25rem 0.7rem",
            "font-size": "12px",
            "line-height": "1.4",
            "pointer-events": "none"
          },
          ".photo-compare-label-before": {
            "right": "0.75rem"
          },
          ".photo-compare-label-after": {
            "left": "0.75rem"
          },
          ".photo-compare-input": {
            "position": "absolute",
            "inset": "0",
            "width": "100%",
            "height": "100%",
            "margin": "0",
            "opacity": "0",
            "appearance": "none",
            "-webkit-appearance": "none",
            "background": "transparent",
            "cursor": "ew-resize",
            "touch-action": "pan-y"
          },
          ".photo-compare-input::-webkit-slider-thumb": {
            "appearance": "none",
            "-webkit-appearance": "none",
            "width": "2.75rem",
            "height": "100%"
          },
          ".photo-compare-input::-moz-range-thumb": {
            "width": "2.75rem",
            "height": "100%",
            "border": "0",
            "background": "transparent"
          },
          ".photo-compare-input:focus-visible ~ .photo-compare-seam .photo-compare-grip": {
            "outline": "none",
            "box-shadow": "var(--focus, 0 0 0 2px var(--ring))"
          },
          ".photo-compare-layer > :not(.photo-compare-label)": {
            "width": "100%",
            "height": "100%",
            "display": "block"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".photo-compare-seam": {
            "transition": "none"
          }
        }
      },
      "categories": [
        "conteudo",
        "foto",
        "antes",
        "depois",
        "comparar",
        "cortina",
        "rebrand",
        "slider"
      ],
      "meta": {
        "uso": {
          "quando": "Comparar antes e depois de rebrand, retoque ou obra com cortina arrastável",
          "evite": "Fotos diferentes em sequência: mist-swap; uma foto em tela cheia, photo-flip"
        }
      }
    },
    {
      "name": "book-3d",
      "type": "registry:ui",
      "title": "Book 3D",
      "description": "O item de catálogo como objeto: capa dura em WebGL com lombada curva, espessura vinda da contagem de páginas e praça. Cor derivada dos tokens da marca e do matiz da própria arte, sem asset baixado.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0",
        "@react-three/fiber@^8.18.0",
        "@react-three/drei@^9.122.0"
      ],
      "registryDependencies": [
        "utils",
        "@visant/cover-art"
      ],
      "files": [
        {
          "path": "registry/visant/lib/book-geometry.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/book-material.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/book-faces.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/ui/book-stage.tsx",
          "type": "registry:ui"
        },
        {
          "path": "registry/visant/ui/book-3d.tsx",
          "type": "registry:ui"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "conteudo",
        "livro",
        "3d",
        "webgl",
        "catalogo",
        "capa",
        "objeto"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar livro, revista ou catálogo como objeto 3D com capa, lombada e espessura reais",
          "evite": "Muitos itens numa grade leve: spine-card ou book-shelf; item sem arte de capa, cover-art"
        }
      }
    },
    {
      "name": "book-shelf",
      "type": "registry:ui",
      "title": "Book Shelf",
      "description": "Estante em vez de vitrine: os itens soltos, sem moldura, e o rótulo só no hover, porque o objeto já tem silhueta e a moldura passa a competir com ela.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/book-3d"
      ],
      "files": [
        {
          "path": "registry/visant/ui/book-shelf.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".book-shelf-label": {
            "background": "linear-gradient(to top, color-mix(in oklch, var(--background) 94%, transparent) 38%, transparent)",
            "transition": "opacity var(--dur-fast, 160ms) var(--ease-out)"
          }
        },
        "@media (hover: hover)": {
          ".book-shelf-label": {
            "opacity": "0"
          },
          ".group:hover .book-shelf-label, .group:focus-within .book-shelf-label": {
            "opacity": "1"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".book-shelf-label": {
            "transition": "none"
          }
        }
      },
      "categories": [
        "conteudo",
        "estante",
        "prateleira",
        "catalogo",
        "grade",
        "hover"
      ],
      "meta": {
        "uso": {
          "quando": "Catálogo de livros ou produtos com silhueta, soltos como numa estante, rótulo só no hover",
          "evite": "Item que precisa de moldura e texto visível: showcase-card; objeto único em 3D, book-3d"
        }
      }
    },
    {
      "name": "carousel-3d",
      "type": "registry:ui",
      "title": "Carousel 3D",
      "description": "Capas num carrossel circular em WebGL: o card da frente cresce no hover, o botão central abre o item e o canvas só nasce perto da dobra. Aposentado da listagem. Bom em vitrine de poucas peças.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0",
        "@react-three/fiber@^8.18.0",
        "@react-three/drei@^9.122.0",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/lib/webgl-stage.tsx",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/ui/carousel-3d.tsx",
          "type": "registry:ui"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "conteudo",
        "carrossel",
        "3d",
        "webgl",
        "portfolio",
        "capa",
        "vitrine"
      ],
      "meta": {
        "uso": {
          "quando": "Vitrine de poucas capas num carrossel circular em WebGL, como portfólio curto",
          "evite": "Está aposentado da listagem: prefira cover-flow, mais leve; muitos itens, rail"
        }
      }
    },
    {
      "name": "css-color",
      "type": "registry:lib",
      "title": "CSS Color",
      "description": "Resolve qualquer cor CSS ou token (var(--x), oklch, color-mix) para sRGB 0..1 e avisa na troca de tema, para shader e canvas pintarem com a cor da marca.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/lib/css-color.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "fundacao",
        "marca",
        "tokens",
        "webgl",
        "canvas",
        "oklch",
        "tema"
      ],
      "meta": {
        "uso": {
          "quando": "Pintar shader, canvas ou WebGL com a cor dos tokens da marca e reagir à troca de tema",
          "evite": "Cor só no CSS ou Tailwind: use var(--token) direto, sem converter"
        }
      }
    },
    {
      "name": "ink-wordmark",
      "type": "registry:ui",
      "title": "Ink Wordmark",
      "description": "Assinatura de ponta a ponta que condensa da fumaça conforme entra na tela, respira como tinta e se agita com a velocidade do ponteiro, só com filtro SVG, ou escrita por prop, com fonte, peso, caixa e ®.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "framer-motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/ink-wordmark.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "texto",
        "assinatura",
        "logo",
        "rodape",
        "fumaca",
        "tinta",
        "svg",
        "scroll"
      ],
      "meta": {
        "uso": {
          "quando": "Assinatura grande de rodapé ou abertura que condensa da fumaça ao entrar na tela",
          "evite": "Título de seção que precisa ler rápido: line-reveal ou mist-text; logo oficial, use o SVG da marca"
        }
      }
    },
    {
      "name": "fog-hero",
      "type": "registry:block",
      "title": "Fog Hero",
      "description": "Hero de tela cheia que abre uma clareira na névoa, troca uma playlist de vídeo P&B pela própria fumaça e sai em desfoque no scroll, com papel e tinta vindos dos tokens.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0",
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/blocks/fog-hero/fog-hero.tsx",
          "type": "registry:component",
          "target": "~/components/fog-hero/fog-hero.tsx"
        },
        {
          "path": "registry/visant/blocks/fog-hero/shader.ts",
          "type": "registry:component",
          "target": "~/components/fog-hero/shader.ts"
        },
        {
          "path": "registry/visant/blocks/fog-hero/params.ts",
          "type": "registry:component",
          "target": "~/components/fog-hero/params.ts"
        },
        {
          "path": "registry/visant/blocks/fog-hero/index.ts",
          "type": "registry:component",
          "target": "~/components/fog-hero/index.ts"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "conteudo",
        "hero",
        "nevoa",
        "webgl",
        "shader",
        "video",
        "abertura",
        "grao"
      ],
      "meta": {
        "uso": {
          "quando": "Hero de tela cheia com névoa em shader, vídeo P&B e saída em desfoque, pra abertura de marca",
          "evite": "Hero leve ou de produto: section-intro com spring-dots; fundo abstrato sem vídeo, shader-neon"
        }
      }
    },
    {
      "name": "lathe-object",
      "type": "registry:ui",
      "title": "Lathe Object",
      "description": "Produto de revolução em WebGL a partir de um perfil de meia silhueta (frasco, vela, pote, difusor com varetas), com giro sozinho, arrasto para orbitar e vento no hover.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/lathe-object.tsx",
          "type": "registry:ui"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "conteudo",
        "3d",
        "webgl",
        "produto",
        "embalagem",
        "objeto",
        "difusor"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar produto de revolução, como frasco, vela ou pote, em 3D que gira e orbita no arrasto",
          "evite": "Livro ou catálogo: book-3d; produto com foto real, plate ou tilt-card"
        }
      }
    },
    {
      "name": "lathe-riso",
      "type": "registry:ui",
      "title": "Lathe Riso",
      "description": "A peça 3D de revolução do lathe-object impressa ao vivo em duas tintas de risografia: gira, orbita no arrasto e sai do registro onde o cursor passa.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0"
      ],
      "registryDependencies": [
        "utils",
        "@visant/lathe-object",
        "@visant/shader-riso"
      ],
      "files": [
        {
          "path": "registry/visant/ui/lathe-riso.tsx",
          "type": "registry:ui"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "efeitos",
        "3d",
        "webgl",
        "shader",
        "riso",
        "produto",
        "impressao"
      ],
      "meta": {
        "uso": {
          "quando": "Hero com objeto 3D (fruta, frasco, pote) que precisa de cara de impresso, em duas tintas, arrastável",
          "evite": "Foto estática em riso: shader-riso; produto em 3D sem efeito: lathe-object"
        }
      }
    },
    {
      "name": "mist-text",
      "type": "registry:ui",
      "title": "Mist Text",
      "description": "Texto que sai da névoa por palavra ou letra (desfoque, opacidade e subida mínima): entra uma vez ao chegar na tela, ou acompanha a rolagem ida e volta com mola que não erra a faixa dentro de sticky; cinco entradas por variant: mist, rise, mask, drift e settle.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/mist-text.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "texto",
        "blur",
        "nevoa",
        "reveal",
        "scroll",
        "palavra",
        "letra",
        "tipografia"
      ],
      "meta": {
        "uso": {
          "quando": "Texto que sai da névoa por palavra ou letra, uma vez ou acompanhando a rolagem",
          "evite": "Título que sobe linha por linha: line-reveal; troca de palavra em rótulo, text-morph"
        }
      }
    },
    {
      "name": "mist-swap",
      "type": "registry:ui",
      "title": "Mist Swap",
      "description": "Troca de slides em névoa: o que sai se desfaz no desfoque enquanto o próximo assenta no mesmo lugar, só gira em tela e para sob movimento reduzido. Preenche o pai, que precisa ter tamanho.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/mist-swap.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "conteudo",
        "foto",
        "slideshow",
        "crossfade",
        "blur",
        "nevoa",
        "troca",
        "atmosfera"
      ],
      "meta": {
        "uso": {
          "quando": "Slideshow atmosférico de fotos que se trocam em névoa, em hero ou dobra editorial",
          "evite": "Galeria que a pessoa navega: rail ou cover-flow; antes e depois, photo-compare"
        }
      }
    },
    {
      "name": "dot-cursor",
      "type": "registry:ui",
      "title": "Dot Cursor",
      "description": "Ponto de 6px que segue o ponteiro com mola calma e abre num anel vazado sobre link, botão ou [data-cursor], em mix-blend-difference; só existe em ponteiro fino e sem movimento reduzido.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/dot-cursor.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "efeitos",
        "cursor",
        "ponteiro",
        "hover",
        "mola",
        "blend",
        "minimal"
      ],
      "meta": {
        "uso": {
          "quando": "Cursor customizado mínimo em site editorial ou portfólio, abrindo anel sobre links",
          "evite": "App de produto ou formulário: cursor do sistema; efeito de calor sob o cursor, heat-word"
        }
      }
    },
    {
      "name": "mist-dialog",
      "type": "registry:ui",
      "title": "Mist Dialog",
      "description": "Modal em <dialog> nativo que entra e sai em névoa só com CSS (@starting-style + allow-discrete), controlado, fecha no Esc e no clique fora, com ganchos onOpen/onClose para pausar o scroll suave. Quatro entradas por variant: mist, rise, zoom e wipe.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/mist-dialog.tsx",
          "type": "registry:ui"
        }
      ],
      "css": {
        "@layer components": {
          ".mist-dialog": {
            "opacity": "0",
            "filter": "blur(14px)",
            "transform": "scale(0.98)",
            "transition": "opacity var(--mist-dialog-dur, 700ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), filter var(--mist-dialog-dur, 700ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), transform var(--mist-dialog-dur, 700ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), overlay var(--mist-dialog-dur, 700ms) allow-discrete, display var(--mist-dialog-dur, 700ms) allow-discrete"
          },
          ".mist-dialog[open]": {
            "opacity": "1",
            "filter": "none",
            "transform": "none"
          },
          ".mist-dialog::backdrop": {
            "background": "color-mix(in oklab, var(--foreground) 40%, transparent)",
            "backdrop-filter": "blur(12px)",
            "opacity": "0",
            "transition": "opacity var(--mist-dialog-dur, 700ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), overlay var(--mist-dialog-dur, 700ms) allow-discrete, display var(--mist-dialog-dur, 700ms) allow-discrete"
          },
          ".mist-dialog[open]::backdrop": {
            "opacity": "1"
          }
        },
        "@starting-style": {
          ".mist-dialog[open]": {
            "opacity": "0",
            "filter": "blur(14px)",
            "transform": "scale(0.98)"
          },
          ".mist-dialog[open]::backdrop": {
            "opacity": "0"
          }
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".mist-dialog, .mist-dialog[open]": {
            "filter": "none",
            "transform": "none",
            "transition": "opacity var(--mist-dialog-dur, 700ms) var(--ease-out, cubic-bezier(0.23, 1, 0.32, 1)), overlay var(--mist-dialog-dur, 700ms) allow-discrete, display var(--mist-dialog-dur, 700ms) allow-discrete"
          }
        }
      },
      "categories": [
        "transicoes",
        "modal",
        "dialog",
        "nevoa",
        "blur",
        "vitrine",
        "starting-style",
        "overlay"
      ],
      "meta": {
        "uso": {
          "quando": "Modal de vitrine ou editorial que entra em névoa, como detalhe de projeto ou contato",
          "evite": "Confirmar ação destrutiva: confirm-morph; aviso passageiro, toast-stack"
        }
      }
    },
    {
      "name": "fog-tree",
      "type": "registry:ui",
      "title": "Fog Tree",
      "description": "Uma árvore procedural sozinha na névoa, em duotone da marca: a cena é cinza e o último passe pinta com --background e --foreground, então o tema escuro inverte a foto sem segunda paleta.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0",
        "@dgreenheck/ez-tree@^1.1.0",
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/lib/fog-post.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/fog-tree-scene.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/ui/fog-tree.tsx",
          "type": "registry:ui"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "efeitos",
        "3d",
        "webgl",
        "nevoa",
        "arvore",
        "scroll",
        "duotone",
        "ez-tree"
      ],
      "meta": {
        "uso": {
          "quando": "Abertura ou dobra de marca com uma árvore 3D na névoa em duotone que acompanha o scroll",
          "evite": "Percurso com várias paradas de texto: fog-garden; hero com vídeo, fog-hero"
        }
      }
    },
    {
      "name": "fog-garden",
      "type": "registry:block",
      "title": "Fog Garden",
      "description": "A caminhada por um jardim na névoa presa ao scroll: cada parada de texto sai da névoa e volta para ela, em mix-blend-difference sobre as copas, com clareiras derivadas das paradas e plantio semeado.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "three@^0.170.0",
        "@dgreenheck/ez-tree@^1.1.0",
        "framer-motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color",
        "@visant/fog-tree"
      ],
      "files": [
        {
          "path": "registry/visant/blocks/fog-garden/garden-scene.ts",
          "type": "registry:component",
          "target": "~/components/fog-garden/garden-scene.ts"
        },
        {
          "path": "registry/visant/blocks/fog-garden/FogGarden.tsx",
          "type": "registry:component",
          "target": "~/components/fog-garden/FogGarden.tsx"
        },
        {
          "path": "registry/visant/blocks/fog-garden/index.ts",
          "type": "registry:component",
          "target": "~/components/fog-garden/index.ts"
        }
      ],
      "devDependencies": [
        "@types/three@^0.170.0"
      ],
      "categories": [
        "conteudo",
        "3d",
        "webgl",
        "scroll",
        "sticky",
        "nevoa",
        "storytelling",
        "jardim"
      ],
      "meta": {
        "uso": {
          "quando": "Storytelling longo de marca: caminhada 3D na névoa com paradas de texto presas ao scroll",
          "evite": "Uma imagem só de atmosfera: fog-tree; passos sem 3D, pinned-scene"
        }
      }
    },
    {
      "name": "activity-heatmap",
      "type": "registry:ui",
      "title": "Activity Heatmap",
      "description": "Um quadrado por dia mostra o ritmo de meses de trabalho, com bolha que desliza entre os dias e teclado de calendário.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/activity-heatmap.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "dados",
        "calendario",
        "heatmap",
        "ritmo",
        "grafico"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar ritmo diário de atividade ao longo de meses, como entregas ou hábitos, em perfil ou dashboard",
          "evite": "Mistura de categorias no tempo: streamgraph; um valor só de cota, gauge"
        }
      }
    },
    {
      "name": "billing-toggle",
      "type": "registry:ui",
      "title": "Billing Toggle",
      "description": "Interruptor mensal e anual com o selo de desconto que vira recibo quando o anual é escolhido, e o preço rolando junto.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/billing-toggle.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "preco",
        "pricing",
        "toggle",
        "assinatura",
        "desconto",
        "radiogroup"
      ],
      "meta": {
        "uso": {
          "quando": "Alternar mensal e anual numa página de preços, com selo de desconto e preço rolando junto",
          "evite": "Alternar opções que não são cobrança: segmented-control"
        }
      }
    },
    {
      "name": "card-stack",
      "type": "registry:ui",
      "title": "Card Stack",
      "description": "Pilha de cards em que o de cima vai pro fundo quando você arrasta e solta, como num baralho.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/card-stack.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "pilha",
        "arrastar",
        "gesto",
        "depoimentos",
        "cards"
      ],
      "meta": {
        "uso": {
          "quando": "Pilha de cards arrastáveis pra passar depoimentos ou dicas um a um, em landing ou onboarding",
          "evite": "Cartões de pagamento com saldo: wallet-stack; depoimentos todos à vista, testimonial-wall"
        }
      }
    },
    {
      "name": "confirm-morph",
      "type": "registry:ui",
      "title": "Confirm Morph",
      "description": "Botão de apagar que vira a pergunta no próprio lugar, depois o andamento e o resultado com desfazer.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/confirm-morph.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "botao",
        "confirmacao",
        "destrutivo",
        "desfazer"
      ],
      "meta": {
        "uso": {
          "quando": "Apagar item com confirmação no próprio botão, andamento e desfazer, quando a ação é reversível",
          "evite": "Ação irreversível e cara: hold-to-confirm; pagamento ou envio no celular, slide-to-confirm"
        }
      }
    },
    {
      "name": "elastic-slider",
      "type": "registry:ui",
      "title": "Elastic Slider",
      "description": "Slider que estica feito elástico quando você puxa além do limite e volta com a velocidade da soltura.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/elastic-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "slider",
        "range",
        "fisica",
        "mola",
        "formulario",
        "teclado"
      ],
      "meta": {
        "uso": {
          "quando": "Slider de formulário ou configuração que estica além do limite e volta com mola",
          "evite": "Valor com peso visual: slosh-slider; projeção com premissa, sim-slider; editor, scrub-input"
        }
      }
    },
    {
      "name": "expandable-card",
      "type": "registry:ui",
      "title": "Expandable Card",
      "description": "Card de resumo que cresce pros lados e pra baixo ao abrir, e rola só a palavra que mudou no resumo.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/expandable-card.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "card",
        "expandir",
        "detalhe",
        "resumo",
        "layout"
      ],
      "meta": {
        "uso": {
          "quando": "Card de resumo que abre no lugar pra mostrar detalhe, como pedido, plano ou tarefa",
          "evite": "Detalhe que pede foco total: mist-dialog; recibo dobrável com total à vista, folding-bill"
        }
      }
    },
    {
      "name": "expanding-search",
      "type": "registry:ui",
      "title": "Expanding Search",
      "description": "Busca que fica guardada num ícone de lupa e só abre o campo quando alguém vai mesmo buscar.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/expanding-search.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "busca",
        "search",
        "combobox",
        "cabecalho",
        "barra-de-ferramentas"
      ],
      "meta": {
        "uso": {
          "quando": "Busca no cabeçalho ou barra de ferramentas que fica num ícone até alguém ir buscar",
          "evite": "Busca é a ação principal da tela: campo sempre aberto; lógica de filtro local, use-local-search"
        }
      }
    },
    {
      "name": "gauge",
      "type": "registry:ui",
      "title": "Gauge",
      "description": "Medidor em arco com ponteiro que enche quando entra em vista e troca o nome da faixa na hora em que a contagem cruza o limite.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/gauge.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "dados",
        "medidor",
        "cota",
        "grafico",
        "meter"
      ],
      "meta": {
        "uso": {
          "quando": "Medidor de cota ou uso em dashboard, com o nome da faixa trocando ao cruzar o limite",
          "evite": "Métrica com régua e evidência: measure-bar; nível de áudio ao vivo, vintage-meter"
        }
      }
    },
    {
      "name": "hold-to-confirm",
      "type": "registry:ui",
      "title": "Hold to Confirm",
      "description": "Botão que só confirma se você segurar, com o preenchimento enchendo e voltando se soltar antes.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/hold-to-confirm.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "botao",
        "confirmacao",
        "destrutivo",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Ação irreversível e cara, como excluir conta ou projeto, exigindo segurar o botão",
          "evite": "Ação reversível e frequente: confirm-morph; pagamento por arrasto no celular, slide-to-confirm"
        }
      }
    },
    {
      "name": "icon-morph",
      "type": "registry:ui",
      "title": "Icon Morph",
      "description": "Ícone de dois estados que vira o outro em vez de trocar, como menu e fechar ou copiar e copiado.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/icon-morph.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "icone",
        "botao",
        "estado",
        "micro-interacao"
      ],
      "meta": {
        "uso": {
          "quando": "Botão de ícone com dois estados que viram um no outro, como menu e fechar ou copiar e copiado",
          "evite": "Rótulo de texto trocando: text-morph; tema claro e escuro, eclipse-switch"
        }
      }
    },
    {
      "name": "morph-select",
      "type": "registry:ui",
      "title": "Morph Select",
      "description": "Select em que o próprio gatilho cresce e vira a lista, sem uma segunda caixa aparecendo embaixo.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/morph-select.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "select",
        "listbox",
        "formulario",
        "morph",
        "teclado"
      ],
      "meta": {
        "uso": {
          "quando": "Select de formulário em que o gatilho cresce e vira a lista, pra listas médias de opções",
          "evite": "Até 5 opções visíveis: segmented-control; escolha lúdica entre poucas, magnetic-select"
        }
      }
    },
    {
      "name": "slot-text",
      "type": "registry:ui",
      "title": "Slot Text",
      "description": "Número ou palavra que gira como rolo de caça-níquel e assenta da esquerda pra direita, sem passar do alvo.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/slot-text.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "texto",
        "numero",
        "preco",
        "contador",
        "slot"
      ],
      "meta": {
        "uso": {
          "quando": "Preço, placar ou contador que muda ao vivo girando como rolo de caça-níquel",
          "evite": "Número que só apura ao entrar na tela: count-up; palavra de botão trocando, text-morph"
        }
      }
    },
    {
      "name": "swipe-actions",
      "type": "registry:ui",
      "title": "Swipe Actions",
      "description": "Lista em que a linha arrasta pro lado e mostra as ações, com o mesmo menu pra quem usa teclado.",
      "dependencies": [
        "motion",
        "lucide-react",
        "@radix-ui/react-dropdown-menu"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/swipe-actions.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "lista",
        "gesto",
        "arrastar",
        "triagem"
      ],
      "meta": {
        "uso": {
          "quando": "Lista de triagem no celular, como inbox ou tarefas, arrastando a linha pra revelar ações",
          "evite": "Apagar vários de uma vez: black-hole; tabela no desktop, data-table"
        }
      }
    },
    {
      "name": "text-morph",
      "type": "registry:ui",
      "title": "Text Morph",
      "description": "Rótulo que vira a próxima palavra letra por letra, com as letras em comum deslizando e a largura indo junto numa mola.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/text-morph.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "texto",
        "morph",
        "botao",
        "estado",
        "micro-interacao"
      ],
      "meta": {
        "uso": {
          "quando": "Rótulo de botão ou status que vira outra palavra letra por letra, como Salvar pra Salvo",
          "evite": "Número mudando: slot-text; título de seção entrando, line-reveal ou mist-text"
        }
      }
    },
    {
      "name": "toast-stack",
      "type": "registry:ui",
      "title": "Toast Stack",
      "description": "Avisos que se empilham no canto e abrem em leque quando o ponteiro chega, com o carregando que vira feito no lugar.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/toast-stack.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "avisos",
        "toast",
        "notificacao",
        "pilha"
      ],
      "meta": {
        "uso": {
          "quando": "Avisos passageiros empilhados no canto, com o carregando que vira feito no lugar",
          "evite": "Atividade em curso com controles: dynamic-island; erro de formulário vai no próprio campo"
        }
      }
    },
    {
      "name": "dynamic-island",
      "type": "registry:ui",
      "title": "Dynamic Island",
      "description": "A pílula que mostra a atividade em curso e cresce no lugar com os controles quando alguém toca nela.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/dynamic-island.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "pilula",
        "atividade",
        "morph",
        "spring",
        "timer",
        "player",
        "chamada"
      ],
      "meta": {
        "uso": {
          "quando": "Pílula de atividade em curso, como timer, player ou chamada, que cresce com controles ao tocar",
          "evite": "Aviso que some sozinho: toast-stack; espera de IA com etapas, status-ticker"
        }
      }
    },
    {
      "name": "folding-bill",
      "type": "registry:ui",
      "title": "Folding Bill",
      "description": "Uma conta que dobra em três como papel e abre quando você puxa ou toca, com o total sempre à vista no cabeçalho.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/folding-bill.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "recibo",
        "pedido",
        "3d",
        "arrastar",
        "acordeao"
      ],
      "meta": {
        "uso": {
          "quando": "Recibo ou resumo de pedido que dobra em três como papel, com o total sempre à vista",
          "evite": "Card genérico que expande: expandable-card; lista longa de itens, tabela do tema"
        }
      }
    },
    {
      "name": "heat-word",
      "type": "registry:ui",
      "title": "Heat Word",
      "description": "Uma grade de gotas ou uma palavra que derrete num mapa de calor por onde o cursor passa, pintada com as cores da marca.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/heat-word.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "canvas",
        "cursor",
        "hover",
        "calor",
        "efeito"
      ],
      "meta": {
        "uso": {
          "quando": "Palavra de destaque ou grade de gotas que derrete num mapa de calor sob o cursor, em hero",
          "evite": "Fundo de pontos que reage: spring-dots; título que precisa ler animado, line-reveal"
        }
      }
    },
    {
      "name": "liquid-toggle",
      "type": "registry:ui",
      "title": "Liquid Toggle",
      "description": "Um interruptor cuja bolinha escorre como gota de um lado pro outro, esticando no caminho e se recolhendo ao chegar.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/liquid-toggle.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "switch",
        "toggle",
        "formulario",
        "mola"
      ],
      "meta": {
        "uso": {
          "quando": "Switch de liga e desliga em configuração ou formulário, com a bolinha escorrendo como gota",
          "evite": "Tema claro e escuro: eclipse-switch; mais de duas opções, segmented-control"
        }
      }
    },
    {
      "name": "magnetic-select",
      "type": "registry:ui",
      "title": "Magnetic Select",
      "description": "Um cacho de opções redondas em que a escolhida incha e empurra as outras, e o cursor puxa a opção que está debaixo dele.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/magnetic-select.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "selecao",
        "radio",
        "ima",
        "hover",
        "escolha"
      ],
      "meta": {
        "uso": {
          "quando": "Escolha única lúdica entre poucas opções redondas, como humor, cor ou objetivo no onboarding",
          "evite": "Formulário sério ou muitas opções: morph-select; opções em linha, segmented-control"
        }
      }
    },
    {
      "name": "magnify-dock",
      "type": "registry:ui",
      "title": "Magnify Dock",
      "description": "A barra de atalhos em que os ícones crescem em onda conforme o cursor chega perto, com o nome em cima do mais próximo.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/magnify-dock.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "dock",
        "navegacao",
        "toolbar",
        "icones",
        "ampliacao",
        "spring"
      ],
      "meta": {
        "uso": {
          "quando": "Barra de atalhos de ícones que amplia em onda, em portfólio ou app de criação no desktop",
          "evite": "Navegação principal de app: side-nav; mobile, nav-drawer; poucas ações num botão, orbit-menu"
        }
      }
    },
    {
      "name": "slosh-slider",
      "type": "registry:ui",
      "title": "Slosh Slider",
      "description": "Um slider em que o preenchimento tem peso: arrastou rápido, a tinta passa do polegar, balança e assenta.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/slosh-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "slider",
        "range",
        "volume",
        "fisica",
        "spring",
        "teclado"
      ],
      "meta": {
        "uso": {
          "quando": "Slider de volume ou intensidade em que o preenchimento tem peso e balança ao soltar",
          "evite": "Formulário neutro: elastic-slider; simulação com projeção, sim-slider; console de áudio, vintage-slider"
        }
      }
    },
    {
      "name": "tilt-card",
      "type": "registry:ui",
      "title": "Tilt Card",
      "description": "O card que inclina em 3D seguindo o mouse, com um brilho que corre pela superfície.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/tilt-card.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "card",
        "3d",
        "tilt",
        "hover",
        "brilho",
        "foto"
      ],
      "meta": {
        "uso": {
          "quando": "Card de foto, capa ou cartão de membro que inclina forte em 3D com brilho sob o mouse",
          "evite": "Grade de muitos cards com luz sutil: gleam; objeto 3D de verdade, book-3d ou lathe-object"
        }
      }
    },
    {
      "name": "eclipse-switch",
      "type": "registry:ui",
      "title": "Eclipse Switch",
      "description": "Chave de tema claro e escuro em que a lua cobre o sol num eclipse, sem mexer na página por conta própria.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/eclipse-switch.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "tema",
        "modo-escuro",
        "chave",
        "eclipse",
        "toggle"
      ],
      "meta": {
        "uso": {
          "quando": "Chave de tema claro e escuro no cabeçalho, com a lua cobrindo o sol",
          "evite": "Switch de configuração comum: liquid-toggle; trocar de marca, brand-selector"
        }
      }
    },
    {
      "name": "black-hole",
      "type": "registry:ui",
      "title": "Black Hole",
      "description": "Apagar em lote com as linhas sugadas para um ponto só, a lista se inclinando em volta e o desfazer devolvendo tudo do mesmo lugar.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/black-hole.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "lista",
        "apagar",
        "desfazer",
        "inbox",
        "canvas",
        "transicao"
      ],
      "meta": {
        "uso": {
          "quando": "Apagar em lote numa lista ou inbox, com as linhas sugadas e o desfazer devolvendo tudo",
          "evite": "Apagar um item só: confirm-morph; triagem linha a linha no celular, swipe-actions"
        }
      }
    },
    {
      "name": "countdown",
      "type": "registry:ui",
      "title": "Countdown",
      "description": "Contagem regressiva em que cada dígito gira pelo caminho curto e vira o aviso de ao vivo quando chega a zero.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/countdown.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "contagem",
        "lancamento",
        "prazo",
        "timer",
        "evento"
      ],
      "meta": {
        "uso": {
          "quando": "Contagem até lançamento, evento ou prazo que vira aviso de ao vivo quando chega a zero",
          "evite": "Número que só apura: count-up; horário de loja aberta, store-status"
        }
      }
    },
    {
      "name": "cover-flow",
      "type": "registry:ui",
      "title": "Cover Flow",
      "description": "Uma prateleira de capas em perspectiva: a da vez fica de frente, as vizinhas giram de lado e você arrasta ou joga pra trocar.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/cover-flow.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "galeria",
        "carrossel",
        "3d",
        "portfolio",
        "arrastar",
        "capas"
      ],
      "meta": {
        "uso": {
          "quando": "Galeria de capas em perspectiva com arrasto, pra portfólio, discos ou livros em destaque",
          "evite": "Muitos itens pra navegar: rail; fotos em mosaico, masonry-gallery"
        }
      }
    },
    {
      "name": "date-reel",
      "type": "registry:ui",
      "title": "Date Reel",
      "description": "Seletor de data em rolos de dia, mês e ano que encaixam sozinhos, como no telefone.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/date-reel.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "data",
        "calendario",
        "rolo",
        "seletor",
        "agendar"
      ],
      "meta": {
        "uso": {
          "quando": "Escolher data em rolos de dia, mês e ano, como nascimento ou agendamento no celular",
          "evite": "Escolher hora: time-dial; intervalo de datas ou mês inteiro, use o date picker do tema"
        }
      }
    },
    {
      "name": "eye-tracker",
      "type": "registry:ui",
      "title": "Agent Bot",
      "description": "Avatar de bot ou agente de IA: a cabeça é um shader vivo na cor da marca, com visor e antena, e os olhos seguem o cursor e o foco, piscam e cumprimentam no clique. Três peles (neon, voronoi, túnel) e quatro formas.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/eye-tracker.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "bot",
        "agent",
        "agente",
        "ia",
        "assistente",
        "avatar",
        "mascote",
        "chat",
        "shader",
        "cursor",
        "estado-vazio"
      ],
      "meta": {
        "uso": {
          "quando": "Avatar de agente ou assistente de IA: cabeçalho e estado vazio de chat, onboarding guiado por bot, tela de espera enquanto o agente pensa",
          "evite": "Interface séria ou densa, foto de perfil de pessoa (use avatar) e mais de um bot vivo na mesma tela"
        }
      }
    },
    {
      "name": "orbit-menu",
      "type": "registry:ui",
      "title": "Orbit Menu",
      "description": "Botão que abre as ações em arco ao redor dele, com mola, pra escolher arrastando o dedo ou clicando.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/orbit-menu.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "menu",
        "acoes",
        "gesto",
        "arco",
        "mola"
      ],
      "meta": {
        "uso": {
          "quando": "Botão flutuante que abre poucas ações em arco, escolhidas arrastando o dedo, em app mobile",
          "evite": "Navegação principal: side-nav ou nav-drawer; barra de atalhos no desktop, magnify-dock"
        }
      }
    },
    {
      "name": "page-curl",
      "type": "registry:ui",
      "title": "Page Curl",
      "description": "Uma revistinha que você folheia puxando o canto: a capa abre, o livro fica com duas páginas e a folha vira com dobra, espessura e verso.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/page-curl.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "revista",
        "catalogo",
        "pagina",
        "dobra",
        "arrastar",
        "editorial"
      ],
      "meta": {
        "uso": {
          "quando": "Folhear revista, catálogo ou lookbook puxando o canto da página, em editorial",
          "evite": "Galeria de fotos: masonry-gallery ou cover-flow; livro como objeto 3D, book-3d"
        }
      }
    },
    {
      "name": "pull-to-refresh",
      "type": "registry:ui",
      "title": "Pull to Refresh",
      "description": "Painel que estica quando você puxa pra baixo, conta os pontos até a marca e gira enquanto atualiza.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/pull-to-refresh.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "feedback",
        "atualizar",
        "arrasto",
        "widget",
        "carregando"
      ],
      "meta": {
        "uso": {
          "quando": "Atualizar feed ou widget no celular puxando pra baixo, com a marca girando enquanto carrega",
          "evite": "Desktop ou conteúdo que atualiza sozinho: botão de atualizar; carga inicial, skeleton-rail"
        }
      }
    },
    {
      "name": "reactions",
      "type": "registry:ui",
      "title": "Reactions",
      "description": "Barra de reações em que a contagem rola pro lado que andou e o ícone dá um pulinho quando você reage.",
      "dependencies": [
        "motion",
        "lucide-react",
        "@radix-ui/react-popover"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/reactions.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "reacao",
        "comentario",
        "contador",
        "emoji",
        "feedback"
      ],
      "meta": {
        "uso": {
          "quando": "Barra de reações em post, comentário ou mensagem, com a contagem rolando",
          "evite": "Avaliação formal de produto: estrelas ou nota; quem está numa tarefa, assignee-stack"
        }
      }
    },
    {
      "name": "signature-pad",
      "type": "registry:ui",
      "title": "Signature Pad",
      "description": "Campo de assinatura com tinta que engrossa e afina como caneta, com desfazer e limpar.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/signature-pad.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "assinatura",
        "formulario",
        "contrato",
        "aceite",
        "desenho"
      ],
      "meta": {
        "uso": {
          "quando": "Coletar assinatura à mão em contrato, aceite ou comprovante de entrega, com desfazer e limpar",
          "evite": "Aceite simples de termos: checkbox do tema; confirmar pagamento, slide-to-confirm"
        }
      }
    },
    {
      "name": "slide-to-confirm",
      "type": "registry:ui",
      "title": "Slide to Confirm",
      "description": "Trilho que só confirma quando você arrasta o polegar até o fim, e volta com mola se soltar antes.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/sfx-bus"
      ],
      "files": [
        {
          "path": "registry/visant/ui/slide-to-confirm.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "confirmacao",
        "arrasto",
        "pagamento",
        "gesto"
      ],
      "meta": {
        "uso": {
          "quando": "Confirmar pagamento, envio ou check-in no celular arrastando até o fim, sem toque acidental",
          "evite": "Apagar com desfazer: confirm-morph; ação destrutiva no desktop, hold-to-confirm"
        }
      }
    },
    {
      "name": "sticker-peel",
      "type": "registry:ui",
      "title": "Sticker Peel",
      "description": "Um adesivo que levanta o canto quando o mouse chega perto, arrasta pra mudar de lugar e, com um clique, descola inteiro da página.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/sticker-peel.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "adesivo",
        "arrastar",
        "dobra",
        "papel",
        "sticker"
      ],
      "meta": {
        "uso": {
          "quando": "Adesivo decorativo de marca que levanta o canto e descola, em landing ou página de campanha",
          "evite": "Conteúdo que precisa ficar parado e legível; card que inclina com o mouse, tilt-card"
        }
      }
    },
    {
      "name": "streamgraph",
      "type": "registry:ui",
      "title": "Streamgraph",
      "description": "Gráfico de várias partes no tempo em sete estilos: fluxo, empilhado, 100%, cristas, linhas, barras e centrado, com camadas que ligam e desligam.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/streamgraph.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "grafico",
        "dados",
        "serie-temporal",
        "camadas",
        "dashboard"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar como a mistura de várias categorias muda no tempo, em dashboard ou relatório",
          "evite": "Ritmo diário de uma atividade: activity-heatmap; valor único de cota, gauge"
        }
      }
    },
    {
      "name": "time-dial",
      "type": "registry:ui",
      "title": "Time Dial",
      "description": "Mostrador de 24 horas que você gira com o dedo ou com as setas, com a faixa do expediente desenhada no aro.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/time-dial.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "hora",
        "relogio",
        "fuso",
        "seletor",
        "agenda"
      ],
      "meta": {
        "uso": {
          "quando": "Escolher hora num mostrador de 24h com o expediente marcado, em agenda ou conversão de fuso",
          "evite": "Escolher data: date-reel; mostrar se a loja está aberta agora, store-status"
        }
      }
    },
    {
      "name": "voice-note",
      "type": "registry:ui",
      "title": "Voice Note",
      "description": "Nota de voz de chat com forma de onda, play e pausa, e busca clicando ou arrastando na onda.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/voice-note.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "audio",
        "chat",
        "player",
        "forma-de-onda"
      ],
      "meta": {
        "uso": {
          "quando": "Player de nota de voz em chat ou mensagem, com onda, play e busca arrastando",
          "evite": "Sinal de áudio ao vivo: vintage-oscilloscope; vídeo vertical, reels-rail"
        }
      }
    },
    {
      "name": "wallet-stack",
      "type": "registry:ui",
      "title": "Wallet Stack",
      "description": "Carteira de cartões empilhados em que um sobe pra mostrar saldo e movimento e os outros se recolhem no pé.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/wallet-stack.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "carteira",
        "cartoes",
        "fintech",
        "pilha",
        "saldo"
      ],
      "meta": {
        "uso": {
          "quando": "Carteira de cartões em app fintech: um sobe com saldo e movimento, os outros recolhem",
          "evite": "Pilha de depoimentos ou dicas: card-stack; recibo de pedido, folding-bill"
        }
      }
    },
    {
      "name": "shader-ascii",
      "type": "registry:ui",
      "title": "Shader ASCII",
      "description": "Uma imagem redesenhada em caracteres, com seis jogos de glifo e as células mais cheias na cor da marca.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-ascii.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "ascii",
        "caracteres"
      ],
      "meta": {
        "uso": {
          "quando": "Redesenhar foto em caracteres na cor da marca, em hero tech ou capa de campanha",
          "evite": "Imagem com cara de impressão: shader-halftone ou shader-riso; fundo sem imagem, shader-neon"
        }
      }
    },
    {
      "name": "shader-halftone",
      "type": "registry:ui",
      "title": "Shader Halftone",
      "description": "Retícula de uma tinta só sobre uma imagem, em pontos, quadrados ou linhas, com uma lupa que amplia debaixo do cursor.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-halftone.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "reticula",
        "impressao"
      ],
      "meta": {
        "uso": {
          "quando": "Foto com retícula de uma tinta e lupa sob o cursor, em editorial ou campanha com cara de jornal",
          "evite": "Duas tintas com grão: shader-riso; caracteres em vez de pontos, shader-ascii"
        }
      }
    },
    {
      "name": "shader-neon",
      "type": "registry:ui",
      "title": "Shader Neon",
      "description": "Fios de luz que ondulam num campo liso na cor da marca e engrossam quando o ponteiro passa rápido.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-neon.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "shader",
        "webgl",
        "fundo",
        "neon",
        "onda"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo abstrato de hero com fios de luz ondulando na cor da marca",
          "evite": "Espiral com profundidade: shader-tunnel; textura orgânica, shader-voronoi; leve sem WebGL, spring-dots"
        }
      }
    },
    {
      "name": "shader-riso",
      "type": "registry:ui",
      "title": "Shader Riso",
      "description": "Uma imagem impressa em duas tintas de risografia, com grão, ângulo próprio por tinta e registro fora do lugar.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-riso.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "riso",
        "impressao"
      ],
      "meta": {
        "uso": {
          "quando": "Foto impressa em duas tintas de risografia com grão, em editorial, zine ou evento",
          "evite": "Uma tinta só com retícula: shader-halftone; caracteres, shader-ascii"
        }
      }
    },
    {
      "name": "shader-tunnel",
      "type": "registry:ui",
      "title": "Shader Tunnel",
      "description": "Túnel de anéis em espiral que corre pro centro na cor da marca e acelera com o ponteiro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-tunnel.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "shader",
        "webgl",
        "fundo",
        "tunel",
        "espiral"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo hipnótico de túnel em espiral pra abertura de evento, lançamento ou música",
          "evite": "Fundo calmo atrás de texto: shader-neon ou grid-dots; textura em células, shader-voronoi"
        }
      }
    },
    {
      "name": "shader-voronoi",
      "type": "registry:ui",
      "title": "Shader Voronoi",
      "description": "Mosaico de células que derivam devagar com um núcleo aceso na cor da marca, empurradas pelo ponteiro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-voronoi.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "shader",
        "webgl",
        "fundo",
        "voronoi",
        "textura"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de textura orgânica em células que derivam e reagem ao ponteiro, na cor da marca",
          "evite": "Fundo leve sem WebGL: spring-dots ou turbulence-field; ondas de luz, shader-neon"
        }
      }
    },
    {
      "name": "anatomia",
      "type": "registry:ui",
      "title": "Anatomia",
      "description": "O núcleo das figuras didáticas: o web component <visant-anatomia> (pinos, painel de peças, passo a passo, pausa, tela cheia, teclado) e o wrapper React. A figura em si vem de um item anatomia-<nome>.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-kit.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-estilo.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-nucleo.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/ui/anatomia.tsx",
          "type": "registry:ui"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "isometrico",
        "explicacao",
        "web-component",
        "passo-a-passo"
      ],
      "meta": {
        "uso": {
          "quando": "Montar figura didática interativa com pinos e passo a passo; é a base de toda anatomia-*",
          "evite": "Diagrama estático ou explicação sem interação: imagem ou SVG simples"
        }
      }
    },
    {
      "name": "anatomia-como-sobe",
      "type": "registry:lib",
      "title": "Anatomia: como a ferramenta sobe",
      "description": "Fig 1.4 do curso IA para Designers: o que sobe pro GitHub, o que o .gitignore segura no computador e quando a Vercel põe no ar.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-como-sobe.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-como-sobe-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "git",
        "github",
        "gitignore",
        "vercel"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar em aula o que vai pro GitHub, o que o .gitignore segura e quando a Vercel publica",
          "evite": "Falar de chave de API e conector: anatomia-tomadas; de permissão no terminal, anatomia-permissao"
        }
      }
    },
    {
      "name": "anatomia-tomadas",
      "type": "registry:lib",
      "title": "Anatomia: conector e chave de API",
      "description": "Fig 2.2 do curso IA para Designers: os programas entram pelo conector do claude.ai, com a tua conta; o serviço pago entra pela chave de API, que mora no .env e conta cada chamada.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-tomadas.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-tomadas-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "conector",
        "chave-de-api",
        "mcp",
        "claude"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar a diferença entre conector do claude.ai e chave de API no .env, em aula ou onboarding",
          "evite": "Falar de permissão de arquivos: anatomia-permissao; de publicar código, anatomia-como-sobe"
        }
      }
    },
    {
      "name": "anatomia-fichario",
      "type": "registry:lib",
      "title": "Anatomia: o fichário de receitas",
      "description": "Fig 2.6 do curso IA para Designers: o agente lê só as etiquetas das skills e abre a receita que casa com o pedido. A pasta references/ só sobe quando a receita pede.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-fichario.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-fichario-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "skill",
        "receita",
        "claude"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar como o agente lê só as etiquetas das skills e abre a receita que casa com o pedido",
          "evite": "Falar de memória do agente: anatomia-memoria; de contexto e tokens, anatomia-tokens"
        }
      }
    },
    {
      "name": "anatomia-memoria",
      "type": "registry:lib",
      "title": "Anatomia: a memória do agente",
      "description": "Fig 2.7 do curso IA para Designers: o agente esquece a conversa quando a janela fecha e lembra o que está no CLAUDE.md, com regra parafusada e fato com data.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-memoria.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-memoria-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "memoria",
        "claude.md"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar o que o agente esquece ao fechar a conversa e o que fica gravado no CLAUDE.md",
          "evite": "Falar de custo e contexto da conversa: anatomia-tokens; de skills, anatomia-fichario"
        }
      }
    },
    {
      "name": "anatomia-tokens",
      "type": "registry:lib",
      "title": "Anatomia: o tanque da conversa",
      "description": "Fig B.7 do curso IA para Designers: cada mensagem fica na conversa e o agente relê tudo a cada volta. Um print resolve em uma volta o que o parágrafo leva três.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-tokens.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-tokens-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "tokens",
        "contexto"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar que o agente relê a conversa toda a cada volta e por que um print economiza",
          "evite": "Falar do que persiste entre sessões: anatomia-memoria; de automatizar repetição, anatomia-script"
        }
      }
    },
    {
      "name": "anatomia-script",
      "type": "registry:lib",
      "title": "Anatomia: do briefing ao script",
      "description": "Fig B.8 do curso IA para Designers: o agente resolve o pedido novo e gasta uso. O que se repete vira script, que roda sem IA e para quando não entende.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-script.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-script-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "script",
        "automacao"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar quando um pedido que se repete deve virar script que roda sem IA",
          "evite": "Falar de custo por mensagem: anatomia-tokens; de skills e receitas, anatomia-fichario"
        }
      }
    },
    {
      "name": "anatomia-permissao",
      "type": "registry:lib",
      "title": "Anatomia: a caixa de permissão",
      "description": "Fig 2.3b do curso IA para Designers: nada do agente entra na tua pasta sem Yes, Yes and don't ask again ou No, e só o don't ask again fica escrito.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "@visant/anatomia"
      ],
      "files": [
        {
          "path": "registry/visant/lib/anatomia-tipos.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-permissao.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/visant/lib/anatomia-permissao-controlador.ts",
          "type": "registry:lib"
        }
      ],
      "categories": [
        "anatomia",
        "didatica",
        "aula",
        "terminal",
        "permissao"
      ],
      "meta": {
        "uso": {
          "quando": "Explicar a caixa de permissão do terminal e o que o don't ask again deixa gravado",
          "evite": "Falar de chave de API e conector: anatomia-tomadas; de memória, anatomia-memoria"
        }
      }
    },
    {
      "name": "agent-rules",
      "type": "registry:item",
      "title": "Agent Rules",
      "description": "Regras pro seu agente de IA (Cursor, Claude Code, Copilot): procurar no @visant antes de escrever UI do zero e escolher a peça certa pela situação.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "files": [
        {
          "path": "registry/visant/rules/visant-ui.mdc",
          "type": "registry:file",
          "target": "~/.cursor/rules/visant-ui.mdc"
        },
        {
          "path": "registry/visant/rules/SKILL.md",
          "type": "registry:file",
          "target": "~/.claude/skills/visant-ui/SKILL.md"
        },
        {
          "path": "registry/visant/rules/visant-ui.instructions.md",
          "type": "registry:file",
          "target": "~/.github/instructions/visant-ui.instructions.md"
        }
      ],
      "categories": [
        "fundacao",
        "ia",
        "agente",
        "mcp",
        "cursor",
        "claude",
        "copilot",
        "regras"
      ],
      "meta": {
        "uso": {
          "quando": "Projeto em que um agente de IA escreve a UI: instala as regras que fazem ele buscar a peça @visant certa antes de criar",
          "evite": "Projeto sem agente de IA escrevendo código; quem escolhe à mão consulta o catálogo direto"
        }
      }
    },
    {
      "name": "use-debounce",
      "type": "registry:hook",
      "title": "useDebounce",
      "description": "Atrasa um valor até ele parar de mudar. Só borda de saída, e o valor inicial passa sem atraso.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-debounce.ts",
          "type": "registry:hook",
          "target": "@hooks/use-debounce.ts"
        }
      ],
      "categories": [
        "fundacao",
        "hook",
        "busca",
        "debounce"
      ]
    },
    {
      "name": "search-field",
      "type": "registry:ui",
      "title": "Search Field",
      "description": "Campo de busca com debounce que não se limpa sozinho: negocia o texto local com o valor de fora por referência acordada.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/use-debounce"
      ],
      "files": [
        {
          "path": "registry/visant/ui/search-field.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "react"
      ],
      "categories": [
        "controles",
        "busca",
        "debounce",
        "formulario"
      ]
    },
    {
      "name": "filter-menu",
      "type": "registry:ui",
      "title": "Filter Menu",
      "description": "Menu de facetas que não conhece o domínio: grupos múltiplos ou excludentes, e o contador conta grupos, não opções.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/filter-menu.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "@radix-ui/react-dropdown-menu",
        "react"
      ],
      "categories": [
        "controles",
        "filtro",
        "menu",
        "facetas"
      ]
    },
    {
      "name": "filter-bar",
      "type": "registry:ui",
      "title": "Filter Bar",
      "description": "Busca e filtro numa peça só: campo, menu de facetas, chips aplicados e a contagem que some quando nada foi filtrado.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/chip",
        "@visant/motion",
        "@visant/search-field",
        "@visant/filter-menu"
      ],
      "files": [
        {
          "path": "registry/visant/ui/filter-bar.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "motion",
        "react"
      ],
      "categories": [
        "controles",
        "filtro",
        "busca",
        "chips"
      ]
    },
    {
      "name": "searchable-select",
      "type": "registry:ui",
      "title": "Searchable Select",
      "description": "Combobox com busca em rótulo e keywords ocultos, grupos, e criação no lugar que sobrevive à falha. Digita dentro de Dialog.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/searchable-select.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "@radix-ui/react-popover",
        "cmdk",
        "react"
      ],
      "categories": [
        "controles",
        "combobox",
        "busca",
        "formulario"
      ]
    },
    {
      "name": "command-search",
      "type": "registry:ui",
      "title": "Command Search",
      "description": "Busca ⌘K que não sabe buscar nem navegar: onSearch entra por prop, e resposta fora de ordem não repovoa a lista.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "registryDependencies": [
        "utils",
        "@visant/use-debounce"
      ],
      "files": [
        {
          "path": "registry/visant/ui/command-search.tsx",
          "type": "registry:ui"
        }
      ],
      "dependencies": [
        "cmdk",
        "react"
      ],
      "categories": [
        "controles",
        "busca",
        "comando",
        "teclado"
      ]
    },
    {
      "name": "shader-chromatic-aberration",
      "type": "registry:ui",
      "title": "Shader Chromatic Aberration",
      "description": "Os canais de cor de uma imagem fora do registro, com a separação apontando para o cursor e crescendo longe do centro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-chromatic-aberration.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto com franja de cor de lente barata que reage ao cursor, em hero de música, moda ou tech",
          "evite": "Falha digital animada em faixas: shader-glitch; fita gasta, shader-vhs"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "aberracao-cromatica",
        "rgb"
      ]
    },
    {
      "name": "shader-crt",
      "type": "registry:ui",
      "title": "Shader CRT",
      "description": "Uma imagem num monitor de tubo, com linhas de varredura, vinheta, tela abaulada e uma faixa de luz que desce devagar.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-crt.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto ou print dentro de um monitor de tubo, em landing de game, retrô ou produto tech",
          "evite": "Fita com onda e vinco: shader-vhs; grão de filme sem tubo, shader-film-grain"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "crt",
        "tubo",
        "retro"
      ]
    },
    {
      "name": "shader-dither",
      "type": "registry:ui",
      "title": "Shader Dither",
      "description": "Uma imagem pixelada em poucos tons da rampa da marca, com o dither de Bayer fazendo a passagem entre um tom e outro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-dither.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto com cara de jogo de 8 bits em poucos tons da marca, em landing de game, evento ou campanha retrô",
          "evite": "Só papel e tinta: shader-matrix-dither; blocos de cor sem trama, shader-pixelate"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "dither",
        "8-bits",
        "pixel"
      ]
    },
    {
      "name": "shader-duotone",
      "type": "registry:ui",
      "title": "Shader Duotone",
      "description": "Uma imagem refeita em duas cores do tema, a mais escura nas sombras e a outra nas luzes, sem sair em negativo no escuro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-duotone.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto de banco com a cara da marca em duas cores, em capa, hero ou card de campanha",
          "evite": "Duas tintas com grão de impressão: shader-riso; poucos tons por canal, shader-posterize"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "duotone",
        "duas-cores"
      ]
    },
    {
      "name": "shader-edge-detect",
      "type": "registry:ui",
      "title": "Shader Edge Detect",
      "description": "Só os contornos de uma imagem, traçados pelo filtro de Sobel na cor da marca, sozinhos ou por cima da foto.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-edge-detect.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto virando desenho a traço na cor da marca, em hero técnico, blueprint ou capa de manual",
          "evite": "Imagem em caracteres: shader-ascii; retícula de pontos, shader-halftone"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "contorno",
        "traco"
      ]
    },
    {
      "name": "shader-film-grain",
      "type": "registry:ui",
      "title": "Shader Film Grain",
      "description": "Grão de película correndo sobre uma imagem a 24 quadros por segundo, em cinza ou com um grão por canal de cor.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-film-grain.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Dar textura de filme a foto limpa de banco, em hero editorial, portfólio ou campanha",
          "evite": "Fita gasta com onda e vinco: shader-vhs; tela de tubo, shader-crt"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "grao",
        "filme"
      ]
    },
    {
      "name": "shader-glitch",
      "type": "registry:ui",
      "title": "Shader Glitch",
      "description": "Uma imagem que falha em faixas, com os canais de cor separados e linhas que pulam, e falha mais quando o mouse passa rápido.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-glitch.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto com falha digital que piora com o mouse rápido, em hero de música, evento ou tech",
          "evite": "Franja de cor parada que segue o cursor: shader-chromatic-aberration; fita analógica, shader-vhs"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "glitch",
        "falha"
      ]
    },
    {
      "name": "shader-matrix-dither",
      "type": "registry:ui",
      "title": "Shader Matrix Dither",
      "description": "Uma imagem em 1 bit pelo dither de Bayer, só papel e tinta da marca, numa trama 2×2, 4×4 ou 8×8.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-matrix-dither.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto em 1 bit com trama xadrez de Mac antigo, em hero tech, zine ou capa de produto",
          "evite": "Vários tons pixelados: shader-dither; pontos redondos de retícula, shader-halftone"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "dither",
        "1-bit",
        "bayer"
      ]
    },
    {
      "name": "shader-pixelate",
      "type": "registry:ui",
      "title": "Shader Pixelate",
      "description": "Uma imagem em blocos de cor chapada, com uma janela redonda que mostra a foto nítida debaixo do cursor.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-pixelate.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Capa de lançamento a revelar ou teaser em que o cursor descobre a foto, em landing ou campanha",
          "evite": "Poucos tons com trama: shader-dither; mostrar uma ampliação de verdade, shader-upscale"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "pixel",
        "revelar"
      ]
    },
    {
      "name": "shader-posterize",
      "type": "registry:ui",
      "title": "Shader Posterize",
      "description": "Uma imagem reduzida a poucos tons por canal, com as transições suaves virando degraus chapados de serigrafia.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-posterize.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto em degraus chapados de cor com cara de cartaz serigrafado, em evento, música ou editorial",
          "evite": "Duas cores da marca: shader-duotone; tons da marca com trama de pixel, shader-dither"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "posterizar",
        "serigrafia"
      ]
    },
    {
      "name": "shader-upscale",
      "type": "registry:ui",
      "title": "Shader Upscale",
      "description": "Uma imagem pequena ampliada em bicúbico com nitidez, e uma linha que segue o cursor mostrando o antes em blocos.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-upscale.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Mostrar o ganho de uma ampliação lado a lado, em página de ferramenta de imagem ou de IA",
          "evite": "Comparar duas fotos diferentes: photo-compare; foto em blocos como estilo, shader-pixelate"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "ampliacao",
        "antes-e-depois"
      ]
    },
    {
      "name": "shader-vhs",
      "type": "registry:ui",
      "title": "Shader VHS",
      "description": "Uma imagem tocada de fita VHS, com a linha ondulando, um vinco que rasga, ruído no pé do quadro e a cor sangrando para o lado.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/shader-vhs.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "meta": {
        "uso": {
          "quando": "Foto com cara de fita VHS gasta, em clipe, capa de música ou campanha retrô anos 90",
          "evite": "Tela de tubo com linhas de varredura: shader-crt; falha digital em faixas, shader-glitch"
        }
      },
      "categories": [
        "shaders",
        "shader",
        "webgl",
        "imagem",
        "vhs",
        "fita",
        "retro"
      ]
    },
    {
      "name": "textura-pinch",
      "type": "registry:ui",
      "title": "Textura Pinch",
      "description": "A imagem é sugada para o ponteiro como pele beliscada, e solta devagar quando ele sai.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-pinch.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "textura",
        "webgl",
        "ponteiro",
        "imagem",
        "beliscar",
        "distorcao"
      ],
      "meta": {
        "uso": {
          "quando": "Foto de produto ou retrato que a pessoa belisca com o cursor, em hero de moda, beleza ou campanha",
          "evite": "Redemoinho em volta do cursor: textura-twist; lupa que amplia, textura-sphere"
        }
      }
    },
    {
      "name": "textura-sphere",
      "type": "registry:ui",
      "title": "Textura Sphere",
      "description": "Uma bolha de vidro passeia sob o ponteiro e amplia a imagem como olho de peixe.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-sphere.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "textura",
        "webgl",
        "ponteiro",
        "imagem",
        "lupa",
        "fisheye"
      ],
      "meta": {
        "uso": {
          "quando": "Foto de produto com uma lupa de vidro sob o cursor, pra mostrar detalhe em hero ou página de produto",
          "evite": "Pele puxada pro cursor: textura-pinch; lupa com retícula de jornal, shader-halftone"
        }
      }
    },
    {
      "name": "textura-twist",
      "type": "registry:ui",
      "title": "Textura Twist",
      "description": "A imagem gira em redemoinho em volta do ponteiro e se desfaz devagar quando ele sai.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-twist.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "textura",
        "webgl",
        "ponteiro",
        "imagem",
        "redemoinho",
        "distorcao"
      ],
      "meta": {
        "uso": {
          "quando": "Foto que gira em redemoinho sob o cursor, em hero de música, evento ou campanha psicodélica",
          "evite": "Pele beliscada sem giro: textura-pinch; foto escorrendo em ruído, textura-warp"
        }
      }
    },
    {
      "name": "textura-tiles",
      "type": "registry:ui",
      "title": "Textura Tiles",
      "description": "A imagem em ladrilhos que encolhem, se afastam e se inclinam perto do ponteiro.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-tiles.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "textura",
        "webgl",
        "ponteiro",
        "imagem",
        "ladrilho",
        "grade"
      ],
      "meta": {
        "uso": {
          "quando": "Foto quebrada em ladrilhos que se abrem perto do cursor, em portfólio, capa de projeto ou hero de arquitetura",
          "evite": "Foto em blocos de cor parados: shader-pixelate; distorção contínua sem grade, textura-pinch"
        }
      }
    },
    {
      "name": "textura-warp",
      "type": "registry:ui",
      "title": "Textura Warp",
      "description": "A imagem escorre em ruído como reflexo na água, e o ponteiro rápido agita a superfície.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-warp.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "shaders",
        "textura",
        "webgl",
        "ponteiro",
        "imagem",
        "ruido",
        "domain-warp"
      ],
      "meta": {
        "uso": {
          "quando": "Foto que escorre como reflexo na água e agita com o mouse rápido, em hero editorial, música ou moda",
          "evite": "Redemoinho preso ao cursor: textura-twist; falha digital em faixas, shader-glitch"
        }
      }
    },
    {
      "name": "textura-watch",
      "type": "registry:ui",
      "title": "Textura Watch",
      "description": "Grade de mostradores de relógio cujos ponteiros apontam para o cursor. O curto chega atrasado, como hora.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-watch.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "relogio",
        "grade"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero lúdico com uma grade de relógios que apontam pro cursor, em landing de produto ou evento",
          "evite": "Olhos que seguem o cursor: textura-gaze; traços finos alinhados ao campo, textura-magnet"
        }
      }
    },
    {
      "name": "textura-gaze",
      "type": "registry:ui",
      "title": "Textura Gaze",
      "description": "Grade de olhos cujas pupilas seguem o cursor e que piscam de vez em quando, cada um no seu tempo.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-gaze.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "olhos",
        "pupila",
        "grade"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero com uma grade de olhos que seguem o cursor, em campanha, portfólio ou página de arte",
          "evite": "Um avatar só com olhos: eye-tracker; ponteiros de relógio em vez de pupilas, textura-watch"
        }
      }
    },
    {
      "name": "textura-magnet",
      "type": "registry:ui",
      "title": "Textura Magnet",
      "description": "Limalha de ferro em traços curtos que se alinham ao campo de um ímã preso ao cursor.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-magnet.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "ima",
        "limalha",
        "campo"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero com limalha de ferro que se alinha ao cursor, em landing tech, ciência ou portfólio",
          "evite": "Linhas de fluxo que desviam do cursor: textura-current; ponteiros grandes de relógio, textura-watch"
        }
      }
    },
    {
      "name": "textura-settle",
      "type": "registry:ui",
      "title": "Textura Settle",
      "description": "Areia rastelada que o cursor espalha e que assenta de volta devagar, com os sulcos reaparecendo.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-settle.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "areia",
        "grao",
        "rastelo"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo calmo de areia rastelada que o cursor espalha e volta a assentar, em bem-estar, spa ou editorial",
          "evite": "Correnteza que nunca para: textura-current; malha de pontos leve sem WebGL, spring-dots"
        }
      }
    },
    {
      "name": "textura-glow",
      "type": "registry:ui",
      "title": "Textura Glow",
      "description": "Brilho macio na cor da marca que segue o cursor sobre grão fino, esticando no rumo do movimento.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-glow.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "brilho",
        "grao",
        "luz"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo escuro de hero com um brilho da marca seguindo o cursor sobre grão fino, atrás de título curto",
          "evite": "Facho de luz vindo do alto: textura-beam; fios de luz ondulando sozinhos, shader-neon"
        }
      }
    },
    {
      "name": "textura-beam",
      "type": "registry:ui",
      "title": "Textura Beam",
      "description": "Facho de luz que desce do alto com poeira boiando dentro e que mira o cursor.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-beam.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "facho",
        "luz",
        "poeira"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de palco com um facho de luz e poeira que mira o cursor, em abertura de evento, lançamento ou música",
          "evite": "Brilho macio sem direção: textura-glow; cortina de palco, textura-curtain"
        }
      }
    },
    {
      "name": "textura-current",
      "type": "registry:ui",
      "title": "Textura Current",
      "description": "Linhas de correnteza com traços que descem pela água e abrem caminho em volta do cursor como de uma pedra.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-current.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "fluxo",
        "correnteza",
        "linhas"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero com linhas de correnteza que abrem caminho em volta do cursor, em landing de dados, clima ou viagem",
          "evite": "Limalha parada alinhada ao campo: textura-magnet; névoa leve sem WebGL, turbulence-field"
        }
      }
    },
    {
      "name": "textura-curtain",
      "type": "registry:ui",
      "title": "Textura Curtain",
      "description": "Cortina de dobras verticais que ondula onde o cursor passa, com a onda morrendo sozinha.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-curtain.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "cortina",
        "dobras",
        "tecido"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de cortina de dobras que ondula onde o cursor passa, em abertura de evento, teatro ou lançamento",
          "evite": "Facho de luz de palco: textura-beam; areia que assenta, textura-settle"
        }
      }
    },
    {
      "name": "textura-pillars",
      "type": "registry:ui",
      "title": "Textura Pillars",
      "description": "Campo de pilares em pseudo-3D que sobem perto do cursor e descem ao sair.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/css-color"
      ],
      "files": [
        {
          "path": "registry/visant/ui/textura-pillars.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "textura",
        "webgl",
        "fundo",
        "ponteiro",
        "pilares",
        "3d",
        "campo"
      ],
      "meta": {
        "uso": {
          "quando": "Fundo de hero com um campo de pilares em pseudo-3D que sobem perto do cursor, em landing tech ou de arquitetura",
          "evite": "Cena 3D de verdade com objeto: uma peça da família 3d; ladrilhos de foto, textura-tiles"
        }
      }
    },
    {
      "name": "liquid-glass",
      "type": "registry:ui",
      "title": "Liquid Glass",
      "description": "A superfície que refrata o fundo de verdade, com franja cromática nas bordas. É a base de todas as peças de vidro.",
      "dependencies": [],
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/visant/ui/liquid-glass.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "efeitos",
        "vidro",
        "refracao",
        "backdrop-filter",
        "primitiva"
      ],
      "meta": {
        "uso": {
          "quando": "Superfície própria que precise refratar o fundo, como barra flutuante ou lente",
          "evite": "Painel grande com conteúdo: glass-panel; controle pronto: glass-button ou glass-slider"
        }
      }
    },
    {
      "name": "glass-panel",
      "type": "registry:ui",
      "title": "Glass Panel",
      "description": "Vidro fosco com borda em degradê, acesa nos cantos, e grão opcional. O cartão pra pôr sobre foto ou fundo com forma.",
      "dependencies": [],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-panel.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "vidro",
        "fosco",
        "superficie",
        "card"
      ],
      "meta": {
        "uso": {
          "quando": "Cartão ou painel sobre foto, vídeo ou gradiente, em landing ou tela de produto",
          "evite": "Fundo liso, onde o fosco não tem o que borrar: um card comum; lista de dados densa"
        }
      },
      "css": {
        ".glass-panel": {
          "position": "relative",
          "isolation": "isolate",
          "border-radius": "var(--glass-panel-radius, var(--r-surface, 1rem))",
          "color": "white",
          "background": "var(--glass-panel-fill, linear-gradient(180deg, color-mix(in srgb, black 34%, transparent), color-mix(in srgb, white 5%, transparent)))",
          "-webkit-backdrop-filter": "var(--glass-panel-filter, blur(20px) saturate(1.1))",
          "backdrop-filter": "var(--glass-panel-filter, blur(20px) saturate(1.1))",
          "box-shadow": "0 30px 60px -28px black"
        },
        ".glass-panel-luz": {
          "position": "absolute",
          "inset": "0",
          "z-index": "-1",
          "border-radius": "inherit",
          "pointer-events": "none",
          "opacity": "0.55",
          "background": "radial-gradient(60% 80% at var(--glass-panel-x, 22%) var(--glass-panel-y, 0%), color-mix(in srgb, white 16%, transparent), transparent 72%)",
          "transition": "opacity var(--dur-slow, 300ms) var(--ease-out)"
        },
        ".glass-panel:hover .glass-panel-luz": {
          "opacity": "1"
        },
        ".glass-panel::after": {
          "content": "\"\"",
          "position": "absolute",
          "inset": "0",
          "z-index": "2",
          "border-radius": "inherit",
          "padding": "1px",
          "pointer-events": "none",
          "background": "linear-gradient(135deg, color-mix(in srgb, white 62%, transparent), color-mix(in srgb, white 10%, transparent) 38%, color-mix(in srgb, white 8%, transparent) 66%, color-mix(in srgb, white 42%, transparent))",
          "-webkit-mask": "linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0)",
          "mask": "linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0)"
        },
        ".glass-panel[data-grain]::before": {
          "content": "\"\"",
          "position": "absolute",
          "inset": "0",
          "z-index": "-1",
          "border-radius": "inherit",
          "pointer-events": "none",
          "opacity": "0.22",
          "mix-blend-mode": "overlay",
          "background-image": "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E\")"
        }
      }
    },
    {
      "name": "glass-button",
      "type": "registry:ui",
      "title": "Glass Button",
      "description": "Botão de vidro, em pílula ou círculo, que refrata o fundo. Com aria-pressed vira alternância.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/liquid-glass"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-button.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "vidro",
        "botao",
        "icone",
        "alternancia"
      ],
      "meta": {
        "uso": {
          "quando": "Ação sobre foto ou vídeo, como player, câmera ou barra flutuante",
          "evite": "Ação principal em fundo claro ou liso: button; a ação que define a dobra, cta-surface"
        }
      },
      "css": {
        ".glass-button": {
          "position": "relative",
          "display": "inline-grid",
          "place-items": "center",
          "min-height": "2.75rem",
          "padding": "0 1.25rem",
          "border": "0",
          "border-radius": "999px",
          "background": "none",
          "color": "white",
          "font": "600 0.875rem/1 var(--font-sans, system-ui)",
          "cursor": "pointer",
          "transition": "transform var(--dur-press, 120ms) var(--ease-out)"
        },
        ".glass-button[data-shape=\"circle\"]": {
          "width": "3.5rem",
          "height": "3.5rem",
          "padding": "0"
        },
        ".glass-button:active": {
          "transform": "scale(0.97)"
        },
        ".glass-button:disabled": {
          "opacity": "0.5",
          "cursor": "default"
        },
        ".glass-button:focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "2px"
        },
        ".glass-button-vidro": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "color-mix(in srgb, white 12%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 26%, transparent), inset 0 1.5px 0 color-mix(in srgb, white 30%, transparent)"
        },
        ".glass-button-miolo": {
          "position": "relative",
          "display": "inline-flex",
          "align-items": "center",
          "gap": "0.5rem"
        },
        ".glass-button[data-shape=\"circle\"] .glass-button-miolo": {
          "width": "60%",
          "height": "60%",
          "justify-content": "center",
          "border-radius": "50%",
          "background": "color-mix(in srgb, white 12%, transparent)",
          "transition": "background-color var(--dur-fast, 160ms) var(--ease-out), color var(--dur-fast, 160ms) var(--ease-out)"
        },
        ".glass-button[data-shape=\"circle\"] svg": {
          "width": "55%",
          "height": "55%"
        },
        ".glass-button[aria-pressed=\"true\"] .glass-button-miolo": {
          "background": "white",
          "color": "black"
        },
        ".glass-button[data-shape=\"pill\"][aria-pressed=\"true\"] .glass-button-miolo": {
          "background": "none",
          "color": "inherit"
        },
        ".glass-button[data-shape=\"pill\"][aria-pressed=\"true\"] .glass-button-vidro": {
          "background": "color-mix(in srgb, white 34%, transparent)"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".glass-button, .glass-button-miolo": {
            "transition": "none !important"
          }
        }
      }
    },
    {
      "name": "glass-slider",
      "type": "registry:ui",
      "title": "Glass Slider",
      "description": "Slider cuja lente de vidro refrata o fundo enquanto anda. Volume, brilho ou qualquer nível sobre imagem.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/liquid-glass"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "vidro",
        "slider",
        "volume",
        "brilho",
        "lente"
      ],
      "meta": {
        "uso": {
          "quando": "Nível contínuo sobre foto ou vídeo, como volume ou brilho em player e painel de casa",
          "evite": "Slider em formulário comum: elastic-slider; projeção com conta, sim-slider"
        }
      },
      "css": {
        ".glass-slider": {
          "--u": "calc(100cqw / 1425)",
          "--folga": "calc(30 * var(--u))",
          "--largura": "calc(1365 * var(--u))",
          "position": "relative",
          "width": "100%",
          "aspect-ratio": "1425 / 413",
          "container-type": "inline-size",
          "border-radius": "999px",
          "color": "white",
          "cursor": "grab",
          "touch-action": "pan-y",
          "user-select": "none",
          "-webkit-user-select": "none"
        },
        ".glass-slider:active": {
          "cursor": "grabbing"
        },
        ".glass-slider-trilho": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "linear-gradient(170deg, color-mix(in srgb, white 9%, transparent), color-mix(in srgb, white 15%, transparent))",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 26%, transparent), inset 0 1.5px 0 color-mix(in srgb, white 34%, transparent)"
        },
        ".glass-slider-lente": {
          "--h": "calc(353 * var(--u))",
          "position": "absolute",
          "top": "var(--folga)",
          "bottom": "var(--folga)",
          "left": "var(--folga)",
          "width": "var(--largura)",
          "border-radius": "999px",
          "background": "color-mix(in srgb, black 12%, transparent)",
          "transform": "translateX(calc((var(--p) - 1) * var(--largura)))",
          "-webkit-mask-image": "radial-gradient(circle closest-side, black calc(100% - 0.5px), transparent), radial-gradient(circle closest-side, black calc(100% - 0.5px), transparent), linear-gradient(black 0 0)",
          "mask-image": "radial-gradient(circle closest-side, black calc(100% - 0.5px), transparent), radial-gradient(circle closest-side, black calc(100% - 0.5px), transparent), linear-gradient(black 0 0)",
          "-webkit-mask-repeat": "no-repeat",
          "mask-repeat": "no-repeat",
          "-webkit-mask-size": "var(--h) var(--h), var(--h) var(--h), calc(var(--p) * var(--largura) - var(--h)) 100%",
          "mask-size": "var(--h) var(--h), var(--h) var(--h), calc(var(--p) * var(--largura) - var(--h)) 100%",
          "-webkit-mask-position": "calc((1 - var(--p)) * var(--largura)) 0, 100% 0, calc(calc((1 - var(--p)) * var(--largura)) + var(--h) / 2) 0",
          "mask-position": "calc((1 - var(--p)) * var(--largura)) 0, 100% 0, calc(calc((1 - var(--p)) * var(--largura)) + var(--h) / 2) 0"
        },
        ".glass-slider-anel": {
          "position": "absolute",
          "top": "var(--folga)",
          "bottom": "var(--folga)",
          "left": "var(--folga)",
          "width": "calc(var(--p) * var(--largura))",
          "border-radius": "999px",
          "padding": "1.5px",
          "pointer-events": "none",
          "background": "linear-gradient(100deg, color-mix(in srgb, white 34%, transparent) 0%, color-mix(in srgb, white 52%, transparent) 62%, color-mix(in srgb, white 80%, transparent) 100%)",
          "-webkit-mask": "linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0)",
          "mask": "linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0)"
        },
        ".glass-slider-leitura": {
          "position": "absolute",
          "left": "calc(132 * var(--u))",
          "top": "50%",
          "translate": "0 -50%",
          "display": "flex",
          "align-items": "center",
          "gap": "calc(36 * var(--u))",
          "opacity": "0.84",
          "pointer-events": "none",
          "font": "700 calc(62 * var(--u))/1 var(--font-sans, system-ui)",
          "font-variant-numeric": "tabular-nums"
        },
        ".glass-slider-leitura svg": {
          "width": "calc(102 * var(--u))",
          "height": "calc(102 * var(--u))"
        },
        ".glass-slider input": {
          "position": "absolute",
          "inset": "0",
          "width": "100%",
          "height": "100%",
          "margin": "0",
          "opacity": "0",
          "pointer-events": "none"
        },
        ".glass-slider:has(input:focus-visible)": {
          "outline": "2px solid white",
          "outline-offset": "3px"
        }
      }
    },
    {
      "name": "glass-tabs",
      "type": "registry:ui",
      "title": "Glass Tabs",
      "description": "Abas em que a seleção é uma lente de vidro andando sobre o trilho, com setas, Home e End.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/liquid-glass",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-tabs.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "vidro",
        "abas",
        "segmentado",
        "navegacao",
        "lente"
      ],
      "meta": {
        "uso": {
          "quando": "Alternar de 2 a 5 opções sobre foto ou vídeo, como barra flutuante ou seletor de modo",
          "evite": "Fundo liso ou claro: segmented-control; muitas opções, morph-select"
        }
      },
      "css": {
        ".glass-tabs": {
          "--folga": "4px",
          "position": "relative",
          "display": "inline-grid",
          "grid-auto-flow": "column",
          "grid-auto-columns": "1fr",
          "padding": "var(--folga)",
          "border-radius": "999px",
          "color": "white",
          "font": "500 0.875rem/1 var(--font-sans, system-ui)"
        },
        ".glass-tabs-trilho": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "color-mix(in srgb, white 10%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 24%, transparent), inset 0 1.5px 0 color-mix(in srgb, white 28%, transparent)"
        },
        ".glass-tabs-lente": {
          "position": "absolute",
          "top": "var(--folga)",
          "bottom": "var(--folga)",
          "left": "var(--folga)",
          "width": "calc((100% - 2 * var(--folga)) / var(--n))",
          "border-radius": "999px",
          "background": "color-mix(in srgb, white 16%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 40%, transparent)",
          "transform": "translateX(calc(var(--i) * 100%))",
          "transition": "transform 460ms cubic-bezier(0.3, 1.15, 0.4, 1)",
          "will-change": "transform"
        },
        ".glass-tabs button": {
          "position": "relative",
          "display": "inline-flex",
          "align-items": "center",
          "justify-content": "center",
          "gap": "0.5rem",
          "min-height": "2.75rem",
          "padding": "0 1.25rem",
          "border": "0",
          "border-radius": "999px",
          "background": "none",
          "color": "color-mix(in srgb, white 72%, transparent)",
          "font": "inherit",
          "white-space": "nowrap",
          "cursor": "pointer",
          "transition": "color var(--dur-base, 200ms) var(--ease-out)"
        },
        ".glass-tabs button[aria-selected=\"true\"]": {
          "color": "white"
        },
        ".glass-tabs button:focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "-2px"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".glass-tabs-lente, .glass-tabs button": {
            "transition": "none"
          }
        }
      }
    },
    {
      "name": "glass-switch",
      "type": "registry:ui",
      "title": "Glass Switch",
      "description": "Interruptor com polegar de vidro: o ligado aparece refratado através dele, em --brand.",
      "dependencies": [],
      "registryDependencies": [
        "utils",
        "@visant/liquid-glass",
        "@visant/motion"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-switch.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "vidro",
        "switch",
        "toggle",
        "formulario"
      ],
      "meta": {
        "uso": {
          "quando": "Liga e desliga sobre foto ou vídeo, em painel flutuante ou tela de produto",
          "evite": "Sem vidro, com a bolinha escorrendo como gota: liquid-toggle; formulário comum, switch"
        }
      },
      "css": {
        ".glass-switch": {
          "position": "relative",
          "display": "inline-block",
          "flex": "none",
          "width": "5rem",
          "height": "2.75rem",
          "padding": "0",
          "border": "0",
          "border-radius": "999px",
          "background": "color-mix(in srgb, white 10%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 24%, transparent), inset 0 1.5px 0 color-mix(in srgb, white 28%, transparent)",
          "cursor": "pointer"
        },
        ".glass-switch:focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "2px"
        },
        ".glass-switch:disabled": {
          "opacity": "0.5",
          "cursor": "default"
        },
        ".glass-switch-fundo": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "var(--brand)",
          "opacity": "0",
          "transition": "opacity var(--dur-slow, 300ms) var(--ease-out)"
        },
        ".glass-switch[aria-checked=\"true\"] .glass-switch-fundo": {
          "opacity": "1"
        },
        ".glass-switch-polegar": {
          "position": "absolute",
          "top": "3px",
          "bottom": "3px",
          "left": "3px",
          "width": "3rem",
          "border-radius": "999px",
          "background": "color-mix(in srgb, white 22%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 50%, transparent), 0 3px 10px color-mix(in srgb, black 35%, transparent)",
          "transition": "transform 440ms cubic-bezier(0.34, 1.4, 0.64, 1), scale var(--dur-press, 120ms) var(--ease-out)"
        },
        ".glass-switch[aria-checked=\"true\"] .glass-switch-polegar": {
          "transform": "translateX(calc(5rem - 3rem - 6px))"
        },
        ".glass-switch:active:not(:disabled) .glass-switch-polegar": {
          "scale": "1.14 0.9"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".glass-switch-fundo, .glass-switch-polegar": {
            "transition": "none"
          }
        }
      }
    },
    {
      "name": "glass-board",
      "type": "registry:ui",
      "title": "Glass Board",
      "description": "Quadro em vidro fosco sobre foto, com busca e cartões que arrastam entre colunas. A roupa de vidro do kanban.",
      "dependencies": [
        "lucide-react"
      ],
      "registryDependencies": [
        "utils",
        "@visant/glass-panel",
        "@visant/kanban"
      ],
      "files": [
        {
          "path": "registry/visant/ui/glass-board.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "vidro",
        "fosco",
        "kanban",
        "board",
        "dnd"
      ],
      "meta": {
        "uso": {
          "quando": "Pipeline ou board de tarefas com a foto da marca atrás, em produto com visual próprio",
          "evite": "Ferramenta interna densa, com seleção múltipla: kanban; lista pra ordenar e editar, data-table"
        }
      },
      "css": {
        ".glass-board": {
          "--glass-panel-radius": "14px",
          "--glass-panel-filter": "blur(24px) saturate(0.72)",
          "--glass-panel-fill": "linear-gradient(180deg, color-mix(in srgb, black 40%, transparent), color-mix(in srgb, black 30%, transparent))",
          "display": "flex",
          "overflow": "hidden",
          "color": "color-mix(in srgb, white 92%, transparent)",
          "font": "500 12px/1.3 var(--font-sans, system-ui)"
        },
        ".glass-board button": {
          "font": "inherit",
          "color": "inherit",
          "cursor": "pointer",
          "border": "0",
          "background": "none"
        },
        ".glass-board :focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "2px"
        },
        ".glass-board-lateral": {
          "flex": "none",
          "width": "56px",
          "display": "flex",
          "flex-direction": "column",
          "align-items": "center",
          "gap": "22px",
          "padding": "12px 0 16px",
          "border-right": "1px solid color-mix(in srgb, white 8%, transparent)"
        },
        ".glass-board-corpo": {
          "position": "relative",
          "flex": "1",
          "min-width": "0",
          "display": "flex",
          "flex-direction": "column",
          "padding": "12px 12px 0 16px"
        },
        ".glass-board-topo": {
          "display": "flex",
          "align-items": "center",
          "gap": "10px"
        },
        ".glass-board-busca": {
          "display": "flex",
          "align-items": "center",
          "gap": "8px",
          "flex": "0 1 212px",
          "min-width": "0",
          "height": "32px",
          "padding": "0 9px",
          "margin-right": "auto",
          "border-radius": "7px",
          "color": "color-mix(in srgb, white 60%, transparent)",
          "box-shadow": "inset 0 0 0 1px color-mix(in srgb, white 10%, transparent)",
          "background": "color-mix(in srgb, white 3%, transparent)"
        },
        ".glass-board-busca input": {
          "flex": "1",
          "min-width": "0",
          "height": "100%",
          "border": "0",
          "outline": "0",
          "background": "none",
          "color": "white",
          "font": "400 11px var(--font-sans, system-ui)"
        },
        ".glass-board-busca input::placeholder": {
          "color": "color-mix(in srgb, white 56%, transparent)"
        },
        ".glass-board-titulo": {
          "margin": "13px 0 10px",
          "font": "600 16px var(--font-sans, system-ui)"
        },
        ".glass-board-rolagem": {
          "flex": "1",
          "min-height": "0",
          "margin-top": "10px",
          "overflow": "auto hidden",
          "padding-bottom": "12px"
        },
        ".glass-board-titulo + .glass-board-rolagem": {
          "margin-top": "0"
        },
        ".glass-board .kanban-root": {
          "--kanban-gap": "12px",
          "--kanban-col-min": "132px",
          "--kanban-col-max": "none",
          "--kanban-card-gap": "8px",
          "--kanban-card-radius": "7px",
          "--kanban-column-min-h": "0",
          "--kanban-accent": "white",
          "width": "100%",
          "align-items": "flex-start"
        },
        ".glass-board .kanban-column": {
          "flex": "1 1 0",
          "padding": "8px",
          "border-radius": "12px",
          "background": "color-mix(in srgb, white 11%, transparent)",
          "min-width": "132px"
        },
        ".glass-board .kanban-column-body": {
          "max-height": "none",
          "overflow": "visible"
        },
        ".glass-board-coluna": {
          "display": "flex",
          "align-items": "center",
          "gap": "7px",
          "height": "28px",
          "margin": "0 -4px 5px 11px"
        },
        ".glass-board-coluna h2": {
          "margin": "0",
          "font": "500 12.5px var(--font-sans, system-ui)"
        },
        ".glass-board-coluna span": {
          "display": "grid",
          "place-items": "center",
          "min-width": "16px",
          "height": "16px",
          "border-radius": "999px",
          "font-size": "10px",
          "background": "color-mix(in srgb, black 34%, transparent)"
        },
        ".glass-board-coluna button": {
          "margin-left": "auto",
          "display": "grid",
          "place-items": "center",
          "width": "28px",
          "height": "28px",
          "color": "color-mix(in srgb, white 42%, transparent)"
        },
        ".glass-board-coluna button:disabled": {
          "opacity": "0.5",
          "cursor": "default"
        },
        ".glass-board-coluna button:not(:focus-visible)": {
          "opacity": "0",
          "transition": "opacity var(--dur-fast, 160ms) var(--ease-out)"
        },
        ".glass-board .kanban-column:hover .glass-board-coluna button": {
          "opacity": "1"
        },
        "@media (hover: none)": {
          ".glass-board-coluna button": {
            "opacity": "1 !important"
          }
        },
        ".glass-board-cartao": {
          "position": "relative",
          "display": "block",
          "padding": "10px 11px 9px",
          "border-radius": "7px",
          "background": "color-mix(in srgb, black 32%, transparent)",
          "color": "color-mix(in srgb, white 92%, transparent)",
          "font": "500 10.5px/1.45 var(--font-sans, system-ui)"
        },
        ".glass-board-cartao header": {
          "position": "relative",
          "display": "flex",
          "align-items": "center",
          "gap": "6px",
          "margin-bottom": "8px"
        },
        ".glass-board-cartao i": {
          "display": "grid",
          "place-items": "center",
          "width": "16px",
          "height": "16px",
          "border-radius": "50%",
          "font": "600 7px var(--font-sans, system-ui)",
          "background": "color-mix(in srgb, white 16%, transparent)"
        },
        ".glass-board-cartao b": {
          "font-weight": "600",
          "font-size": "10px"
        },
        ".glass-board-cartao time": {
          "margin-left": "auto",
          "font-size": "10px",
          "color": "color-mix(in srgb, white 62%, transparent)"
        },
        ".glass-board-cartao em": {
          "position": "absolute",
          "top": "-5px",
          "right": "-6px",
          "width": "5px",
          "height": "5px",
          "border-radius": "50%",
          "background": "var(--destructive)"
        },
        ".glass-board-cartao p": {
          "margin": "0"
        },
        ".glass-board-cartao small": {
          "font-size": "10.5px",
          "color": "color-mix(in srgb, white 62%, transparent)"
        },
        ".glass-board-cartao[data-no-ar]": {
          "rotate": "-4.5deg",
          "background": "color-mix(in srgb, black 78%, transparent)",
          "color": "white",
          "box-shadow": "0 16px 28px -8px color-mix(in srgb, black 55%, transparent)"
        },
        ".glass-board-adicionar": {
          "display": "flex",
          "align-items": "center",
          "gap": "9px",
          "width": "100%",
          "height": "34px",
          "padding": "0 12px",
          "font-size": "11.5px !important",
          "font-weight": "600 !important",
          "border-radius": "7px"
        },
        ".kanban-card:has(> .glass-board-adicionar)": {
          "cursor": "default"
        },
        ".glass-board-canto": {
          "position": "absolute",
          "right": "12px",
          "bottom": "12px",
          "z-index": "2"
        },
        "@media (max-width: 639px)": {
          ".glass-board-lateral": {
            "display": "none"
          },
          ".glass-board-corpo": {
            "padding-left": "12px"
          }
        }
      }
    },
    {
      "name": "color-picker",
      "type": "registry:ui",
      "title": "Color Picker",
      "description": "Seletor de cor de editor: arraste no campo e na matiz, digite o valor exato, pegue uma cor da tela ou use as amostras da marca.",
      "dependencies": [
        "react-colorful",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/color-picker.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "cor",
        "seletor",
        "hex",
        "conta-gotas",
        "paleta",
        "editor"
      ],
      "meta": {
        "uso": {
          "quando": "Escolher uma cor livre num editor, tema ou painel de marca",
          "evite": "Escolher entre poucas cores fixas: chip; ajustar um número: scrub-input"
        }
      }
    },
    {
      "name": "sensor-dial",
      "type": "registry:ui",
      "title": "Sensor Dial",
      "description": "Mira de pareamento: gire o feixe até o alvo, e o disco cresce conforme chega perto. Em repouso, o feixe procura sozinho.",
      "dependencies": [
        "motion",
        "lucide-react"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/sensor-dial.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "mostrador",
        "pareamento",
        "mira",
        "sensor",
        "camera"
      ],
      "meta": {
        "uso": {
          "quando": "Passo de parear ou alinhar um dispositivo, em app de IoT ou de câmera",
          "evite": "Escolher uma hora: time-dial; mostrar um nível sem interação, gauge"
        }
      },
      "css": {
        ".sensor-dial": {
          "--folha": "var(--sensor-sheet, var(--brand))",
          "--tinta": "var(--sensor-ink, color-mix(in srgb, black 88%, navy))",
          "position": "relative",
          "display": "flex",
          "flex-direction": "column",
          "align-items": "center",
          "width": "100%",
          "height": "100%",
          "min-height": "26rem",
          "overflow": "hidden",
          "container-type": "inline-size",
          "border-radius": "inherit",
          "font-family": "var(--font-sans, system-ui)",
          "background": "radial-gradient(64cqw 84cqw at 50% 74cqw, var(--tinta) 58%, color-mix(in srgb, var(--tinta) 62%, var(--folha)) 78%, var(--folha) 100%)"
        },
        ".sensor-dial-titulo": {
          "margin": "6.5cqw 0 0",
          "color": "var(--sensor-title, var(--brand-foreground))",
          "font-size": "5.2cqw",
          "font-weight": "400",
          "line-height": "1.2",
          "text-align": "center",
          "white-space": "pre-line"
        },
        ".sensor-dial-mostrador": {
          "flex": "none",
          "width": "92cqw",
          "aspect-ratio": "1",
          "margin-top": "1cqw",
          "border-radius": "50%",
          "cursor": "grab",
          "outline": "0",
          "touch-action": "none"
        },
        ".sensor-dial-mostrador:active": {
          "cursor": "grabbing"
        },
        ".sensor-dial-mostrador:focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "-6px"
        },
        ".sensor-dial-marca": {
          "stroke": "white",
          "stroke-width": "1.8",
          "stroke-linecap": "round"
        },
        ".sensor-dial-eixo": {
          "stroke": "color-mix(in srgb, white 72%, transparent)",
          "stroke-width": "1",
          "stroke-dasharray": "2 3"
        },
        ".sensor-dial-orbita": {
          "fill": "none",
          "stroke": "color-mix(in srgb, white 48%, transparent)",
          "stroke-width": "1.2"
        },
        ".sensor-dial-feixe": {
          "stroke": "color-mix(in srgb, white 76%, transparent)",
          "stroke-width": "1.5"
        },
        ".sensor-dial-alvo": {
          "stroke": "var(--sensor-hit, var(--brand))",
          "stroke-width": "2.2"
        },
        ".sensor-dial-disco": {
          "fill": "white",
          "filter": "drop-shadow(0 3px 7px color-mix(in srgb, black 60%, transparent))"
        },
        ".sensor-dial-aro": {
          "fill": "none",
          "stroke": "color-mix(in srgb, white 82%, black)",
          "stroke-width": "1.5"
        },
        ".sensor-dial-lente": {
          "fill": "color-mix(in srgb, white 65%, black)"
        },
        ".sensor-dial-guia": {
          "position": "absolute",
          "left": "13cqw",
          "bottom": "-2cqw",
          "width": "74cqw",
          "height": "auto",
          "overflow": "visible",
          "fill": "none",
          "stroke": "color-mix(in srgb, white 62%, transparent)",
          "stroke-width": "1.1",
          "pointer-events": "none"
        },
        ".sensor-dial-guia circle": {
          "fill": "white",
          "stroke": "none"
        },
        ".sensor-dial-acao": {
          "position": "absolute",
          "bottom": "8cqw",
          "left": "50%",
          "translate": "-50% 0",
          "display": "flex",
          "align-items": "center",
          "justify-content": "space-between",
          "width": "62cqw",
          "min-height": "2.75rem",
          "height": "14.5cqw",
          "padding": "0 2cqw 0 7cqw",
          "border": "0",
          "border-radius": "4.5cqw",
          "color": "white",
          "font": "400 max(0.8125rem, 4.3cqw) var(--font-sans, system-ui)",
          "cursor": "pointer",
          "background": "color-mix(in srgb, black 44%, transparent)",
          "-webkit-backdrop-filter": "blur(10px)",
          "backdrop-filter": "blur(10px)"
        },
        ".sensor-dial-acao i": {
          "display": "grid",
          "place-items": "center",
          "width": "10.5cqw",
          "height": "10.5cqw",
          "border-radius": "50%",
          "color": "black",
          "background": "white",
          "transition": "transform var(--dur-fast, 160ms) var(--ease-out)"
        },
        ".sensor-dial-acao:active i": {
          "transform": "scale(0.94)"
        },
        ".sensor-dial-acao:focus-visible": {
          "outline": "2px solid white",
          "outline-offset": "2px"
        },
        "@media (prefers-reduced-motion: reduce)": {
          ".sensor-dial-acao i": {
            "transition": "none"
          }
        }
      }
    },
    {
      "name": "device-frame",
      "type": "registry:ui",
      "title": "Device Frame",
      "description": "Aparelho em CSS 3D com a tela viva dentro: celular, tablet ou notebook, cinco poses, entrada animada e balanço por ponteiro, flutuação ou rolagem.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/device-frame.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "mockup",
        "celular",
        "aparelho",
        "3d",
        "tela"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar uma tela de app funcionando em hero ou página de produto",
          "evite": "Giro de 360° ou objeto de verdade: lathe-object; só uma foto de tela, photo-frame"
        }
      },
      "css": {
        ".device-frame": {
          "--device-body": "color-mix(in srgb, white 14%, black)",
          "--device-edge": "color-mix(in srgb, white 28%, black)",
          "position": "relative",
          "width": "100%",
          "aspect-ratio": "1 / 2.05",
          "container-type": "inline-size",
          "perspective": "var(--device-perspective, 1400px)"
        },
        ".device-frame[data-finish=\"silver\"]": {
          "--device-body": "color-mix(in srgb, white 78%, black)",
          "--device-edge": "color-mix(in srgb, white 92%, black)"
        },
        ".device-frame-corpo": {
          "position": "absolute",
          "inset": "0",
          "transform-style": "preserve-3d",
          "border-radius": "15cqw",
          "will-change": "transform"
        },
        ".device-frame-camada": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "var(--device-edge)",
          "transform": "translateZ(calc(var(--c) * var(--device-step, -0.45cqw)))"
        },
        ".device-frame-botao": {
          "position": "absolute",
          "top": "var(--t)",
          "height": "var(--a)",
          "width": "1cqw",
          "border-radius": "1cqw",
          "background": "var(--device-edge)",
          "transform": "translateZ(-2.2cqw)"
        },
        ".device-frame-botao[data-lado=\"e\"]": {
          "left": "-0.7cqw"
        },
        ".device-frame-botao[data-lado=\"d\"]": {
          "right": "-0.7cqw"
        },
        ".device-frame-frente": {
          "position": "absolute",
          "inset": "0",
          "padding": "3.5cqw",
          "border-radius": "inherit",
          "background": "var(--device-body)",
          "box-shadow": "inset 0 0 0 1px var(--device-edge), inset 0 0 0 0.9cqw black"
        },
        ".device-frame-tela": {
          "position": "relative",
          "width": "100%",
          "height": "100%",
          "overflow": "hidden",
          "border-radius": "11.5cqw",
          "background": "black"
        },
        ".device-frame-ilha": {
          "position": "absolute",
          "top": "2.6cqw",
          "left": "50%",
          "translate": "-50% 0",
          "width": "26cqw",
          "height": "7cqw",
          "border-radius": "999px",
          "background": "black",
          "pointer-events": "none"
        },
        ".device-frame-brilho": {
          "position": "absolute",
          "inset": "0 -30%",
          "pointer-events": "none",
          "background": "linear-gradient(112deg, transparent 38%, color-mix(in srgb, white var(--device-glare, 7%), transparent) 48%, transparent 58%)"
        },
        ".device-frame[data-device=\"tablet\"]": {
          "--device-step": "-0.13cqw",
          "aspect-ratio": "4 / 3"
        },
        ".device-frame[data-device=\"tablet\"] .device-frame-corpo": {
          "border-radius": "3.6cqw"
        },
        ".device-frame[data-device=\"tablet\"] .device-frame-frente": {
          "padding": "2.4cqw",
          "background": "color-mix(in srgb, white 4%, black)",
          "box-shadow": "inset 0 0 0 0.3cqw var(--device-edge)"
        },
        ".device-frame[data-device=\"tablet\"] .device-frame-tela": {
          "border-radius": "1.4cqw"
        },
        ".device-frame-camera": {
          "position": "absolute",
          "top": "0.85cqw",
          "left": "50%",
          "translate": "-50% 0",
          "width": "0.7cqw",
          "height": "0.7cqw",
          "border-radius": "50%",
          "background": "color-mix(in srgb, white 14%, black)"
        },
        ".device-frame-botao[data-lado=\"t\"]": {
          "top": "-0.35cqw",
          "left": "var(--t)",
          "width": "var(--a)",
          "height": "0.5cqw",
          "border-radius": "0.5cqw",
          "transform": "translateZ(-0.7cqw)"
        },
        ".device-frame[data-device=\"laptop\"]": {
          "--device-step": "-0.05cqw",
          "aspect-ratio": "16 / 10"
        },
        ".device-frame[data-device=\"laptop\"] .device-frame-corpo": {
          "border-radius": "1.9cqw"
        },
        ".device-frame[data-device=\"laptop\"] .device-frame-frente": {
          "padding": "1.1cqw",
          "background": "color-mix(in srgb, white 3%, black)",
          "box-shadow": "inset 0 0 0 0.22cqw var(--device-edge)"
        },
        ".device-frame[data-device=\"laptop\"] .device-frame-tela": {
          "border-radius": "0.8cqw"
        },
        ".device-frame[data-device=\"laptop\"] .device-frame-ilha": {
          "top": "0",
          "width": "11cqw",
          "height": "1.5cqw",
          "border-radius": "0 0 0.7cqw 0.7cqw"
        },
        ".device-frame-base": {
          "--device-step": "-0.16cqw",
          "position": "absolute",
          "top": "100%",
          "left": "-1cqw",
          "right": "-1cqw",
          "height": "68cqw",
          "border-radius": "0.6cqw 0.6cqw 2cqw 2cqw",
          "transform-origin": "50% 0",
          "transform": "rotateX(70deg)",
          "transform-style": "preserve-3d"
        },
        ".device-frame-deck": {
          "position": "absolute",
          "inset": "0",
          "border-radius": "inherit",
          "background": "var(--device-body)",
          "box-shadow": "inset 0 0 0 0.2cqw var(--device-edge)"
        },
        ".device-frame-teclado": {
          "position": "absolute",
          "top": "4%",
          "left": "5%",
          "right": "5%",
          "height": "52%",
          "border-radius": "0.6cqw",
          "background-color": "color-mix(in srgb, black 62%, var(--device-body))",
          "background-image": "repeating-linear-gradient(90deg, var(--device-body) 0 0.24cqw, transparent 0.24cqw 6.55cqw), repeating-linear-gradient(0deg, var(--device-body) 0 0.24cqw, transparent 0.24cqw 5.9cqw)"
        },
        ".device-frame-trackpad": {
          "position": "absolute",
          "top": "60%",
          "left": "50%",
          "translate": "-50% 0",
          "width": "38cqw",
          "height": "34%",
          "border-radius": "1cqw",
          "background": "color-mix(in srgb, white 5%, var(--device-body))",
          "box-shadow": "inset 0 0 0 0.12cqw var(--device-edge)"
        }
      }
    },
    {
      "name": "use-idle",
      "type": "registry:hook",
      "title": "useIdle",
      "description": "Chama uma função enquanto a peça está na tela e ninguém mexe nela, e cala com movimento reduzido. Vem com useInView.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "motion"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-idle.ts",
          "type": "registry:hook",
          "target": "@hooks/use-idle.ts"
        }
      ],
      "categories": [
        "fundacao",
        "hook",
        "gesto",
        "toque"
      ],
      "meta": {
        "uso": {
          "quando": "Peça com gesto que precisa parecer viva no celular, onde não existe hover",
          "evite": "Animação contínua: requestAnimationFrame no próprio componente"
        }
      }
    },
    {
      "name": "use-tilt",
      "type": "registry:hook",
      "title": "useTilt",
      "description": "A inclinação lateral do celular, com o pedido de permissão do iOS dentro do gesto. Sem sensor, nada acontece.",
      "author": "Visant Labs <visantsupply@gmail.com>",
      "dependencies": [
        "react"
      ],
      "files": [
        {
          "path": "registry/visant/hooks/use-tilt.ts",
          "type": "registry:hook",
          "target": "@hooks/use-tilt.ts"
        }
      ],
      "categories": [
        "fundacao",
        "hook",
        "giroscopio",
        "toque"
      ],
      "meta": {
        "uso": {
          "quando": "Deixar a inclinação do aparelho pilotar uma peça que já funciona por arrasto",
          "evite": "Como única entrada: boa parte dos aparelhos não concede o sensor"
        }
      }
    },
    {
      "name": "compass",
      "type": "registry:ui",
      "title": "Compass",
      "description": "Bússola em camadas: a agulha vai até o ponteiro, passa e volta, e o mostrador inclina em direção à mão.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/use-idle"
      ],
      "files": [
        {
          "path": "registry/visant/ui/compass.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "bussola",
        "mostrador",
        "3d",
        "mola",
        "direcao"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar ou escolher uma direção, ou dar um objeto vivo a uma página que fala de rumo",
          "evite": "Alinhar com um alvo: sensor-dial; escolher uma hora: time-dial"
        }
      }
    },
    {
      "name": "drip-word",
      "type": "registry:ui",
      "title": "Drip Word",
      "description": "Uma palavra de tinta viscosa em shader: dos pés das letras descem fios que soltam a gota, e arrastar de lado inclina a gravidade.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/css-color",
        "@visant/use-tilt"
      ],
      "files": [
        {
          "path": "registry/visant/ui/drip-word.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "texto",
        "shader",
        "webgl",
        "liquido",
        "gota",
        "palavra",
        "tipografia"
      ],
      "meta": {
        "uso": {
          "quando": "Uma palavra de abertura com presença, em dobra de marca ou tela de entrada",
          "evite": "Texto que derrete sob o cursor: heat-word; texto corrido ou título longo: line-reveal"
        }
      }
    },
    {
      "name": "ratchet",
      "type": "registry:ui",
      "title": "Ratchet",
      "description": "Catraca de aço: o gesto dá corda numa roda que só gira para um lado, com a lingueta caindo a cada dente.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/use-idle"
      ],
      "files": [
        {
          "path": "registry/visant/ui/ratchet.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "catraca",
        "engrenagem",
        "metal",
        "gesto",
        "clique"
      ],
      "meta": {
        "uso": {
          "quando": "Um gesto de dar corda: contar passos para a frente, avançar sem poder voltar",
          "evite": "Ajustar um número nos dois sentidos: scrub-input; girar para os dois lados: vintage-knob"
        }
      }
    },
    {
      "name": "raking-light",
      "type": "registry:ui",
      "title": "Raking Light",
      "description": "Relevo seco em papel com fibra: a palavra só existe na sombra e no brilho de uma lâmpada baixa.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/use-idle"
      ],
      "files": [
        {
          "path": "registry/visant/ui/raking-light.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "texto",
        "relevo",
        "papel",
        "luz",
        "textura",
        "grao",
        "tipografia"
      ],
      "meta": {
        "uso": {
          "quando": "Uma palavra ou nome com tato de papel, em abertura de marca ou capa",
          "evite": "Palavra que precisa ser lida de imediato ou em texto pequeno: line-reveal"
        }
      }
    },
    {
      "name": "word-dial",
      "type": "registry:ui",
      "title": "Word Dial",
      "description": "Um anel que reordena as letras de uma palavra em linha, onda, anel, escada e espelho, com paradas como um tambor de caleidoscópio.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/use-idle"
      ],
      "files": [
        {
          "path": "registry/visant/ui/word-dial.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "texto",
        "palavra",
        "tipografia",
        "marca",
        "anel",
        "arranjo"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar uma marca ou palavra-chave que muda de arranjo sem deixar de ser ela",
          "evite": "Trocar uma palavra por outra: text-morph; escolher entre opções de verdade: segmented-control"
        }
      }
    },
    {
      "name": "detent-slider",
      "type": "registry:ui",
      "title": "Detent Slider",
      "description": "Slider com paradas que agarram e a consequência em letra grande, com dígitos que rolam antes de confirmar.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/visant/ui/detent-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "controles",
        "slider",
        "paradas",
        "percentual",
        "formulario",
        "digitos"
      ],
      "meta": {
        "uso": {
          "quando": "Escolher quanto de algo, vendo o resultado antes de confirmar: fechar parte, dividir, repartir",
          "evite": "Simular um cenário com vários valores: sim-slider; ajustar sem consequência a mostrar: elastic-slider"
        }
      }
    },
    {
      "name": "route-profile",
      "type": "registry:ui",
      "title": "Route Profile",
      "description": "Perfil de terreno que se lê arrastando: a altitude e a rampa sob o cursor, e um clinômetro cuja agulha balança com a inclinação.",
      "dependencies": [
        "motion"
      ],
      "registryDependencies": [
        "utils",
        "@visant/use-idle",
        "@visant/use-tilt"
      ],
      "files": [
        {
          "path": "registry/visant/ui/route-profile.tsx",
          "type": "registry:ui"
        }
      ],
      "author": "Visant Labs <visantsupply@gmail.com>",
      "categories": [
        "conteudo",
        "rota",
        "grafico",
        "altitude",
        "terreno",
        "clinometro"
      ],
      "meta": {
        "uso": {
          "quando": "Mostrar uma rota, trilha ou prova pelo relevo, com leitura ponto a ponto",
          "evite": "Uma série de números sem terreno: streamgraph; só um nível, sem percurso: gauge"
        }
      }
    }
  ]
}
