33import { useEffect , useMemo , useState } from 'react' ;
44import { type VariantProps } from 'class-variance-authority' ;
55import { Track } from 'livekit-client' ;
6+ import { RoomAudioRenderer , StartAudio } from '@livekit/components-react' ;
67import {
78 type AgentState ,
89 type TrackReference ,
910 type TrackReferenceOrPlaceholder ,
1011 useLocalParticipant ,
12+ useVoiceAssistant ,
1113} from '@livekit/components-react' ;
1214import { MicrophoneIcon } from '@phosphor-icons/react/dist/ssr' ;
1315import { useSession } from '@/components/app/session-provider' ;
@@ -22,15 +24,13 @@ import {
2224 AudioBarVisualizer ,
2325 audioBarVisualizerVariants ,
2426} from '@/components/livekit/audio-visualizer/audio-bar-visualizer/audio-bar-visualizer' ;
25- import {
26- AudioGridVisualizer ,
27- type GridOptions ,
28- } from '@/components/livekit/audio-visualizer/audio-grid-visualizer/audio-grid-visualizer' ;
27+ import { AudioGridVisualizer } from '@/components/livekit/audio-visualizer/audio-grid-visualizer/audio-grid-visualizer' ;
2928import { gridVariants } from '@/components/livekit/audio-visualizer/audio-grid-visualizer/demos' ;
3029import {
3130 AudioRadialVisualizer ,
3231 audioRadialVisualizerVariants ,
3332} from '@/components/livekit/audio-visualizer/audio-radial-visualizer/audio-radial-visualizer' ;
33+ import { AudioShaderVisualizer } from '@/components/livekit/audio-visualizer/audio-shader-visualizer/audio-shader-visualizer' ;
3434import { Button , buttonVariants } from '@/components/livekit/button' ;
3535import { ChatEntry } from '@/components/livekit/chat-entry' ;
3636import {
@@ -442,11 +442,11 @@ export const COMPONENTS = {
442442 'speaking' ,
443443 ] as AgentState [ ] ;
444444
445- const { microphoneTrack, localParticipant } = useLocalParticipant ( ) ;
446445 const [ rowCount , setRowCount ] = useState ( rowCounts [ 0 ] ) ;
447446 const [ columnCount , setColumnCount ] = useState ( columnCounts [ 0 ] ) ;
448447 const [ state , setState ] = useState < AgentState > ( states [ 0 ] ) ;
449448 const [ demoIndex , setDemoIndex ] = useState ( 0 ) ;
449+ const { microphoneTrack, localParticipant } = useLocalParticipant ( ) ;
450450
451451 const micTrackRef = useMemo < TrackReferenceOrPlaceholder | undefined > ( ( ) => {
452452 return state === 'speaking'
@@ -562,6 +562,99 @@ export const COMPONENTS = {
562562 ) ;
563563 } ,
564564
565+ AudioShaderVisualizer : ( ) => {
566+ const [ presetIndex , setPresetIndex ] = useState ( 3 ) ;
567+
568+ // speed
569+ const [ a , setA ] = useState ( 50 ) ;
570+ // // color scale
571+ const [ h , setH ] = useState ( 0.1 ) ;
572+ // // color position
573+ const [ i , setI ] = useState ( 0.15 ) ;
574+ // blur
575+ const [ f , setF ] = useState ( 0.1 ) ;
576+ // shape
577+ const [ g , setG ] = useState ( 1.0 ) ;
578+
579+ const {
580+ // state,
581+ audioTrack,
582+ } = useVoiceAssistant ( ) ;
583+
584+ useMicrophone ( ) ;
585+
586+ const fields = [
587+ [ 'speed' , a , setA , 0 , 250 , 10 ] ,
588+ [ 'color position' , i , setI , 0 , 1 , 0.01 ] ,
589+ [ 'color scale' , h , setH , 0 , 1 , 0.01 ] ,
590+ [ 'blur' , f , setF , 0 , 2 , 0.01 ] ,
591+ [ 'shape' , g , setG , 1 , 5 , 1 ] ,
592+ ] as const ;
593+
594+ return (
595+ < Container componentName = "AudioShaderVisualizer" >
596+ < StartAudio label = "Start Audio" />
597+ < RoomAudioRenderer />
598+ < div className = "grid grid-cols-2 gap-4" >
599+ < AudioShaderVisualizer
600+ speed = { a }
601+ blur = { f }
602+ shape = { g }
603+ colorScale = { h }
604+ colorPosition = { i }
605+ audioTrack = { audioTrack }
606+ presetIndex = { presetIndex }
607+ // className="bg-amber-100"
608+ />
609+ < div >
610+ < div className = "mb-4" >
611+ < StoryTitle > Preset</ StoryTitle >
612+ < Select
613+ value = { String ( presetIndex ) }
614+ onValueChange = { ( value ) => setPresetIndex ( parseInt ( value ) ) }
615+ >
616+ < SelectTrigger id = "presetIndex" className = "w-full" >
617+ < SelectValue placeholder = "Select a preset" />
618+ </ SelectTrigger >
619+ < SelectContent >
620+ < SelectItem value = "0" > Preset 1</ SelectItem >
621+ < SelectItem value = "1" > Preset 2</ SelectItem >
622+ < SelectItem value = "2" > Preset 3</ SelectItem >
623+ < SelectItem value = "3" > Preset 4</ SelectItem >
624+ </ SelectContent >
625+ </ Select >
626+ </ div >
627+
628+ { fields . map ( ( [ name , value , setValue , min = 0.1 , max = 10 , step = 0.1 ] ) => {
629+ // Use 0-1 range for color phase channels
630+ const isColorPhase = name . toString ( ) . startsWith ( 'colorPhase' ) ;
631+
632+ return (
633+ < div key = { name } >
634+ < div className = "flex items-center justify-between" >
635+ < StoryTitle > { name } </ StoryTitle >
636+ < div className = "text-muted-foreground mb-2 text-xs" >
637+ { isColorPhase ? Number ( value ) . toFixed ( 2 ) : String ( value ) }
638+ </ div >
639+ </ div >
640+ < input
641+ type = "range"
642+ value = { String ( value ) }
643+ min = { min }
644+ max = { max }
645+ step = { step }
646+ onChange = { ( e ) => setValue ( parseFloat ( e . target . value ) ) }
647+ className = "w-full"
648+ />
649+ </ div >
650+ ) ;
651+ } ) }
652+ </ div >
653+ </ div >
654+ </ Container >
655+ ) ;
656+ } ,
657+
565658 // Agent control bar
566659 AgentControlBar : ( ) => {
567660 useMicrophone ( ) ;
0 commit comments