Zkt Timer
Здравствуйте, меня зовут Ибрагим. Я давно собираю кубик, и когда начал выступать на соревнованиях, это перестало быть для меня просто хобби и превратилось в куда более серьёзное занятие. Чем серьёзнее становились тренировки, тем чаще после каждой сборки я задавал себе одни и те же вопросы: где я потерял время, на каком переходе замедлился, какой алгоритм до сих пор не довёл до автоматизма? Инструменты, которыми я пользовался, отлично засекали время, но почти не помогали найти ответы на эти вопросы. А мне хотелось инструмента, в котором можно было бы глубоко разбирать свои сборки, системно отрабатывать алгоритмы и делать всё это в одном месте. Я перепробовал разные приложения, но ни в одном не нашёл именно того, что искал, и в итоге решил сделать его сам.
Поначалу моя цель была довольно скромной: я хотел просто сделать для себя простой таймер, в котором понимал бы каждую мелочь. Но каждая новая часть приносила с собой новую потребность. Сначала я написал инструменты анализа, чтобы разбирать свои сборки, затем тренажёр для отработки алгоритмов, а потом добавил подключение умного кубика и синхронизацию между устройствами. Ничто из этого не далось так легко, как может показаться: Bluetooth-протокол каждой марки кубиков был отдельной головоломкой, функция, безупречно работавшая на одном устройстве, могла сломаться на другом там, где я меньше всего ожидал, а иногда я часами и даже днями гонялся за одной-единственной ошибкой. И всё же каждая решённая проблема продвигала меня ещё на шаг, и со временем тот маленький таймер превратился в целую экосистему.
Проект начался в 2025 году и с тех пор ушёл очень далеко от того, с чего начинался. То, что зародилось в вебе, со временем перешло на iOS и Android; сегодня одна и та же кодовая база работает в браузере, на телефоне и на планшете. Большую часть этого пути я прошёл в одиночку. От проверок в магазинах приложений до платёжных систем, от нативного кода до матчей в реальном времени: каждый шаг был для меня отдельной школой, и почти ничто не встало на место с первой попытки. Всё это время моя работа никогда не сводилась только к добавлению новых функций; настоящей борьбой было снова и снова возвращаться к системам, не раз перепроектировать некоторые из них с нуля и добиваться того, чтобы все части работали слаженно.
Инструмент, который я поначалу писал только для себя, стал местом, где другие спидкуберы каждый день тренируются, соревнуются друг с другом и следят за соревнованиями. Когда я вижу, как совершенно незнакомый мне человек ставит личный рекорд в Zkt Timer, я понимаю, что все эти усилия были не напрасны. К тому же значительная часть новых функций теперь рождается из отзывов тех, кто им пользуется. Я не считаю Zkt Timer готовым продуктом: это проект, над которым я по-прежнему работаю каждый день и который продолжает расти, и, честно говоря, мне кажется, что я всё ещё в самом начале этого пути.

