feat: интеграция Lottie анимации AI robot в assist.html

This commit is contained in:
2026-05-25 18:01:35 +03:00
parent 26d09501fb
commit a31fb3a112
+70 -105
View File
@@ -4,6 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>NOVA Assistant</title>
<!-- Lottie Player -->
<script src="https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs" type="module"></script>
<style>
* {
margin: 0;
@@ -102,91 +104,51 @@
50% { transform: scale(1.2); opacity: 0.8; }
}
/* Главная сфера (ORB) */
/* Главная сфера (ORB) - Lottie анимация */
.orb-container {
position: relative;
width: 300px;
height: 300px;
width: 400px;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
}
.orb {
width: 250px;
height: 250px;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #00ffff, #0066aa);
box-shadow:
0 0 60px rgba(0, 255, 255, 0.4),
inset 0 0 40px rgba(255, 255, 255, 0.1);
.lottie-player {
width: 100%;
height: 100%;
filter: drop-shadow(0 0 40px rgba(0, 255, 255, 0.3));
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
/* Анимация пульсации при прослушивании */
.orb.listening {
animation: orb-pulse 1.5s ease-in-out infinite;
box-shadow:
0 0 100px rgba(0, 255, 255, 0.8),
0 0 150px rgba(0, 255, 255, 0.4),
inset 0 0 60px rgba(255, 255, 255, 0.2);
/* Эффекты для разных состояний */
.lottie-player.listening {
filter: drop-shadow(0 0 80px rgba(0, 255, 255, 0.8))
drop-shadow(0 0 120px rgba(0, 255, 255, 0.5));
animation: lottie-pulse 1.5s ease-in-out infinite;
}
@keyframes orb-pulse {
@keyframes lottie-pulse {
0%, 100% {
transform: scale(1);
box-shadow:
0 0 60px rgba(0, 255, 255, 0.4),
inset 0 0 40px rgba(255, 255, 255, 0.1);
}
50% {
transform: scale(1.05);
box-shadow:
0 0 120px rgba(0, 255, 255, 0.8),
0 0 180px rgba(0, 255, 255, 0.5),
inset 0 0 80px rgba(255, 255, 255, 0.3);
}
}
/* Анимация при говорении */
.orb.speaking {
animation: orb-speak 0.8s ease-in-out infinite;
background: radial-gradient(circle at 35% 35%, #ff00ff, #ff0088);
box-shadow:
0 0 100px rgba(255, 0, 255, 0.6),
0 0 150px rgba(255, 0, 255, 0.3);
.lottie-player.speaking {
filter: drop-shadow(0 0 80px rgba(255, 0, 255, 0.8))
drop-shadow(0 0 120px rgba(255, 0, 255, 0.5));
animation: lottie-speak 0.8s ease-in-out infinite;
}
@keyframes orb-speak {
@keyframes lottie-speak {
0%, 100% { transform: scale(1); }
25% { transform: scale(1.03); }
75% { transform: scale(0.98); }
}
/* RMS визуализация внутри сферы */
.orb-waves {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.wave-bar {
width: 6px;
height: 20px;
background: rgba(255, 255, 255, 0.6);
border-radius: 3px;
transition: height 0.1s ease;
}
/* Статус текст */
.status-text {
font-size: 24px;
@@ -383,13 +345,17 @@
<!-- Главный контейнер -->
<div class="assistant-container">
<!-- Сфера с анимацией -->
<!-- Lottie анимация робота -->
<div class="orb-container">
<div class="orb" id="orb">
<div class="orb-waves" id="orbWaves">
<!-- Волны будут добавлены через JS -->
</div>
</div>
<dotlottie-player
id="lottiePlayer"
class="lottie-player"
src="AI robot.lottie"
background="transparent"
speed="1"
loop
autoplay>
</dotlottie-player>
</div>
<!-- Статус -->
@@ -433,8 +399,7 @@
// ==================== DOM ЭЛЕМЕНТЫ ====================
const statusDot = document.getElementById('statusDot');
const statusLabel = document.getElementById('statusLabel');
const orb = document.getElementById('orb');
const orbWaves = document.getElementById('orbWaves');
const lottiePlayer = document.getElementById('lottiePlayer');
const statusText = document.getElementById('statusText');
const volumeSlider = document.getElementById('volumeSlider');
const volumeValue = document.getElementById('volumeValue');
@@ -442,19 +407,6 @@
const volDownBtn = document.getElementById('volDownBtn');
const transcriptText = document.getElementById('transcriptText');
// ==================== ИНИЦИАЛИЗАЦИЯ ====================
// Создать волновые бары
function initWaveBars() {
orbWaves.innerHTML = '';
for (let i = 0; i < NUM_WAVE_BARS; i++) {
const bar = document.createElement('div');
bar.className = 'wave-bar';
bar.dataset.index = i;
orbWaves.appendChild(bar);
}
}
// Создать фоновые частицы
function initParticles() {
const particles = document.getElementById('particles');
@@ -468,28 +420,30 @@
}
}
// ==================== АНИМАЦИЯ ВОЛН ====================
function animateWaves() {
const bars = orbWaves.querySelectorAll('.wave-bar');
// ==================== УПРАВЛЕНИЕ LOTTIE ====================
function updateLottieSpeed() {
if (!lottiePlayer) return;
bars.forEach((bar, index) => {
let height = 20;
if (currentState === 'listening' || currentState === 'speaking') {
// Анимация на основе RMS
const rmsScaled = Math.min(1, currentRms * 5); // Усиление RMS
const baseHeight = 20 + rmsScaled * 80;
const wave = Math.sin(Date.now() / 200 + index * 0.5) * 20;
height = baseHeight + wave;
} else {
// Минимальная анимация в idle
height = 20 + Math.sin(Date.now() / 500 + index * 0.3) * 5;
}
bar.style.height = height + 'px';
});
// Изменяем скорость анимации в зависимости от состояния и RMS
let speed = 1.0;
requestAnimationFrame(animateWaves);
if (currentState === 'listening') {
// При прослушивании скорость зависит от RMS
const rmsScaled = Math.min(1, currentRms * 5);
speed = 0.8 + rmsScaled * 1.2; // 0.8 - 2.0
} else if (currentState === 'speaking') {
speed = 1.5; // Быстрее при говорении
} else {
speed = 0.6; // Медленнее в idle
}
lottiePlayer.setSpeed(speed);
}
// Обновление скорости анимации в реальном времени
function animateLottie() {
updateLottieSpeed();
requestAnimationFrame(animateLottie);
}
// ==================== WEBSOCKET ====================
@@ -615,15 +569,19 @@
}
}
// ==================== ОБНОВЛЕНИЕ СОСТОЯНИЯ СФЕРЫ ====================
// ==================== ОБНОВЛЕНИЕ СОСТОЯНИЯ АНИМАЦИИ ====================
function updateOrbState() {
orb.classList.remove('listening', 'speaking');
if (!lottiePlayer) return;
lottiePlayer.classList.remove('listening', 'speaking');
if (currentState === 'listening') {
orb.classList.add('listening');
lottiePlayer.classList.add('listening');
} else if (currentState === 'speaking') {
orb.classList.add('speaking');
lottiePlayer.classList.add('speaking');
}
updateLottieSpeed();
}
// ==================== УПРАВЛЕНИЕ ГРОМКОСТЬЮ ====================
@@ -664,10 +622,17 @@
// ==================== ЗАПУСК ====================
window.addEventListener('load', () => {
console.log('🚀 NOVA Assistant initialized');
initWaveBars();
initParticles();
animateWaves();
animateLottie();
connectWebSocket();
// Дождаться загрузки Lottie
if (lottiePlayer) {
lottiePlayer.addEventListener('ready', () => {
console.log('✅ Lottie animation loaded');
updateLottieSpeed();
});
}
});
</script>