Как мы детектили фрод, а получили Джонни и Джулию: история одной браузерной разминки
Статья о том, как система видеоидентификации стала браузерной разминкой, а Джонни и Джулия - частью команды.

Привет, Тпрогер. Меня зовут Степанян Альберт (albert.stepanyan@beorg.ru), и я всё ещё бегун по граблям и разработчик отдела R&D в компании «Биорг».
В Древнем Риме говорили: «Mens sana in corpore sano» - в здоровом теле здоровый дух. Два тысячелетия спустя мы, айтишники, превратили эту мудрость в её полную противоположность: здоровый дух, сидящий в нездоровом теле перед монитором. Наш позвоночник принимает форму вопросительного знака, а шея начинает напоминать ржавый механизм - повернуть голову можно только всем корпусом, издавая при этом характерный хруст.
Мы в «Биорг» знаем об этой проблеме не понаслышке. Но, в отличие от большинства офисных работников, у нас под рукой оказалась система видеоидентификации, способная видеть каждое микродвижение человеческого лица. И как-то раз, тестируя систему видеоидентификации, мы поймали себя на мысли:
- То, что мы создавали для идентификации личности, по сути готовый трекер движений. Дай ему только интерфейс и он превратится в игру. Осталось только придумать, во что играть…
Попробовать разминку с Джонни и Джулией
Бесплатно, без смс, без регистрации и без подвоха. Под музыку или без! Нам не жалко. Мы вообще-то хотим просто шею размять, а не бизнес на этом строить.
Обычный антифрод и его необычная судьба
Одна из основных наших задач в R&D - борьба с фродом. Мы разработали систему видеоидентификации, которая определяет живость человека по движениям головы, согласно командам. Корректность их выполнения подтверждает, что перед нами живой пользователь.
О том, как мы пришли к этому решению и почему оно эффективно, уже рассказано в статье Развенчан маскарад подделок: прорыв в проверке документов
В процессе работы мы научились детектировать ключевые точки лица с высокой точностью. Алгоритм в реальном времени вычисляет углы поворота головы, наклоны, моргания. И однажды мы заметили, что эти движения похожи на те, которые человек выполняет во время зарядки.
Тогда и родилась идея: а что, если мы сделаем не просто идентификацию, а полезную разминку для шеи, встроенную прямо в браузер?
Рождение Джонни и Джулии
Испытать искреннее удивление от собственных возможностей и окружающего мира - это прекрасные и глубокие ощущения. Получить их может человек, который вырвался из привычной рутины и столкнулся с тем, что выходит за рамки его повседневного опыта. Так на свет появились два персонажа: Джонни и Джулия.
Их история похожа на красивый роман. За плечами дипломы одного из лучших университетов мира и блестящие перспективы за рубежом. Они приехали в Россию как гости, желая увидеть страну. Россия встретила их искренним гостеприимством, новой культурой, непередаваемой атмосферой. Наша страна покорила их сердца навсегда. Очарованные увиденным, они приняли главное решение в своей жизни - остаться здесь, с нами.
Почему двое? Мы добавили в виджет определение пола пользователя на старте - система определяет, кто перед камерой, и предлагает тренера того же пола. Это мелочь, но она делает взаимодействие чуть более персонализированным. Для определения пола используется открытая библиотека face-api.js с лицензией MIT. По желанию, пол инструктора можно сменить. Для этого есть специальная кнопка на экране - справа вверху.
Персонажей мы нарисовали в мультяшном стиле - яркие, добрые, с улыбкой. Потому что разминка должна вызывать радость, а не напряжение. К тому же, мы подумали: если пользователь сейчас будет делать серьёзное лицо, разминая шею, это выглядит глупо. А если рядом весёлый инструктор - процесс идёт легче.
Есть один нехитрый приём, который делает картинку цельной. Мы убираем фон у окна с пользователем и заменяем его на белый. То же самое делаем с фоном инструктора. В результате их фоны сливаются с общим белым фоном страницы, и визуально окна перестают быть «окнами» - они превращаются в единую композицию. Пользователь видит себя и тренера в одном пространстве, а не в двух отдельных квадратах.
Как мы считаем синхронизацию
Разминка состоит из 30 движений, и они каждый раз генерируются случайным образом. Никаких заучиваний - каждый новый подход будет отличаться от предыдущего. Это не даёт скучать и не позволяет мозгу «засыпать» на автоматических движениях.
Разминка состоит из нескольких упражнений. У каждого есть ожидаемая длительность - t.time. Пока пользователь выполняет движение, мы замеряем его фактическую скорость и фиксируем задержку (тот самый delay) - насколько пользователь отстаёт от тренера.
Когда все упражнения завершены, мы суммируем две величины:
totalExp - общее ожидаемое время всех движений;
totalDelay - суммарное отставание пользователя.
Дальше простая формула:
То есть, если вы выполнили разминку идеально синхронно - твой скор стремится к 100. Но мы оставили люфт, потому что в реальном мире есть погрешности: камера может чуть дрожать, браузер - подвисать, а твоя шея - иметь свою точку зрения на то, как быстро надо поворачиваться.
И ещё один важный нюанс по геймплею. Мы заметили в тестах, что некоторые пользователи не могли с первого раза повторить то или иное движение. Может шея затекла, может не поняли траекторию. Зависать на одном движении бесконечно - плохая идея. Это раздражает и убивает смысл разминки.
Поэтому мы сделали так: после двух неудачных повторов инструктор переходит к следующему движению. Пользователь не чувствует себя неудачником, а просто продолжает разминку. А если он вообще не понял, что делать, - система не наказывает, а мягко ведёт дальше. В конце его ждёт честный результат, а не строгий экзамен.
Итоговый результат мы очеловечиваем:
98%, а не 100% специально обозначено как идеал. Потому что перфекционизм это хорошо в коде, но вредно для здоровья. Если ты получил 98%, то считай, что ты чемпион. А вот 30% это повод не расстраиваться, а попробовать ещё раз, просто поймав ритм.
Как мы подружили разминку с телефонами
Мы изначально проектировали разминку для больших мониторов лэптов и рабочих станций - удобно: сидишь перед камерой ноутбука, поворачиваешь голову, и Джонни с Джулией тебя понимают. Но когда мы решили затестить у коллег, то первым их вопросом было:
- А на телефоне это работать будет?
Первая мысль была определять устройство по размеру экрана. Но это оказалось ловушкой. Современные телефоны имеют диагональ почти как у небольших ноутбуков, а планшеты и вовсе размывают границы.
Я лично столкнулся с этой проблемой на своём Redmi Note 9. Экран у него, конечно, не как у ноутбука, но по ширине в пикселях он вполне сопоставим с некоторыми дешёвыми ноутбуками. Система считала, что раз экран достаточно широкий значит, это компьютер, и отказывалась переключаться в мобильный режим. Кнопки оставались мелкими, интерфейс не адаптировался, а инструктор с пользователем пытались уместиться в той же раскладке, что и на большом экране. Работать было невозможно.
Стало понятно, размер экрана это ненадёжный признак, и нужно искать что-то другое.
Тогда я пошёл другим путём: проверять наличие датчика ориентации, но не одним, а двумя признаками:
Первое условие - поддержка события ориентации (есть у телефонов и планшетов). Второе - поддержка касаний (отсекает компьютеры, даже если у них случайно затесался акселерометр). Вместе 2 условия дают почти 100% точность.
Если проверка проходит, то добавляем на страницу класс mobile:
И дальше уже через CSS управляем всем, что должно отличаться. Но самое главное это размер и положение окна с пользователем и инструктором.
На компьютере, как и на телефоне, в горизонтальном режиме, мы используем классическую раскладку: пользователь слева, инструктор справа. Это естественно для широкого экрана - взгляд скользит слева направо, и ты видишь одновременно и себя, и тренера.
На телефоне в вертикальном режиме всё иначе. Экран узкий, и раскладка «слева-направо» не работает. Поэтому пользователь занимает верхнюю половину экрана, а окно с инструктором нижнюю. Так пользователь видит и тренера, и себя одновременно.
И это не просто визуальная прихоть. Если окно с пользователем слишком маленькое - он не видит, правильно ли выполняет движения. Если слишком большое - перекрывает инструктора: теряется смысл «повторяй за мной». Поэтому мы потратили несколько итераций, чтобы найти идеальные пропорции для каждого типа устройства и каждой ориентации.
Сам полноэкранный режим мы, кстати, реализовали и для компа, и для телефона:
Справедливости ради: подсказка про выход из полноэкранного режима появляется и на компьютере, и на телефоне. Просто она разная. На компьютере - «Нажмите Esc для выхода из полноэкранного режима». На телефоне - «Проведите снизу вверх для выхода из полноэкранного режима». В обоих случаях она исчезает через 3 секунды, чтобы не мешать пользователю разминаться.
Трекинг лица: локальная сборка без сюрпризов
Для трекинга лица в разминке мы используем MediaPipe Face Mesh. Это открытая библиотека от Google, распространяемая под лицензией Apache 2.0. Мы взяли её в локальную сборку, поэтому всё работает стабильно и без внешних запросов к CDN. Никаких сюрпризов с недоступными серверами или обновлёнными API. Только предсказуемая логика в твоём браузере.
Инициализируем трекер так:
Обратите внимание на refineLandmarks: false - мы выключили его специально. Нам не нужна микро-детализация губ и глаз, только общий контур головы. Экономия ресурсов браузера это наше всё. И, кстати, именно благодаря локальной сборке мы можем настраивать параметры под свои задачи, не оглядываясь на внешние зависимости.
И ещё один бонус локального подхода: библиотека лежит в нашем проекте, а браузер кеширует её при первом запросе, так что при повторных запусках она не скачивается заново.
И главное, что MediaPipe работает независимо от того, как ты держишь телефон: вертикально или горизонтально. Главное, чтобы лицо было в кадре!
Какой режим выбрать?
В итоге оказалось, что в вертикальном режиме пользователь интуитивно держит телефон на уровне лица и это идеально для детекции. Плюс, интерфейс с Джонни и Джулией выглядит как видеозвонок с личным тренером.
А в горизонтальном режиме телефон можно поставить на подставку или положить на стол и выполнять упражнения, глядя на экран как на маленькое зеркало. Такой формат больше похож на классический фитнес-гаджет.
Так что теперь мы рекомендуем вертикальный режим для атмосферы, а горизонтальный для техничного прохождения с максимальным комфортом.
Музыка - двигатель прогресса (и шеи)
Когда прототип с Джонни и Джулией заработал, мы дали его потестить коллегам. Офис разделился на два лагеря.
Первые, хмуро глядя в монитор, синхронно поворачивали головы и напоминали роботов на конвейере. Вторые незаметно покачивались в такт и слегка пританцовывали, даже когда никто не смотрел. Разница была в одном: у вторых на фоне тихо играла музыка.
Мы решили, что пусть пользователь сам решает, хочет ли он разминаться в тишине или под ритмичный трек. Так появились две кнопки: «Под музыку» и «Без музыки».
И если с «тихим» режимом всё просто, то с музыкой пришлось повозиться. Мы перебрали десяток треков разного темпа, пока не нашли тот самый, который совпадает с комфортной скоростью поворота головы при разминке. Слишком быстро - пользователь не успевает, слишком медленно - скучно. Идеальный темп нашёлся где-то около 140 BPM, как у хорошего транс-хауса.
И вот теперь представь: ты сидишь после пяти часов дебаггинга, запускаешь разминку, выбираешь «Под музыку», и на экране появляется симпатичная Джулия, которая под ритмичный бит начинает поворачивать голову. Ты повторяешь и незаметно для себя перестаёшь думать о багах и просто двигаешься. Это работает как медитация.
Тайна, которую мы не раскроем (но вы всё равно узнаете)
Когда разминка заканчивается и на экране появляется твой результат что-то происходит.
Не будем раскрывать, что именно. Пусть это останется сюрпризом для тех, кто дойдёт до финала. Скажем одно: мы вложили туда частичку нашей души, и, судя по первым тестам, это вызывает чистую, детскую радость даже у самых суровых бэкенд-разработчиков.
Так что когда дойдёте до конца, поделитесь в комментариях, какой бонус увидели и понравилось ли вам.
Заключение
История этой разминки это отличное напоминание о том, что лучшие идеи рождаются не из строгих ТЗ. Мы не планировали делать разминку. Мы планировали делать антифрод. А заодно получили продукт, который одинаково полезен и для безопасности системы, и для шеи разработчика.
А вообще, Джонни и Джулии у нас нравится. Они уже члены нашей команды - с удовольствием ходят на парады и даже поздравляют нас с праздниками.

















