claude theft auto Играть

Как это сделано

Открытый мир, который целиком считается в браузере телефона: город, трафик, толпа, полиция, самолёты и катера. Ниже — то, что мешало, то, что выручило, и то, что стоит знать заранее. Все числа в тексте из замеров, а не по памяти.

Из чего собрано

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

Three.js r160Отрисовка. Лежит рядом с игрой отдельным файлом, а не тянется из сети: версия зафиксирована, обновление не может сломать выложенную сборку.1388 КБ
Обычный JavaScriptДвадцать один модуль ES, никакого фреймворка и никакой сборки. Браузер получает ровно те файлы, что лежат в папке проекта.1527 КБ кода
WebGL через InstancedMeshВесь трафик — один вызов отрисовки на тип кузова, толпа и город тоже собраны экземплярами. Отсюда и держится потолок в сотню вызовов.
Canvas 2D для текстурАсфальт, фасады, вывески, приборы в салоне рисуются кодом при запуске. Мегабайтных карт в игре нет вовсе.атлас 512×512 ≈ 40 КБ
Web AudioДвигатель собирается из сэмплов и синтеза на лету, радио — обычные файлы. Панорама считается от камеры.
localStorageПрогресс, гараж и рекорды лежат у игрока. Сервера у игры нет.
Yandex CloudObject Storage раздаёт файлы, API Gateway отвечает за адреса /game, /make и счётчик. Ни одной серверной функции.

Инструменты

Шесть сервисов и программ, каждая на своём шаге.

Nano Banana ProКонцепт-лист по текстовому описанию: фигура в А-позе на ровном сером фоне, без теней и подложек. Требования жёсткие потому, что дальше картинку читает не человек, а алгоритм.33 промпта
MeshyТри разных сервиса под одной крышей: картинка → трёхмерная модель, автоматическая оснастка скелетом и библиотека готовых движений с номерами действий.модель 30 кредитов, оснастка 5
Blender 5.2, без окнаВсё, что между генератором и игрой: сшивка швов, прореживание, разделение головы и тела, сборка клипов в один файл, пересчёт нормалей, экспорт.14 скриптов
ElevenLabsТри радиостанции, вальс и звук двигателя. Треки режутся до 75 секунд, сводятся в моно и зацикливаются так, чтобы конец совпадал с началом.
Puppeteer + ChromeСтенд проверки и съёмка трейлера. Он же меряет кадры, вызовы отрисовки и треугольники — все числа на этой странице получены им.
RemotionМонтаж трейлера кодом: ритм склеек, вспышки на стыках, наезд внутри кадра.версия 4.0.506

Конвейер

Пять шагов от строчки текста до файла, который открывается по ссылке.

  1. Описание словами

    Каждый объект начинается с текста: «молодая женщина в красном платье, волосы собраны в хвост, А-поза, ровный свет, серый фон». Ограничения в промпте — не про красоту, а про то, переживёт ли картинка следующий шаг.

  2. Картинка становится телом

    Meshy строит по концепту модель на 20–30 тысяч треугольников с текстурой. Это ещё не то, что поедет в браузер: один такой файл весит больше, чем весь город.

  3. Скелет и движения

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

  4. Облегчение под телефон

    Blender сшивает разошедшиеся швы, режет фигуру на голову и тело, прореживает их разными бюджетами и сшивает обратно. Модель худеет в десять раз и остаётся собой.

  5. Сборка, замер и выкладка

    Клипы сшиваются в один файл на персонажа, страница и адреса штампуются версией, стенд меряет кадр, и всё уезжает в облако одной командой. Правка, не прошедшая замер, не выкладывается.

Сложности