Zkt Timer — ibrhyyme
Человек, который проектирует и разрабатывает Zkt Timer.
Credits
Выше я сказал, что прошёл большую часть этого пути в одиночку, но на самом деле я никогда не был по-настоящему один. В мире спидкубинга за годы сложилась удивительно щедрая культура открытого кода, и, работая над Zkt Timer, я постоянно черпал из неё. Я подолгу изучал множество проектов: одни запускал на своём компьютере, чтобы попробовать в деле, другие читал строка за строкой, чтобы по-настоящему понять, как они устроены.
Каждый проект научил меня чему-то своему. Одни подсказали путь в технических вопросах, например в генерации скрамблов или подходах к солверам; другие помогли понять, что действительно работает в тренажёре и в пользовательском опыте. Иногда идея алгоритма, иногда модель данных, а иногда взгляд на систему целиком оказывались тем, что выводило меня из тупика.
Вместо того чтобы брать эти части и использовать их как есть, я переосмыслил каждую из них так, чтобы она вписывалась в собственную структуру Zkt Timer. Большинство систем я переписал с нуля, одни упростил, другие расширил по мере необходимости. Собрать подходы из разных источников в единую архитектуру, где всё работает слаженно, было одновременно самой трудной и самой поучительной частью этого пути.
Поэтому нынешняя структура не опирается на какой-то один источник: она сложилась из того, чему я научился у множества разных проектов, собранного воедино и выстроенного заново. Но скажу прямо: без труда разработчиков, названных ниже, Zkt Timer никогда не стал бы тем, чем является сегодня, за такой короткий срок.
Я верю, что двигать что-то вперёд никогда не значит только добавлять новое; не менее важно по-настоящему понять работу, сделанную до тебя, отнестись к ней с уважением и внести поверх неё честный вклад. Поэтому отдать должное каждому, кто прямо или косвенно повлиял на этот проект, для меня не столько вопрос вежливости, сколько долг, который нужно вернуть.
Каждый из проектов и разработчиков, которых я называю ниже, сыграл свою роль в становлении Zkt Timer. Одни стали отправной точкой для идеи, другие помогли решить проблему, на которой я долго стоял на месте, третьи расширили мой кругозор и позволили увидеть лучший подход. Большая часть этих работ создана людьми, которые жертвовали своим свободным временем и делились результатом со всеми, ничего не ожидая взамен; насколько это ценно, я понял гораздо лучше, когда сам взвалил на себя такую же ношу в собственном проекте.
Всем, кто делится своим трудом, временем и знаниями с этим сообществом, я выражаю глубочайшее уважение и искреннюю благодарность. Спасибо, что вы есть.
— ibrhyyme
Новое в Zkt Timer
В этом разделе собраны функции, спроектированные и разработанные для Zkt Timer. Каждая из них выросла из потребностей самой платформы и отзывов её пользователей.
Система уведомлений и обратного отсчёта соревнований
Zkt Timer формирует автоматические уведомления по соревнованиям, за которыми вы следите. Открытие регистрации, публикация групп и назначений, внесение результатов и побитые рекорды приходят в виде уведомлений, а до даты соревнования ведётся обратный отсчёт. Система работает на сервере как запланированные задачи и создаёт как уведомления внутри приложения, так и push-уведомления.
Радар рекордов
Заранее рассчитывает, какие рекорды могут пасть на соревновании, куда вы едете. Список участников, расписание дисциплин и действующие национальные рекорды сравниваются, чтобы определить, какие рекорды под угрозой, и результат показывается на странице соревнования.
Нативное мобильное приложение
Zkt Timer выпускается как нативное приложение для iOS и Android. Подключение умного кубика работает через нативный слой BLE, а поддержка акселерометра и тактильной отдачи обеспечивается нативными плагинами. Краевые жесты, безопасные зоны и поведение клавиатуры обрабатываются отдельно для каждой платформы.
Magnet Timer
Тип таймера, доступный только в приложениях для iOS и Android, который засекает время без касания экрана. Телефон лежит на столе, а кубик стоит у края телефона со стороны задней камеры; датчик компаса телефона улавливает магниты внутри кубика. Когда кубик поднимают, время запускается, а когда его ставят на стол, останавливается. Поскольку датчик каждого телефона ведёт себя по-своему, калибровка выполняется отдельно для каждого кубика и модели телефона, а пороги вычисляются из сырых значений датчика. Нативный слой, читающий датчик, написан отдельно для iOS и Android, а логика распознавания проверена на записях с реальных устройств.
Полный офлайн-режим
Сборки можно записывать, сессии открывать, а статистику просматривать без подключения к интернету. Когда связь возвращается, ожидающие сборки ставятся в очередь и сверяются с сервером, конфликты разрешаются, а дубликаты отсеиваются по отпечатку.
Offline Battle (1 на 1)
Режим, в котором два человека соревнуются друг с другом на одном устройстве. На телефонах и планшетах экран делится на две половины, обращённые друг к другу; на компьютере игроки сидят рядом и используют клавиши A и L. Игроки стартуют независимо, и каждый может подключить свой умный кубик. Штрафы и очки учитываются раздельно, а история раундов сохраняется подробно.
Online Battle
Матч 1 на 1 с умным кубиком против другого игрока, который ищет соперника в тот же момент. Оба собирают один и тот же скрамбл, а матч выигрывает тот, кто первым возьмёт три раунда. Время измеряют собственные часы кубика, а не интернет, поэтому задержка соединения не влияет на результат. Чем дольше ожидание, тем шире диапазон рейтинга при подборе соперника; матчем управляет сервер, который проверяет каждую сборку по журналу ходов и часам кубика. Рейтинг рассчитывается по системе Glicko-2 и публикуется на странице «Рейтинг».
Наборы алгоритмов
Возможность собрать алгоритмы, которые вы хотите отработать, в собственные наборы. Случаи из разных категорий, например OLL, PLL и F2L, могут находиться в одном наборе. Набор можно оставить личным, открыть только по ссылке или сделать публичным; ссылка открывается с собственным превью. Публичные наборы попадают в «Наборы сообщества», где другие могут их сохранить. Изменения сохраняются сразу, а наборы хранятся и на устройстве для работы без интернета.
Сообщения
Система личных сообщений для переписки один на один. Первое сообщение от нового человека не попадает сразу во входящие, а ждёт одобрения во вкладке «Запросы». К переписке можно прикрепить сборку: собеседник видит время и может открыть её подробности. Отправленное сообщение можно отредактировать или отозвать. Кто может вам писать, отметки о прочтении, индикатор набора текста и точка «в сети» зависят от настроек каждого пользователя; блокировка и жалобы встроены в систему.
Персонализация
Цвета головоломок выбираются отдельными группами, от 2x2 до 7x7, а также для Square-1, Clock и FTO, и все изображения в приложении следуют им: картинка скрамбла, вид умного кубика и остальные. За таймером можно поставить изображение или видео MP4 размером до 40 МБ; во время сборки видео ставится на паузу, а настройка хранится для каждого устройства отдельно. На компьютере модули экрана таймера свободно перетаскиваются в колонки, нижнюю полосу или на любое пустое место и меняют размер за края.
Cuber Card
Карточка для публикации, превращающая информацию профиля в одно изображение. На ней размещаются аватар, имя, количество соревнований, медали и рекорды WCA. На мобильных она подключена к нативному меню «Поделиться», на десктопе к прямой загрузке.
Референсы
Проекты ниже по-разному служили референсами на протяжении разработки Zkt Timer. Каждый пункт говорит о двух вещах: что было взято из этого проекта и что было построено поверх него.

