Skip to main content

📱 ИНТЕРАКТИВНЫЙ ВЕБ-ИНТЕРФЕЙС УПРАВЛЕНИЯ

От статической панели к живому цифровому опыту


🎯 МЕТОДОЛОГИЧЕСКАЯ КОНЦЕПЦИЯ СПРИНТА

Философия трансформации:

БЫЛО: Веб-страница отвечает на клики (реактивный интерфейс)
СТАЛО: Интерфейс ведет диалог с пользователем (проактивный партнер)

Ключевая идея: Дети создают “цифрового помощника” - интерфейс, который не просто выполняет команды, а понимает контекст, предлагает решения и адаптируется под каждого пользователя.

Эволюционный скачок:

  • Кнопки → Жесты: От механических кликов к естественным движениям
  • Статика → Анимация: Каждое взаимодействие живое и отзывчивое
  • Универсальность → Персонализация: Интерфейс помнит и адаптируется
  • Инструмент → Собеседник: Система ведет диалог с пользователем

🧠 ПЕДАГОГИЧЕСКИЕ ЦЕЛИ СПРИНТА

Концептуальные цели:

  • “Интерактивность” как двусторонний разговор человека и машины
  • “Контекстное мышление” - система понимает ситуацию пользователя
  • “Адаптивность” - интерфейс эволюционирует от использования
  • “Эмпатический дизайн” - технология должна понимать эмоции

Технические цели:

  • Advanced JavaScript: жесты, анимации, real-time обновления
  • CSS3: transitions, transforms, keyframes для живого интерфейса
  • Web APIs: геолокация, вибрация, battery, device orientation
  • Progressive Web App (PWA) - превращаем в мобильное приложение
  • Machine Learning на клиенте: TensorFlow.js для предсказаний

Метакогнитивные цели:

  • “UX мышление” - как пользователь думает и чувствует
  • “Поведенческий дизайн” - как интерфейс влияет на действия
  • “Инклюзивное мышление” - дизайн для всех типов пользователей

📚 СТРУКТУРА СПРИНТА (4 занятия)

Занятие 1: “Психология взаимодействия” 🧠

Длительность: 90 минут

Фаза 1: Эксперимент “Эмоции интерфейса” (25 мин)

Метод: Экспериментальная психология UX

Практический эксперимент: Дети тестируют 3 версии одного интерфейса:

<!-- Версия 1: "Холодный робот" -->
<button onclick="turnOnLight()">ВКЛЮЧИТЬ СВЕТ</button>

<!-- Версия 2: "Дружелюбный помощник" -->
<button onclick="turnOnLight()" class="friendly">
    ☀️ Сделать светлее
</button>

<!-- Версия 3: "Умный собеседник" -->
<button onclick="smartLighting()" class="smart">
    💡 <span id="lightSuggestion">Создать комфортное освещение</span>
</button>

Ключевые открытия:

  • “Слова = эмоции. Технология тоже может быть дружелюбной”
  • “Эмодзи = универсальный язык эмоций”
  • “Предложения лучше команд”

Фаза 2: Анализ пользовательских ролей (30 мин)

Метод: Persona Development

Создание “Персон” для системы:

const userPersonas = {
    teacher: {
        name: "Мария Ивановна",
        age: 45,
        techLevel: "средний",
        goals: ["быстро подготовить класс", "сэкономить время"],
        frustrations: ["сложные интерфейсы", "медленные системы"],
        preferredInteraction: "голосовые команды",
        timeOfDay: "утро",
        interface: {
            buttonSize: "large",
            textSize: "18px",
            animations: "minimal",
            shortcuts: true
        }
    },
    
    student: {
        name: "Максим",
        age: 12,
        techLevel: "высокий",
        goals: ["изучить как работает", "поиграть с системой"],
        frustrations: ["скучные интерфейсы", "много текста"],
        preferredInteraction: "жесты и анимации",
        timeOfDay: "любое",
        interface: {
            buttonSize: "medium",
            textSize: "16px", 
            animations: "rich",
            gamification: true
        }
    },
    
    janitor: {
        name: "Сергей Петрович",
        age: 55,
        techLevel: "низкий",
        goals: ["проверить что все выключено", "безопасность"],
        frustrations: ["сложная технология", "мелкий текст"],
        preferredInteraction: "простые кнопки",
        timeOfDay: "вечер",
        interface: {
            buttonSize: "extra-large",
            textSize: "24px",
            animations: "none",
            highContrast: true
        }
    }
};

Практическое задание: Дети адаптируют один интерфейс под каждую персону.

Фаза 3: Принципы живого интерфейса (20 мин)

Концепция: “12 принципов интерактивности”

const interactivityPrinciples = {
    1: "Немедленная реакция - система отвечает за 100мс",
    2: "Визуальная обратная связь - пользователь видит результат",
    3: "Тактильная обратная связь - вибрация подтверждает действие", 
    4: "Звуковая обратная связь - звуки создают атмосферу",
    5: "Предсказание желаний - система предлагает действия",
    6: "Контекстная адаптация - интерфейс меняется по ситуации",
    7: "Прощение ошибок - любое действие можно отменить",
    8: "Прогрессивное раскрытие - сложность появляется постепенно",
    9: "Эмоциональный дизайн - интерфейс вызывает положительные эмоции",
    10: "Инклюзивность - доступно для людей с ограничениями",
    11: "Персонализация - система помнит предпочтения",
    12: "Обучение - интерфейс становится умнее от использования"
};

Фаза 4: Wireframing интерактивного интерфейса (15 мин)

Метод: Collaborative Design

Дети рисуют схемы интерфейса с учетом всех принципов:

  • Где располагаются элементы для каждой персоны
  • Какие анимации и переходы будут
  • Как система будет адаптироваться
  • Какие жесты и взаимодействия поддерживать

Занятие 2: “Создание живого интерфейса” ✨

Длительность: 90 минут

Фаза 1: Продвинутый HTML с семантикой (20 мин)