Девять мест, где время ушло впустую, пока я не начал мерить.

  1. Модель из генератора разваливается, когда её облегчаешь

    Meshy отдаёт машину в 24 тысячи треугольников, а в браузер помещается пара тысяч. Прореживание съедает не детали, а форму: отваливаются колёса, борта сворачиваются внутрь. По числам этого не видно — счётчик треугольников доволен, а машина уже не машина.

    пикап при 1400 треугольниках — лоскут без колёс, при 2500 — целая машина

  2. Лицо схлопывается раньше всего остального

    Прореживание режет фигуру равномерно, а лицо — самая мелкая геометрия в ней. При общем бюджете 1600 треугольников голове доставалось 450, и нос с глазами просто исчезали. Фигура при этом выглядела нормально — пока не подойдёшь.

    голова 450 из 1600 — лица нет; 1200 из 2200 — лицо есть

  3. Часть брака приходит из самого генератора

    У девушки длинные распущенные волосы падали на щёку. Генератор строит такие пряди отдельной тонкой оболочкой поверх лица, и при любом прореживании она рвётся в крупные плоские осколки. Ни один способ облегчения это не чинит — я перебрал четыре.

    осколки видны уже в сыром файле на 20 тысячах треугольников

  4. Бюджет кадра телефона держит за горло

    Потолок — 90 тысяч треугольников и меньше сотни вызовов отрисовки на кадр. Каждое улучшение приходится оплачивать: подняли качество лиц — сняли модель с самой дальней машины и с шестого прохожего.

    60 кадров в секунду, 85–86 тысяч треугольников, 89–91 вызов

  5. Тихие отказы страшнее падений

    Загрузчик моделей прохожих отвергал файлы, не влезающие в его предел, и писал об этом предупреждением. Когда бюджет подняли до 2200, а предел остался 1800, отвергнуты оказались все семь типов. Ошибок ноль, игра работает — просто весь город ходит дешёвыми заготовками.

    ноль прохожих со скелетом из шестидесяти — поймано замером, не глазами

  6. Разовое действие без условия становится постоянной силой

    Удар о кромку тротуара должен срабатывать один раз при съезде. Условия в коде не было, и он отрабатывал каждый кадр — шестьдесят раз в секунду снимал три четверти скорости. На экране это невидимая стена вдоль дороги.

    54 км/ч на асфальте и 3.7 км/ч через секунду после съезда

  7. Чужие файлы приносят свои системы координат

    Клипы анимации несли собственный масштаб скелета — герой уменьшался на ходу и вырастал на месте. А поза покоя таза оказалась в сотню раз крупнее ожидаемой: запись «правильной» высоты загоняла героя по пояс в асфальт.

    рост 1.567 м на ходу против 1.176 м стоя; таз: ожидалось 0.954, в файле 90.141

  8. Угол обзора не постоянен, и масштаб его не компенсирует

    В альбоме 62 градуса, в портрете до 80. Салон, собранный под один угол, в другом расползается. Первая попытка растянуть узел целиком не дала ничего: равномерный масштаб вокруг начала координат камеры проекцию не меняет вовсе.

    панель на y = −0.30 при z = −0.70 ложится на 86% высоты кадра — под нижний край

  9. Монтаж может гасить кадры на каждой склейке

    Каждый кусок трейлера плавно уходил в ноль, а следующий начинался с нуля — и ровно на стыке оба оказывались прозрачными. Один пустой кадр восемнадцать раз за минуту.

    на выборке по секунде поймалось три пустых кадра из тридцати семи

Находки

