Кейс: 3D-веб
ENRU
Кейс - люксовый 3D-веб

Один экран золота.
Люксовый 3D-сайт на чистой статике.


Имиджевый сайт для финансовой компании из Гонконга. Вся страница - одна фуллскрин 3D-сцена: медленно вращающийся золотой самородок, студийный свет, который следует за курсором посетителя, и две минималистичные чёрные плашки с брендом и контактами. Без бэкенда, без базы данных, без трекеров. Настоящий 3D в реальном времени вместо зацикленного видеофайла, поставлен как статика.

three.jsReact Three Fiberdrei TypeScript strictViteglTF-TransformCloudflare Pages
530 строк
живого кода, весь продукт целиком
-61%
размер GLB: с 56,5 до 22,2 МБ
136K
треугольников в одном меше
0
бэкенда: ни эндпоинтов, ни таблиц
1
разработчик: дизайн, 3D и вёрстка в одних руках
01 Задача клиента

Цифровая визитка уровня private banking

Клиент работает в сфере привлечения капитала и структурирования сделок. Его сайту не нужны страницы текста и блог. Нужно одно: первое впечатление тихого богатства. Сдержанность, золото, воздух. Страница, которую контрагент открывает один раз перед встречей.

I.Не корпоративный сайт, а заявление

Один экран, без скролла, без меню. Чёрная плашка с именем компании сверху, контакты снизу, кусок золота в центре экрана. Всё остальное убрано намеренно.

II.Люкс - это сдержанность

Пять цветов на весь продукт. Один шрифт в лёгких начертаниях. Капс с широкой разрядкой. Слоган лежит на матовой стеклянной подложке поверх 3D-сцены. Ничего не мигает и не выезжает.

III.Вау-эффект без видеофайла

Очевидный путь - зацикленный шоурил. Вместо этого страница рендерит 3D-сцену в реальном времени: она реагирует на курсор посетителя, весит долю видео, не дёргается на стыке цикла и не требует разрешений на автоплей.

IV.Дёшево владеть

Чистая статика на Cloudflare Pages. Нет CMS, которую надо обновлять, нет сервера, который надо патчить, нет счетов за хостинг. Сайт - это папка файлов, которую раздаёт глобальный CDN.

02 Инженерия 3D

Световая схема: лампа в руке посетителя

Весь продукт живёт в одном Scene.tsx на 345 строк. Центральный приём: точечный свет скользит за курсором, и блики со светотенью скользят по вращающемуся золоту так, будто посетитель обходит скульптуру с лампой в руке.

4 ПАНЕЛИ LIGHTFORMER Окружение без HDRI-файла environmentIntensity 0.75 БАЗОВАЯ ЗАЛИВКА directionalLight 0.38 ambientLight 0.45 ПРОХОД ПО МАТЕРИАЛУ стоковый GLB чистится в рантайме: metalness 1.0, roughness 0.42 золото #d4af37 задано кодом битые карты отключены sRGB / linear приведены в норму САМОРОДОК, GLB 136 224 треугольника, золото задано кодом вращение 0.168 рад/с, покачивание по Y 0.045 СТАТИЧНАЯ КАМЕРА fov 40, позиция 0 / 2.9 / 7.6 POINTLIGHT, ИНТЕНСИВНОСТЬ 40 следует за курсором с лерпом 0.14 за кадр: лампа в руке посетителя Два движения, один эффект: самородок вращается, лампа идёт за курсором. Блики и светотень скользят по золоту в реальном времени. ACES FILMIC, ЭКСПОЗИЦИЯ 0.85 GLB ПРЕДЗАГРУЖЕН ДО ПЕРВОГО КАДРА DPR В ПРЕДЕЛАХ 1-2
Золото и свет Камера и заливающий свет Лучи и пояснения

I.Точечный свет следует за курсором

pointLight с интенсивностью 40 догоняет указатель с лерпом 0.14 за кадр. Благодаря сглаживанию свет ощущается несомым, а не приклеенным. Блики и светотень скользят по вращающемуся золоту вслед за светом, и это мгновенно читается как глубина.

