@tavus/cvi-ui 0.0.1-beta.1 → 0.0.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +54 -31
  2. package/dev-components/components/README.md +162 -0
  3. package/dev-components/components/audio-wave/audio-wave.module.css +33 -0
  4. package/dev-components/components/audio-wave/index.tsx +55 -0
  5. package/dev-components/components/controls/controls.module.css +115 -0
  6. package/dev-components/components/controls/index.tsx +260 -0
  7. package/dev-components/components/conversation-01/conversation.module.css +222 -0
  8. package/dev-components/components/conversation-01/index.tsx +180 -0
  9. package/dev-components/components/hair-check-01/hair-check.module.css +212 -0
  10. package/dev-components/components/hair-check-01/index.tsx +184 -0
  11. package/dev-components/hooks/README.md +3 -2
  12. package/dev-components/hooks/cvi-events-hooks.tsx +1 -1
  13. package/dev-components/hooks/use-local-camera.tsx +8 -2
  14. package/dev-components/hooks/use-local-microphone.tsx +8 -2
  15. package/dev-components/hooks/use-local-screenshare.tsx +7 -2
  16. package/dev-components/hooks/use-remote-participant-ids.tsx +1 -1
  17. package/dev-components/hooks/use-replica-ids.tsx +1 -1
  18. package/dev-components/hooks/use-start-haircheck.tsx +7 -1
  19. package/dist/index.js +305 -101
  20. package/dist/templates/components/controls.tsx +279 -0
  21. package/dist/templates/components/cvi-provider.tsx +9 -0
  22. package/dist/templates/controls.tsx +279 -0
  23. package/dist/templates/cvi-hooks.tsx +38 -0
  24. package/dist/templates/cvi-provider.tsx +9 -0
  25. package/dist/templates/hooks/cvi-hooks.tsx +38 -0
  26. package/dist/templates/tsx/components/controls.tsx +279 -0
  27. package/dist/templates/tsx/components/cvi-provider.tsx +9 -0
  28. package/dist/types/templates/components.d.ts +44 -0
  29. package/dist/types/templates/index.d.ts +2 -0
  30. package/dist/types/templates/jsx/index.d.ts +14 -0
  31. package/dist/types/templates/tsx/index.d.ts +14 -0
  32. package/dist/types/utils/version-utils.d.ts +3 -0
  33. package/package.json +6 -4
  34. package/src/templates/components.ts +18 -0
  35. package/src/templates/index.ts +2 -0
  36. package/src/templates/jsx/components/audio-wave.json +5 -0
  37. package/src/templates/jsx/components/controls.json +10 -0
  38. package/src/templates/jsx/components/conversation-01.json +11 -0
  39. package/src/templates/jsx/components/cvi-provider.json +5 -0
  40. package/src/templates/jsx/components/hair-check-01.json +10 -0
  41. package/src/templates/jsx/hooks/cvi-events-hooks.json +5 -0
  42. package/src/templates/jsx/hooks/use-cvi-call.json +5 -0
  43. package/src/templates/jsx/hooks/use-local-camera.json +5 -0
  44. package/src/templates/jsx/hooks/use-local-microphone.json +5 -0
  45. package/src/templates/jsx/hooks/use-local-screenshare.json +5 -0
  46. package/src/templates/jsx/hooks/use-remote-participant-ids.json +5 -0
  47. package/src/templates/jsx/hooks/use-replica-ids.json +5 -0
  48. package/src/templates/jsx/hooks/use-request-permissions.json +5 -0
  49. package/src/templates/jsx/hooks/use-start-haircheck.json +5 -0
  50. package/src/templates/jsx/index.ts +14 -0
  51. package/src/templates/tsx/components/audio-wave.json +5 -0
  52. package/src/templates/tsx/components/controls.json +10 -0
  53. package/src/templates/tsx/components/conversation-01.json +11 -0
  54. package/src/templates/tsx/components/cvi-provider.json +5 -0
  55. package/src/templates/tsx/components/hair-check-01.json +10 -0
  56. package/src/templates/tsx/hooks/cvi-events-hooks.json +5 -0
  57. package/src/templates/tsx/hooks/use-cvi-call.json +5 -0
  58. package/src/templates/tsx/hooks/use-local-camera.json +5 -0
  59. package/src/templates/tsx/hooks/use-local-microphone.json +5 -0
  60. package/src/templates/tsx/hooks/use-local-screenshare.json +5 -0
  61. package/src/templates/tsx/hooks/use-remote-participant-ids.json +5 -0
  62. package/src/templates/tsx/hooks/use-replica-ids.json +5 -0
  63. package/src/templates/tsx/hooks/use-request-permissions.json +8 -0
  64. package/src/templates/tsx/hooks/use-start-haircheck.json +5 -0
  65. package/src/templates/tsx/index.ts +14 -0
  66. package/src/utils/resolve-components-tree.ts +59 -2
  67. package/src/utils/update-files.ts +38 -10
  68. package/src/utils/version-utils.ts +26 -0