Семь решений, которые сняли причину, а не симптом.

  1. Резать голову и тело врозь

    Фигура делится по линии шеи, обе части прореживаются своими бюджетами и сшиваются обратно. Половина бюджета уходит голове. Тело на игровой дистанции теряет незаметно, а лицо появляется.

    та же цена в треугольниках, лицо читается

  2. Вмятины — атрибутом экземпляра, а не отдельной сеткой

    Весь трафик рисуется одним InstancedMesh. Битая машина не получает свою геометрию: направление и сила удара едут в атрибут экземпляра, вершины сдвигает шейдер.

    вмятины стоят ноль вызовов отрисовки

  3. Салон задавать долями кадра, а не метрами

    Честная геометрия уводила панель под нижний край. Салон описан в долях экрана: линия панели — две трети сверху, приборы над ней, руль под ней. Высота в метрах считается из доли и глубины.

    дорога занимает верхние две трети кадра при любом угле обзора

  4. Спрашивать не «далеко ли», а «видит ли игрок»

    Машины из пробок переселяются по городу. Радиус «не трогать ближе 70 метров» запрещал разбирать пробку, вставшую в 65 метрах прямо по курсу. Проверка по направлению камеры отвечает на нужный вопрос.

    стоящих машин 0–4 из 59 вместо растущих до 17

  5. Два набора фар вместо одного

    Коробка фары посчитана по плоскому носу процедурного кузова. У модели нос скруглён, и та же коробка висит в воздухе перед бампером. Держим второй набор, утопленный внутрь, и выбираем по способу отрисовки.

    шесть матриц на тип, ноль стоимости в кадре

  6. Растянуть солнце, не трогая часы

    Темнело в шесть вечера. Вместо переписывания световой таблицы день растянут отдельной функцией: часы на экране остаются честными, по растянутой шкале идёт только солнце.

    восход 4:30, закат 22:30; в 20:00 ещё полный день

  7. Снимать трейлер прямо в игре скриптом

    Никакого отдельного рендера: камера отключается от героя, план описывается функцией от времени, кадры снимаются по одному и склеиваются. Пролёты дрона и погоня — это та же игра, что открывается по ссылке.

    семнадцать планов, всё снято на той же сборке, что и выложена

Советы

Восемь правил. Каждое я нарушил в этом же проекте.

  1. Не гадайте — мерьте, и меряйте то, что видно

    Когда счётчик и картинка спорят, прав рендер. Половина времени здесь ушла на проверки, которые я строил, чтобы перестать угадывать: показать модель крупно, посчитать стоящие машины, спроецировать точку и посмотреть, куда она легла.

  2. Считайте успешной только ту операцию, результат которой вы видели

    Генератор пропускал шаг, если файл уже существовал. Установка времени суток молча ничего не делала, потому что за свойством стоял только геттер. Обе «сработали» без единой ошибки.

  3. Проверка «нет ошибок в консоли» ничего не гарантирует

    Предупреждение — не ошибка. Ищите не отсутствие ошибок, а присутствие ожидаемого: сколько прохожих получили модель, сколько машин нарисовано моделью, доехала ли машина до точки.

  4. Один и тот же предел не должен жить в двух местах

    Бюджет в инструменте сборки и предел в загрузчике — это одно число. Разъехались на четыреста треугольников — и город остался без единой модели человека.

  5. Стройте управляемый опыт, а не наблюдение

    «Поезжай и посмотри» даёт разный ответ каждый раз. Поставьте машину на открытую площадку по проверенному направлению, дайте газ и снимите скорость по секундам — вот тогда число значит ровно то, что значит.

  6. Пишите в коде не «что», а «почему», и с числом

    Комментарий «сшить швы» бесполезен через неделю. Комментарий «две трети рёбер без второй грани, поэтому прореживание рвёт сетку в лоскуты» спасает следующего.

  7. Генерируйте исходники с оглядкой на весь конвейер

    Красивая картинка не значит пригодную модель. Волосы, падающие на лицо, дают осколки после прореживания. Промпт с собранными волосами снял проблему, которую не решала ни одна настройка облегчения.

  8. Держите бюджет кадра как валюту

    Улучшение всегда за чей-то счёт. Заведите потолок, меряйте его на каждой правке и решайте, у кого забрать: у дальней машины, у шестого прохожего или у тени.

Посмотреть, что вышло

Игра открывается по ссылке, ничего скачивать не нужно.

Играть ← описание игры