Концепция: “HTML как язык смысла”

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="ALEX - Умная система управления классом">
    <meta name="theme-color" content="#667eea">
    
    <!-- PWA мета-теги -->
    <link rel="manifest" href="/manifest.json">
    <link rel="apple-touch-icon" href="/icon-192.png">
    
    <title>🤖 ALEX - Ваш умный помощник</title>
    
    <style>
        /* CSS Custom Properties для динамической темизации */
        :root {
            --primary-color: #667eea;
            --secondary-color: #764ba2;
            --accent-color: #4ECDC4;
            --text-color: white;
            --background-opacity: 0.1;
            --animation-speed: 0.3s;
            --border-radius: 15px;
            --shadow-color: rgba(0,0,0,0.2);
            
            /* Адаптивные размеры */
            --button-size: clamp(120px, 15vw, 200px);
            --text-size: clamp(14px, 2vw, 18px);
            --icon-size: clamp(2rem, 4vw, 4rem);
        }
        
        /* Темы для разных персон */
        [data-persona="teacher"] {
            --button-size: clamp(150px, 20vw, 250px);
            --text-size: clamp(16px, 2.5vw, 20px);
            --animation-speed: 0.2s;
        }
        
        [data-persona="student"] {
            --accent-color: #FF6B6B;
            --animation-speed: 0.4s;
            --border-radius: 20px;
        }
        
        [data-persona="janitor"] {
            --button-size: clamp(180px, 25vw, 300px);
            --text-size: clamp(18px, 3vw, 24px);
            --animation-speed: 0.1s;
            --background-opacity: 0.2;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
            min-height: 100vh;
            overflow-x: hidden;
            transition: all var(--animation-speed) ease;
            user-select: none;
        }
        
        /* Адаптивный контейнер */
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: clamp(15px, 3vw, 30px);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
        }
        
        /* Семантическая шапка */
        .system-header {
            text-align: center;
            margin-bottom: 2rem;
            animation: slideInDown 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }
        
        .system-title {
            font-size: clamp(2rem, 6vw, 4rem);
            color: var(--text-color);
            margin-bottom: 1rem;
            text-shadow: 2px 2px 4px var(--shadow-color);
            position: relative;
        }
        
        .system-title::after {
            content: '';
            position: absolute;
            bottom: -10px;
            left: 50%;
            transform: translateX(-50%);
            width: 100px;
            height: 3px;
            background: var(--accent-color);
            border-radius: 2px;
            animation: expandWidth 1s ease-out 0.5s backwards;
        }
        
        @keyframes expandWidth {
            from { width: 0; }
            to { width: 100px; }
        }
        
        /* Адаптивная статус-панель */
        .status-panel {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 1rem;
            background: rgba(255,255,255, var(--background-opacity));
            padding: 1rem 2rem;
            border-radius: var(--border-radius);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255,255,255,0.2);
            margin-bottom: 2rem;
            transition: all var(--animation-speed) ease;
        }
        
        .status-panel:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 25px var(--shadow-color);
        }
        
        .status-indicator {
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }
        
        .status-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: var(--accent-color);
            animation: pulse 2s infinite;
            position: relative;
        }
        
        .status-dot::after {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: var(--accent-color);
            animation: ripple 2s infinite;
        }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }
        
        @keyframes ripple {
            0% {
                transform: scale(1);
                opacity: 0.7;
            }
            100% {
                transform: scale(2);
                opacity: 0;
            }
        }
        
        /* Основная область контента */
        .main-content {
            flex: 1;
            display: grid;
            gap: 2rem;
            grid-template-columns: 1fr;
        }
        
        @media (min-width: 768px) {
            .main-content {
                grid-template-columns: 2fr 1fr;
            }
        }
        
        /* Интерактивная панель датчиков */
        .sensors-section {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 1.5rem;
        }
        
        .sensor-card {
            background: rgba(255,255,255, var(--background-opacity));
            backdrop-filter: blur(15px);
            border-radius: var(--border-radius);
            padding: 1.5rem;
            border: 1px solid rgba(255,255,255,0.2);
            position: relative;
            overflow: hidden;
            cursor: pointer;
            transition: all var(--animation-speed) cubic-bezier(0.175, 0.885, 0.32, 1.275);
            
            /* Подготовка к анимациям */
            transform-origin: center;
            will-change: transform;
        }
        
        .sensor-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
            transition: left 0.5s ease;
            z-index: 1;
        }
        
        .sensor-card:hover::before {
            left: 100%;
        }
        
        .sensor-card:hover {
            transform: translateY(-8px) scale(1.02);
            box-shadow: 0 20px 40px var(--shadow-color);
            border-color: rgba(255,255,255,0.4);
        }
        
        .sensor-card:active {
            transform: translateY(-4px) scale(0.98);
        }
        
        /* Семантическая структура датчика */
        .sensor-icon {
            font-size: var(--icon-size);
            margin-bottom: 1rem;
            display: block;
            transition: transform var(--animation-speed) ease;
            position: relative;
            z-index: 2;
        }
        
        .sensor-card:hover .sensor-icon {
            transform: scale(1.2) rotate(5deg);
        }
        
        .sensor-name {
            font-size: calc(var(--text-size) * 1.1);
            color: rgba(255,255,255,0.9);
            margin-bottom: 0.5rem;
            font-weight: 600;
            position: relative;
            z-index: 2;
        }
        
        .sensor-value {
            font-size: calc(var(--text-size) * 1.8);
            font-weight: bold;
            color: var(--text-color);
            margin: 1rem 0;
            position: relative;
            z-index: 2;
            transition: all var(--animation-speed) ease;
        }
        
        .sensor-status {
            font-size: calc(var(--text-size) * 0.9);
            color: rgba(255,255,255,0.8);
            font-style: italic;
            position: relative;
            z-index: 2;
        }
        
        /* Визуальный прогресс-бар */
        .sensor-progress {
            width: 100%;
            height: 6px;
            background: rgba(255,255,255,0.2);
            border-radius: 3px;
            overflow: hidden;
            margin-top: 1rem;
            position: relative;
            z-index: 2;
        }
        
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, var(--accent-color), var(--primary-color));
            border-radius: 3px;
            transition: width 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            position: relative;
        }
        
        .progress-fill::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
            animation: progressShine 2s infinite;
        }
        
        @keyframes progressShine {
            0% { transform: translateX(-100%); }
            100% { transform: translateX(100%); }
        }
        
        /* Панель управления */
        .controls-section {
            display: flex;
            flex-direction: column;
            gap: 1.5rem;
        }
        
        .section-title {
            color: var(--text-color);
            font-size: calc(var(--text-size) * 1.3);
            margin-bottom: 1rem;
            text-align: center;
            position: relative;
        }
        
        .section-title::after {
            content: '';
            position: absolute;
            bottom: -5px;
            left: 50%;
            transform: translateX(-50%);
            width: 50px;
            height: 2px;
            background: var(--accent-color);
            border-radius: 1px;
        }
        
        /* Умные кнопки управления */
        .control-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(var(--button-size), 1fr));
            gap: 1rem;
        }
        
        .smart-button {
            background: rgba(255,255,255, var(--background-opacity));
            border: 2px solid rgba(255,255,255,0.3);
            border-radius: var(--border-radius);
            padding: 1.5rem 1rem;
            color: var(--text-color);
            font-size: var(--text-size);
            font-weight: 600;
            cursor: pointer;
            position: relative;
            overflow: hidden;
            transition: all var(--animation-speed) cubic-bezier(0.175, 0.885, 0.32, 1.275);
            text-align: center;
            user-select: none;
            backdrop-filter: blur(10px);
            
            /* Подготовка к трансформациям */
            transform-origin: center;
            will-change: transform;
        }
        
        .smart-button::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: radial-gradient(circle at center, rgba(255,255,255,0.3) 0%, transparent 70%);
            opacity: 0;
            transition: opacity var(--animation-speed) ease;
            z-index: 1;
        }
        
        .smart-button:hover::before {
            opacity: 1;
        }
        
        .smart-button:hover {
            transform: translateY(-4px) scale(1.05);
            box-shadow: 0 15px 35px var(--shadow-color);
            border-color: rgba(255,255,255,0.5);
            background: rgba(255,255,255, calc(var(--background-opacity) + 0.1));
        }
        
        .smart-button:active {
            transform: translateY(-2px) scale(0.95);
            transition: transform 0.1s ease;
        }
        
        /* Содержимое кнопки */
        .button-content {
            position: relative;
            z-index: 2;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 0.5rem;
        }
        
        .button-icon {
            font-size: calc(var(--text-size) * 1.5);
            margin-bottom: 0.5rem;
        }
        
        .button-text {
            font-weight: 600;
            line-height: 1.2;
        }
        
        .button-description {
            font-size: calc(var(--text-size) * 0.8);
            opacity: 0.8;
            line-height: 1.2;
        }
        
        /* Специальные кнопки */
        .smart-button.primary {
            background: linear-gradient(135deg, var(--accent-color), var(--primary-color));
            border: none;
            animation: primaryGlow 3s infinite;
        }
        
        @keyframes primaryGlow {
            0%, 100% {
                box-shadow: 0 5px 20px rgba(78, 205, 196, 0.4);
            }
            50% {
                box-shadow: 0 5px 30px rgba(78, 205, 196, 0.6);
            }
        }
        
        .smart-button.danger {
            border-color: #ff6b6b;
            color: #ff6b6b;
        }
        
        .smart-button.danger:hover {
            background: rgba(255, 107, 107, 0.1);
            border-color: #ff5252;
        }
        
        /* Рипл-эффект для кнопок */
        .smart-button::after {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            width: 0;
            height: 0;
            border-radius: 50%;
            background: rgba(255,255,255,0.4);
            transform: translate(-50%, -50%);
            transition: width 0.6s ease, height 0.6s ease;
            z-index: 1;
        }
        
        .smart-button:active::after {
            width: 300px;
            height: 300px;
        }
        
        /* Адаптивность */
        @media (max-width: 768px) {
            .main-content {
                grid-template-columns: 1fr;
            }
            
            .sensors-section {
                grid-template-columns: 1fr;
            }
        }
        
        @media (max-width: 480px) {
            .sensor-card {
                padding: 1rem;
            }
            
            .smart-button {
                padding: 1rem 0.5rem;
            }
        }
        
        /* Темы времени суток */
        .theme-morning {
            --primary-color: #ffeaa7;
            --secondary-color: #fdcb6e;
            --accent-color: #e17055;
        }
        
        .theme-evening {
            --primary-color: #6c5ce7;
            --secondary-color: #a29bfe;
            --accent-color: #fd79a8;
        }
        
        .theme-night {
            --primary-color: #2d3436;
            --secondary-color: #636e72;
            --accent-color: #00b894;
        }
        
        /* Анимации появления */
        @keyframes slideInDown {
            from {
                transform: translateY(-50px);
                opacity: 0;
            }
            to {
                transform: translateY(0);
                opacity: 1;
            }
        }
        
        @keyframes slideInUp {
            from {
                transform: translateY(50px);
                opacity: 0;
            }
            to {
                transform: translateY(0);
                opacity: 1;
            }
        }
        
        @keyframes fadeInScale {
            from {
                transform: scale(0.8);
                opacity: 0;
            }
            to {
                transform: scale(1);
                opacity: 1;
            }
        }
        
        /* Применение анимаций */
        .sensor-card {
            animation: fadeInScale 0.6s ease-out backwards;
        }
        
        .sensor-card:nth-child(1) { animation-delay: 0.1s; }
        .sensor-card:nth-child(2) { animation-delay: 0.2s; }
        .sensor-card:nth-child(3) { animation-delay: 0.3s; }
        .sensor-card:nth-child(4) { animation-delay: 0.4s; }
        
        .smart-button {
            animation: slideInUp 0.6s ease-out backwards;
        }
        
        .smart-button:nth-child(1) { animation-delay: 0.5s; }
        .smart-button:nth-child(2) { animation-delay: 0.6s; }
        .smart-button:nth-child(3) { animation-delay: 0.7s; }
        .smart-button:nth-child(4) { animation-delay: 0.8s; }
        .smart-button:nth-child(5) { animation-delay: 0.9s; }
        .smart-button:nth-child(6) { animation-delay: 1.0s; }
    </style>
