🚀 Auto-deploy: melhoria no snap e medição AR em 25/05/2026 17:15:39
This commit is contained in:
+72
-48
@@ -115,27 +115,27 @@ const CHAIRS = [
|
||||
|
||||
const AVATAR_PRESETS: AvatarPreset[] = [
|
||||
// Masculinos (1 a 10)
|
||||
{ id: 1, name: 'Leo', desc: 'Negro, cabelo curto preto', url: '/avatars/avatar_1.png', color: '#ef4444' },
|
||||
{ id: 2, name: 'Marcus', desc: 'Loiro, cabelo curto', url: '/avatars/avatar_2.png', color: '#b45309' },
|
||||
{ id: 3, name: 'Arthur', desc: 'Ruivo com barba', url: '/avatars/avatar_3.png', color: '#eab308' },
|
||||
{ id: 4, name: 'Jin', desc: 'Asiático, cabelo preto liso', url: '/avatars/avatar_4.png', color: '#3b82f6' },
|
||||
{ id: 5, name: 'Mateo', desc: 'Castanho, cabelo cacheado', url: '/avatars/avatar_5.png', color: '#f97316' },
|
||||
{ id: 6, name: 'Malik', desc: 'Negro, careca com barba', url: '/avatars/avatar_6.png', color: '#84cc16' },
|
||||
{ id: 7, name: 'Oliver', desc: 'Cabelo grisalho com óculos', url: '/avatars/avatar_7.png', color: '#06b6d4' },
|
||||
{ id: 8, name: 'Carlos', desc: 'Latino com bigode', url: '/avatars/avatar_8.png', color: '#6366f1' },
|
||||
{ id: 9, name: 'Yuki', desc: 'Cabelo espetado azul escuro', url: '/avatars/avatar_9.png', color: '#a855f7' },
|
||||
{ id: 10, name: 'Elijah', desc: 'Negro com dreadlocks', url: '/avatars/avatar_10.png', color: '#ec4899' },
|
||||
{ id: 1, name: 'Av. 01', desc: 'Avatar de Reunião', url: '/avatars/avatar_1.png', color: '#ef4444' },
|
||||
{ id: 2, name: 'Av. 02', desc: 'Avatar de Reunião', url: '/avatars/avatar_2.png', color: '#b45309' },
|
||||
{ id: 3, name: 'Av. 03', desc: 'Avatar de Reunião', url: '/avatars/avatar_3.png', color: '#eab308' },
|
||||
{ id: 4, name: 'Av. 04', desc: 'Avatar de Reunião', url: '/avatars/avatar_4.png', color: '#3b82f6' },
|
||||
{ id: 5, name: 'Av. 05', desc: 'Avatar de Reunião', url: '/avatars/avatar_5.png', color: '#f97316' },
|
||||
{ id: 6, name: 'Av. 06', desc: 'Avatar de Reunião', url: '/avatars/avatar_6.png', color: '#84cc16' },
|
||||
{ id: 7, name: 'Av. 07', desc: 'Avatar de Reunião', url: '/avatars/avatar_7.png', color: '#06b6d4' },
|
||||
{ id: 8, name: 'Av. 08', desc: 'Avatar de Reunião', url: '/avatars/avatar_8.png', color: '#6366f1' },
|
||||
{ id: 9, name: 'Av. 09', desc: 'Avatar de Reunião', url: '/avatars/avatar_9.png', color: '#a855f7' },
|
||||
{ id: 10, name: 'Av. 10', desc: 'Avatar de Reunião', url: '/avatars/avatar_10.png', color: '#ec4899' },
|
||||
// Femininos (11 a 20)
|
||||
{ id: 11, name: 'Sophia', desc: 'Morena, cabelo longo castanho', url: '/avatars/avatar_11.png', color: '#10b981' },
|
||||
{ id: 12, name: 'Aisha', desc: 'Negra com turbante/lenço', url: '/avatars/avatar_12.png', color: '#78350f' },
|
||||
{ id: 13, name: 'Isabella', desc: 'Loira, cabelo longo ondulado', url: '/avatars/avatar_13.png', color: '#1e293b' },
|
||||
{ id: 14, name: 'Chloe', desc: 'Ruiva, corte canal/bob', url: '/avatars/avatar_14.png', color: '#ca8a04' },
|
||||
{ id: 15, name: 'Mei', desc: 'Asiática, cabelo com franja', url: '/avatars/avatar_15.png', color: '#f43f5e' },
|
||||
{ id: 16, name: 'Elena', desc: 'Castanha, cabelo afro volumoso', url: '/avatars/avatar_16.png', color: '#14b8a6' },
|
||||
{ id: 17, name: 'Zara', desc: 'Cabelo roxo moderno', url: '/avatars/avatar_17.png', color: '#0ea5e9' },
|
||||
{ id: 18, name: 'Naomi', desc: 'Negra de óculos e rabo de cavalo', url: '/avatars/avatar_18.png', color: '#4f46e5' },
|
||||
{ id: 19, name: 'Harper', desc: 'Corte pixie rosa', url: '/avatars/avatar_19.png', color: '#d946ef' },
|
||||
{ id: 20, name: 'Amara', desc: 'Negra com tranças', url: '/avatars/avatar_20.png', color: '#f59e0b' }
|
||||
{ id: 11, name: 'Av. 11', desc: 'Avatar de Reunião', url: '/avatars/avatar_11.png', color: '#10b981' },
|
||||
{ id: 12, name: 'Av. 12', desc: 'Avatar de Reunião', url: '/avatars/avatar_12.png', color: '#78350f' },
|
||||
{ id: 13, name: 'Av. 13', desc: 'Avatar de Reunião', url: '/avatars/avatar_13.png', color: '#1e293b' },
|
||||
{ id: 14, name: 'Av. 14', desc: 'Avatar de Reunião', url: '/avatars/avatar_14.png', color: '#ca8a04' },
|
||||
{ id: 15, name: 'Av. 15', desc: 'Avatar de Reunião', url: '/avatars/avatar_15.png', color: '#f43f5e' },
|
||||
{ id: 16, name: 'Av. 16', desc: 'Avatar de Reunião', url: '/avatars/avatar_16.png', color: '#14b8a6' },
|
||||
{ id: 17, name: 'Av. 17', desc: 'Avatar de Reunião', url: '/avatars/avatar_17.png', color: '#0ea5e9' },
|
||||
{ id: 18, name: 'Av. 18', desc: 'Avatar de Reunião', url: '/avatars/avatar_18.png', color: '#4f46e5' },
|
||||
{ id: 19, name: 'Av. 19', desc: 'Avatar de Reunião', url: '/avatars/avatar_19.png', color: '#d946ef' },
|
||||
{ id: 20, name: 'Av. 20', desc: 'Avatar de Reunião', url: '/avatars/avatar_20.png', color: '#f59e0b' }
|
||||
];
|
||||
|
||||
const SKIN_COLORS = ['#fed7aa', '#fdba74', '#f59e0b', '#d97706', '#9a3412', '#ffedd5'];
|
||||
@@ -178,6 +178,7 @@ function MiiAvatarBackup({
|
||||
isTalking,
|
||||
scale = 1,
|
||||
isLastChatSender = false,
|
||||
inLobby = false,
|
||||
...props
|
||||
}: {
|
||||
avatarId: number;
|
||||
@@ -185,6 +186,7 @@ function MiiAvatarBackup({
|
||||
isTalking?: boolean;
|
||||
scale?: number;
|
||||
isLastChatSender?: boolean;
|
||||
inLobby?: boolean;
|
||||
} & Record<string, unknown>) {
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
const ringRef = useRef<THREE.Mesh>(null);
|
||||
@@ -258,15 +260,17 @@ function MiiAvatarBackup({
|
||||
|
||||
return (
|
||||
<group ref={groupRef} position={positionVector} rotation={rotationEuler} scale={scale}>
|
||||
<group position={[0, 0.38, 0]}>
|
||||
<mesh position={[0, 0, -0.001]}>
|
||||
<planeGeometry args={[0.44, 0.1]} />
|
||||
<meshBasicMaterial color="#0f172a" transparent opacity={0.7} />
|
||||
</mesh>
|
||||
<Text fontSize={0.048} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
|
||||
{username}
|
||||
</Text>
|
||||
</group>
|
||||
{!inLobby && (
|
||||
<group position={[0, 0.32, 0]}>
|
||||
<mesh position={[0, 0, -0.001]}>
|
||||
<planeGeometry args={[0.22, 0.05]} />
|
||||
<meshBasicMaterial color="#0f172a" transparent opacity={0.7} />
|
||||
</mesh>
|
||||
<Text fontSize={0.024} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
|
||||
{username}
|
||||
</Text>
|
||||
</group>
|
||||
)}
|
||||
|
||||
{(isTalking || isLastChatSender) && (
|
||||
<mesh ref={ringRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.01, 0]}>
|
||||
@@ -277,18 +281,33 @@ function MiiAvatarBackup({
|
||||
|
||||
{/* Cabeça do Avatar: Toon Head do Dicebear em HTML Transformado em 3D Plano (olhando para a mesa) */}
|
||||
<group ref={headRef} position={[0, 0.16, 0]}>
|
||||
<Html transform center distanceFactor={1.2}>
|
||||
<div className="w-16 h-16 flex items-center justify-center pointer-events-none select-none">
|
||||
<img
|
||||
src={avatarUrl}
|
||||
alt={username}
|
||||
className="w-full h-full object-contain drop-shadow-md"
|
||||
onError={(e) => {
|
||||
(e.currentTarget as HTMLImageElement).src = `https://ui-avatars.com/api/?name=${encodeURIComponent(username || 'U')}&background=475569&color=fff&size=128&rounded=true`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Html>
|
||||
{inLobby ? (
|
||||
<Html center distanceFactor={0.8}>
|
||||
<div className="w-20 h-20 flex items-center justify-center pointer-events-none select-none">
|
||||
<img
|
||||
src={avatarUrl}
|
||||
alt={username}
|
||||
className="w-full h-full object-contain drop-shadow-md"
|
||||
onError={(e) => {
|
||||
(e.currentTarget as HTMLImageElement).src = `https://ui-avatars.com/api/?name=${encodeURIComponent(username || 'U')}&background=475569&color=fff&size=128&rounded=true`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Html>
|
||||
) : (
|
||||
<Html transform center distanceFactor={1.2}>
|
||||
<div className="w-16 h-16 flex items-center justify-center pointer-events-none select-none">
|
||||
<img
|
||||
src={avatarUrl}
|
||||
alt={username}
|
||||
className="w-full h-full object-contain drop-shadow-md"
|
||||
onError={(e) => {
|
||||
(e.currentTarget as HTMLImageElement).src = `https://ui-avatars.com/api/?name=${encodeURIComponent(username || 'U')}&background=475569&color=fff&size=128&rounded=true`;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Html>
|
||||
)}
|
||||
</group>
|
||||
|
||||
{/* Base cônica para dar uma sustentação 3D estilizada */}
|
||||
@@ -332,6 +351,7 @@ function MiiAvatar(props: {
|
||||
isTalking?: boolean;
|
||||
scale?: number;
|
||||
isLastChatSender?: boolean;
|
||||
inLobby?: boolean;
|
||||
} & Record<string, unknown>) {
|
||||
const preset = AVATAR_PRESETS.find((p) => p.id === props.avatarId);
|
||||
const isPng = preset?.url.endsWith('.png');
|
||||
@@ -477,12 +497,12 @@ function RealMiiAvatar({
|
||||
return (
|
||||
<group ref={groupRef} position={positionVector} rotation={rotationEuler} scale={scale}>
|
||||
{/* Balão de Nome acima da cabeça */}
|
||||
<group position={[0, 0.9, 0]}>
|
||||
<group position={[0, 0.76, 0]}>
|
||||
<mesh position={[0, 0, -0.001]}>
|
||||
<planeGeometry args={[0.52, 0.11]} />
|
||||
<planeGeometry args={[0.26, 0.055]} />
|
||||
<meshBasicMaterial color="#0f172a" transparent opacity={0.8} />
|
||||
</mesh>
|
||||
<Text fontSize={0.052} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
|
||||
<Text fontSize={0.026} color="#ffffff" anchorX="center" anchorY="middle" fontWeight="bold">
|
||||
{username}
|
||||
</Text>
|
||||
</group>
|
||||
@@ -1157,16 +1177,20 @@ export default function MeetingRoom() {
|
||||
|
||||
// Escuta mensagens do Chat via Broadcast
|
||||
channel.on('broadcast', { event: 'chat_msg' }, (payload) => {
|
||||
const sender = payload.payload.sender;
|
||||
// Se a mensagem veio do próprio usuário local, ignora para não duplicar
|
||||
if (sender === name.substring(0, 10)) return;
|
||||
|
||||
setChatMessages((prev) => [
|
||||
...prev,
|
||||
{
|
||||
id: Math.random().toString(),
|
||||
sender: payload.payload.sender,
|
||||
sender: sender,
|
||||
text: payload.payload.text,
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
},
|
||||
]);
|
||||
setLastChatSender(payload.payload.sender);
|
||||
setLastChatSender(sender);
|
||||
});
|
||||
|
||||
// Escuta atualizações de Apresentação da Maquete via Broadcast (apenas para convidados)
|
||||
@@ -1351,7 +1375,7 @@ export default function MeetingRoom() {
|
||||
<ambientLight intensity={0.8} />
|
||||
<directionalLight position={[2, 3, 2]} intensity={1.5} />
|
||||
<pointLight position={[0, 0.15, 0.2]} intensity={1} color={currentAvatar.color} />
|
||||
<MiiAvatar avatarId={selectedAvatar} username={name || 'Você'} position={[0, -0.04, 0]} isTalking={true} scale={0.6} />
|
||||
<MiiAvatar avatarId={selectedAvatar} username={name || 'Você'} position={[0, -0.04, 0]} isTalking={true} scale={0.6} inLobby={true} />
|
||||
</Canvas>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-full w-full bg-slate-950/80 p-4 text-center">
|
||||
@@ -1654,7 +1678,7 @@ export default function MeetingRoom() {
|
||||
rotation={chairConf.rot}
|
||||
isTalking={isLocalUser ? isTalking : (isTalking && Math.random() > 0.5)}
|
||||
isLastChatSender={peer.username === lastChatSender}
|
||||
scale={4.8}
|
||||
scale={3.84}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user