Racelink
Шаги руководства · 05 / 08
  1. 00Перед началом
  2. 01Создайте проект
  3. 02Запустите оверлей
  4. 03Выведите живые данные
  5. 04Добавьте настройки
  6. 05Доведите вид
  7. 06Соберите и проверьте
  8. 07Опубликуйте в Мастерской
  9. 08Выпускайте обновления

// Руководство по оверлеям · 05

Доведите вид

Racelink показывает оверлей поверх игры, в OBS и в превью — и всегда с первого кадра. Научим HUD подстраиваться под любой размер, ограничим размер в манифесте и добавим анимацию, которая не мелькает при открытии. Около 20 минут.

Держите запущенными npm run dev и Racelink, а My HUD — на экране.

Растяните оверлей

Игрок сам выбирает размер оверлея, поэтому вёрстка не знает его заранее. Проверьте, как HUD ведёт себя сейчас:

  1. Откройте Макеты и нажмите Изменить расположение.
  2. Потяните My HUD за правый нижний угол: сделайте его вдвое больше, потом совсем маленьким.

Полоски педалей тянутся, а передача, скорость и время круга растут и уменьшаются вместе с окном. Это работает благодаря двум приёмам шаблона в src/style.css:

src/style.css
#root {
/* … */
container-type: size;
}

.gear {
font-size: clamp(24px, 45cqh, 120px);
}
container-type: size
Делает #root контейнером: внутри него можно мерить размеры в процентах от него.
45cqh
45% высоты контейнера. Окно выше — цифра больше. Есть и cqw — процент ширины.
clamp(24px, …, 120px)
Не меньше 24 и не больше 120 пикселей, чтобы текст оставался читаемым и не разрастался.

Отступы и промежутки в шаблоне заданы в процентах, а не в пикселях, по той же причине. Держитесь этого и в своих элементах: время круга из шага «Выведите живые данные» уже использует 12cqh.

Ограничьте размер

Совсем маленький HUD нечитаем, а слишком большой бессмыслен. Пределы задаёт поле size в racelink.overlay.json. В шаблоне оно такое:

racelink.overlay.json
"size": { "default": [360, 120], "min": [200, 80], "max": [1200, 400] },
default
Ширина и высота нового оверлея в пикселях, когда игрок добавляет его на макет.
min
Меньше этого растянуть нельзя.
max
Больше этого растянуть нельзя.

Попробуйте, как выглядит предел:

  1. Поменяйте max на [600, 200] и сохраните файл.
  2. В режиме редактирования тяните правый край My HUD дальше 600 пикселей. Край станет янтарным и чуть подастся, как резина, а отпущенный — вернётся к пределу. Так игрок видит, что дальше оверлей не растёт.

Если оверлей был больше нового предела, Racelink сам уменьшит его до допустимого размера. Оставьте пределы, которые вам удобны: [600, 200] или те, что были.

Ещё два варианта, которые пригодятся для других оверлеев:

Одна сторона фиксирована
Одинаковые min и max по стороне: "min": [200, 120], "max": [1200, 120] — высота всегда 120, меняется только ширина. Такой край в редакторе не тянется.
"resize": "scale"
Для оверлея, нарисованного под один размер: "size": { "default": [400, 300], "resize": "scale" }, без min и max. Окно всегда 400 × 300, а растягивание увеличивает или уменьшает оверлей целиком, сохраняя пропорции, от 0,25× до 4×.

Кнопки Уменьшить и Увеличить у оверлея в режиме редактирования масштабируют любой оверлей так же — целиком.

Анимации без мелькания

Анимация оживляет оверлей, но при открытии мешает: если строки при каждом показе въезжают и проявляются, оверлей в превью и в OBS выглядит недорисованным. Поэтому SDK первые 1,5 секунды после ready мгновенно завершает все CSS-переходы и анимации. Оверлей открывается сразу в готовом виде, а дальше анимации работают как обычно.

Проверим на деле: пусть цифра передачи вспыхивает цветом газа при каждом переключении.

1. В src/main.ts над render добавьте переменную с показанной передачей:

src/main.ts
let shownGear = '';

2. В render замените строку if (gear) gear.textContent = … на:

src/main.ts
  const gearText = car.gear < 0 ? 'R' : car.gear === 0 ? 'N' : String(car.gear);
if (gear && gearText !== shownGear) {
shownGear = gearText;
gear.textContent = gearText;
// Restart the animation: take the class off, let the browser notice, put it back.
gear.classList.remove('shift');
void gear.offsetWidth;
gear.classList.add('shift');
}

3. В конец src/style.css:

src/style.css
.gear.shift {
animation: shift 400ms ease-out;
}

@keyframes shift {
from {
color: var(--throttle);
transform: scale(1.15);
}
}

Сохраните. С ?demo передача вспыхивает при каждом переключении, но не при открытии страницы, хотя render в ready тоже ставит передачу впервые.

Чтобы увидеть разницу, временно включите анимации с первого кадра и обновите страницу:

src/main.ts
const overlay = createOverlay<Settings>({ defaults: defaultSettings, animateStart: true });

Теперь передача вспыхивает и при открытии. Уберите animateStart: true: для оверлея почти всегда лучше без него.

История с первого кадра

В My HUD истории нет, но запомните на будущее. Оверлей, который рисует прошлое — график педалей за последние секунды, след перегрузок, — при открытии пуст: прошлого он ещё не видел. В превью и в демо-режиме это выглядит как поломка. Для этого есть overlay.demoHistory: демо-значения темы за последние секунды, от старых к новым.

src/main.ts
overlay.on('ready', () => {
// Empty outside demo mode, so this does nothing with a real game.
for (const { sampledAt, data } of overlay.demoHistory('car', 10)) trace.push(sampledAt, data);
});

Здесь trace — ваш график. С игрой demoHistory пуст, и график наполняется живыми данными.

Прозрачный фон

Окно оверлея прозрачно: всё, что вы не нарисовали, показывает игру. В шаблоне html, body и #root заданы с background: transparent, а тёмная подложка — это фон #root с прозрачностью из настройки. Чего не делать:

  • Не задавайте фон у html и body — закроете игру прямоугольником.
  • Не ставьте color-scheme ни в <meta>, ни в CSS: браузер закрасит окно белым или чёрным.

Посмотрите в превью

Racelink показывает оверлей не только на экране. Откройте Макеты, выберите My HUD: в панели Настройки превью на демо-данных. Переключитесь на другой оверлей и обратно: HUD должен появляться сразу готовым — с вашими цветами, без вспышки передачи, без пустых мест.

Если что-то пошло не так

  • Текст не меняет размер вместе с окном. У элемента размер шрифта в px, а не в cqh, или над ним нет элемента с container-type: size.
  • Край не становится янтарным. Проверьте терминал: манифест с ошибкой (например, min больше max) Racelink не принимает, и там будет racelink.overlay.json has problems.
  • Передача вспыхивает только один раз. Пропущена строка void gear.offsetWidth;: без неё браузер не замечает, что класс снимали, и анимация не перезапускается.

Что должно получиться

  • My HUD читается и в маленьком, и в большом окне.
  • У предела край оверлея становится янтарным и пружинит.
  • Передача вспыхивает при переключении, но не при открытии оверлея.
  • В превью Racelink HUD появляется сразу готовым.