Браузерный Kinect на коленке: пишем игру «Съедобное-несъедобное» с DeepSeek и TensorFlow.js
Привет, VC.
Бывают выходные, когда инженерный зуд совпадает с родительским долгом. Задача стояла простая: развлечь двух свих детей 2 и 5 лет, потратить их энергию и, желательно, чему-то научить. Xbox с Kinect под рукой не оказалось.
И тут возникла мысль: у нас у всех в карманах лежат устройства с камерами и мощными процессорами. А в браузере уже давно живет TensorFlow.js. Почему бы не собрать аналог Fruit Ninja, но с образовательным уклоном, где контроллером будут руки ребенка?
В качестве эксперимента я решил не писать код руками. Вообще. Моим «джуном» на этот вечер стал DeepSeek. Мне было интересно проверить, на сколько он стал лучше с момента моего последнего эксперемента тут, способен ли он выдать рабочий продукт на стыке Computer Vision, Canvas-рендеринга и Web Speech API, или снова придется все переписывать самому.
Ниже — лог того, что из этого вышло: конкретные промты, архитектурные решения и борьба с режимом сна на смартфоне.
Контекст: зачем нам TensorFlow в браузере?
Немного истории. Раньше, чтобы распознать позу человека, нужен был C++, OpenCV, мощная видеокарта и пару дней на настройку окружения.
С появлением TensorFlow.js ситуация изменилась. Google портировал свои модели для запуска прямо в браузере, используя WebGL для ускорения вычислений на GPU клиента.
Для нашей задачи идеально подходит модель PoseNet (или более новая MoveNet). Она легкая, работает в реалтайме и выдает координаты ключевых точек тела: нос, глаза, уши, плечи, локти, кисти рук.Нам не нужно распознавать лицо или сложные жесты. Достаточно знать координаты leftWrist и rightWrist (левого и правого запястья), чтобы превратить их в курсоры на экране.
Задача для ИИ-ассистента формулировалась так:
- Захватить поток с веб-камеры.
- Наложить поверх скелет или маркеры рук (инференс модели).
- Отрисовать падающие объекты (физика на Canvas).
- Реализовать коллизии (рука коснулась объекта).
- Добавить геймификацию (счет, звуки).
Процесс разработки: Промт-инжиниринг вместо кодинга
Я использовал DeepSeek, так как он бесплатен и в последнее время показывает неплохие результаты в кодогенерации, иногда обходя GPT-4 в контексте понимания старых библиотек.
Весь процесс занял 9 основных итераций. Рассмотрим, какими именно командами я направлял «джуна».
Этап 1: MVP и базовая физика
Начал с базы. Мне нужен был минимально рабочий прототип, соединяющий камеру и канвас. Важное уточнение в первом промте — ссылка на конкретное демо PoseNet, чтобы модель понимала, какой именно API я хочу использовать, а не выдумывала несуществующие библиотеки.
Промт 1 (Старт):
«Создай игру, где медленно двигаются небольшие разноцветные шарики сверху вниз. Пользователь при помощи рук сбивает эти шарики. Для отслеживания рук пользователя используй пример https://storage.googleapis.com/tfjs-models/demos/posenet/camera.html»
Результат: Рабочий прототип с первого раза. Шарики падали, камера работала, скелет рисовался.
Но тут вылезли UX-проблемы. Во-первых, ребенок путался в зеркальном отображении. Во-вторых, отладочная информация мешала. В-третьих, дети случайно нажимают на все кнопки браузера.
Промты 2 и 3 (Допиливание UX):
«Сделай исправление при работе фронтальной камерой. Сейчас движение рук по горизонтали инвертировано. Убери инструкцию и изображение с камеры (оставь только канвас)».
«Добавь полноэкранный режим и выход из него. В полноэкранном режиме:
- Убери кнопки старт, продолжить, сброс.
- Убери лишний текст.
- Текст с отображением очков сделай небольшим и убери вниз экрана».
Решение от ИИ: Для инверсии был корректно применен transform: scaleX(-1) к видеопотоку и зеркалирование координат отрисовки на канвасе. Интерфейс был очищен и подготовлен к фуллскрину.
Этап 2: От шариков к фруктам и TTS
Сбивать цветные круги скучно. Пора добавить контент и киллер-фичу — озвучку. Дети в 4–5 лет могут не знать названия всех экзотических фруктов, поэтому игра должна быть говорящей.
Промты 4 и 5 (Контент и звук):
«Поменяй шарики на эмодзи разных фруктов».
«При попадании во фрукт произноси его название на русском языке, используй TTS (Text-to-Speech)».
Инсайт: DeepSeek сам предложил структуру объекта Fruit с полями speed, rotation, score и emoji. Это позволило легко расширять игру в будущем.
С озвучкой есть нюанс: браузеры блокируют AudioContext до первого взаимодействия пользователя. ИИ корректно обработал это, инициализируя синтез речи по стартовому клику.
А вот с мобильными устройствами пришлось повозиться отдельно.Проблема: Экран гаснет, если не тыкать в него пальцем. А мы машем руками перед камерой.Решение: Wake Lock API.
Промт 6 (Мобильные костыли):
«В полноэкранном формате:
- Экран не должен уходить в спящий режим.
- Не показывать панель настройки звука».
DeepSeek сгенерировал код с использованием navigator.wakeLock.request('screen'), что критично для бесконтактных игр.
Этап 3: Игра в «Съедобное-несъедобное»
Механика Fruit Ninja проста, но хотелось образовательного элемента. Я решил переделать игру в классическое «Съедобное-несъедобное».
Промт 7 (Смена логики):
«Преврати игру в игру 'Съедобное-несъедобное'. Теперь вместо фруктов будут появляться как съедобные, так и несъедобные предметы. Если игрок сбивает съедобное, он получает положительные очки, если несъедобное — отрицательные. Добавь озвучку, которая говорит название предмета и добавляет слово 'бяка' для несъедобного».
Логика изменилась корректно: съедобное плюсует счет, несъедобное минусует и добавляет забавный звуковой комментарий (например, «Носок — бяка!»).
Самое сложное здесь — датасет. Я попросил сгенерировать массивы предметов. И тут пришлось включить «родительский контроль». ИИ изначально, не подумав, добавил в несъедобное опасные предметы (ножи, иголки). Демонстрировать такое дошкольникам не стоит.
Промты 8 и 9 (Генерация и фильтрация данных):
«Добавь по 20 элементов каждого вида».
«Добавь по 40 элементов каждого вида. В съедобное добавь больше фруктов и полезного. Из несъедобного убери опасные предметы для детей до 5 лет. Оставь только безопасные бытовые вещи».
В итоге мы получили сбалансированный массив из 80 безопасных предметов.
Что «под капотом»?
В итоге получился один HTML-файл (с включенным JS), который делает следующее:
- Инициализация PoseNet: Загружает модель MobileNetV1 (оптимизирована для слабых устройств).
- Game Loop (requestAnimationFrame):
- Очистка Canvas.
- Получение позы: net.estimateSinglePose(video) — самый ресурсоемкий шаг.
- Фильтрация: берем только rightWrist и leftWrist, если уверенность модели (confidence) > 0.5.
- Отрисовка и физика: Проход по массиву падающих объектов, обновление их Y-координаты.
- Коллизия: Простая проверка дистанции между координатой руки и центром объекта.
- State Management:
- Если коллизия с «съедобным» -> score += value, speak(name).
- Если коллизия с «несъедобным» -> score -= value, speak(name + " бяка").
Пример логики генерации предметов (псевдокод на основе генерации ИИ)
Ошибки и подводные камни
Даже с помощью ИИ всё не так гладко, как в презентациях.
- Освещение — это всё. PoseNet — это компьютерное зрение. В полумраке модель начинает терять руки или «находить» их на фоне узора ковра. Играть нужно в хорошо освещенной комнате.
- Производительность. На десктопе (MacBook M1) всё летает. На бюджетном Android-смартфоне FPS может проседать, так как инференс модели каждый кадр — это дорого. Решение (не реализовано в MVP): Делать детекцию не каждый кадр, а каждый второй-третий, интерполируя координаты между ними.
- TTS и русский язык. window.speechSynthesis зависит от голосов, установленных в ОС. На мобильных всё обычно хорошо, а вот на десктопном Windows может подхватиться дефолтный «робо-голос», который пугает детей.
Выводы
За один вечер, не написав ни строчки кода вручную, а только управляя промтами со смартфона, удалось создать рабочий прототип интерактивной игры.
Что мы получили:
- Образовательная ценность: 80 предметов, тренировка моторики и словарного запаса.
- Технологичность: Zero-install, работает по ссылке в браузере.
- Стоимость разработки: 0 рублей, пара часов времени на промтинг и тесты.
Насколько хорош код от DeepSeek? Он рабочий. Это не Enterprise-архитектура, всё свалено в один файл (что нормально для такого прототипа). Он удивительно хорошо справился с контекстом — помнил, что мы делали 5 шагов назад, и корректно вносил правки, например, расширяя массивы данных без поломки логики рендера.
Кому подойдет этот подход?
- Продакт-менеджерам: Быстро проверить гипотезу (PoC).
- Родителям-айтишникам: Быстро сделать кастомную развлекаловку.
- Педагогам/методистам: Создавать простые интерактивные пособия без бюджета.
Кому НЕ подойдет?
- Разработчикам высоконагруженных игр: JS + Canvas + PoseNet в таком виде — это не про 144 FPS и сложную физику.
- Тем, кто ищет production-ready решение: Тут нет тестов, нет обработки всех edge-кейсов (например, если у пользователя нет камеры) и нет CI/CD.
Ссылка на репозиторий с результатом (файл 11allTS.html): GitHub FruitKinect
P.S. Ребенок доволен, соседи, возможно, не очень (хлопки и радостные крики ). Но цель достигнута.