</head>

<body data-persona="student" id="app">
    <div class="container">
        <!-- Семантическая шапка -->
        <header class="system-header">
            <h1 class="system-title">🤖 ALEX</h1>
            <div class="status-panel">
                <div class="status-indicator">
                    <div class="status-dot" id="statusDot"></div>
                    <span id="systemStatus">Подключаюсь к системе...</span>
                </div>
                <div class="status-indicator">
                    <span id="connectionQuality">📶</span>
                    <span id="batteryLevel">🔋</span>
                </div>
            </div>
        </header>
        
        <!-- Основной контент -->
        <main class="main-content">
            <!-- Секция датчиков -->
            <section class="sensors-section">
                <article class="sensor-card" data-sensor="temperature" role="button" tabindex="0" aria-label="Датчик температуры">
                    <span class="sensor-icon" aria-hidden="true">🌡️</span>
                    <h3 class="sensor-name">Температура</h3>
                    <div class="sensor-value" id="temperature" aria-live="polite">--°C</div>
                    <p class="sensor-status" id="tempStatus">Загрузка...</p>
                    <div class="sensor-progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
                        <div class="progress-fill" id="tempProgress" style="width: 0%"></div>
                    </div>
                </article>
                
                <article class="sensor-card" data-sensor="light" role="button" tabindex="0" aria-label="Датчик освещенности">
                    <span class="sensor-icon" aria-hidden="true">💡</span>
                    <h3 class="sensor-name">Освещенность</h3>
                    <div class="sensor-value" id="light" aria-live="polite">--%</div>
                    <p class="sensor-status" id="lightStatus">Загрузка...</p>
                    <div class="sensor-progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
                        <div class="progress-fill" id="lightProgress" style="width: 0%"></div>
                    </div>
                </article>
                
                <article class="sensor-card" data-sensor="sound" role="button" tabindex="0" aria-label="Датчик звука">
                    <span class="sensor-icon" aria-hidden="true">🔊</span>
                    <h3 class="sensor-name">Уровень шума</h3>
                    <div class="sensor-value" id="sound" aria-live="polite">--дБ</div>
                    <p class="sensor-status" id="soundStatus">Загрузка...</p>
                    <div class="sensor-progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
                        <div class="progress-fill" id="soundProgress" style="width: 0%"></div>
                    </div>
                </article>
                
                <article class="sensor-card" data-sensor="motion" role="button" tabindex="0" aria-label="Датчик движения">
                    <span class="sensor-icon" aria-hidden="true">🚶</span>
                    <h3 class="sensor-name">Движение</h3>
                    <div class="sensor-value" id="motion" aria-live="polite">--</div>
                    <p class="sensor-status" id="motionStatus">Загрузка...</p>
                    <div class="sensor-progress" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
                        <div class="progress-fill" id="motionProgress" style="width: 0%"></div>
                    </div>
                </article>
            </section>
            
            <!-- Панель управления -->
            <aside class="controls-section">
                <h2 class="section-title">🎛️ Умное управление</h2>
                <div class="control-grid">
                    <button class="smart-button primary" data-mode="comfort" data-description="Идеальная температура и освещение">
                        <div class="button-content">
                            <span class="button-icon">😌</span>
                            <span class="button-text">Комфорт</span>
                            <span class="button-description">Создать уют</span>
                        </div>
                    </button>
                    
                    <button class="smart-button" data-mode="eco" data-description="Экономия энергии с умом">
                        <div class="button-content">
                            <span class="button-icon">🌱</span>
                            <span class="button-text">Эко-режим</span>
                            <span class="button-description">Сберечь планету</span>
                        </div>
                    </button>
                    
                    <button class="smart-button" data-mode="focus" data-description="Оптимальные условия для концентрации">
                        <div class="button-content">
                            <span class="button-icon">🎯</span>
                            <span class="button-text">Фокус</span>
                            <span class="button-description">Время учиться</span>
                        </div>
                    </button>
                    
                    <button class="smart-button" data-mode="party" data-description="Атмосфера для веселья">
                        <div class="button-content">
                            <span class="button-icon">🎉</span>
                            <span class="button-text">Вечеринка</span>
                            <span class="button-description">Время радости</span>
                        </div>
                    </button>
                    
                    <button class="smart-button" data-mode="presentation" data-description="Подготовка к показу">
                        <div class="button-content">
                            <span class="button-icon">📽️</span>
                            <span class="button-text">Презентация</span>
                            <span class="button-description">Все внимание</span>
                        </div>
                    </button>
                    
                    <button class="smart-button danger" data-mode="emergency" data-description="Экстренное отключение">
                        <div class="button-content">
                            <span class="button-icon">🚨</span>
                            <span class="button-text">Экстренный</span>
                            <span class="button-description">Все выключить</span>
                        </div>
                    </button>
                </div>
            </aside>
        </main>
    </div>
