feat: sound system — 12 new sounds + navigation category; dashboard FAB widget button
Sounds: - UI: modal_open, modal_close, tab_switch, delete - Navigation (new category): page_enter, section_reveal - Classroom: timer_warning, wb_clear, file_shared - Gamification: challenge_complete, daily_login - Quiz: time_up, quiz_bonus Dashboard: - Widget configurator moved from header to fixed FAB (bottom-right) no longer pushed off-screen by wide sidebar Profile settings: - Added Navigation category toggle - Expanded preview section: 12 test buttons covering all categories Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+31
-34
@@ -1167,39 +1167,37 @@
|
|||||||
/* Heatmap popup always right-anchored */
|
/* Heatmap popup always right-anchored */
|
||||||
.hm-day-popup { right: 10px !important; left: auto !important; top: auto !important; }
|
.hm-day-popup { right: 10px !important; left: auto !important; top: auto !important; }
|
||||||
}
|
}
|
||||||
/* ── Widget configurator ── */
|
/* ── Widget configurator FAB ── */
|
||||||
.dash-cfg-btn {
|
.dash-cfg-fab {
|
||||||
margin-left: auto; flex-shrink: 0;
|
display: none; /* shown for students via JS */
|
||||||
display: none; /* shown only for students via JS */
|
position: fixed; bottom: 88px; right: 20px; z-index: 80;
|
||||||
align-items: center; gap: 6px;
|
width: 44px; height: 44px; border-radius: 50%;
|
||||||
padding: 6px 12px; border-radius: 8px;
|
background: #9B5DE5; border: none; cursor: pointer;
|
||||||
background: rgba(155,93,229,0.13); border: 1px solid rgba(155,93,229,0.3);
|
box-shadow: 0 4px 16px rgba(155,93,229,0.45);
|
||||||
color: #9B5DE5; font-size: 0.78rem; font-weight: 600; cursor: pointer;
|
align-items: center; justify-content: center;
|
||||||
transition: background .15s;
|
transition: transform .15s, box-shadow .15s;
|
||||||
}
|
}
|
||||||
.dash-cfg-btn:hover { background: rgba(155,93,229,0.22); }
|
.dash-cfg-fab:hover { transform: scale(1.08); box-shadow: 0 6px 24px rgba(155,93,229,0.55); }
|
||||||
.dash-cfg-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
|
.dash-cfg-fab svg { width: 20px; height: 20px; color: #fff; flex-shrink: 0; }
|
||||||
.dash-cfg-panel {
|
.dash-cfg-panel {
|
||||||
display: none; position: absolute; top: calc(100% + 6px); right: 0;
|
display: none; position: fixed; bottom: 140px; right: 20px;
|
||||||
background: #1e1b2e; border: 1px solid rgba(155,93,229,0.3);
|
background: #1e1b2e; border: 1px solid rgba(155,93,229,0.3);
|
||||||
border-radius: 12px; padding: 12px; min-width: 210px; z-index: 50;
|
border-radius: 14px; padding: 14px; min-width: 220px; z-index: 81;
|
||||||
box-shadow: 0 8px 24px rgba(0,0,0,.35);
|
box-shadow: 0 8px 32px rgba(0,0,0,.45);
|
||||||
}
|
}
|
||||||
.dash-cfg-panel.open { display: block; }
|
.dash-cfg-panel.open { display: block; }
|
||||||
.dash-cfg-title {
|
.dash-cfg-title {
|
||||||
font-size: 0.72rem; font-weight: 700; color: #9B5DE5;
|
font-size: 0.72rem; font-weight: 700; color: #9B5DE5;
|
||||||
text-transform: uppercase; letter-spacing: .5px; margin-bottom: 8px;
|
text-transform: uppercase; letter-spacing: .5px; margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.dash-cfg-row {
|
.dash-cfg-row {
|
||||||
display: flex; align-items: center; justify-content: space-between;
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
padding: 6px 4px; border-radius: 6px; cursor: pointer;
|
padding: 7px 4px; border-radius: 6px; cursor: pointer;
|
||||||
}
|
}
|
||||||
.dash-cfg-row:hover { background: rgba(255,255,255,.05); }
|
.dash-cfg-row:hover { background: rgba(255,255,255,.05); }
|
||||||
.dash-cfg-row label {
|
.dash-cfg-row label { font-size: 0.83rem; color: #e2e8f0; cursor: pointer; flex: 1; }
|
||||||
font-size: 0.82rem; color: #e2e8f0; cursor: pointer; flex: 1;
|
|
||||||
}
|
|
||||||
.dash-cfg-row input[type=checkbox] { accent-color: #9B5DE5; width: 15px; height: 15px; cursor: pointer; }
|
.dash-cfg-row input[type=checkbox] { accent-color: #9B5DE5; width: 15px; height: 15px; cursor: pointer; }
|
||||||
.dash-cfg-wrap { position: relative; }
|
.dash-cfg-wrap { display: contents; }
|
||||||
</style>
|
</style>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -1222,20 +1220,19 @@
|
|||||||
<div class="stat-ring" id="sr-streak"></div>
|
<div class="stat-ring" id="sr-streak"></div>
|
||||||
<div class="stat-ring" id="sr-pending"></div>
|
<div class="stat-ring" id="sr-pending"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dash-cfg-wrap" id="dash-cfg-wrap">
|
</div>
|
||||||
<button class="dash-cfg-btn" id="dash-cfg-btn" onclick="toggleDashCfg(event)" title="Настроить виджеты">
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
<!-- Widget configurator FAB (fixed, outside header flow) -->
|
||||||
Виджеты
|
<button class="dash-cfg-fab" id="dash-cfg-btn" onclick="toggleDashCfg(event)" title="Настроить виджеты">
|
||||||
</button>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||||
<div class="dash-cfg-panel" id="dash-cfg-panel">
|
</button>
|
||||||
<div class="dash-cfg-title">Показывать виджеты</div>
|
<div class="dash-cfg-panel" id="dash-cfg-panel">
|
||||||
<div class="dash-cfg-row" onclick="toggleDashWidget('lb-section',this)"><label>Рейтинг</label><input type="checkbox" data-widget="lb-section" checked></div>
|
<div class="dash-cfg-title">Показывать виджеты</div>
|
||||||
<div class="dash-cfg-row" onclick="toggleDashWidget('ch-section',this)"><label>Испытания недели</label><input type="checkbox" data-widget="ch-section" checked></div>
|
<div class="dash-cfg-row" onclick="toggleDashWidget('lb-section',this)"><label>Рейтинг</label><input type="checkbox" data-widget="lb-section" checked></div>
|
||||||
<div class="dash-cfg-row" onclick="toggleDashWidget('stats-section',this)"><label>Статистика</label><input type="checkbox" data-widget="stats-section" checked></div>
|
<div class="dash-cfg-row" onclick="toggleDashWidget('ch-section',this)"><label>Испытания недели</label><input type="checkbox" data-widget="ch-section" checked></div>
|
||||||
<div class="dash-cfg-row" onclick="toggleDashWidget('w-my-subs',this)"><label>Мои сдачи</label><input type="checkbox" data-widget="w-my-subs" checked></div>
|
<div class="dash-cfg-row" onclick="toggleDashWidget('stats-section',this)"><label>Статистика</label><input type="checkbox" data-widget="stats-section" checked></div>
|
||||||
<div class="dash-cfg-row" onclick="toggleDashWidget('w-theory-progress',this)"><label>Теория</label><input type="checkbox" data-widget="w-theory-progress" checked></div>
|
<div class="dash-cfg-row" onclick="toggleDashWidget('w-my-subs',this)"><label>Мои сдачи</label><input type="checkbox" data-widget="w-my-subs" checked></div>
|
||||||
</div>
|
<div class="dash-cfg-row" onclick="toggleDashWidget('w-theory-progress',this)"><label>Теория</label><input type="checkbox" data-widget="w-theory-progress" checked></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
+56
-10
@@ -819,7 +819,7 @@
|
|||||||
<div class="p-card-icon"><i data-lucide="volume-2" style="width:15px;height:15px"></i></div>
|
<div class="p-card-icon"><i data-lucide="volume-2" style="width:15px;height:15px"></i></div>
|
||||||
<div>
|
<div>
|
||||||
<div class="p-card-title">Звуки системы</div>
|
<div class="p-card-title">Звуки системы</div>
|
||||||
<div class="p-card-sub">Уведомления, геймификация, classroom, квизы</div>
|
<div class="p-card-sub">Синтезированные — не требуют загрузки файлов</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -854,7 +854,7 @@
|
|||||||
<div class="pref-row">
|
<div class="pref-row">
|
||||||
<div class="pref-row-info">
|
<div class="pref-row-info">
|
||||||
<div class="pref-row-label">Интерфейс</div>
|
<div class="pref-row-label">Интерфейс</div>
|
||||||
<div class="pref-row-desc">Клики, успех, ошибки, уведомления</div>
|
<div class="pref-row-desc">Клики, модальные окна, удаление, уведомления</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="pref-toggle">
|
<label class="pref-toggle">
|
||||||
<input type="checkbox" id="pref-sfx-ui" onchange="prefSfxCat('ui',this.checked)">
|
<input type="checkbox" id="pref-sfx-ui" onchange="prefSfxCat('ui',this.checked)">
|
||||||
@@ -862,11 +862,23 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation sounds -->
|
||||||
|
<div class="pref-row">
|
||||||
|
<div class="pref-row-info">
|
||||||
|
<div class="pref-row-label">Навигация</div>
|
||||||
|
<div class="pref-row-desc">Переходы между страницами и секциями</div>
|
||||||
|
</div>
|
||||||
|
<label class="pref-toggle">
|
||||||
|
<input type="checkbox" id="pref-sfx-navigation" onchange="prefSfxCat('navigation',this.checked)">
|
||||||
|
<span class="pref-toggle-track"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Classroom sounds -->
|
<!-- Classroom sounds -->
|
||||||
<div class="pref-row">
|
<div class="pref-row">
|
||||||
<div class="pref-row-info">
|
<div class="pref-row-info">
|
||||||
<div class="pref-row-label">Classroom</div>
|
<div class="pref-row-label">Classroom</div>
|
||||||
<div class="pref-row-desc">Урок, участники, чат, рука, рисование</div>
|
<div class="pref-row-desc">Урок, участники, таймер, доска, файлы</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="pref-toggle">
|
<label class="pref-toggle">
|
||||||
<input type="checkbox" id="pref-sfx-classroom" onchange="prefSfxCat('classroom',this.checked)">
|
<input type="checkbox" id="pref-sfx-classroom" onchange="prefSfxCat('classroom',this.checked)">
|
||||||
@@ -878,7 +890,7 @@
|
|||||||
<div class="pref-row">
|
<div class="pref-row">
|
||||||
<div class="pref-row-info">
|
<div class="pref-row-info">
|
||||||
<div class="pref-row-label">Геймификация</div>
|
<div class="pref-row-label">Геймификация</div>
|
||||||
<div class="pref-row-desc">XP, уровень, достижения, монеты</div>
|
<div class="pref-row-desc">XP, уровень, достижения, испытания, вход</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="pref-toggle">
|
<label class="pref-toggle">
|
||||||
<input type="checkbox" id="pref-sfx-gamification" onchange="prefSfxCat('gamification',this.checked)">
|
<input type="checkbox" id="pref-sfx-gamification" onchange="prefSfxCat('gamification',this.checked)">
|
||||||
@@ -890,7 +902,7 @@
|
|||||||
<div class="pref-row">
|
<div class="pref-row">
|
||||||
<div class="pref-row-info">
|
<div class="pref-row-info">
|
||||||
<div class="pref-row-label">Квизы</div>
|
<div class="pref-row-label">Квизы</div>
|
||||||
<div class="pref-row-desc">Старт вопроса, правильно, неправильно</div>
|
<div class="pref-row-desc">Старт, правильно/неправильно, таймер, бонус</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="pref-toggle">
|
<label class="pref-toggle">
|
||||||
<input type="checkbox" id="pref-sfx-quiz" onchange="prefSfxCat('quiz',this.checked)">
|
<input type="checkbox" id="pref-sfx-quiz" onchange="prefSfxCat('quiz',this.checked)">
|
||||||
@@ -898,23 +910,56 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Test button -->
|
<!-- Preview buttons -->
|
||||||
<div style="margin-top:14px;display:flex;gap:8px;flex-wrap:wrap">
|
<div class="pref-section-label" style="margin-top:14px">Прослушать</div>
|
||||||
|
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:8px">
|
||||||
<button class="pref-test-btn" onclick="prefSfxTest('notification')">
|
<button class="pref-test-btn" onclick="prefSfxTest('notification')">
|
||||||
<i data-lucide="bell" style="width:12px;height:12px;vertical-align:-2px"></i>
|
<i data-lucide="bell" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
Уведомление
|
Уведомление
|
||||||
</button>
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('success')">
|
||||||
|
<i data-lucide="check-circle" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Успех
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('error')">
|
||||||
|
<i data-lucide="x-circle" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Ошибка
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('modal_open')">
|
||||||
|
<i data-lucide="layout" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Модал
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('page_enter')">
|
||||||
|
<i data-lucide="arrow-right" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Навигация
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('lesson_start')">
|
||||||
|
<i data-lucide="play" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Урок
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('timer_warning')">
|
||||||
|
<i data-lucide="clock" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Таймер
|
||||||
|
</button>
|
||||||
<button class="pref-test-btn" onclick="prefSfxTest('achievement')">
|
<button class="pref-test-btn" onclick="prefSfxTest('achievement')">
|
||||||
<i data-lucide="trophy" style="width:12px;height:12px;vertical-align:-2px"></i>
|
<i data-lucide="trophy" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
Ачивка
|
Ачивка
|
||||||
</button>
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('challenge_complete')">
|
||||||
|
<i data-lucide="target" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Испытание
|
||||||
|
</button>
|
||||||
<button class="pref-test-btn" onclick="prefSfxTest('level_up')">
|
<button class="pref-test-btn" onclick="prefSfxTest('level_up')">
|
||||||
<i data-lucide="zap" style="width:12px;height:12px;vertical-align:-2px"></i>
|
<i data-lucide="zap" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
Уровень
|
Уровень
|
||||||
</button>
|
</button>
|
||||||
<button class="pref-test-btn" onclick="prefSfxTest('lesson_start')">
|
<button class="pref-test-btn" onclick="prefSfxTest('quiz_correct')">
|
||||||
<i data-lucide="play" style="width:12px;height:12px;vertical-align:-2px"></i>
|
<i data-lucide="check" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
Урок
|
Правильно
|
||||||
|
</button>
|
||||||
|
<button class="pref-test-btn" onclick="prefSfxTest('time_up')">
|
||||||
|
<i data-lucide="timer-off" style="width:12px;height:12px;vertical-align:-2px"></i>
|
||||||
|
Время вышло
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1537,6 +1582,7 @@
|
|||||||
const setChk = (id, v) => { const el = document.getElementById(id); if (el) el.checked = v; };
|
const setChk = (id, v) => { const el = document.getElementById(id); if (el) el.checked = v; };
|
||||||
setChk('pref-sfx-enabled', sfx.enabled);
|
setChk('pref-sfx-enabled', sfx.enabled);
|
||||||
setChk('pref-sfx-ui', sfx.prefs.ui);
|
setChk('pref-sfx-ui', sfx.prefs.ui);
|
||||||
|
setChk('pref-sfx-navigation', sfx.prefs.navigation !== false);
|
||||||
setChk('pref-sfx-classroom', sfx.prefs.classroom);
|
setChk('pref-sfx-classroom', sfx.prefs.classroom);
|
||||||
setChk('pref-sfx-gamification', sfx.prefs.gamification);
|
setChk('pref-sfx-gamification', sfx.prefs.gamification);
|
||||||
setChk('pref-sfx-quiz', sfx.prefs.quiz);
|
setChk('pref-sfx-quiz', sfx.prefs.quiz);
|
||||||
|
|||||||
+82
-1
@@ -134,6 +134,36 @@
|
|||||||
_tone(880, 80, 'sine', 0.13, 5, 50);
|
_tone(880, 80, 'sine', 0.13, 5, 50);
|
||||||
setTimeout(function () { _tone(1108, 120, 'sine', 0.15, 5, 80); }, 90);
|
setTimeout(function () { _tone(1108, 120, 'sine', 0.15, 5, 80); }, 90);
|
||||||
},
|
},
|
||||||
|
modal_open: function () {
|
||||||
|
// Soft sweep in — airy whoosh up
|
||||||
|
_sweep(300, 520, 180, 'sine', 0.09);
|
||||||
|
setTimeout(function () { _tone(660, 100, 'sine', 0.08, 5, 70); }, 160);
|
||||||
|
},
|
||||||
|
modal_close: function () {
|
||||||
|
// Sweep down — gentle dismiss
|
||||||
|
_sweep(520, 300, 150, 'sine', 0.08);
|
||||||
|
},
|
||||||
|
tab_switch: function () {
|
||||||
|
// Double-click feel
|
||||||
|
_tone(900, 35, 'sine', 0.09, 2, 25);
|
||||||
|
setTimeout(function () { _tone(1100, 35, 'sine', 0.09, 2, 25); }, 45);
|
||||||
|
},
|
||||||
|
delete: function () {
|
||||||
|
// Descending soft thud
|
||||||
|
_sweep(400, 180, 120, 'triangle', 0.10);
|
||||||
|
_noise(80, 0.04);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── Navigation ────────────────────────────────────────────────────────
|
||||||
|
page_enter: function () {
|
||||||
|
// Subtle arrival chime
|
||||||
|
_tone(784, 80, 'sine', 0.08, 5, 55);
|
||||||
|
setTimeout(function () { _tone(1047, 120, 'sine', 0.07, 5, 80); }, 75);
|
||||||
|
},
|
||||||
|
section_reveal: function () {
|
||||||
|
// Very quiet rising whoosh
|
||||||
|
_sweep(250, 420, 200, 'sine', 0.07);
|
||||||
|
},
|
||||||
|
|
||||||
// ── Classroom ─────────────────────────────────────────────────────────
|
// ── Classroom ─────────────────────────────────────────────────────────
|
||||||
hand_raise: function () {
|
hand_raise: function () {
|
||||||
@@ -173,6 +203,23 @@
|
|||||||
setTimeout(function () { _tone(330, 160, 'sine', 0.14, 10, 100); }, 140);
|
setTimeout(function () { _tone(330, 160, 'sine', 0.14, 10, 100); }, 140);
|
||||||
setTimeout(function () { _tone(261, 350, 'sine', 0.13, 10, 220); }, 280);
|
setTimeout(function () { _tone(261, 350, 'sine', 0.13, 10, 220); }, 280);
|
||||||
},
|
},
|
||||||
|
timer_warning: function () {
|
||||||
|
// Urgent triple beep — last 10 seconds
|
||||||
|
_tone(880, 60, 'square', 0.12, 2, 40);
|
||||||
|
setTimeout(function () { _tone(880, 60, 'square', 0.13, 2, 40); }, 200);
|
||||||
|
setTimeout(function () { _tone(1108, 100, 'square', 0.15, 2, 70); }, 400);
|
||||||
|
},
|
||||||
|
wb_clear: function () {
|
||||||
|
// Erasing noise sweep
|
||||||
|
_noise(220, 0.08);
|
||||||
|
_sweep(600, 200, 220, 'triangle', 0.06);
|
||||||
|
},
|
||||||
|
file_shared: function () {
|
||||||
|
// Paper rustle + chime
|
||||||
|
_noise(80, 0.05);
|
||||||
|
setTimeout(function () { _tone(784, 100, 'sine', 0.12, 5, 70); }, 60);
|
||||||
|
setTimeout(function () { _tone(1047, 120, 'sine', 0.10, 5, 80); }, 160);
|
||||||
|
},
|
||||||
|
|
||||||
// ── Gamification ──────────────────────────────────────────────────────
|
// ── Gamification ──────────────────────────────────────────────────────
|
||||||
xp_gain: function () {
|
xp_gain: function () {
|
||||||
@@ -218,6 +265,21 @@
|
|||||||
setTimeout(function () { _tone(659, 80, 'sine', 0.14, 5, 55); }, 80);
|
setTimeout(function () { _tone(659, 80, 'sine', 0.14, 5, 55); }, 80);
|
||||||
setTimeout(function () { _tone(784, 160, 'sine', 0.16, 5, 100); }, 160);
|
setTimeout(function () { _tone(784, 160, 'sine', 0.16, 5, 100); }, 160);
|
||||||
},
|
},
|
||||||
|
challenge_complete: function () {
|
||||||
|
// Heroic: E4-G4-B4-E5 arpeggio
|
||||||
|
_tone(330, 140, 'sine', 0.15, 8, 90);
|
||||||
|
setTimeout(function () { _tone(392, 140, 'sine', 0.16, 8, 90); }, 130);
|
||||||
|
setTimeout(function () { _tone(494, 140, 'sine', 0.17, 8, 90); }, 260);
|
||||||
|
setTimeout(function () { _tone(659, 400, 'sine', 0.20, 8, 260); }, 390);
|
||||||
|
// Sparkle on top
|
||||||
|
setTimeout(function () { _tone(1319, 200, 'triangle', 0.07); }, 450);
|
||||||
|
},
|
||||||
|
daily_login: function () {
|
||||||
|
// Morning chime: G-A-B
|
||||||
|
_tone(392, 120, 'sine', 0.12, 8, 80);
|
||||||
|
setTimeout(function () { _tone(440, 120, 'sine', 0.13, 8, 80); }, 110);
|
||||||
|
setTimeout(function () { _tone(494, 250, 'sine', 0.15, 8, 160); }, 220);
|
||||||
|
},
|
||||||
|
|
||||||
// ── Quiz ──────────────────────────────────────────────────────────────
|
// ── Quiz ──────────────────────────────────────────────────────────────
|
||||||
quiz_start: function () {
|
quiz_start: function () {
|
||||||
@@ -244,6 +306,20 @@
|
|||||||
quiz_tick: function () {
|
quiz_tick: function () {
|
||||||
_tone(660, 40, 'square', 0.08, 2, 25);
|
_tone(660, 40, 'square', 0.08, 2, 25);
|
||||||
},
|
},
|
||||||
|
time_up: function () {
|
||||||
|
// Buzzer — descending sawtooth alarm
|
||||||
|
_tone(440, 120, 'sawtooth', 0.14, 3, 80);
|
||||||
|
_noise(120, 0.06);
|
||||||
|
setTimeout(function () { _tone(330, 160, 'sawtooth', 0.12, 3, 110); }, 110);
|
||||||
|
setTimeout(function () { _tone(220, 220, 'sawtooth', 0.10, 3, 160); }, 240);
|
||||||
|
},
|
||||||
|
quiz_bonus: function () {
|
||||||
|
// Golden sparkle — high twinkling
|
||||||
|
_tone(1047, 60, 'sine', 0.14, 2, 45);
|
||||||
|
setTimeout(function () { _tone(1319, 60, 'sine', 0.16, 2, 45); }, 65);
|
||||||
|
setTimeout(function () { _tone(1568, 60, 'sine', 0.17, 2, 45); }, 130);
|
||||||
|
setTimeout(function () { _tone(2093, 180, 'sine', 0.18, 2, 120); }, 195);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Persistence ───────────────────────────────────────────────────────────
|
// ── Persistence ───────────────────────────────────────────────────────────
|
||||||
@@ -272,6 +348,7 @@
|
|||||||
volume : 0.75,
|
volume : 0.75,
|
||||||
prefs : {
|
prefs : {
|
||||||
ui : true,
|
ui : true,
|
||||||
|
navigation : true,
|
||||||
classroom : true,
|
classroom : true,
|
||||||
gamification : true,
|
gamification : true,
|
||||||
quiz : true,
|
quiz : true,
|
||||||
@@ -280,14 +357,18 @@
|
|||||||
// Category map — which prefs key each sound belongs to
|
// Category map — which prefs key each sound belongs to
|
||||||
_cats: {
|
_cats: {
|
||||||
click: 'ui', success: 'ui', error: 'ui', notification: 'ui',
|
click: 'ui', success: 'ui', error: 'ui', notification: 'ui',
|
||||||
|
modal_open: 'ui', modal_close: 'ui', tab_switch: 'ui', delete: 'ui',
|
||||||
|
page_enter: 'navigation', section_reveal: 'navigation',
|
||||||
hand_raise: 'classroom', chat_message: 'classroom',
|
hand_raise: 'classroom', chat_message: 'classroom',
|
||||||
user_joined: 'classroom', user_left: 'classroom',
|
user_joined: 'classroom', user_left: 'classroom',
|
||||||
muted: 'classroom', draw_permitted: 'classroom',
|
muted: 'classroom', draw_permitted: 'classroom',
|
||||||
lesson_start: 'classroom', lesson_end: 'classroom',
|
lesson_start: 'classroom', lesson_end: 'classroom',
|
||||||
|
timer_warning: 'classroom', wb_clear: 'classroom', file_shared: 'classroom',
|
||||||
xp_gain: 'gamification', level_up: 'gamification',
|
xp_gain: 'gamification', level_up: 'gamification',
|
||||||
achievement: 'gamification', coin: 'gamification', streak: 'gamification',
|
achievement: 'gamification', coin: 'gamification', streak: 'gamification',
|
||||||
|
challenge_complete: 'gamification', daily_login: 'gamification',
|
||||||
quiz_start: 'quiz', quiz_correct: 'quiz', quiz_wrong: 'quiz',
|
quiz_start: 'quiz', quiz_correct: 'quiz', quiz_wrong: 'quiz',
|
||||||
quiz_end: 'quiz', quiz_tick: 'quiz',
|
quiz_end: 'quiz', quiz_tick: 'quiz', time_up: 'quiz', quiz_bonus: 'quiz',
|
||||||
},
|
},
|
||||||
|
|
||||||
play: function (name) {
|
play: function (name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user