BIGBOARD.GAMES: зсуньте телефони докупи й грайте в одну гру

Покладіть два телефони поруч на стіл і вдарте по шайбі на одному з них. Вона ковзає до краю, на частку секунди зникає під рамками й виринає на другому телефоні — саме там, де й має, і з тією самою швидкістю. Це BIGBOARD.GAMES — колекція безкоштовних мультиплеєрних браузерних ігор, де 2–4 телефони чи планшети, зсунуті докупи, стають одним великим ігровим полем. Проєкт запрацював учора з чотирма іграми для пристроїв за одним столом, а згодом з'являться й ігри, у які можна грати на відстані.
Я роблю ігри з 12 років: сотні міні-ігор у Warcraft III, Ballzirum на GameMaker, головоломка з пересуванням плиток, яку я запакував у мобільний застосунок через PhoneGap. Жодна з них не вийшла на люди: я не знав, що таке маркетинг, та й ділитися ними не збирався. Проте понад 30 таких ігор і проєктів, у які можна було бодай пограти, потрапили в моє резюме — і саме завдяки цьому мене помітили й узяли на мою першу роботу — в InterSystems. Тож воно було того варте :) BIGBOARD.GAMES — перша гра, яку я справді випустив, щоб у неї міг пограти будь-хто.
Виглядає це так:
Спробуйте вже зараз: відкрийте bigboard.games на двох пристроях і на одному з них натисніть Створити стіл. В одній мережі Wi-Fi другий пристрій знайде стіл сам. Потім зсуньте їх докупи.
Як грати в одну гру на кількох телефонах
- Нічого не треба встановлювати. Відкрийте bigboard.games у будь-якому браузері: Safari, Chrome, навіть у тому, що вбудований у TikTok.
- Будь-яке поєднання пристроїв. iPhone і Android, телефони й планшети — до 4 за одним столом.
- Приєднатися — швидко. В одній мережі Wi-Fi пристрої знаходять одне одного й під'єднуються самі. Інакше — скануйте QR-код або введіть код із чотирьох літер. У мобільному інтернеті їх з'єднує захищений ретранслятор.
- Трьома мовами: англійською, українською та іспанською.
- Безкоштовно, а щоб створити стіл, реєструватися не треба.
Чотири гри на старті
- Настільний хокей: аерохокей на кількох телефонах і планшетах. Дуелі на двох пристроях, командна гра або кожен сам за себе на трьох чи чотирьох, і п'ять арен: Класика, Відбійники, Лід, Важка шайба й Міни.
- Через край: малюйте фігури на сітці й скидайте їх на бік суперника. Головне — не переповніть свій.
- Бий крота: лупіть кротів, поки ті не сховалися, — один на один, командою або на час.
- Острови: класична гра в точки на папері: в Україні її знають як «Точки», а тут, у Польщі, — як Kropki. Оточіть точки суперника, щоб захопити острів, — на дзеркальних полях або на одному аркуші, що тягнеться через обидва пристрої.
Усі чотири працюють і на одному пристрої — раптом заряджений лише один телефон :)
Ще три вже готові й чекають своєї черги: «Нахили», де ви нахиляєте пристрій і котите одну кульку лабіринтом, що тягнеться через усі екрани; «Зграйка», де пальці стають парканами, а ви разом заганяєте сяйливу зграйку в сіть; і «Маяк», де ви заломлюєте світло через увесь стіл, доки не запалають усі вогні.
Від двох планшетів до будь-якого телефона
Ігри, у які грають в одній кімнаті, мені близькі: майже два роки я проводив вечори настільних ігор у Кракові, де за столами збиралося близько 30 людей.
Проєкт BIGBOARD.GAMES почався 26 вересня як прототип із дуже буквальним першим комітом: «shared platform for two-tablet games» (спільна платформа для ігор на двох планшетах). 2 жовтня я пограв у нього з друзями. Мої нотатки з того вечора: «Дуже сподобалися хокей і spillover, і whack a mole, а island був більш-менш цікавий». Ці чотири й увійшли до стартового набору.
Утім, найкорисніший відгук був не про ігри, а про те, що двох планшетів ні в кого немає, а телефон є в кожного. Тож у пріоритеті опинилися телефони. Будь-який пристрій можна покласти поруч із будь-яким іншим, а поле підлаштується:
Сама ідея об'єднувати екрани не нова. Компанія Google показала Racer на I/O 2013 — трасу для перегонів іграшкових машинок на п'яти телефонах і планшетах, а бібліотека Swip.js у 2016 році з'єднувала екрани жестом щипка. Обидва демо були блискучими. А я хотів ігор, до яких люди повертаються, — на тих пристроях, що якраз опинилися на столі.
Мультиплеєрні ігри: за одним столом і на відстані
Спільний екран — це гачок, але BIGBOARD.GAMES задумано як колекцію мультиплеєрних ігор, і один стіл для неї лише початок. Ігри вже підлаштовуються під те, скільки пристроїв приєдналося і наскільки великі в них екрани. Далі вони підлаштовуватимуться під те, де перебувають гравці: режими для друзів у різних містах чи раунд тимбілдингу для колег у різних кінцях офісу. Технічна основа вже є: код із чотирьох літер і ретранслятор уже з'єднують пристрої, які не в одній мережі Wi-Fi. Але сьогоднішні чотири ігри поки що розраховані на один стіл: гра на відстані — це напрямок, а не те, що вже працює.
Як два екрани стають одним полем
Найскладніше — стик. У двох телефонів різні розміри екранів, різна щільність пікселів, різні рамки, і зазвичай ще й чохол. Якщо зшити їхні екрани піксель до пікселя, шайба перестрибує проміжок, виходить не на своїй лінії й змінює розмір на другому телефоні.
Тому кожен пристрій визначає розмір свого екрана в реальних міліметрах: за профілем пристрою, за даними про модель на Android або через калібрування — ви прикладаєте до екрана банківську картку, адже всі банківські картки мають однаковий розмір ID-1: 85,60 × 53,98 мм. До цього пристрій додає свої рамки й ще по 3 мм на кожен чохол. Ігровий світ розмічено в міліметрах реального столу, з урахуванням проміжків:
Поле вимірюється в міліметрах столу, а не в пікселях. Уявіть вікно з рамою посередині: машина, що проїжджає повз, не стрибає, коли ховається за рамою. Шайба теж не стрибає.
Масштаб теж підлаштовується під стіл. Якщо хоч один пристрій більший за телефон, ігри йдуть у реальному розмірі; якщо за столом лише телефони — у половинному; і ніколи не дрібніше, ніж потрібно грі, щоб грати було зручно. Якщо гра не вміщається, вона підкаже, якому пристрою потрібен більший екран.
Одне відоме обмеження: коли браузер показує свої панелі інструментів, стик уздовж краю панелі виходить коротшим на її висоту. Тут браузери життя не полегшують.
Покажіть грі, як лежать пристрої
Перед кожним матчем усі пристрої показують ту саму схему столу — кожен зі свого боку. Гравці перетягують і повертають прямокутники, доки схема не збіжеться з тим, як пристрої лежать насправді:
Редагувати можуть усі одночасно. Кожна правка — крихітна зміна за принципом «виграє останній запис» (last-writer-wins), а прямокутник, який хтось схопив, закріплюється за ним на 3 секунди, щоб двоє не билися за той самий. Кнопка Start підтверджує розкладку й запускає зворотний відлік. Якщо повернути пристрій до початку матчу, старт скасовується й редактор відкривається знову: поле, яке вже не відповідає столу, гірше за коротке очікування.
Ігровий трафік ніколи не йде через мої сервери
Кожне ігрове повідомлення йде з пристрою на пристрій через канали даних WebRTC: локальною мережею, коли це можливо, і через ретранслятор TURN від Cloudflare лише тоді, коли прямого шляху немає, як-от у мобільному інтернеті.
Серверна частина — один Cloudflare Worker із двома Durable Objects: один на кожен стіл — для місць, вибору гри, відліку, налаштування з'єднань і результатів, — а другий — для відстеження присутності, щоб пристрої в одній мережі Wi-Fi знаходили одне одного. Я за замовчуванням роблю проєкти на Cloudflare, і цей проєкт добре показує чому.
Коли ігровий трафік оминає сервер, затримка лишається низькою, а рахунок — мізерним. Рання версія пінгувала Durable Object столу кожні 2 секунди, тож той ніколи не засинав. Тепер, коли матч іде без збоїв, кожен пристрій закриває з'єднання зі столом, і об'єкт переходить у сплячий режим. Я виміряв це на headless-пристроях: близько 916 запитів до Durable Object на пристрій-годину матчу до змін і 0 після. За моєю оцінкою, якщо на день буде 1 000 сесій пристроїв, це близько $5 на місяць — стільки й так коштує тариф Workers Paid. Наскільки я влучив, покаже реальний трафік.
Ще кілька речей, завдяки яким усе відчувається як одне поле:
- «Настільний хокей» передає шайбу. Пристрій, на якому зараз шайба, симулює її рух і транслює його іншим. Шайба переходить до іншого пристрою, коли перетинає стик або коли її відбирають, і саме ця передача ховає мережеву затримку прямо на стику.
- Гра «Через край» працює в режимі lockstep. Обидва пристрої симулюють той самий фізичний світ на рушії Rapier. Для цього обчислення мають збігатися до біта, тож власні реалізації синуса й косинуса використовують лише додавання, віднімання, множення й округлення та дають однакові результати в JavaScriptCore від Safari і V8 від Chrome.
- Годинники узгоджені. Пристрої синхронізують годинники так, як це робить NTP, з точністю близько 1 мс на локальному з'єднанні, тож кожен відлік закінчується в ту саму мить.
- Оновлення ніколи не переривають матч. Стіл приймає і поточну версію, і попередню, а оновлення чекає на спокійний момент.
Десять днів від прототипу до продакшну з ШІ-агентами
Перший коміт прототипу — 26 вересня. Перший деплой у продакшн — 5 жовтня. Поки я це пишу, у продакшн-репозиторії 344 коміти, і в 337 із них співавтор — Claude Code — 233 лише за 5 жовтня.
Це близько 140 000 рядків TypeScript і 51 000 рядків тестів. Тести запускають окремий браузер на кожен пристрій, а симулятор мережі з фіксованим сідом відтворює перетини стиків у «Настільному хокеї» на профілях Wi-Fi, ретранслятора й мобільного зв'язку: 200 прогонів кожного сценарію, близько 1 150 перетинів стику на профіль. Без цього я б не довірив шайбі перетинати стик на готельному Wi-Fi.
Моя роль була такою, як я описав у пості «Як бути інженером-програмістом в епоху ШІ»: вирішити, що будувати, записати це у вигляді issue на GitHub і правил для агентів, а потім оцінювати те, що вони повертають. Мультиплеєрна гра за десять днів — це все одно чимало оцінювання.
Під захистом AfterPack
Минулого тижня я запустив AfterPack — обфускатор JavaScript, і кожна збірка BIGBOARD.GAMES проходить через нього. У peer-to-peer грі немає сервера-арбітра: матч веде код на пристроях гравців, тож пропатчений клієнт — це вже чит.
Продакшн-збірку обробляє Vite-плагін AfterPack, а скрипт деплою запускає npx afterpack verify dist, перш ніж щось викотити. Якщо квитанції про захист немає, вона належить іншій збірці або якийсь файл змінився після обфускації, деплой зупиняється.
Сторонні бібліотеки й прості дані я навмисно лишив без обфускації. Обфускований кодувальник QR-кодів утричі виріс — приблизно до 25 КБ у gzip, а мовні файли — приблизно в 10 разів. Ця вага не захищає нічого, що варто захищати. Відкрийте DevTools на bigboard.games і подивіться :)
Спробуйте на наступному ігровому вечорі
Далі на черзі «Нахили», «Зграйка», «Маяк», «Пінбол», а потім перші режими для гри на відстані. А поки що мені дуже цікаво, як перші чотири покажуть себе за справжніми столами, на справжніх телефонах.
Якщо сьогодні ввечері ви з друзями й телефонами в одній кімнаті, відкрийте bigboard.games, зсуньте телефони докупи й напишіть у коментарях, яка гра підкорила стіл. А якщо сподобалося, найкраще, чим можна допомогти, — поділитися з другом :)