{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "wave-field", "title": "Wave Field", "description": "A periodic glyph encoding rhythm rather than trend. Arcade, sine and pulse variants.", "dependencies": [ "class-variance-authority" ], "registryDependencies": [ "http://localhost:5173/r/liquid-theme.json", "http://localhost:5173/r/liquid-path.json" ], "files": [ { "path": "src/components/ui/wave-field.tsx", "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { linePath, scale, smoothPath } from \"@/lib/liquid-path\"\n\nconst wave = cva(\"block max-w-full overflow-visible\", {\n variants: {\n tone: {\n ink: \"text-ink dark:text-white\",\n current: \"text-current\",\n volt: \"text-volt\",\n flare: \"text-flare\",\n muted: \"text-current opacity-40\",\n },\n },\n defaultVariants: { tone: \"ink\" },\n})\n\n/**\n * The periodic glyph on the Total Accounts tile. It encodes rhythm rather than\n * a data series — use it where the fact is \"this recurs\", not \"this trended\".\n */\nexport interface WaveFieldProps\n extends React.ComponentProps<\"svg\">,\n VariantProps {\n /** `arcade` is the reference: flat troughs with rounded crowns. */\n variant?: \"arcade\" | \"sine\" | \"pulse\"\n periods?: number\n width?: number\n height?: number\n strokeWidth?: number\n /** 0–1. Flattens the wave without changing the box. */\n amplitude?: number\n}\n\nfunction samples(variant: \"arcade\" | \"sine\" | \"pulse\", periods: number, amplitude: number) {\n const out: number[] = []\n // Arcade holds the trough for four samples and the crown for two, so the\n // smoother rounds only the shoulders — flat bottoms, domed tops.\n const perPeriod = variant === \"sine\" ? 12 : variant === \"arcade\" ? 6 : 4\n\n for (let i = 0; i <= periods * perPeriod; i++) {\n if (variant === \"sine\") {\n out.push((Math.sin((i / perPeriod) * Math.PI * 2) * 0.5 + 0.5) * amplitude)\n } else if (variant === \"arcade\") {\n const phase = i % 6\n out.push((phase === 4 || phase === 5 ? 1 : 0) * amplitude)\n } else {\n const phase = i % 4\n out.push((phase === 2 || phase === 3 ? 1 : 0) * amplitude)\n }\n }\n return out\n}\n\nexport function WaveField({\n variant = \"arcade\",\n periods = 4,\n width = 130,\n height = 34,\n strokeWidth = 1.5,\n amplitude = 1,\n tone,\n className,\n ...props\n}: WaveFieldProps) {\n const pad = strokeWidth + 1\n const values = React.useMemo(\n () => samples(variant, periods, amplitude),\n [variant, periods, amplitude],\n )\n const points = React.useMemo(\n () => scale(values, width, height, { pad, min: 0, max: 1 }),\n [values, width, height, pad],\n )\n const d = variant === \"pulse\" ? linePath(points) : smoothPath(points, variant === \"arcade\" ? 1 : 0.5)\n\n return (\n \n \n \n )\n}\n", "type": "registry:ui" } ], "type": "registry:ui" }