Skip to content

About

An interactive web application that turns hand gestures in front of a webcam into notes, chords, and a full-fledged musical interface.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

🎹 Finger Counter

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 build

Проверить 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.

About

An interactive web application that turns hand gestures in front of a webcam into notes, chords, and a full-fledged musical interface.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages