Реплей задачи соревнований: пилоты летят над 3D-рельефом по своим GPS-трекам

Проект
Собственный проект
Год
2026
Что делали
Сайты на ProcessWire
Стек
ProcessWire, PHP, Интерактивные 3D-карты, three.js
Сайт
replay.sla.events/a241c30d592e

Типичная соревновательная задача: 38 пилотов летят над 3D-рельефом по своим трекам, а 324 тысячи GPS-точек приходят в браузер файлом на 1,6 МБ.

38
пилотов в одном повторе
МС «Peregrine Falkon», задача 3: все треки на общей шкале времени
B
1,6МБ
было 3,9 МБ
все треки задачи
324 тысячи GPS-точек: MessagePack с дельта-кодированием против того же ответа в JSON, 14 сентября 2026
B
306КБ
стартовая загрузка
gzip; three.js — ещё 189 КБ — загружается, только когда посетитель включает 3D
B
3
приложения на одном движке
replay.sla.events, карты задач и полётных мест на sla.events, планировщик задач tasker
B

Задача

sla.events — наша платформа для соревнований по парапланерному и дельтапланерному спорту: календарь, результаты, рейтинги. После каждой задачи пилоты загружают на неё свои GPS-треки. Всё прекрасно, но сайту очень не хватало реплея треков. Задача эта настолько сложная, что существует всего несколько популярных сервисов реплея. И все они основаны на одной и той же библиотеке Cesium. Для разработчиков она имеет низкий порог вхождения, и картинка «на выходе» очень детальная и красивая. Обратная сторона медали — очень большие объёмы передаваемых данных и высокая требовательность к железу. Использовать такой реплей в полевых условиях очень сложно, часто невозможно. Нужен был альтернативный реплей: может быть, не такой эффектный, как на Cesium, но быстрый и нетребовательный к железу.

Решение

Мы подобрали уникальный технологический стек: он лёгкий, быстрый, но даёт картинку хорошего качества даже на слабых устройствах. Несколько десятков треков одного таска можно смотреть одновременно на одной карте с общей шкалой времени. Ограничением становится не ширина интернет-канала и возможности устройства, а комфорт пользователя: просматривать больше 10−15 треков одновременно достаточно сложно даже на больших экранах. Цилиндры и оптимальный маршрут отображаются на карте так же, как в самой задаче. Карту можно наклонить и включить трёхмерный рельеф. Тогда пилоты летят на своей настоящей высоте, а от трека к земле опускается полупрозрачная «шторка» — видно, и насколько пилот высоко над склоном, и где он набирал высоту.

Как трек попадает в браузер

На сервере. Пилоты загружают треки в IGC, GPX или KML — всё, что не IGC, сервер переводит в IGC. Для повтора трек обрезается окном задачи, из него выбрасывается время, когда пилот стоял на месте, а точки кодируются дельтами: первая — целиком, каждая следующая — разницей с предыдущей.

На проводе. Ответ уходит в двоичном формате MessagePack. В задаче с 38 пилотами 324 тысячи точек занимают 1,6 МБ вместо 3,9 МБ в JSON. Геометрию задачи сервер берёт из файла FSComp или XCTrack и сам считает оптимальный маршрут по правилам FAI.

Передача треков

{
  title: 'МС. Параплан-маршрутный полет Peregrine Falkon. nonFAI, Задача 3',
  tracks: [
    { number: 30, name: '…', pts: [
      [4283512, 4721035, 612, 1782976516], // первая точка: широта×1e5, долгота×1e5, высота, время
      [3, -2, 1, 1],                        // дальше — только разница с предыдущей
      [4, -1, 2, 1],
      …
    ] },
    … // ещё 37 пилотов
  ],
  geo: { … },            // цилиндры, линии старта и финиша, оптимальный маршрут
  marks: [{ text: 'Stop', ts: … }],
}

Структура ответа API повтора; координаты и время в примере условные.

three.js внутри MapLibre

Карта — MapLibre GL с рельефом из открытых данных. Треки в 3D рисует three.js, но не отдельным холстом поверх карты, а внутри неё: каждый трек — собственный слой MapLibre, и все слои делят с картой один WebGL-контекст и одну камеру. Поэтому при вращении и наклоне треки не отстают от рельефа ни на кадр.

Маркер пилота держит постоянный размер на экране при любом масштабе. А сам three.js — это ещё 189 КБ, и браузер скачивает его, только когда посетитель включает 3D.

Ссылка — это набор пилотов

В адресе повтора после # стоят номера пилотов, которых видно на карте. Пилот может отправить ссылку на свой полёт или на сравнение с соперником, и она откроется с теми же пилотами. Если поменять номера прямо в адресе, приложение догрузит только недостающие треки.

Дальше — таймлайн со скоростью от 1x до 8x, перемотка с клавиатуры и камера, которая следует за выбранным пилотом.

Один движок — три приложения

Карта, рельеф, проигрыватель треков и виджеты вынесены в отдельный движок на TypeScript. На нём работают сам повтор, карты задач и полётных мест на sla.events и task.er — планировщик задач для организаторов, который работает и без интернета. Исправление в движке доходит до всех трёх.