package/README.md CHANGED
@@ -6,49 +6,49 @@ A CLI tool for installing and managing CVI (Conversational Video Interface) comp
6
6
 
7
7
  **Initialize the project**:
8
8
 
9
- ```bash
10
- npx @tavus/cvi-ui init
11
- ```
9
+ ```bash
10
+ npx @tavus/cvi-ui@latest init
11
+ ```
12
12
 
13
- This will:
13
+ This will:
14
14
 
15
- - Create a `cvi-components.json` configuration file
16
- - Prompt for TypeScript preference
17
- - Install the necessary dependencies
15
+ - Create a `cvi-components.json` configuration file
16
+ - Prompt for TypeScript preference
17
+ - Install the necessary dependencies
18
18
 
19
19
  **Add components to your project**:
20
20
 
21
- ```bash
22
- npx @tavus/cvi-ui add conversation
23
- ```
21
+ ```bash
22
+ npx @tavus/cvi-ui@latest add conversation
23
+ ```
24
24
 
25
25
  **Wrap your app with the CVI provider**:
26
26
 
27
- ```tsx
28
- import { CVIProvider } from './components/cvi/components/cvi-provider';
27
+ ```tsx
28
+ import { CVIProvider } from './components/cvi/components/cvi-provider';
29
29
 
30
- function App() {
31
- return (
32
- <CVIProvider>
33
- {/* Your app content */}
34
- </CVIProvider>
35
- );
36
- }
37
- ```
30
+ function App() {
31
+ return (
32
+ <CVIProvider>
33
+ {/* Your app content */}
34
+ </CVIProvider>
35
+ );
36
+ }
37
+ ```
38
38
 
39
39
  **Add conversation components**:
40
40
 
41
- ```tsx
42
- import { Conversation } from './components/cvi/components/conversation';
41
+ ```tsx
42
+ import { Conversation } from './components/cvi/components/conversation';
43
43
 
44
- function Call() {
45
- return (
46
- <div>
47
- <Conversation {...conversationProps} />
48
- </div>
49
- );
50
- }
51
- ```
44
+ function Call() {
45
+ return (
46
+ <div>
47
+ <Conversation {...conversationProps} />
48
+ </div>
49
+ );
50
+ }
51
+ ```
52
52
 
53
53
  ## Available Components
54
54
 
@@ -56,6 +56,30 @@ A CLI tool for installing and managing CVI (Conversational Video Interface) comp
56
56
 
57
57
  - **`cvi-provider`** - Main provider component that wraps your app with CVI context
58
58
 
59
+ ### UI Components
60
+
61
+ - **`controls`** - Video chat control buttons with device selection capabilities
62
+
63
+ - `MicrophoneButton` - Toggle microphone with device dropdown
64
+ - `CameraButton` - Toggle camera with device dropdown
65
+ - `ScreenShareButton` - Toggle screen sharing
66
+
67
+ - **`hair-check-01`** - Pre-call interface for testing and configuring audio/video devices
68
+
69
+ - Live camera preview with mirror effect
70
+ - Permission management and device controls
71
+ - Join interface with loading states
72
+
73
+ - **`conversation-01`** - Conversation component for video chat
74
+
75
+ - Video chat with audio wave indicator
76
+ - Device selection and permission management
77
+ - Screen sharing support
78
+ - Error handling
79
+
80
+ - **`audio-wave`** - Audio wave indicator for conversation
81
+ - Shows active speaker audio level
82
+
59
83
  ### Hooks
60
84
 
61
85
  #### Core Call Management
@@ -88,4 +112,3 @@ MIT License - see the [LICENSE](LICENSE) file for details.
88
112
 
