Files
pipu-music/docs/design.md
T
mrleo1nid 1e3b350dfc
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m1s
ci / db / db (push) Successful in 1m16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m12s
ci / api / api (push) Successful in 45s
ci / recommender / recommender (push) Successful in 1m50s
ci / ts / ts (packages + web) (push) Failing after 6m53s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m13s
feat(upload): enhance audio upload handling and user feedback
- Introduced a new warning for users uploading non-FLAC or WAV formats, indicating that these formats should only be used as a last resort.
- Added functionality to highlight files needing format attention in the upload queue.
- Updated the UI to provide clearer guidance on acceptable audio formats during uploads.
- Improved documentation to reflect changes in upload requirements and user interface updates.
2026-10-21 10:07:43 +03:00

13 KiB
Raw Permalink Blame History

Дизайн и дизайн-система

1. Внешний вид

Развилка Решение
Кнопка «Моя волна» Сфера с шумом (orb) и Жидкая форма (liquid) — пользователь выбирает в профиле, по умолчанию orb
Каркас веба Classic: сайдбар 240 px, топбар 60 px, разделители-линии, без «парящих» панелей
Плеер веба Оба: bar (полоса 88 px внизу, по умолчанию) и island (плавающий остров) — выбор в профиле
Главная Center: волна по центру, под ней чипы «Занятие» и «Настроение»
Очередь на добавление (админ) Группировка по пачкам (обычно альбом)
Полноэкранный плеер Android cover (крупная обложка) по умолчанию, wave (визуализация волны) — переключатель в профиле
Тема Тёмная (по умолчанию) и светлая, переключатель в профиле; system — следовать ОС
Ambient-фон Включён: размытые дрейфующие пятна, третье пятно окрашено в цвет обложки текущего трека; отключается в профиле и при prefers-reduced-motion

Пользовательские настройки внешнего вида хранятся в users.ui_prefs и синхронизируются между устройствами (см. data-model.md).

2. Токены

Источник истины — packages/design-tokens/tokens.json; из него генерируются CSS-переменные (веб) и TS-объект (React Native).

Цвета

Токен Тёмная Светлая Назначение
bg #05070D #F3F5FA Фон приложения
bg2 #080B14 #EBEEF5 Вторичный фон
surface #0B0F1A #FFFFFF Карточки, панели
surface2 #121827 #F0F3F9 Поля ввода, вложенные блоки
surface3 #1A2236 #E4E9F3 Чипы, кнопки второго уровня
elev #111726 #FFFFFF Поповеры, меню
hover rgba(120,150,255,.07) rgba(30,60,140,.06) Подсветка при наведении
line / line2 rgba(130,160,255,.10) / .18 rgba(20,35,80,.10) / .17 Разделители / рамки
text / text2 / text3 #EDF1FF / #A0ABC6 / #7F8BA8 #0A0F1E / #4B5675 / #5C6785 Текст: основной / вторичный / подписи
accent / accent2 #2F80FF / #5E9BFF #1F6FF2 / #1F6FF2 Основной акцент, ссылки
accent-fill / accent-fill2 #1A66E6 / #1F6FF2 #1A63DB / #165ED6 Заливка под белым текстом (кнопки, выбранные сегменты) и её hover — контраст ≥ 4.5:1
accent-soft rgba(47,128,255,.15) rgba(31,111,242,.10) Активный пункт меню, фокус
violet / violet-soft #9B7CFF / rgba(124,92,255,.16) #6A47F0 / .10 Второй акцент (волна, бейджи)
ok / ok-soft #2FD39A #0E9465 Успех
warn / warn-soft #FFB547 #A86200 Предупреждение
danger / danger-soft #FF5C70 #D32F47 Ошибка, дизлайк, отклонение
overlay rgba(3,5,10,.66) rgba(20,30,60,.32) Подложка диалогов
glass rgba(12,16,28,.78) rgba(255,255,255,.84) Стеклянные карточки (вход, диалоги) + backdrop-filter: blur(28px) saturate(1.3)

Палитра волны по умолчанию: #2F80FF, #7C5CFF, #35D3FF. Логотип — радиальный градиент #9CC6FF → #2F80FF → #3A1FA8.

Типографика

Роль Шрифт Где
Заголовки, логотип, надпись на волне Unbounded 500–700, letter-spacing: -0.01em Заголовки страниц 24–28 px, «Моя волна»
Основной текст Onest 400–700 Всё остальное; базовый размер 15 px, подписи 12–13 px
Моноширинный JetBrains Mono 400/600 Пути файлов, регэкспы, шаблоны, временные пароли, хэши
Иконки Material Symbols Rounded (вариативный, FILL 0..1) Залитые иконки — активное состояние

