DataSage12's picture
Initial commit - HOLOKIA-AVATAR v2.2
de63014
import React, { Suspense, useState, useEffect } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, Environment } from "@react-three/drei";
import AvatarModel from "./AvatarModel";
import Loader from "./Loader";
// Vérification de la disponibilité WebGL
function checkWebGLSupport() {
try {
const canvas = document.createElement('canvas');
return !!(
window.WebGLRenderingContext &&
(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
);
} catch (e) {
return false;
}
}
export default function Avatar3D({ audioUrl }) { // Accepte audioUrl comme prop optionnelle
const [webGLAvailable, setWebGLAvailable] = useState(true);
const [loading, setLoading] = useState(true);
useEffect(() => {
setWebGLAvailable(checkWebGLSupport());
}, []);
if (!webGLAvailable) {
return (
<div className="h-full flex flex-col items-center justify-center bg-gray-50 rounded-2xl p-6 text-center">
<div className="max-w-md">
<h2 className="text-xl font-bold text-red-600 mb-3">WebGL non supporté</h2>
<p className="mb-4 text-gray-700">
Votre navigateur ne supporte pas WebGL, nécessaire pour afficher l'avatar 3D.
Veuillez utiliser un navigateur moderne comme Chrome, Firefox ou Edge.
</p>
<div className="bg-gray-200 border-2 border-dashed rounded-xl w-full h-64 flex items-center justify-center">
<span className="text-gray-500">Prévisualisation non disponible</span>
</div>
</div>
</div>
);
}
return (
<div className="w-full h-full relative">
<Canvas
camera={{ position: [0, 1.6, 3], fov: 50 }}
className="rounded-2xl"
onCreated={() => setLoading(false)}
>
{/* Éclairage amélioré */}
<ambientLight intensity={0.8} />
<directionalLight
position={[5, 5, 5]}
intensity={1.2}
castShadow
shadow-mapSize-width={1024}
shadow-mapSize-height={1024}
/>
<pointLight position={[-5, 5, 5]} intensity={0.8} />
{/* Environnement */}
<Environment preset="city" />
{/* Avatar */}
<Suspense fallback={null}>
<AvatarModel
scale={[1, 1, 1]}
position={[0, -1, 0]}
audioUrl={audioUrl} // Passe audioUrl pour la synchronisation labiale
/>
</Suspense>
{/* Contrôles */}
<OrbitControls
enablePan={false}
enableZoom={true}
enableRotate={true}
maxPolarAngle={Math.PI / 2}
minPolarAngle={0}
minDistance={2}
maxDistance={5}
/>
</Canvas>
{loading && (
<div className="absolute inset-0 flex items-center justify-center bg-white/80 backdrop-blur-sm rounded-2xl z-10">
<div className="text-center">
<div className="inline-block relative">
<div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
<div className="absolute inset-0 flex items-center justify-center">
<div className="w-8 h-8 bg-blue-500 rounded-full animate-ping"></div>
</div>
</div>
<p className="mt-4 text-gray-700 font-medium">Chargement de l'avatar...</p>
</div>
</div>
)}
</div>
);
}