Мой самый сильный референс по архитектуре Zkt Timer. То, как React + SSR, Node.js + GraphQL, PostgreSQL + Prisma и Redis сочетаются внутри платформы для спидкубинга, было выведено при изучении cubedesk от kash. Он задал направление в организации сервисов и структуре папок. Влияние не ограничилось серверной частью: язык интерфейса, заданный cubedesk, тоже стал референсом для компоновки экрана таймера, списка сборок и расположения модулей. Где мы расходимся: cubedesk это веб-приложение. Я хотел, чтобы та же кодовая база выходила на iOS и Android через Capacitor, поэтому переработал слой SSR, управление сессиями и синхронизацию между устройствами так, чтобы они несли и нативную сторону.

Основа генерации скрамблов. Алгоритмы скрамблов и структура подмножеств для типов головоломок, решатель Кочиембы min2phase и библиотека теории групп были построены с опорой на csTimer и min2phase от cs0x7f. При переносе этого кода с JavaScript на TypeScript он был перестроен вокруг архитектуры генераторов на основе реестра; теперь каждый тип головоломки регистрирует собственный генератор, а клиент и сервер могут выдавать один и тот же скрамбл. Поверх этого добавлены более 40 подмножеств CFOP, Roux, Mehta и ZZ, мои собственные 2D-отрисовщики для Square-1 и Clock, а также слой Web Worker, который запускает тяжёлые решатели, не подвешивая интерфейс.

Один из моих главных референсов по пользовательскому опыту модуля Trainer. То, как умный кубик подключается к тренировочному потоку, было выведено при изучении проекта Pau Oliva Fora. В Zkt Timer эта структура разделена на четыре отдельных режима (Стандартный, Умный кубик, Распознавание, Эффективность); ведётся статистика по каждому алгоритму, порядок очереди адаптируется к случаям, в которых пользователь слаб, добавлены 2D- и 3D-визуализация паттернов и экспорт в PDF для печати листов с алгоритмами.

Значительная часть коллекции алгоритмов, используемой в Trainer, пришла из набора данных cubingapp, созданного spencerchubb, и была адаптирована под модель данных Zkt Timer. Установочные алгоритмы были перегенерированы моими собственными скриптами, изображения паттернов прошли через мой конвейер отрисовки, коллекция разделена на 31 категорию и расширена моими алгоритмами.

Отправная точка логики решателей Cross, XCross, EOCross и пар F2L. Реализации IDA* на координатах, разработанные or18, стали фундаментальным референсом в проектировании системы решателей Zkt Timer. Работа в этом модуле заключалась в переносе и адаптации: решатели были перенесены в архитектуру Web Worker и подключены к пошаговому интерфейсу решения. Математика, стоящая за алгоритмом, принадлежит or18.