</body>
</html>

Фаза 2: Продвинутый JavaScript для интерактивности (35 мин)

Концепция: “JavaScript как мозг интерфейса”

// === КЛАСС УМНОГО ИНТЕРФЕЙСА ===
class SmartInterface {
    constructor() {
        this.sensorData = {};
        this.userPreferences = this.loadUserPreferences();
        this.currentPersona = this.detectPersona();
        this.socket = null;
        this.isOnline = false;
        this.gestureRecognizer = null;
        
        this.init();
    }
    
    async init() {
        console.log('🚀 Инициализация умного интерфейса...');
        
        // Определяем возможности устройства
        await this.detectDeviceCapabilities();
        
        // Настраиваем персону
        this.applyPersona(this.currentPersona);
        
        // Подключаемся к системе
        this.connectToSystem();
        
        // Инициализируем взаимодействия
        this.setupInteractions();
        
        // Запускаем адаптивную логику
        this.startAdaptiveEngine();
        
        console.log('✅ Умный интерфейс готов!');
        this.showWelcomeMessage();
    }
    
    // === ОПРЕДЕЛЕНИЕ ВОЗМОЖНОСТЕЙ УСТРОЙСТВА ===
    async detectDeviceCapabilities() {
        const capabilities = {
            vibration: 'vibrate' in navigator,
            geolocation: 'geolocation' in navigator,
            battery: 'getBattery' in navigator,
            deviceMotion: 'DeviceMotionEvent' in window,
            touchGestures: 'ontouchstart' in window,
            voiceRecognition: 'SpeechRecognition' in window || 'webkitSpeechRecognition' in window,
            notifications: 'Notification' in window,
            serviceWorker: 'serviceWorker' in navigator
        };
        
        this.deviceCapabilities = capabilities;
        
        // Запрашиваем разрешения
        if (capabilities.notifications && Notification.permission !== 'granted') {
            await Notification.requestPermission();
        }
        
        // Получаем информацию о батарее
        if (capabilities.battery) {
            try {
                this.battery = await navigator.getBattery();
                this.updateBatteryIndicator();
                this.battery.addEventListener('levelchange', () => this.updateBatteryIndicator());
            } catch (e) {
                console.log('Информация о батарее недоступна');
            }
        }
        
        console.log('📱 Возможности устройства:', capabilities);
    }
    
    // === ОПРЕДЕЛЕНИЕ ПЕРСОНЫ ПОЛЬЗОВАТЕЛЯ ===
    detectPersona() {
        const hour = new Date().getHours();
        const userAgent = navigator.userAgent;
        const screenSize = window.innerWidth;
        
        // Простая эвристика определения типа пользователя
        if (hour >= 7 && hour <= 9) {
            return 'teacher'; // Утром обычно учителя
        } else if (hour >= 16 && hour <= 18) {
            return 'janitor'; // Вечером техперсонал
        } else if (screenSize < 768) {
            return 'student'; // Мобильные устройства чаще у учеников
        }
        
        return 'student'; // По умолчанию
    }
    
    // === ПРИМЕНЕНИЕ ПЕРСОНЫ ===
    applyPersona(persona) {
        document.body.setAttribute('data-persona', persona);
        
        const personaSettings = {
            teacher: {
                animationSpeed: '0.2s',
                buttonSize: '200px',
                textSize: '18px',
                shortcuts: true,
                voiceControl: true
            },
            student: {
                animationSpeed: '0.4s',
                buttonSize: '150px',
                textSize: '16px',
                richAnimations: true,
                gameElements: true
            },
            janitor: {
                animationSpeed: '0.1s',
                buttonSize: '250px',
                textSize: '20px',
                highContrast: true,
                largeTargets: true
            }
        };
        
        const settings = personaSettings[persona];
        if (settings) {
            // Применяем CSS переменные для персоны
            Object.entries(settings).forEach(([key, value]) => {
                if (typeof value === 'string' && value.includes('px') || value.includes('s')) {
                    document.documentElement.style.setProperty(`--${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`, value);
                }
            });
            
            // Специфичные настройки
            if (settings.shortcuts) this.enableKeyboardShortcuts();
            if (settings.voiceControl) this.enableVoiceControl();
            if (settings.richAnimations) this.enableRichAnimations();
            if (settings.gameElements) this.enableGameElements();
        }
        
        console.log(`👤 Применена персона: ${persona}`);
    }
    
    // === ПОДКЛЮЧЕНИЕ К СИСТЕМЕ ===
    connectToSystem() {
        const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${wsProtocol}//${window.location.hostname}:81`;
        
        try {
            this.socket = new WebSocket(wsUrl);
            
            this.socket.onopen = () => {
                this.isOnline = true;
                this.updateConnectionStatus('🟢 Подключен к системе', 'online');
                console.log('🔗 WebSocket подключен');
                
                // Отправляем информацию о пользователе
                this.socket.send(JSON.stringify({
                    type: 'user_info',
                    persona: this.currentPersona,
                    capabilities: this.deviceCapabilities,
                    preferences: this.userPreferences
                }));
            };
            
            this.socket.onmessage = (event) => {
                this.handleSystemMessage(event.data);
            };
            
            this.socket.onclose = () => {
                this.isOnline = false;
                this.updateConnectionStatus('🔴 Переподключение...', 'reconnecting');
                console.log('📡 WebSocket отключен, переподключаюсь...');
                
                // Автоматическое переподключение
                setTimeout(() => this.connectToSystem(), 3000);
            };
            
            this.socket.onerror = (error) => {
                console.error('❌ Ошибка WebSocket:', error);
                this.updateConnectionStatus('🔴 Ошибка соединения', 'error');
            };
            
        } catch (error) {
            console.error('❌ Не удалось подключиться к системе:', error);
            this.updateConnectionStatus('🔴 Офлайн режим', 'offline');
        }
    }
    
    // === ОБРАБОТКА СООБЩЕНИЙ ОТ СИСТЕМЫ ===
    handleSystemMessage(message) {
        try {
            const data = JSON.parse(message);
            
            switch (data.type) {
                case 'sensor_update':
                    this.updateSensorData(data);
                    break;
                case 'system_alert':
                    this.showAlert(data.message, data.level);
                    break;
                case 'suggestion':
                    this.showSuggestion(data.suggestion);
                    break;
                case 'mood_update':
                    this.updateSystemMood(data.mood);
                    break;
                default:
                    console.log('💬 Сообщение от системы:', message);
            }
        } catch (e) {
            // Обычное текстовое сообщение
            console.log('📝 Текст от системы:', message);
        }
    }
    