Все шрифты — OFL / Apache 2.0. Встраиваем в сборку (@fontsource/*, сабсеты latin + cyrillic) — self-hosted сервис не должен зависеть от Google Fonts. Иконки — сабсет Material Symbols только с используемыми глифами (генерируется скриптом при сборке).

Формы и тени

Токен Значение
Радиусы 8 (мелкие кнопки), 10–12 (поля, кнопки), 16 (карточки), 24 (крупные карточки, диалоги), 999 (чипы, бейджи)
Высота поля / основной кнопки 48 px
shadow 0 24px 64px rgba(0,0,0,.55) (светлая: rgba(20,30,60,.18))
glow 0 8px 28px rgba(47,128,255,.38) — основная кнопка
Фокус border-color: accent + box-shadow: 0 0 0 3px accent-soft

Анимация

Что Как
Появление контента pipuIn: opacity + translateY(6px), 200 мс
Эквалайзер текущего трека pipuEq: scaleY 0.25 → 1
Ambient-фон 3 пятна 55–70vmax, blur 30 px, дрейф 16 / 21 / 26 с, hue-rotate ±35° за 30 с, прозрачность amb-op (0.8 тёмная / 0.45 светлая)
Пружины (волна, нажатия) Демпфированная пружина (v += (target − x)·0.35; v *= 0.62)
prefers-reduced-motion Ambient статичен, волна замедлена ×0.15 без пульса

3. Кнопка «Моя волна»

Кнопка рисуется на Canvas 2D (веб) и Skia (Android). WebGL не используется.

interface WaveButtonProps {
  variant: 'orb' | 'liquid';
  playing: boolean;
  bpm?: number;          // из TrackDto.features, по умолчанию 100
  energy?: number;       // 0..1, по умолчанию 0.6
  colors?: [string, string, string]; // палитра обложки текущего трека, иначе палитра волны
  theme: 'dark' | 'light';
  reduced?: boolean;     // prefers-reduced-motion
  interactive?: boolean; // false — декоративный фон экрана входа
  size: number;          // 260–360 px на главной, 620 px на фоне входа
  onClick?(): void;
}

Поведение:

  • Пульс в такт: фаза растёт со скоростью bpm/60, импульс (1 − phase)^4 · (0.35 + 0.65·energy); в покое — медленное «дыхание».
  • Hover: скорость анимации ×(1 + 1.4·hover), формы смещаются к курсору; press: сжатие до 0.93 с отскоком; клик / Enter / Space — запуск / пауза.
  • Внутри — иконка play_arrow / pause (44 px) и надпись «Моя волна» (Unbounded 18 px), подпись контекста («Под ваш вкус», «Бегаю · Энергичное»).
  • Канвас масштабируется по devicePixelRatio; анимация останавливается, когда вкладка скрыта.
  • Android: тот же алгоритм на @shopify/react-native-skia (API Skia Canvas близок к Canvas 2D), общие формулы — в packages/core/wave-anim.

4. Каркас и экраны

Веб (Classic)

  • Сетка: grid-template-rows: 60px 1fr 88px (плеер bar) или 60px 1fr + остров снизу (island, отступ контента 132 px).
  • Топбар: логотип, поиск по центру (выпадающий список с группами «Исполнители / Альбомы / Треки» и подсказкой исправленной раскладки), аватар с меню профиля (тема, язык, выход).
  • Сайдбар: Главная · Коллекция (История, Лайки + счётчик, Дизлайки + счётчик) · Админка (Пользователи, Хранилища, Библиотека, Предложить треки, Очередь + бейдж, Настройки) — пункты по ролям.
  • Плеер: обложка, название / исполнитель, лайк / дизлайк, назад / play (круглая белая кнопка) / вперёд, прогресс со временем, очередь, громкость. Очередь — выезжающая справа панель; в режиме волны внизу пометка «Волна бесконечна…».
  • Диалоги: стеклянные карточки по центру поверх overlay. Тосты — внизу над плеером.

Экраны и документы, где описана логика:

Экран Логика
Вход, смена учётных данных админа, обязательная смена пароля auth-and-roles.md
Главная, поиск, исполнитель, альбом web.md, library-and-storage.md
Коллекция: История (по дням) / Лайки / Дизлайки api.md
Профиль: пароль, язык, тема, кроссфейд, выравнивание громкости (EBU R128), вид волны, вид плеера, выход playback.md
Пользователи: таблица, создание (пароль генерируется автоматически), временный пароль один раз, меню действий auth-and-roles.md
Хранилища: NFS / local, опции, «Принимает новые треки», регэкспы с перетаскиванием, предпросмотр, шаблон раскладки с автоподбором и проверкой library-and-storage.md
Библиотека: состояние, скан, аудиоанализ, качество волны за 7 дней, ошибки recommendations.md
Предложить треки, Очередь на добавление, Настройки очереди uploads.md

Android

  • Нижняя навигация: Главная · Поиск · Коллекция · Профиль; мини-плеер над ней; полноэкранный плеер (cover / wave).
  • Подключение: адрес сервера → проверка (/server-info: версия, HTTPS, совместимость) → список сохранённых серверов.
  • Поиск: недавние запросы (локально), подсказка про опечатки и раскладку.
  • Коллекция → Скачанное: занято / свободно, «Скачивать новые лайки», «Скачать все лайки», очередь загрузок «по Wi-Fi».
  • Профиль: пароль, язык, качество звука (лист), только Wi-Fi, кэш недавних треков (очистить), проверка обновлений (точка-индикатор), сервер, «Админка — откроется в браузере» (для персонала), выход.
  • Лист обновления: «Что нового» → разрешение на установку (один раз) → загрузка → проверка SHA-256 → «Установить».
  • Офлайн-баннер при отсутствии сети.

5. Адаптив и онбординг

  • Адаптивность веба: при ширине < 1024 px сайдбар сворачивается в иконки, при < 768 px — нижняя навигация.
  • Онбординг вкуса показывается на главной, пока GET /onboarding отвечает required.
  • Пустые состояния — иконка, короткий текст и действие там, где список может быть пустым (поиск, коллекция, очередь).
  • Строки интерфейса есть на русском и английском; длинные подписи проверяются на обоих языках.