Концептуальная основа комнат 1 на 1 и формата дружеских забегов идёт из этого проекта. То, как строится синхронизированная модель совместной сборки, было выведено при изучении работы coder13. Система комнат Zkt Timer написана с нуля поверх этой идеи, и в неё добавлено то, чего, на мой взгляд, не хватало в LetsCube: поддержка умного кубика внутри комнат, живой чат, режим зрителя, модерация комнат и блокировка пользователей, режим дуэли 1 на 1 и слой Socket.IO, вещающий между несколькими серверами через Redis.

Проект, созданный для того, чтобы участники могли следить за своими группами и назначениями на соревнованиях WCA, и он делает это очень хорошо. Я не хотел, чтобы за этой информацией участникам приходилось идти на отдельный сайт, поэтому тот же опыт был перенесён внутрь Zkt Timer. Собственное расписание участника, его назначения судьи и скрамблера, личные рекорды по дисциплинам и результаты раундов теперь собраны на одном экране. Компоновка экранов групп сложилась под влиянием этого проекта.

Платформа, созданная для живого отслеживания соревнований WCA, и она действительно хорошо решает задачу потока результатов по раундам. Работа WCA Software Team стала прямым источником структурного подхода к интеграции WCA Live в Zkt Timer. Сама платформа соревнований ZKT написана с нуля для Zkt Timer: регистрация, ввод скоркарт, пакетный режим ввода, управление раундами, назначение судей, скрамблеров и раннеров, отслеживание национальных рекордов, управление делегатами, соревнования с разделением на дни A и B и генерация WCIF. Из wca-live взята логика рабочего процесса делегата.

Интерактивный 3D-кубик на главной странице был перенесён один в один из этого проекта Dev-tanay. Исходник был написан под Three.js r95; при переходе на r125 изменившиеся API были адаптированы, а код переведён на TypeScript. Структура классов и имена методов остались такими же, как в исходнике. Моим вкладом стало подключение кубика к таймеру Zkt Timer: генерация скрамбла, определение сборки и замер времени. В этом пункте скелет кода принадлежит Dev-tanay.

Прямая основа модуля тренажёра распознавания PLL. Практика распознавания PLL с клавиатуры, двустороннее руководство по распознаванию и адаптивная логика повторений пришли из проекта Roman Strakhov. Исходник был написан на Vue; модуль был переписан на React и TypeScript. При переписывании руководство по распознаванию было доведено до охвата всех 73 случаев, добавлены слой истории на устройстве, представление глоссария и направляемый квест из 13 шагов. Сегодня модуль примерно в четыре раза больше исходника.
Используемые Библиотеки
Основные cubing-библиотеки, используемые непосредственно в инфраструктуре Zkt Timer.

cubing.js — Lucas Garron & the cubing.js team Основная библиотека, используемая для отслеживания состояния smart cube, нотации WCA и сопоставления KPattern. Разрабатывается Lucas Garron и контрибьюторами cubing.js.

Библиотека, обеспечивающая управление Bluetooth-соединением и логику гироскопа/движения для smart cube GAN. Модуль Smart Cube построен поверх этой библиотеки.

Поддерживаемый преемник gan-web-bluetooth. Многие исправления в наших драйверах GAN, QiYi, MoYu, Giiker и GoCube (чтение нескольких ходов GAN из одного Bluetooth-пакета, проверка пакетов, поддержка гироскопа, варианты MAC-адреса) взяты из этой библиотеки, а её записи реальных кубов используются в наших тестах.
Основная библиотека решателя куба, используемая в различных функциях анализа и решения.
Открытый Исходный Код
Zkt Timer построен на сотнях пакетов с открытым исходным кодом, включая React, Apollo, Prisma и Three.js. Полный список зависимостей можно найти в файле package.json. Искренняя благодарность всем, кто на протяжении многих лет разрабатывал и поддерживал эти библиотеки.
Сообществу
WCA и глобальному сообществу спидкубинга. Вокруг одной головоломки построено выдающееся мировое сообщество. Истинная причина того, что Zkt Timer имеет смысл, заключается в том, что он может быть частью этого сообщества.
Уведомления об Авторских Правах
Части этого программного обеспечения ссылаются на код или концепции из упомянутых выше проектов. Каждый проект сохраняет свои оригинальные авторские права. Собственная архитектура, системы и функции Zkt Timer защищены следующими авторскими правами:
Этот проект выпущен под GNU General Public License v3.0.