    // === ОБНОВЛЕНИЕ ДАННЫХ ДАТЧИКОВ ===
    updateSensorData(data) {
        const oldData = { ...this.sensorData };
        this.sensorData = data;
        
        // Анимированное обновление каждого датчика
        this.animateValueUpdate('temperature', data.temperature + '°C', oldData.temperature);
        this.animateValueUpdate('light', Math.round((data.light / 4095) * 100) + '%', oldData.light);
        this.animateValueUpdate('sound', Math.round((data.sound / 4095) * 100) + 'дБ', oldData.sound);
        this.animateValueUpdate('motion', data.motion ? 'Есть' : 'Нет', oldData.motion);
        
        // Обновляем прогресс-бары
        this.updateProgressBar('tempProgress', data.temperature, 0, 40);
        this.updateProgressBar('lightProgress', (data.light / 4095) * 100, 0, 100);
        this.updateProgressBar('soundProgress', (data.sound / 4095) * 100, 0, 100);
        this.updateProgressBar('motionProgress', data.motion ? 100 : 0, 0, 100);
        
        // Обновляем статусы
        this.updateSensorStatus('tempStatus', this.getTemperatureStatus(data.temperature));
        this.updateSensorStatus('lightStatus', this.getLightStatus((data.light / 4095) * 100));
        this.updateSensorStatus('soundStatus', this.getSoundStatus((data.sound / 4095) * 100));
        this.updateSensorStatus('motionStatus', this.getMotionStatus(data.motion));
        
        // Проверяем нужны ли предложения
        this.checkForSuggestions(data);
        
        // Адаптируем интерфейс под условия
        this.adaptInterfaceToConditions(data);
    }
    
    // === АНИМИРОВАННОЕ ОБНОВЛЕНИЕ ЗНАЧЕНИЙ ===
    animateValueUpdate(elementId, newValue, oldValue) {
        const element = document.getElementById(elementId);
        const currentValue = element.textContent;
        
        if (currentValue !== newValue) {
            // Создаем эффект изменения
            element.style.transform = 'scale(1.1)';
            element.style.color = '#FFD93D';
            
            // Добавляем вибрацию на мобильных
            if (this.deviceCapabilities.vibration && oldValue !== undefined) {
                navigator.vibrate(50);
            }
            
            setTimeout(() => {
                element.textContent = newValue;
                element.style.transform = 'scale(1)';
                element.style.color = '';
                
                // Подсвечиваем родительскую карточку
                const card = element.closest('.sensor-card');
                if (card) {
                    card.style.boxShadow = '0 0 30px rgba(255, 217, 61, 0.5)';
                    setTimeout(() => {
                        card.style.boxShadow = '';
                    }, 800);
                }
            }, 200);
            
            // Обновляем ARIA атрибуты для скринридеров
            element.setAttribute('aria-live', 'polite');
        }
    }
    
    // === ОБНОВЛЕНИЕ ПРОГРЕСС-БАРОВ ===
    updateProgressBar(progressId, value, min, max) {
        const progressElement = document.getElementById(progressId);
        const percentage = Math.max(0, Math.min(100, ((value - min) / (max - min)) * 100));
        
        // Плавная анимация изменения
        progressElement.style.width = percentage + '%';
        
        // Обновляем ARIA атрибуты
        const progressBar = progressElement.closest('[role="progressbar"]');
        if (progressBar) {
            progressBar.setAttribute('aria-valuenow', Math.round(percentage));
        }
    }
    
    // === УМНЫЕ СТАТУСЫ ДАТЧИКОВ ===
    getTemperatureStatus(temp) {
        if (temp < 18) return { message: '🥶 Холодно! Предлагаю включить обогрев', color: '#4FC3F7', action: 'heating' };
        if (temp > 26) return { message: '🔥 Жарко! Нужно охлаждение', color: '#FF7043', action: 'cooling' };
        if (temp >= 20 && temp <= 24) return { message: '😌 Идеальная температура', color: '#66BB6A', action: null };
        return { message: '🌡️ Нормальная температура', color: '#FFD54F', action: null };
    }
    
    getLightStatus(light) {
        if (light < 20) return { message: '🌙 Темно! Включить освещение?', color: '#9575CD', action: 'lighting' };
        if (light > 80) return { message: '☀️ Очень светло', color: '#FFB74D', action: null };
        return { message: '👍 Комфортное освещение', color: '#81C784', action: null };
    }
    
    getSoundStatus(sound) {
        if (sound < 20) return { message: '🤫 Очень тихо', color: '#4DB6AC', action: null };
        if (sound > 70) return { message: '📢 Шумно! Попросить потише?', color: '#E57373', action: 'noise_control' };
        return { message: '🎵 Комфортный уровень звука', color: '#AED581', action: null };
    }
    
    getMotionStatus(motion) {
        return motion ? 
            { message: '👥 Люди в классе', color: '#64B5F6', action: null } : 
            { message: '🏫 Класс пустой - эко-режим?', color: '#90A4AE', action: 'eco_mode' };
    }
    
    // === ОБНОВЛЕНИЕ СТАТУСОВ ===
    updateSensorStatus(statusId, status) {
        const statusElement = document.getElementById(statusId);
        statusElement.textContent = status.message;
        statusElement.style.color = status.color;
        
        // Если есть предлагаемое действие, показываем кнопку
        if (status.action) {
            this.showActionSuggestion(statusId, status.action, status.message);
        }
    }
    
    // === ПРЕДЛОЖЕНИЯ ДЕЙСТВИЙ ===
    showActionSuggestion(statusId, action, message) {
        const statusElement = document.getElementById(statusId);
        const existingSuggestion = statusElement.parentElement.querySelector('.action-suggestion');
        
        if (existingSuggestion) {
            existingSuggestion.remove();
        }
        
        const suggestionButton = document.createElement('button');
        suggestionButton.className = 'action-suggestion';
        suggestionButton.innerHTML = '✨ Исправить';
        suggestionButton.style.cssText = `
            margin-top: 8px;
            padding: 6px 12px;
            background: rgba(255,255,255,0.2);
            border: 1px solid rgba(255,255,255,0.3);
            border-radius: 15px;
            color: white;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.3s ease;
        `;
        
        suggestionButton.addEventListener('click', () => {
            this.executeQuickAction(action);
            suggestionButton.remove();
        });
        
        suggestionButton.addEventListener('mouseenter', () => {
            suggestionButton.style.background = 'rgba(255,255,255,0.3)';
            suggestionButton.style.transform = 'scale(1.05)';
        });
        
        suggestionButton.addEventListener('mouseleave', () => {
            suggestionButton.style.background = 'rgba(255,255,255,0.2)';
            suggestionButton.style.transform = 'scale(1)';
        });
        
        statusElement.parentElement.appendChild(suggestionButton);
    }
    
    // === БЫСТРЫЕ ДЕЙСТВИЯ ===
    async executeQuickAction(action) {
        const actionMap = {
            'heating': () => this.executeSmartMode('comfort'),
            'cooling': () => this.executeSmartMode('cool'),
            'lighting': () => this.executeSmartMode('bright'),
            'noise_control': () => this.showNoiseAlert(),
            'eco_mode': () => this.executeSmartMode('eco')
        };
        
        if (actionMap[action]) {
            await actionMap[action]();
        }
    }
    