II.Стоковый материал пересобран в рантайме

Стоковый ассет рендерился грязным серым металлом: битые карты ao, light и metalness, неверные цветовые пространства. Код отключает плохие карты и принуждает физику золота, metalness 1.0 и базовый цвет #d4af37, при каждой загрузке модели. Замените модель, и фикс продолжит работать.

III.Студия без HDRI

Вместо загрузки многомегабайтного HDR-окружения сцена строит собственный софтбокс: 4 прямоугольника Lightformer внутри drei Environment с интенсивностью 0.75. Золото получает свои длинные белые блики, а сеть не передаёт ни одного лишнего байта.

IV.Картинка киношного уровня

Тонмаппинг ACES Filmic с экспозицией 0.85 не даёт бликам на металле выгорать. Device pixel ratio ограничен диапазоном 1-2, чтобы телефоны не тормозили, а модель предзагружается до первого кадра. Антиалиасинг включён, канвас запрашивает производительный GPU.

Фуллскрин-сцена: курсор слева, самородок освещён слева
Курсор слева: лампа освещает самородок слева, правый бок уходит в тень.
Фуллскрин-сцена: курсор справа, самородок освещён справа
Курсор справа: тот же кадр с зеркальным светом. Блики уходят вправо, левый бок в тени.

Стоковый ассет не идёт в прод сырым

Самородок взят с 3D-стока. Загруженный как есть, он выглядел серым грязным камнем: битые карты, неверные цветовые пространства, произвольный масштаб. Сцена санитизирует материал в рантайме, кодом, поэтому любая будущая замена модели получит ту же обработку бесплатно.

  1. Нормализовать геометрию. GLTF клонируется, автоцентрируется и автомасштабируется по bounding box до цели около 5 юнитов. Любая стоковая модель встаёт в кадр правильно.
  2. Принудить физику золота. Metalness 1.0, roughness 0.42, базовый цвет #d4af37, envMapIntensity 0.92 и лёгкий clearcoat 0.06. Материал задаёт кейс, а не стоковый файл.
  3. Отключить битые карты. Стоковые aoMap, lightMap, metalnessMap и emissiveMap давали серые грязные пятна на металле. Выключены явно.
  4. Починить цветовые пространства. Base color в sRGB, карты нормалей и шероховатости в linear, anisotropy 8 для резкой текстуры под острыми углами, normalScale 0.55 для смягчения артефактов отсутствующих тангентов.
  5. Пересчитать и закрепить. Нормали и bounding sphere перестраиваются, frustum culling отключён, чтобы модель не пропадала из кадра, когда её границы выходят из математического конуса обзора.
Крупный план золотого самородка после санитизации материала
Санитизированный материал крупным планом: принудительная физика золота поверх стоковой геометрии, блики ACES.
345строк в Scene.tsx, всё ядро 3D
40интенсивность pointLight, лерп 0.14
1-2диапазон dpr, телефоны не тормозят
4Lightformer вместо HDRI
0.168рад/с базовое вращение, дрейф осей
03 Оптимизация ассета

56,5 МБ не задеплоятся: пайплайн GLB

Cloudflare Pages жёстко ограничивает размер файла: 25 МБ. Стоковый самородок весил 56,5 МБ и просто не проходил в деплой. glTF-Transform сжал его до 22,2 МБ, минус 61%, не тронув ничего видимого глазу.

ЛИМИТ CLOUDFLARE PAGES: 25 МБ НА ФАЙЛ ИСХОДНЫЙ GLB С 3D-СТОКА 56,5 МБ ПОСЛЕ GLTF-TRANSFORM 22,2 МБ -61% EXT_meshopt_compression + KHR_mesh_quantization, glTF-Transform 4.2.1 Геометрия цела: 69 104 вершины, 136 224 треугольника, 3 PBR-текстуры (8,6 + 6,6 + 6,2 МБ)
Исходный ассет Задеплоенный ассет Лимит платформы

