Bars Theme
nexvyn/bars-themeFreeComponent
A traveling-wave bars visualization with 5 vertical bars sharing a sine-wave frequency, evenly phase-shifted left to right so the wave appears to travel across. Volume scales bar heights with a diamond-shaped idle boost.
Live preview
live · rendered by the registry
Rendered by nexvyn on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.nexvyn.dev/r/bars-theme.jsonSource
1'use client'23import { useEffect, useRef } from 'react'4import type { AriaAttributes, CSSProperties } from 'react'5import { useReducedMotion } from 'motion/react'6import { useCssColorRgb } from '@/lib/hooks/use-css-color-rgb'78export type OrbState = 'idle' | 'connecting' | 'listening' | 'thinking' | 'speaking' | 'error'910type DataAttributeValue = string | number | boolean | null | undefined1112export interface OrbHtmlAttributes extends AriaAttributes {13 id?: string14 title?: string15 role?: string16 tabIndex?: number17 [dataAttribute: `data-${string}`]: DataAttributeValue18}1920export interface BarsThemeProps extends OrbHtmlAttributes {21 state: OrbState22 volume: number23 size: number24 className?: string25 style?: CSSProperties26 disabled?: boolean27 interactive?: boolean28 onClick?: () => void29}3031const BAR_COUNT = 532const WAVE_FREQ = 1.433const WAVE_PHASE_STEP = (Math.PI * 2) / BAR_COUNT3435const STATE_COLOR_TOKEN: Record<OrbState, 'accent' | 'destructive'> = {36 idle: 'accent',37 connecting: 'accent',38 listening: 'accent',39 thinking: 'accent',40 speaking: 'accent',41 error: 'destructive',42}4344const FALLBACK_ACCENT: [number, number, number] = [26, 115, 242]45const FALLBACK_DESTRUCTIVE: [number, number, number] = [232, 80, 80]4647const BLEND_MS = 2804849export function BarsTheme({50 state,51 volume,52 size,53 className,54 style,55 disabled = false,56 interactive = false,57 onClick,58 ...controlProps59}: BarsThemeProps) {60 const barRefs = useRef<(HTMLSpanElement | null)[]>([])61 const containerRef = useRef<HTMLSpanElement>(null)62 const rafRef = useRef<number>(0)63 const smoothed = useRef<number[]>(new Array(BAR_COUNT).fill(0))64 const volumeRef = useRef(volume)65 const hoveredRef = useRef(false)66 const hoverBoostRef = useRef(0)67 const blendStartRef = useRef<number | null>(null)68 const frozenHeightsRef = useRef<number[]>(new Array(BAR_COUNT).fill(0))69 const prevStateRef = useRef(state)70 const touchEndTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)7172 const reduceMotion = useReducedMotion()7374 const accentRgb = useCssColorRgb('--color-accent', FALLBACK_ACCENT)75 const destructiveRgb = useCssColorRgb('--color-destructive', FALLBACK_DESTRUCTIVE)76 const accentRgbRef = useRef(accentRgb)77 const destructiveRgbRef = useRef(destructiveRgb)78 const currentColorRef = useRef<[number, number, number]>(accentRgb)79 useEffect(() => {80 accentRgbRef.current = accentRgb81 }, [accentRgb])82 useEffect(() => {83 destructiveRgbRef.current = destructiveRgb84// … truncated
What it pulls in
npm packages
Files it writes
More from nexvyn
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Badgebadge | nexvyn | Components | Free | 2 deps · 2 files | |
| Bounce Sidebarbounce-sidebar | nexvyn | Components | Free | 1 dep · 2 files | |
| Breadcrumbsbreadcrumbs | nexvyn | Components | Free | 1 dep · 2 files | |
| Checkboxcheckbox | nexvyn | Components | Free | 1 dep · 3 files | |
| Clipboard Fieldclipboard-field | nexvyn | Components | Free | no deps · 2 files | |
| Color Pickercolor-picker | nexvyn | Components | Free | no deps · 16 files | |
| Comboboxcombobox | nexvyn | Components | Free | 1 dep · 2 files | |
| Context Menucontext-menu | nexvyn | Components | Free | 1 dep · 2 files |