    // === НАСТРОЙКА ВЗАИМОДЕЙСТВИЙ ===
    setupInteractions() {
        // Обработчики кнопок управления
        document.querySelectorAll('.smart-button').forEach(button => {
            this.setupSmartButton(button);
        });
        
        // Обработчики карточек датчиков
        document.querySelectorAll('.sensor-card').forEach(card => {
            this.setupSensorCard(card);
        });
        
        // Клавиатурные сокращения
        this.setupKeyboardShortcuts();
        
        // Жесты
        if (this.deviceCapabilities.touchGestures) {
            this.setupTouchGestures();
        }
        
        // Голосовое управление
        if (this.deviceCapabilities.voiceRecognition) {
            this.setupVoiceControl();
        }
        
        // Адаптация к ориентации устройства
        if (this.deviceCapabilities.deviceMotion) {
            this.setupOrientationAdaptation();
        }
    }
    
    // === НАСТРОЙКА УМНЫХ КНОПОК ===
    setupSmartButton(button) {
        const mode = button.dataset.mode;
        
        button.addEventListener('click', async (e) => {
            e.preventDefault();
            await this.executeSmartMode(mode, button);
        });
        
        // Предварительный просмотр при наведении
        button.addEventListener('mouseenter', () => {
            this.showModePreview(mode, button);
        });
        
        button.addEventListener('mouseleave', () => {
            this.hideModePreview();
        });
        
        // Поддержка клавиатуры
        button.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                button.click();
            }
        });
    }
    
    // === ВЫПОЛНЕНИЕ УМНОГО РЕЖИМА ===
    async executeSmartMode(mode, buttonElement = null) {
        if (buttonElement) {
            // Визуальная обратная связь
            const originalContent = buttonElement.innerHTML;
            buttonElement.innerHTML = '<div class="button-content"><span class="button-icon">⏳</span><span class="button-text">Применяю...</span></div>';
            buttonElement.disabled = true;
            
            // Тактильная обратная связь
            if (this.deviceCapabilities.vibration) {
                navigator.vibrate([100, 50, 100]);
            }
        }
        
        try {
            const response = await fetch(`/api/smart-mode/${mode}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    currentSensors: this.sensorData,
                    userPreferences: this.userPreferences,
                    persona: this.currentPersona,
                    deviceCapabilities: this.deviceCapabilities,
                    timestamp: Date.now()
                })
            });
            
            const result = await response.json();
            
            if (result.success) {
                if (buttonElement) {
                    buttonElement.innerHTML = '<div class="button-content"><span class="button-icon">✅</span><span class="button-text">Готово!</span></div>';
                    buttonElement.style.background = 'linear-gradient(135deg, #4CAF50, #45a049)';
                }
                
                // Показываем детали изменений
                this.showModeResult(mode, result);
                
                // Обучаем систему на выборе пользователя
                this.learnFromUserChoice(mode, this.sensorData);
                
                // Показываем уведомление
                this.showNotification(`Режим "${this.getModeTitle(mode)}" активирован`, 'success');
                
            } else {
                throw new Error(result.message || 'Ошибка выполнения');
            }
            
        } catch (error) {
            console.error('❌ Ошибка выполнения режима:', error);
            
            if (buttonElement) {
                buttonElement.innerHTML = '<div class="button-content"><span class="button-icon">❌</span><span class="button-text">Ошибка</span></div>';
                buttonElement.style.background = 'linear-gradient(135deg, #f44336, #d32f2f)';
            }
            
            this.showNotification('Ошибка выполнения команды', 'error');
        } finally {
            // Возвращаем кнопку в исходное состояние
            if (buttonElement) {
                setTimeout(() => {
                    buttonElement.innerHTML = buttonElement.dataset.originalContent || originalContent;
                    buttonElement.style.background = '';
                    buttonElement.disabled = false;
                }, 2000);
            }
        }
    }
    
    // === ПРЕДВАРИТЕЛЬНЫЙ ПРОСМОТР РЕЖИМА ===
    showModePreview(mode, button) {
        const preview = this.getModePreview(mode);
        
        // Создаем всплывающую подсказку
        const tooltip = document.createElement('div');
        tooltip.className = 'mode-preview-tooltip';
        tooltip.innerHTML = `
            <h4>${preview.title}</h4>
            <p>${preview.description}</p>
            <ul>
                ${preview.effects.map(effect => `<li>${effect}</li>`).join('')}
            </ul>
        `;
        
        tooltip.style.cssText = `
            position: absolute;
            bottom: 100%;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.9);
            color: white;
            padding: 15px;
            border-radius: 10px;
            font-size: 14px;
            max-width: 250px;
            z-index: 1000;
            animation: fadeInUp 0.3s ease;
            box-shadow: 0 5px 20px rgba(0,0,0,0.3);
        `;
        
        button.style.position = 'relative';
        button.appendChild(tooltip);
    }
    
    hideModePreview() {
        document.querySelectorAll('.mode-preview-tooltip').forEach(tooltip => {
            tooltip.style.animation = 'fadeOut 0.2s ease';
            setTimeout(() => tooltip.remove(), 200);
        });
    }
    
    getModePreview(mode) {
        const previews = {
            comfort: {
                title: '😌 Комфортный режим',
                description: 'Создаю идеальные условия для отдыха и работы',
                effects: ['🌡️ Температура 22°C', '💡 Мягкое освещение', '🔇 Контроль шума']
            },
            eco: {
                title: '🌱 Эко-режим',
                description: 'Экономлю энергию с умом',
                effects: ['⚡ Снижение потребления на 40%', '🌍 Забота об экологии', '💚 Умная оптимизация']
            },
            focus: {
                title: '🎯 Режим концентрации',
                description: 'Оптимальные условия для учебы',
                effects: ['🧠 Температура для мозга 21°C', '📚 Яркое освещение', '🤫 Минимум отвлечений']
            },
            party: {
                title: '🎉 Вечеринка',
                description: 'Создаю атмосферу веселья',
                effects: ['🌟 Яркое освещение', '🎵 Разрешен шум', '💃 Энергичная атмосфера']
            },
            presentation: {
                title: '📽️ Презентация',
                description: 'Готовлю класс для показа',
                effects: ['🔅 Приглушенный свет', '👥 Комфорт для аудитории', '📊 Фокус на экране']
            }
        };
        
        return previews[mode] || { title: mode, description: 'Специальный режим', effects: [] };
    }
    


    // === НАСТРОЙКА КАРТОЧЕК ДАТЧИКОВ ===
    setupSensorCard(card) {
        const sensorType = card.dataset.sensor;
        
        card.addEventListener('click', () => {
            this.showSensorDetails(sensorType);
        });
        
        // Двойной клик для быстрой калибровки
        card.addEventListener('dblclick', () => {
            this.calibrateSensor(sensorType);
        });
        
        // Поддержка клавиатуры
        card.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                this.showSensorDetails(sensorType);
            }
        });
    }
    
    showSensorDetails(sensorType) {
        // Показываем детальную аналитику датчика
        console.log(`📊 Детали датчика: ${sensorType}`);
        
        const modal = this.createModal(`
            <h3>📊 Аналитика датчика: ${this.getSensorName(sensorType)}</h3>
            <div class="sensor-analytics">
                <div class="chart-container">
                    <canvas id="sensorChart" width="300" height="200"></canvas>
                </div>
                <div class="stats">
                    <p><strong>Текущее значение:</strong> <span id="currentValue">--</span></p>
                    <p><strong>Среднее за день:</strong> <span id="avgValue">--</span></p>
                    <p><strong>Минимум:</strong> <span id="minValue">--</span></p>
                    <p><strong>Максимум:</strong> <span id="maxValue">--</span></p>
                </div>
                <button onclick="smartInterface.calibrateSensor('${sensorType}')" class="calibrate-btn">
                    🔧 Калибровать датчик
                </button>
            </div>
        `);
        
        // Здесь можно добавить реальную визуализацию данных
        this.drawSensorChart(sensorType);
    }
    
    getSensorName(type) {
        const names = {
            temperature: '🌡️ Температура',
            light: '💡 Освещенность', 
            sound: '🔊 Звук',
            motion: '🚶 Движение'
        };
        return names[type] || type;
    }
    
    // === ГОЛОСОВОЕ УПРАВЛЕНИЕ ===
    setupVoiceControl() {
        if (!this.deviceCapabilities.voiceRecognition) return;
        
        const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
        this.recognition = new SpeechRecognition();
        
        this.recognition.lang = 'ru-RU';
        this.recognition.continuous = false;
        this.recognition.interimResults = false;
        
        this.recognition.onresult = (event) => {
            const command = event.results[0][0].transcript.toLowerCase();
            this.processVoiceCommand(command);
        };
        
        // Кнопка активации голосового управления
        const voiceButton = this.createVoiceButton();
        document.body.appendChild(voiceButton);
    }
    
    processVoiceCommand(command) {
        console.log(`🎤 Голосовая команда: ${command}`);
        
        const commandMap = {
            'комфорт': () => this.executeSmartMode('comfort'),
            'эко режим': () => this.executeSmartMode('eco'),
            'фокус': () => this.executeSmartMode('focus'),
            'вечеринка': () => this.executeSmartMode('party'),
            'презентация': () => this.executeSmartMode('presentation'),
            'включить свет': () => this.executeQuickAction('lighting'),
            'включить обогрев': () => this.executeQuickAction('heating'),
            'статус системы': () => this.showSystemStatus()
        };
        
        for (const [pattern, action] of Object.entries(commandMap)) {
            if (command.includes(pattern)) {
                action();
                this.speak(`Выполняю команду: ${pattern}`);
                return;
            }
        }
        
        this.speak('Команда не распознана. Повторите, пожалуйста.');
    }
    
    speak(text) {
        const utterance = new SpeechSynthesisUtterance(text);
        utterance.lang = 'ru-RU';
        speechSynthesis.speak(utterance);
    }
    
    // === ЖЕСТОВОЕ УПРАВЛЕНИЕ ===
    setupTouchGestures() {
        let startX, startY, endX, endY;
        
        document.addEventListener('touchstart', (e) => {
            startX = e.touches[0].clientX;
            startY = e.touches[0].clientY;
        });
        
        document.addEventListener('touchend', (e) => {
            endX = e.changedTouches[0].clientX;
            endY = e.changedTouches[0].clientY;
            
            this.handleGesture(startX, startY, endX, endY);
        });
    }
    
    handleGesture(startX, startY, endX, endY) {
        const deltaX = endX - startX;
        const deltaY = endY - startY;
        const threshold = 100;
        
        if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) {
            if (Math.abs(deltaX) > Math.abs(deltaY)) {
                // Горизонтальный свайп
                if (deltaX > 0) {
                    this.executeSmartMode('comfort'); // Свайп вправо = комфорт
                } else {
                    this.executeSmartMode('eco'); // Свайп влево = эко
                }
            } else {
                // Вертикальный свайп
                if (deltaY < 0) {
                    this.showSystemStatus(); // Свайп вверх = статус
                } else {
                    this.hideAllModals(); // Свайп вниз = закрыть
                }
            }
        }
    }
    
    // === АДАПТАЦИЯ К УСЛОВИЯМ ===
    adaptInterfaceToConditions(data) {
        // Меняем тему в зависимости от времени суток
        const hour = new Date().getHours();
        let theme = 'default';
        
        if (hour >= 6 && hour < 12) {
            theme = 'morning';
        } else if (hour >= 12 && hour < 18) {
            theme = 'day';
        } else if (hour >= 18 && hour < 22) {
            theme = 'evening';
        } else {
            theme = 'night';
        }
        
        document.body.className = `theme-${theme}`;
        
        // Адаптируем яркость интерфейса к освещенности
        const lightLevel = (data.light / 4095) * 100;
        if (lightLevel < 30) {
            document.documentElement.style.setProperty('--background-opacity', '0.05');
            document.documentElement.style.setProperty('--text-color', '#ffffff');
        } else {
            document.documentElement.style.setProperty('--background-opacity', '0.1');
            document.documentElement.style.setProperty('--text-color', '#ffffff');
        }
    }
    
    // === УВЕДОМЛЕНИЯ И МОДАЛЬНЫЕ ОКНА ===
    showNotification(message, type = 'info') {
        const notification = document.createElement('div');
        notification.className = `notification ${type}`;
        notification.innerHTML = `
            <div class="notification-content">
                <span class="notification-icon">${this.getNotificationIcon(type)}</span>
                <span class="notification-text">${message}</span>
                <button class="notification-close" onclick="this.parentElement.parentElement.remove()">×</button>
            </div>
        `;
        
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: ${this.getNotificationColor(type)};
            color: white;
            padding: 15px 20px;
            border-radius: 10px;
            box-shadow: 0 5px 20px rgba(0,0,0,0.3);
            z-index: 1000;
            animation: slideInRight 0.5s ease;
            max-width: 300px;
        `;
        
        document.body.appendChild(notification);
        
        // Автоудаление через 5 секунд
        setTimeout(() => {
            if (notification.parentElement) {
                notification.style.animation = 'slideOutRight 0.5s ease';
                setTimeout(() => notification.remove(), 500);
            }
        }, 5000);
        
        // Push-уведомление если разрешено
        if (this.deviceCapabilities.notifications && Notification.permission === 'granted') {
            new Notification('🤖 ALEX', {
                body: message,
                icon: '/icon-192.png'
            });
        }
    }
    
    getNotificationIcon(type) {
        const icons = {
            success: '✅',
            error: '❌',
            warning: '⚠️',
            info: 'ℹ️'
        };
        return icons[type] || 'ℹ️';
    }
    
    getNotificationColor(type) {
        const colors = {
            success: 'linear-gradient(135deg, #4CAF50, #45a049)',
            error: 'linear-gradient(135deg, #f44336, #d32f2f)',
            warning: 'linear-gradient(135deg, #ff9800, #f57c00)',
            info: 'linear-gradient(135deg, #2196F3, #1976D2)'
        };
        return colors[type] || colors.info;
    }
    
    createModal(content) {
        const modal = document.createElement('div');
        modal.className = 'modal-overlay';
        modal.innerHTML = `
            <div class="modal-content">
                <button class="modal-close" onclick="this.closest('.modal-overlay').remove()">×</button>
                ${content}
            </div>
        `;
        
        modal.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.8);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 2000;
            animation: fadeIn 0.3s ease;
        `;
        
        document.body.appendChild(modal);
        return modal;
    }
    
    // === СОХРАНЕНИЕ ПРЕДПОЧТЕНИЙ ===
    saveUserPreferences() {
        localStorage.setItem('alexUserPreferences', JSON.stringify(this.userPreferences));
    }
    
    loadUserPreferences() {
        const stored = localStorage.getItem('alexUserPreferences');
        return stored ? JSON.parse(stored) : {
            preferredMode: 'comfort',
            notifications: true,
            voiceControl: false,
            animations: true,
            theme: 'auto'
        };
    }
    
    learnFromUserChoice(mode, sensorData) {
        // Обучение на основе выбора пользователя
        this.userPreferences.preferredMode = mode;
        this.userPreferences.lastUsed = Date.now();
        
        // Запоминаем контекст выбора
        if (!this.userPreferences.contextualChoices) {
            this.userPreferences.contextualChoices = [];
        }
        
        this.userPreferences.contextualChoices.push({
            mode: mode,
            temperature: sensorData.temperature,
            light: sensorData.light,
            time: new Date().getHours(),
            timestamp: Date.now()
        });
        
        // Ограничиваем историю последними 50 выборами
        if (this.userPreferences.contextualChoices.length > 50) {
            this.userPreferences.contextualChoices = this.userPreferences.contextualChoices.slice(-50);
        }
        
        this.saveUserPreferences();
        console.log('🧠 Система изучила предпочтения пользователя');
    }
    
    // === ОБНОВЛЕНИЕ СТАТУСА ===
    updateConnectionStatus(status, type) {
        document.getElementById('systemStatus').textContent = status;
        
        const statusDot = document.getElementById('statusDot');
        const colors = {
            online: '#4CAF50',
            offline: '#f44336',
            reconnecting: '#ff9800',
            error: '#f44336'
        };
        
        statusDot.style.backgroundColor = colors[type] || colors.offline;
    }
    
    updateBatteryIndicator() {
        if (!this.battery) return;
        
        const batteryElement = document.getElementById('batteryLevel');
        const level = Math.round(this.battery.level * 100);
        
        let icon = '🔋';
        if (level < 20) icon = '🪫';
        else if (level < 50) icon = '🔋';
        else icon = '🔋';
        
        if (this.battery.charging) icon = '⚡';
        
        batteryElement.textContent = icon;
        batteryElement.title = `Батарея: ${level}%`;
    }
    
    showWelcomeMessage() {
        const persona = this.currentPersona;
        const messages = {
            teacher: '👋 Добро пожаловать! Готов помочь с управлением классом.',
            student: '🎉 Привет! Давай изучать умные технологии вместе!',
            janitor: '🔧 Здравствуйте! Помогу следить за всеми системами.'
        };
        
        setTimeout(() => {
            this.showNotification(messages[persona] || messages.student, 'info');
        }, 1000);
    }
}

// === ИНИЦИАЛИЗАЦИЯ ===
let smartInterface;

document.addEventListener('DOMContentLoaded', function() {
    smartInterface = new SmartInterface();
});

// === ДОПОЛНИТЕЛЬНЫЕ CSS АНИМАЦИИ ===
const additionalStyles = `
    @keyframes slideInRight {
        from { transform: translateX(100%); opacity: 0; }
        to { transform: translateX(0); opacity: 1; }
    }
    
    @keyframes slideOutRight {
        from { transform: translateX(0); opacity: 1; }
        to { transform: translateX(100%); opacity: 0; }
    }
    
    @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }
    
    .modal-content {
        background: white;
        padding: 30px;
        border-radius: 15px;
        max-width: 500px;
        max-height: 80vh;
        overflow-y: auto;
        position: relative;
        color: #333;
    }
    
    .modal-close {
        position: absolute;
        top: 10px;
        right: 15px;
        background: none;
        border: none;
        font-size: 24px;
        cursor: pointer;
        color: #999;
    }
    
    .notification-content {
        display: flex;
        align-items: center;
        gap: 10px;
    }
    
    .notification-close {
        background: none;
        border: none;
        color: white;
        font-size: 18px;
        cursor: pointer;
        margin-left: auto;
    }
