@@ -30,7 +30,10 @@ import {
3030  AudioRadialVisualizer , 
3131  audioRadialVisualizerVariants , 
3232}  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' ; 
33+ import  { 
34+   AudioShaderVisualizer , 
35+   audioShaderVisualizerVariants , 
36+ }  from  '@/components/livekit/audio-visualizer/audio-shader-visualizer/audio-shader-visualizer' ; 
3437import  {  Button ,  buttonVariants  }  from  '@/components/livekit/button' ; 
3538import  {  ChatEntry  }  from  '@/components/livekit/chat-entry' ; 
3639import  { 
@@ -52,6 +55,9 @@ type audioBarVisualizerVariantsSizeType = VariantProps<typeof audioBarVisualizer
5255type  audioRadialVisualizerVariantsSizeType  =  VariantProps < 
5356  typeof  audioRadialVisualizerVariants 
5457> [ 'size' ] ; 
58+ type  audioShaderVisualizerVariantsSizeType  =  VariantProps < 
59+   typeof  audioShaderVisualizerVariants 
60+ > [ 'size' ] ; 
5561
5662export  function  useMicrophone ( )  { 
5763  const  {  startSession }  =  useSession ( ) ; 
@@ -563,93 +569,142 @@ export const COMPONENTS = {
563569  } , 
564570
565571  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 ) ; 
572+     const  {  startSession,  endSession }  =  useSession ( ) ; 
573+     const  {  localParticipant }  =  useLocalParticipant ( ) ; 
574+ 
576575    // shape 
577-     const  [ g ,  setG ]  =  useState ( 1.0 ) ; 
576+     const  [ shape ,  setShape ]  =  useState ( 1.0 ) ; 
577+     // color scale 
578+     const  [ colorScale ,  setColorScale ]  =  useState ( 0.1 ) ; 
579+     // color position 
580+     const  [ colorPosition ,  setColorPosition ]  =  useState ( 0.15 ) ; 
581+ 
582+     const  sizes  =  [ 'icon' ,  'sm' ,  'md' ,  'lg' ,  'xl' ] ; 
583+     const  states  =  [ 
584+       'disconnected' , 
585+       'connecting' , 
586+       'initializing' , 
587+       'listening' , 
588+       'thinking' , 
589+       'speaking' , 
590+     ]  as  AgentState [ ] ; 
591+ 
592+     const  [ size ,  setSize ]  =  useState < audioShaderVisualizerVariantsSizeType > ( 'lg' ) ; 
593+     const  [ state ,  setState ]  =  useState < AgentState > ( states [ 0 ] ) ; 
578594
579595    const  { 
580596      // state, 
581597      audioTrack, 
582598    }  =  useVoiceAssistant ( ) ; 
583599
584-     useMicrophone ( ) ; 
600+     useEffect ( ( )  =>  { 
601+       if  ( state  ===  'speaking' )  { 
602+         startSession ( ) ; 
603+         localParticipant . setMicrophoneEnabled ( true ,  undefined ) ; 
604+       }  else  { 
605+         endSession ( ) ; 
606+         localParticipant . setMicrophoneEnabled ( false ,  undefined ) ; 
607+       } 
608+     } ,  [ startSession ,  endSession ,  state ,  localParticipant ] ) ; 
585609
586610    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 ] , 
611+       [ 'color position' ,  colorPosition ,  setColorPosition ,  0 ,  1 ,  0.01 ] , 
612+       [ 'color scale' ,  colorScale ,  setColorScale ,  0 ,  1 ,  0.01 ] , 
592613    ]  as  const ; 
593614
594615    return  ( 
595616      < Container  componentName = "AudioShaderVisualizer" > 
596617        < StartAudio  label = "Start Audio"  /> 
597618        < RoomAudioRenderer  /> 
598-         < div  className = "grid grid-cols-2 gap-4" > 
619+ 
620+         < div  className = "flex gap-4" > 
621+           < div  className = "flex-1" > 
622+             < label  className = "font-mono text-xs uppercase"  htmlFor = "state" > 
623+               State
624+             </ label > 
625+             < Select  value = { state }  onValueChange = { ( value )  =>  setState ( value  as  AgentState ) } > 
626+               < SelectTrigger  id = "state"  className = "w-full" > 
627+                 < SelectValue  placeholder = "Select a state"  /> 
628+               </ SelectTrigger > 
629+               < SelectContent > 
630+                 { states . map ( ( state )  =>  ( 
631+                   < SelectItem  key = { state }  value = { state } > 
632+                     { state } 
633+                   </ SelectItem > 
634+                 ) ) } 
635+               </ SelectContent > 
636+             </ Select > 
637+           </ div > 
638+ 
639+           < div  className = "flex-1" > 
640+             < label  className = "font-mono text-xs uppercase"  htmlFor = "size" > 
641+               Size
642+             </ label > 
643+             < Select 
644+               value = { size  as  string } 
645+               onValueChange = { ( value )  =>  setSize ( value  as  audioShaderVisualizerVariantsSizeType ) } 
646+             > 
647+               < SelectTrigger  id = "size"  className = "w-full" > 
648+                 < SelectValue  placeholder = "Select a size"  /> 
649+               </ SelectTrigger > 
650+               < SelectContent > 
651+                 { sizes . map ( ( size )  =>  ( 
652+                   < SelectItem  key = { size }  value = { size  as  string } > 
653+                     { size . toUpperCase ( ) } 
654+                   </ SelectItem > 
655+                 ) ) } 
656+               </ SelectContent > 
657+             </ Select > 
658+           </ div > 
659+ 
660+           < div  className = "flex-1" > 
661+             < label  className = "font-mono text-xs uppercase"  htmlFor = "shape" > 
662+               Shape
663+             </ label > 
664+             < Select  value = { shape . toString ( ) }  onValueChange = { ( value )  =>  setShape ( parseInt ( value ) ) } > 
665+               < SelectTrigger  id = "shape"  className = "w-full" > 
666+                 < SelectValue  placeholder = "Select a shape"  /> 
667+               </ SelectTrigger > 
668+               < SelectContent > 
669+                 < SelectItem  value = "1" > Circle</ SelectItem > 
670+                 < SelectItem  value = "2" > Line</ SelectItem > 
671+               </ SelectContent > 
672+             </ Select > 
673+           </ div > 
674+         </ div > 
675+ 
676+         < div  className = "py-12" > 
599677          < 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" 
678+             size = { size } 
679+             state = { state } 
680+             shape = { shape } 
681+             colorScale = { colorScale } 
682+             colorPosition = { colorPosition } 
683+             audioTrack = { audioTrack  as  TrackReferenceOrPlaceholder } 
684+             className = "mx-auto bg-black" 
608685          /> 
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 > 
686+         </ div > 
627687
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-                   /> 
688+         < div  className = "grid grid-cols-2 gap-4" > 
689+           { fields . map ( ( [ name ,  value ,  setValue ,  min  =  0.1 ,  max  =  10 ,  step  =  0.1 ] )  =>  { 
690+             return  ( 
691+               < div  key = { name } > 
692+                 < div  className = "flex items-center justify-between" > 
693+                   < StoryTitle > { name } </ StoryTitle > 
694+                   < div  className = "text-muted-foreground mb-2 text-xs" > { String ( value ) } </ div > 
649695                </ div > 
650-               ) ; 
651-             } ) } 
652-           </ div > 
696+                 < input 
697+                   type = "range" 
698+                   value = { String ( value ) } 
699+                   min = { min } 
700+                   max = { max } 
701+                   step = { step } 
702+                   onChange = { ( e )  =>  setValue ( parseFloat ( e . target . value ) ) } 
703+                   className = "w-full" 
704+                 /> 
705+               </ div > 
706+             ) ; 
707+           } ) } 
653708        </ div > 
654709      </ Container > 
655710    ) ; 
0 commit comments