import React, { useState } from 'react'; import { AppState, AvatarConfig, Rect } from './types'; import AvatarCreator from './components/AvatarCreator'; import RiggingEditor from './components/RiggingEditor'; import Studio from './components/Studio'; const App: React.FC = () => { const [appState, setAppState] = useState(AppState.SETUP); // Temp storage for the generated image before rigging const [generatedData, setGeneratedData] = useState<{url: string, name: string, initialData?: any} | null>(null); const [avatar, setAvatar] = useState(null); const handleStartCreation = async () => { try { if (window.aistudio) { const hasKey = await window.aistudio.hasSelectedApiKey(); if (!hasKey) { await window.aistudio.openSelectKey(); } } setAppState(AppState.CREATION); } catch (error) { console.error("Error during API key selection:", error); setAppState(AppState.CREATION); } }; const handleAvatarGenerated = (url: string, name: string, initialData?: any) => { setGeneratedData({ url, name, initialData }); setAppState(AppState.RIGGING); }; const handleRiggingComplete = (data: { leftEye: Rect, rightEye: Rect, mouth: Rect, skinColor: string, textureClosedEye: Rect, textureOpenMouth: Rect }) => { if (generatedData) { setAvatar({ imageUrl: generatedData.url, name: generatedData.name, description: '', leftEye: data.leftEye, rightEye: data.rightEye, mouth: data.mouth, skinColor: data.skinColor, textureClosedEye: data.textureClosedEye, textureOpenMouth: data.textureOpenMouth, }); setAppState(AppState.STUDIO); } }; return (
{appState === AppState.SETUP && (

GEMINI V-STUDIO

The next-generation browser-based VTuber studio. Generate your persona with AI and animate it with your face.

AI Generation

Describe your dream character. Gemini 3 Pro creates high-fidelity sprites in seconds.

📸

Face Tracking

Powered by MediaPipe. No expensive equipment needed—just your webcam.

🎥

Live Animation

Your avatar mimics your head movements and speech in real-time.

)} {appState === AppState.CREATION && (
)} {appState === AppState.RIGGING && generatedData && (
)} {appState === AppState.STUDIO && avatar && ( setAppState(AppState.SETUP)} /> )}
); }; export default App;