89
113
  - [CVI Documentation](https://docs.tavus.io/sections/conversational-video-interface/cvi-overview)
90
114
  - [Tavus Examples](https://github.com/Tavus-Engineering/tavus-examples)
91
-
@@ -0,0 +1,162 @@
1
+ # CVI Components
2
+
3
+ ## Components
4
+
5
+ ### Controls
6
+
7
+ The `Controls` component provides a set of video chat control buttons with integrated device selection capabilities.
8
+
9
+ #### Exported Components:
10
+
11
+ - **`MicrophoneButton`**: A button component that toggles microphone on/off with a dropdown for device selection
12
+ - **`CameraButton`**: A button component that toggles camera on/off with a dropdown for device selection
13
+ - **`ScreenShareButton`**: A button component that toggles screen sharing on/off
14
+ - **`SelectDevice`**: A reusable dropdown component for selecting camera and microphone devices
15
+
16
+ #### Usage:
17
+
18
+ ```tsx
19
+ import { MicrophoneButton, CameraButton, ScreenShareButton } from './controls';
20
+
21
+ // Use individual control buttons
22
+ <MicrophoneButton />
23
+ <CameraButton />
24
+ <ScreenShareButton />
25
+ ```
26
+
27
+ #### Component Details:
28
+
29
+ **MicrophoneButton**
30
+
31
+ - Toggles microphone mute/unmute state
32
+ - Shows visual indicators for muted/unmuted states
33
+ - Includes device selection dropdown
34
+ - Disabled when microphone is not ready
35
+ - Uses `useLocalMicrophone` and `useDevices` hooks
36
+
37
+ **CameraButton**
38
+
39
+ - Toggles camera on/off
40
+ - Shows visual indicators for camera muted/unmuted states
41
+ - Includes device selection dropdown
42
+ - Disabled when camera is not ready or no camera is available
43
+ - Uses `useLocalCamera` and `useDevices` hooks
44
+
45
+ **ScreenShareButton**
46
+
47
+ - Toggles screen sharing on/off
48
+ - Shows visual feedback with different icons for active/inactive states
49
+ - Uses `useLocalScreenshare` hook
50
+
51
+ **SelectDevice**
52
+
53
+ - Reusable dropdown component for device selection
54
+ - Accepts devices array, current value, disabled state, and onChange handler
55
+ - Includes custom dropdown arrow styling
56
+
57
+ #### Key Features:
58
+
59
+ - Automatic device detection and switching via Daily.co hooks
60
+ - Visual state indicators with SVG icons
61
+ - Accessibility support with screen reader labels (`srOnly` class)
62
+ - Responsive design with mobile-friendly controls
63
+ - Integration with Daily.co device management system
64
+ - CSS modules for scoped styling
65
+
66
+ ### Hair Check 01
67
+
68
+ The `HairCheck` component provides a pre-call interface for users to test and configure their audio/video devices before joining a video chat.
69
+
70
+ #### Features:
71
+
72
+ - **Device Testing**: Live preview of camera feed with mirror effect
73
+ - **Permission Management**: Handles camera and microphone permission requests
74
+ - **Device Controls**: Integrated microphone and camera controls
75
+ - **Join Interface**: Call-to-action button to join the video chat
76
+ - **Responsive Design**: Works on both desktop and mobile devices
77
+
78
+ #### Usage:
79
+
80
+ ```tsx
81
+ import { HairCheck } from './hair-check';
82
+
83
+ <HairCheck
84
+ isJoinBtnLoading={false}
85
+ onJoin={() => handleJoinCall()}
86
+ onCancel={() => handleCancel()}
87
+ />
88
+ ```
89
+
90
+ #### Props:
91
+
92
+ - `isJoinBtnLoading` (boolean): Shows loading state on join button
93
+ - `onJoin` (function): Callback when user clicks join
94
+ - `onCancel` (function, optional): Callback when user cancels
95
+
96
+ #### Key Features:
97
+
98
+ - Automatic permission request flow
99
+ - Visual feedback for different permission states
100
+ - Fallback user avatar when camera is unavailable
101
+ - Integrated device controls for easy testing
102
+ - Clean, intuitive interface for pre-call setup
103
+
104
+ ### Conversation 01
105
+
106
+ The `Conversation` component provides a complete video chat interface for one-to-one conversations with AI replicas, featuring main video display, self-view preview, and integrated controls.
107
+
108
+ #### Features:
109
+
110
+ - **Main Video Display**: Large video area showing the AI replica or screen share
111
+ - **Self-View Preview**: Small preview window showing local camera feed
112
+ - **Screen Sharing Support**: Automatic switching between replica video and screen share
113
+ - **Device Controls**: Integrated microphone, camera, and screen share controls
114
+ - **Error Handling**: Graceful handling of camera/microphone permission errors
115
+ - **Responsive Layout**: Adaptive design for different screen sizes
116
+
117
+ #### Usage:
118
+
119
+ ```tsx
120
+ import { Conversation } from './conversation-01';
121
+
122
+ <Conversation
123
+ conversation={conversationData}
124
+ onLeave={() => handleLeaveCall()}
125
+ />
126
+ ```
127
+
128
+ #### Props:
129
+
130
+ - `conversation` (ConversationData): Object containing conversation details
131
+ - `conversation_id` (string): Unique identifier for the conversation
132
+ - `conversation_name` (string): Display name for the conversation
133
+ - `status` ('active' | 'ended' | 'error'): Current conversation status
134
+ - `conversation_url` (string): Daily.co room URL for joining
135
+ - `replica_id` (string | null): ID of the AI replica participant
136
+ - `persona_id` (string | null): ID of the persona being used
137
+ - `created_at` (string): Timestamp of conversation creation
138
+ - `onLeave` (function): Callback when user leaves the conversation
139
+
140
+ ### Audio Wave
141
+
142
+ The `AudioWave` component provides real-time audio level visualization for video chat participants, displaying animated bars that respond to audio input levels.
143
+
144
+ #### Features:
145
+
146
+ - **Real-time Audio Visualization**: Three animated bars that respond to audio levels
147
+ - **Active Speaker Detection**: Visual distinction between active and inactive speakers
148
+ - **Performance Optimized**: Uses `requestAnimationFrame` for smooth animations
149
+ - **Responsive Design**: Compact circular design that fits well in video previews
150
+ - **Audio Level Scaling**: Intelligent volume scaling for consistent visual feedback
151
+
152
+ #### Usage:
153
+
154
+ ```tsx
155
+ import { AudioWave } from './audio-wave';
156
+
157
+ <AudioWave id={participantId} />
158
+ ```
159
+
160
+ #### Props:
161
+
162
+ - `id` (string): The participant's session ID to monitor audio levels for
@@ -0,0 +1,33 @@
1
+ .container {
2
+ overflow: hidden;
3
+ border: 1px solid white;
4
+ width: 1.5rem;
5
+ height: 1.5rem;
6
+ border-radius: 9999px;
7
+ will-change: transform;
8
+ transform: translateZ(0);
9
+ }
10
+
11
+ .waveContainer {
12
+ display: flex;
13
+ justify-content: center;
14
+ align-items: center;
15
+ gap: 0.125rem;
16
+ width: 100%;
17
+ height: 100%;
18
+ }
19
+
20
+ .bar {
21
+ width: 0.25rem;
22
+ height: 0.25rem;
23
+ background-color: white;
24
+ border-radius: 9999px;
25
+ transition: height 200ms ease-out;
26
+ will-change: height;
27
+ transform: translateZ(0);
28
+ }
29
+
30
+ .barInactive {
31
+ width: 0.25rem !important;
32
+ height: 0.25rem !important;
33
+ }
@@ -0,0 +1,55 @@
1
+ import React, { useCallback, useRef, memo } from "react";
2
+ import { useActiveSpeakerId } from "@daily-co/daily-react";
3
+ import { useAudioLevelObserver } from "@daily-co/daily-react";
4
+ import styles from "./audio-wave.module.css";
5
+
6
+ export const AudioWave = memo(({ id }: { id: string }) => {
7
+ const activeSpeakerId = useActiveSpeakerId();
8
+ const isActiveSpeaker = activeSpeakerId === id;
9
+
10
+ const leftBarRef = useRef<HTMLDivElement>(null);
11
+ const centerBarRef = useRef<HTMLDivElement>(null);
12
+ const rightBarRef = useRef<HTMLDivElement>(null);
13
+ const animationFrameRef = useRef<number | undefined>(undefined);
14
+
15
+ useAudioLevelObserver(
16
+ id,
17
+ useCallback((volume) => {
18
+ // Cancel any pending animation frame to prevent accumulation
19
+ if (animationFrameRef.current) {
20
+ cancelAnimationFrame(animationFrameRef.current);
21
+ }
22
+
23
+ // Use requestAnimationFrame to batch DOM updates
24
+ animationFrameRef.current = requestAnimationFrame(() => {
25
+ const scaledVolume = Number(Math.max(0.01, volume).toFixed(2));
26
+ if (leftBarRef.current && centerBarRef.current && rightBarRef.current) {
27
+ leftBarRef.current.style.height = `${20 + scaledVolume * 40}%`;
28
+ centerBarRef.current.style.height = `${20 + scaledVolume * 130}%`;
29
+ rightBarRef.current.style.height = `${20 + scaledVolume * 40}%`;
30
+ }
31
+ });
32
+ }, []),
33
+ );
34
+
35
+ return (
36
+ <div className={styles.container}>
37
+ <div className={styles.waveContainer}>
38
+ <div
39
+ ref={leftBarRef}
40
+ className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
41
+ />
42
+ <div
43
+ ref={centerBarRef}
44
+ className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
45
+ />
46
+ <div
47
+ ref={rightBarRef}
48
+ className={`${styles.bar} ${!isActiveSpeaker ? styles.barInactive : ''}`}
49
+ />
50
+ </div>
51
+ </div>
52
+ );
53
+ });
54
+
55
+ AudioWave.displayName = 'AudioWave';
@@ -0,0 +1,115 @@
1
+ /* SelectDevice styles */
2
+ .selectDevice {
3
+ height: 3rem;
4
+ width: 5.5rem;
5
+ border-radius: 9999px;
6
+ background-color: rgba(255, 255, 255, 0.2);
7
+ padding: 0 0.75rem;
8
+ border: 1px solid rgba(255, 255, 255, 0.2);
9
+ backdrop-filter: blur(10px);
10
+ color: transparent;
11
+ padding-right: 2rem; /* space for arrow */
12
+ box-sizing: border-box;
13
+ -webkit-appearance: none;
14
+ -moz-appearance: none;
15
+ appearance: none;
16
+ cursor: pointer;
17
+ }
18
+
19
+ .selectDevice::-ms-expand {
20
+ display: none;
21
+ }
22
+
23
+ .selectDevice option {
24
+ color: transparent;
25
+ background-color: transparent;
26
+ }
27
+
28
+ .selectDevice:focus {
29
+ outline: none;
30
+ }
31
+
32
+ /* Device button container styles */
33
+ .deviceButtonContainer {
34
+ position: relative;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ border-radius: 9999px;
39
+ backdrop-filter: blur(4px);
40
+ }
41
+
42
+ /* Device button styles */
43
+ .deviceButton {
44
+ position: absolute;
45
+ left: 0;
46
+ top: 0;
47
+ z-index: 10;
48
+ height: 3rem;
49
+ width: 3rem;
50
+ border-radius: 9999px;
51
+ background-color: white;
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ border: 1px solid transparent;
56
+ cursor: pointer;
57
+ }
58
+
59
+ .deviceButtonIcon {
60
+ display: flex;
61
+ }
62
+
63
+ .deviceButton:disabled {
64
+ opacity: 0.5;
65
+ }
66
+
67
+ /* Screen reader only text */
68
+ .srOnly {
69
+ position: absolute;
70
+ width: 1px;
71
+ height: 1px;
72
+ padding: 0;
73
+ margin: -1px;
74
+ overflow: hidden;
75
+ clip: rect(0, 0, 0, 0);
76
+ white-space: nowrap;
77
+ border-width: 0;
78
+ }
79
+
80
+ /* Controls container */
81
+ .controlsContainer {
82
+ display: flex;
83
+ gap: 1rem;
84
+ justify-content: center;
85
+ align-items: center;
86
+ }
87
+
88
+ .selectDeviceContainer {
89
+ position: relative;
90
+ display: flex;
91
+ align-items: center;
92
+ }
93
+
94
+ .selectArrow {
95
+ position: absolute;
96
+ right: 1rem;
97
+ pointer-events: none;
98
+ display: flex;
99
+ align-items: center;
100
+ height: 100%;
101
+ }
102
+
103
+ .screenShareButton {
104
+ cursor: pointer;
105
+ position: relative;
106
+ height: 3rem;
107
+ width: 3rem;
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ border-radius: 9999px;
112
+ backdrop-filter: blur(4px);
113
+ background-color: rgba(255, 255, 255, 0.2);
114
+ border: 1px solid rgba(255, 255, 255, 0.2);
115
+ }