Finger Counter — интерактивное веб-приложение, которое превращает жесты рук перед веб-камерой в ноты, аккорды и полноценный музыкальный интерфейс.
Проект объединяет React, MediaPipe Hand Landmarker и Tone.js: камера распознаёт положение пальцев, приложение определяет левую и правую руку, интерпретирует комбинацию поднятых пальцев как ноту и аккорд, а затем воспроизводит результат в реальном времени.
Это не просто счётчик пальцев. Это экспериментальный gesture-based музыкальный интерфейс, в котором руки становятся клавиатурой.
- 📷 Распознавание рук в реальном времени через веб-камеру
- 🖐️ Поддержка до двух рук одновременно
- 🔢 Определение состояния пяти пальцев каждой руки
- 🎼 Управление мелодией и аккордами с помощью жестов
- 🎹 Встроенная визуальная клавиатура
- ⌨️ Управление клавиатурой компьютера
- 🎛️ Переключение между 34 тембрами
- 🔊 Полифоническое воспроизведение через Tone.js
- 👈 Настройка ведущей руки
- 🟡 Визуальное выделение руки, отвечающей за ноту
- 🔵 Визуальное выделение руки, отвечающей за аккорд
- 🦴 Отрисовка скелета рук поверх изображения с камеры
- ⏱️ Стабилизация распознавания жеста перед сменой звучания
- 📊 Vercel Analytics
- 📱 Адаптивный интерфейс
- 🧩 Разделённая компонентная архитектура React
Приложение использует две руки с разными ролями.
Одна рука задаёт основную ноту, а вторая определяет тип аккорда. Какая именно рука отвечает за ноту, зависит от выбранной ведущей руки.
Например:
| Жест | Музыкальное значение |
|---|---|
| ☝️ | До |
| ✌️ | Ре |
| 🤟 | Ми |
| 🖐️ | Соль |
| комбинация пальцев | другие ноты |
Для аккордов используется отдельная система жестов:
| Пальцы | Аккорд |
|---|---|
| нет пальцев | Одна нота |
| ☝️ | Major |
| ☝️✌️ | Minor |
| ☝️✌️🤟 | Major 7 |
| ☝️✌️🤟☝️ | Minor 7 |
| ☝️ + мизинец | sus4 |
| ✌️ + мизинец | sus2 |
| другие комбинации | 6, 7, m7, 9, m9, 13 и др. |
Фактические комбинации определяются в src/domain/piano.js, поэтому музыкальную систему можно расширять независимо от React-интерфейса.
Помимо управления жестами, приложение содержит обычную экранную клавиатуру.
Клавиши можно нажимать мышью или использовать клавиатуру компьютера.
Используемая раскладка:
A W S D R F T G H U J I
Это позволяет использовать приложение даже без камеры или одновременно с распознаванием рук.
В приложении доступно 34 варианта звучания:
- Acoustic Piano
- Electric Piano
- Wavetable Synth
- Celesta
- Marimba
- Nylon Pluck
- Vibraphone
- Soft Pad
- Analog Lead
- Retro Synth
- Synth Brass
- Flute
- Choir Pad
- Digital Piano
- Сопилка
- Укулеле
- Акустическая гитара
- Калимба
- Арфа
- Музыкальная шкатулка
- Хэндпан
- Стальной tongue drum
- Кото
- Сямисэн
- Ситар
- Банджо
- Мандолина
- Флейта Пана
- Блокфлейта
- Кларнет
- Гобой
- Саксофон
- Труба
- Валторна
Большинство тембров синтезируются непосредственно через Tone.js. Акустическое пианино использует сэмплы Salamander Piano.
Для компьютерного зрения используется MediaPipe Hand Landmarker.
Для каждой обнаруженной руки MediaPipe предоставляет 21 landmark:
0 — запястье
1–4 — большой палец
5–8 — указательный
9–12 — средний
13–16 — безымянный
17–20 — мизинец
На основе этих точек приложение определяет, какие пальцы разогнуты.
Алгоритм подсчёта пальцев находится в:
src/domain/fingerCounter.js
Он работает с геометрией landmark-точек и не зависит напрямую от React или аудиодвижка.
Проект построен с разделением ответственности между UI, состоянием приложения, предметной логикой и инфраструктурой.
Текущая структура:
src/
├── app/
│ └── App.jsx
│
├── components/
│ ├── controls/
│ │ ├── InstrumentSelect.jsx
│ │ ├── Segmented.jsx
│ │ └── SoundButton.jsx
│ │
│ ├── hand/
│ │ └── HandPanel.jsx
│ │
│ ├── layout/
│ │ └── AppHeader.jsx
│ │
│ ├── piano/
│ │ └── Keyboard.jsx
│ │
│ ├── stage/
│ │ ├── CurrentSound.jsx
│ │ └── VideoStage.jsx
│ │
│ ├── styles/
│ │ ├── AppHeader.css
│ │ ├── CurrentSound.css
│ │ ├── HandPanel.css
│ │ ├── InstrumentSelect.css
│ │ ├── Keyboard.css
│ │ ├── Segmented.css
│ │ ├── SoundButton.css
│ │ └── VideoStage.css
│ │
│ └── PianoScreen.jsx
│
├── domain/
│ ├── constants.js
│ ├── fingerCounter.js
│ ├── handRoles.js
│ └── piano.js
│
├── hooks/
│ ├── useKeyboardPiano.js
│ └── usePianoApp.js
│
├── infrastructure/
│ ├── audio/
│ │ └── Player.js
│ └── handTracking/
│ └── useHandTracking.js
│
├── styles/
│ └── global.css
│
└── main.jsx
components/
React-компоненты пользовательского интерфейса. Компоненты разделены по назначению: управление, руки, клавиатура, сцена и layout.
components/styles/
Стили конкретных компонентов. Это позволяет не превращать один глобальный CSS-файл в огромную таблицу стилей.
domain/
Предметная логика приложения: пальцы, роли рук, ноты, аккорды и музыкальные правила.
hooks/
React-хуки, связывающие пользовательский интерфейс с состоянием приложения и управлением клавиатурой.
infrastructure/
Внешние технологии и интеграции: MediaPipe для компьютерного зрения и Tone.js для звука.
app/
Корневой уровень приложения, связывающий основной экран, состояние и глобальные сервисы.
Такое разделение позволяет менять интерфейс, музыкальную модель или конкретную технологию распознавания независимо друг от друга.
Основной путь от камеры до звука выглядит так:
Web Camera
│
▼
MediaPipe Hand Landmarker
│
▼
21 landmark каждой руки
│
▼
fingerCounter
│
▼
Состояние пальцев
│
├───────────────┐
▼ ▼
Роль руки Роль руки
«нота» «аккорд»
│ │
└───────┬───────┘
▼
planSound()
│
▼
MIDI-ноты
│
▼
Tone.js
│
▼
Звук 🎶
При этом UI получает отдельное состояние распознавания и отображает его независимо от аудиодвижка.
| Технология | Назначение |
|---|---|
| React 18 | Пользовательский интерфейс |
| Vite 5 | Сборка и dev-сервер |
| MediaPipe Tasks Vision | Распознавание рук |
| Tone.js | Синтез и воспроизведение звука |
| Vercel Analytics | Веб-аналитика |
| JavaScript / JSX | Основной язык приложения |
| CSS | Стилизация интерфейса |
Требования:
- Node.js
- npm
- современный браузер с поддержкой WebRTC
- веб-камера для управления жестами
Установка:
git clone https://github.com/sunmeat/finger-counter.git
cd finger-counter
npm installЗапуск dev-сервера:
npm run devПосле этого откройте адрес, который покажет Vite, обычно:
http://localhost:5173
Браузер запросит доступ к камере. Для работы распознавания его необходимо разрешить.
Проверить production-сборку:
npm run buildЛокально посмотреть результат сборки:
npm run previewПри запуске приложение загружает ресурсы MediaPipe из CDN:
- WASM runtime для MediaPipe Tasks Vision
- модель Hand Landmarker
Акустическое пианино загружает аудиосэмплы из Tone.js / Salamander Piano.
Поэтому для полноценной работы приложения требуется интернет-соединение.
Обработка изображения с камеры используется приложением для распознавания рук непосредственно в браузере.
Видео с камеры не требуется загружать на собственный сервер приложения для выполнения основного распознавания.
Для работы аналитики используется Vercel Analytics.
Перед использованием приложения браузер отдельно запрашивает разрешение на доступ к камере.
Проект подключает Vercel Analytics через:
import { Analytics } from "@vercel/analytics/react";и размещает компонент аналитики на уровне приложения.
В production-среде это позволяет получать статистику использования приложения без необходимости самостоятельно реализовывать систему аналитики.
При добавлении новой функции желательно придерживаться существующего разделения:
- новый UI-компонент →
components/ - стили компонента →
components/styles/ - музыкальное правило или алгоритм →
domain/ - React-логика состояния →
hooks/ - интеграция с внешней библиотекой →
infrastructure/
Например, новый тип аккорда не должен появляться внутри JSX-компонента. Его место в музыкальной модели приложения.
А новый визуальный элемент интерфейса, наоборот, не должен знать о внутреннем устройстве MediaPipe.
Finger Counter начинался как задача компьютерного зрения: определить, сколько пальцев показывает человек.
Но сама идея быстро выходит за рамки простого счётчика.
Если компьютер умеет видеть положение пальцев, он может воспринимать руку как контроллер:
жест → состояние пальцев → музыкальная команда → MIDI → звук
В результате веб-камера превращается в бесконтактный музыкальный интерфейс.
Следующий естественный шаг развития проекта — расширять язык жестов, добавлять новые музыкальные режимы, ритм, октавы, дополнительные контроллеры и более сложные способы взаимодействия двух рук.
Если в репозитории не указана отдельная лицензия, условия использования кода определяются текущими настройками и содержимым репозитория.
Finger Counter — эксперимент на пересечении компьютерного зрения, веб-разработки и музыки. 🎹🖐️
Made with React, MediaPipe и Tone.js.