I.Что именно сжато

Meshopt-компрессия перекодирует вершинные данные в компактный поток, удобный для GPU, квантование хранит позиции и нормали в меньшем числе бит. В этом масштабе оба приёма визуально без потерь. Один меш, один материал, все три PBR-текстуры сохранены.

II.Почему это важнее лимита

GLB - самая тяжёлая загрузка страницы с большим отрывом. Срезать 61% - это разница между люксовым первым впечатлением и крутящимся спиннером. Лимит платформы навязал дисциплину, а выгоду посетитель получает при каждой загрузке.

25 МБжёсткий лимит хостинга на файл
22,2 МБитоговый GLB, влезает с запасом
69 104вершины, без изменений
3PBR-текстуры: normal, color, metal-rough
04 Стек и деплой

Пять зависимостей, ноль серверов

Рантайм намеренно крошечный: react, react-dom, three, @react-three/fiber и @react-three/drei. Больше в браузер не едет ничего.

TypeScript работает в strict-режиме, и сборка начинается с полной проверки типов: сначала tsc, потом Vite. Конфиг Vite дефолтный, поэтому сборка тривиально воспроизводима. Деплой на Cloudflare Pages: пуш, сборка, готово. Сайт раздаётся с глобального CDN на бесплатном тарифе.

TypeScript ~5.9 strictVite 7React 19 three.js 0.182React Three Fiber 9drei 10
5 рантайм-зависимостей0 эндпоинтов0 таблиц БД0 трекеров

Что это даёт клиенту

Нечего обслуживать. Нет CMS, которую надо обновлять, нет сервера, который надо патчить, нет админки, которую могут взломать, нет счёта за хостинг. Сайт - это папка статических файлов, которая через годы откроется так же. Для компании, чей продукт - доверие, страница, которая не может сломаться - это фича, а не компромисс.

Мобильная версия сайта: фуллскрин 3D-сцена с плашками
Мобильная версия: та же сцена с dpr под устройство, плашки и стеклянная подложка масштабируются на clamp().
05 Как это строилось

Маленький проект, та же дисциплина

Небольшой проект собран теми же правилами, что и большой: строгий TypeScript, дней фактической работы. История git читается как чистый короткий сюжет.

  1. Концепция переживает итерации. Рабочее имя в package.json до сих пор luxury-light-cube. Идея эволюционировала от абстрактного светового куба к золотому самородку, и световая схема пережила разворот без потерь.
  2. Типобезопасность даже на одностраничнике. Строгий TypeScript с воротами tsc перед каждой сборкой. Проект на 530 строк заслуживает те же ограждения, что и большой.
  3. Лимиты платформы как требования. Лимит Cloudflare Pages в 25 МБ стал явным шагом пайплайна ассетов, а не поздним сюрпризом: отдельный шаг сжимает GLB на 61%.
  4. Полировка - отдельный проход. Финальные шаги - чистое ремесло: лучшая модель самородка, полная санитизация материала, затем доводка света и фона. Визуальное качество итерировалось на реально задеплоенной сцене.

Профиль поставки

530 строк проектастрогий TypeScript1 разработчик

Объём кода

530 строк всегоScene.tsx 345 строкCSS 143 строки

Честные цифры

Каждая цифра в этом кейсе сверена с репозиторием проекта: размеры файлов, число строк, параметры сцены. Оценки помечены как оценки.

06 Итог и контакт

Присутствие, поставленное как инженерия

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

Кирилл Седов

Бизнес-аналитик и строитель систем. Основа моего портфолио - ERP и автоматизация бэк-офиса: сначала анализ, потом код. Этот кейс - другая сторона того же ремесла. Когда бизнесу нужно присутствие, а не процесс, я применяю ту же дисциплину: ясные требования, лимиты платформы как ограничения, честные цифры, чистая поставка.

Связаться в LinkedIn