`;

// Добавляем дополнительные стили
const styleSheet = document.createElement('style');
styleSheet.textContent = additionalStyles;
document.head.appendChild(styleSheet);

Занятие 3: “PWA и адаптивность” 📱

Длительность: 90 минут

Создание Progressive Web App (PWA):

// manifest.json
{
    "name": "ALEX - Умная система класса",
    "short_name": "ALEX",
    "description": "Интеллектуальная система управления классом",
    "start_url": "/",
    "display": "standalone",
    "theme_color": "#667eea",
    "background_color": "#667eea",
    "orientation": "portrait-primary",
    "icons": [
        {
            "src": "/icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "/icon-512.png", 
            "sizes": "512x512",
            "type": "image/png"
        }
    ],
    "categories": ["education", "productivity"],
    "screenshots": [
        {
            "src": "/screenshot1.png",
            "sizes": "1080x1920",
            "type": "image/png"
        }
    ]
}

Service Worker для офлайн работы:

// sw.js
const CACHE_NAME = 'alex-v1.0.0';
const urlsToCache = [
    '/',
    '/styles.css',
    '/script.js',
    '/manifest.json',
    '/icon-192.png',
    '/icon-512.png'
];

self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => cache.addAll(urlsToCache))
    );
});

self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                return response || fetch(event.request);
            }
        )
    );
});

Занятие 4: “Тестирование и оптимизация” 🧪

Длительность: 90 минут

A/B тестирование интерфейсов:

  • Дети создают 2 версии одного элемента
  • Тестируют на разных пользователях
  • Анализируют какой вариант лучше

Оптимизация производительности:

  • Минификация CSS/JS
  • Ленивая загрузка изображений
  • Кэширование данных

🎯 ИТОГИ СПРИНТА 18

Ключевые достижения:

Интерактивный интерфейс - живое взаимодействие с пользователем
Адаптивность - подстройка под разные типы пользователей
Мультимодальность - голос, жесты, клавиатура, касания
PWA - веб-приложение как нативное мобильное
Персонализация - система запоминает предпочтения
Доступность - интерфейс для всех категорий пользователей

Концептуальные прорывы:

  • UX-мышление - понимание потребностей пользователя
  • Эмпатический дизайн - технология с человеческим лицом
  • Адаптивные системы - интерфейс как живой организм
  • Мультимодальное взаимодействие - общение на языке пользователя

Технические навыки:

  • Продвинутый JavaScript и CSS3
  • Web APIs и PWA технологии
  • Accessibility и инклюзивный дизайн
  • UX/UI принципы и методологии

🚀 ПОДГОТОВКА К СПРИНТУ 19

Мостик к машинному обучению:

“Наш интерфейс умеет адаптироваться, но что если он научится предсказывать желания пользователей и самостоятельно предлагать оптимальные решения?”

Фундамент для AI:

  • ✅ Сбор данных о поведении пользователей
  • ✅ Контекстное понимание ситуаций
  • ✅ Персонализация и обучение на предпочтениях
  • ✅ Предиктивные предложения действий

Спринт 18 завершен! 📱
Дети создали по-настоящему живой интерфейс, который понимает пользователей и адаптируется под них!

Готов к анализу Спринта 19: “Введение в Machine Learning”! 🤖🧠