Все статьи

3D-конфигуратор не обязан быть «тяжёлым CAD»: кейс Blum AMBIA-LINE

Как мы собрали 3D-конфигуратор Blum AMBIA-LINE на React Three Fiber: процедурная геометрия вместо CAD, отделение логики размещения от рендера, snap, коллизии и спецификация заказа.

3D в браузере кажется сложным. Со правильным стеком — это обычная инженерия

Когда заказчик говорит «нужен 3D-конфигуратор», в голове часто всплывает тяжёлая картинка: CAD, дорогое моделирование, Unreal, отдельная 3D-команда, месяцы до первого демо.

На практике для многих product-конфигураторов это не та задача. Нужен не фотореализм ради фотореализма, а понятная сцена, в которой пользователь:

  1. видит изделие;
  2. меняет параметры;
  3. ставит элементы;
  4. сразу получает спецификацию.

Именно такой MVP мы собрали для конфигуратора внутреннего наполнения ящиков Blum AMBIA-LINE: системы LEGRABOX / MERIVOBOX / TANDEMBOX, каталог разделителей, drag в 3D, snap, коллизии, печать заказа.

Короткий ответ: сложность 3D взрывается, когда вы тащите CAD-мышление в веб. Она падает, когда стек разделён на три слоя — UI, доменная логика размещения, лёгкий WebGL-рендер — и модели процедурные, а не «все STEP-файлы мира».


Какую задачу решали

Нужен был веб-демо для дистрибьюторского/клиентского контура Blum:

  • выбрать систему ящика;
  • задать внутренние размеры (ширина 450–1300 мм и связанная глубина);
  • выбрать цвет фасада;
  • добавить элементы AMBIA-LINE из каталога;
  • разместить их в ящике (drag, поворот 90°, копия, удаление);
  • видеть свободные зоны и snap к стенкам;
  • сформировать спецификацию заказа и распечатать.

Это классический product configurator, а не digital twin завода. Значит, и стек должен быть product-web, а не CAD-pipeline.


Почему 3D часто кажется сложнее, чем есть

Страх команды Что обычно имеется в виду Что нужно для конфигуратора
«Нужны дорогие 3D-модели» Полные CAD/GLTF со всеми фасками Узнаваемая процедурная геометрия
«Нужен отдельный 3D-движок» Unity/Unreal WebGL через Three.js в браузере
«Нужна физика» Полноценный physics engine 2D AABB-коллизии на полу ящика
«Нужен сложный state» Свой event-bus на всё Один store (Zustand) + React
«Долго до первого результата» Пайплайн ассетов Скелет сцены за дни, не месяцы

Главная ошибка — смешать визуализацию и бизнес-логику в одном комке мешей. Тогда любое правило «не ставь в стенку» превращается в отладку Three.js вместо простой геометрии на миллиметрах.


Правильный стек для этой задачи

Слой Технология Роль
Приложение Vite + React 19 + TypeScript Быстрый SPA, строгие типы
Состояние Zustand Система ящика, размеры, placed items, selection
3D React Three Fiber + drei + Three.js Сцена, свет, камера, меши
Логика Чистые utils (geometry.ts, placement.ts) Коллизии, snap, свободные зоны
Данные catalog.ts, drawerGeometry.ts Артикулы, габариты, параметры систем

Почему именно так:

  • React Three Fiber даёт Three.js в привычной React-модели: компоненты, props, хуки. Не нужно писать «второй фреймворк» на голом requestAnimationFrame.
  • Zustand держит конфигурацию вне Canvas. UI-панели и 3D читают один источник правды.
  • Процедурные меши (box, простые материалы) закрывают 80% узнаваемости без склада GLB.
  • Геометрия в мм считается в обычном TypeScript; в сцену уходит только масштаб 1 unit = 10 mm.

blum-3d-ill-02-stack

Итоговая схема:

LeftPanel / RightPanel (DOM)
            │
   useConfiguratorStore (Zustand)
            │
     Scene3D (R3F Canvas)
        ├── DrawerBox
        ├── PlacedItemMesh
        └── SnapGuides / FreeZones
            │
     geometry.ts + placement.ts

3D здесь — view. Правила — отдельный слой. Это и делает задачу управляемой.


Как устроено «моделирование» без CAD

Ящик

DrawerBox собирается из примитивов: дно, стенки, фасад, ручка, направляющие. Параметры систем (толщины, металл боковин, reveal фасада) лежат в drawerGeometry.ts.

Меняется система или цвет — меняются материалы и размеры, а не «переимпортируется модель».

Элементы каталога

Каждый товар в каталоге имеет:

  • реальные артикулы/цены (для демо);
  • габариты в мм;
  • visualType — какой процедурный шаблон рисовать в CatalogItemModel.

Новый товар чаще всего = новая запись в данных + при необходимости один case визуала. Не полноценный 3D-пайплайн.

Почему этого достаточно

Для конфигуратора важны:

  • пропорции;
  • занятое место на полу;
  • понятный drag;
  • читаемая спецификация.

Фотореалистичный AMBIA-LINE с микрофасками на демо почти не добавляет конверсии, зато сильно добавляет срок и стоимость.

blum-3d-ill-01-viewport


Настоящая сложность — не меши, а размещение

Именно здесь обычно «ломается» ощущение простоты. Но и она хорошо решается, если не тащить её в шейдеры.

Задача Решение в проекте
Поворот 0/90/180/270 getRotatedSize() — footprint отдельно от 3D rotation
Не выходить за стенки isInsideDrawer + margin
Не пересекаться AABB 2D + COLLISION_GAP
Drag с «скольжением» resolveDragPosition
Прилипание applySnapping (порог ~12 мм), оранжевые guides
Автодобавление из каталога findBestPlacement — offsets × повороты × free zones
Свободное место computeFreeZones + статус «Свободно ~N%»

Важный архитектурный принцип:

  • в store хранятся логические мм и rotation;
  • 3D-модель при повороте вращает группу, а не пересчитывает width/depth меша;
  • для коллизий используется footprint после getRotatedSize().

Так визуал и правила не конфликтуют.

blum-3d-ill-03-logic


Производительность: что сознательно не делали

Чтобы демо летало в браузере:

  • без тяжёлого Environment и realtime-теней;
  • ограниченный dpr ([1, 1.25]);
  • во время drag обновляется локальный state, в store — на pointerup;
  • OrbitControls отключается, пока пользователь тащит элемент.

Это снова про правильный scope: конфигуратор должен быть отзывчивым, а не «игровым AAA».


Что получил заказчик на выходе

Рабочее веб-демо:

  • 3 системы ящиков;
  • размеры и цвет;
  • каталог AMBIA-LINE с поиском;
  • 3D-сцена с drag/rotate/copy/delete;
  • snap и свободные зоны;
  • спецификация + печать/PDF;
  • onboarding и toast-уведомления.

И понятный roadmap без иллюзии, что «3D уже = готовый enterprise»:

Уже есть Следующий этап
Клиентский конфигуратор Backend / админка
Локальный каталог Синхронизация с 1С/API
Процедурный 3D Более детальные ассеты точечно
Демо-продажа сценария AI-render / расширенные режимы

Чеклист: когда 3D-конфигуратор можно делать «просто»

Подходит стек уровня R3F + процедурная геометрия, если:

  1. изделия собираются из повторяемых модулей;
  2. важны габариты и комплектация, а не киношный рендер;
  3. взаимодействие — select / drag / rotate / snap;
  4. результат нужен как спецификация/заказ;
  5. первый демо-стенд нужен быстро для согласования.

Лучше сразу усложнять стек (CAD viewer, WASM-ядро, Unreal pixel streaming), если:

  1. нужна точная инженерная модель «как в CAD»;
  2. критичны сложные кривые поверхности и BOM из PLM;
  3. пользователь должен инспектировать допуски/сборку на уровне производства.

Для Blum AMBIA-LINE первый путь оказался правильным.


Практические выводы

1. Не начинайте с «моделей».
Начните с координат, единиц измерения и правил размещения.

2. Отделите store от Canvas.
UI и 3D должны читать одно состояние, а не жить в двух мирах.

3. Рисуйте процедурно, пока хватает узнаваемости.
GLTF подключайте точечно, когда ассет реально повышает доверие.

4. Коллизии делайте на логической плоскости.
2D AABB на полу ящика закрывает 90% UX-кейсов конфигуратора.

5. Оптимизируйте под демо-устройство.
Меньше эффектов — больше ощущения «продукт уже живой».


Итог

3D-моделирование для product-конфигуратора — это не обязательно сложная мультимесячная дисциплина. При стеке Vite + React + TypeScript + React Three Fiber + Zustand и процедурной геометрии задача раскладывается на понятные инженерные куски: данные каталога, логика размещения, лёгкая сцена, спецификация.

Кейс Blum AMBIA-LINE как раз про это: быстро показать объём ящика, дать поставить разделители «руками» в 3D и сразу собрать заказ — без превращения демо в CAD-платформу.

Сложность появляется не от слова «3D». Она появляется от неправильного выбора инструмента под класс задачи.


FAQ

Нужен ли Three.js «с нуля», если есть React?
Для такого продукта удобнее React Three Fiber: меньше бойлерплейта, проще связка с UI.

Когда переходить на готовые GLTF-модели?
Когда процедурные примитивы перестают убеждать на демо или нужен маркетинг-shot. Не до первого работающего сценария.

Почему коллизии 2D, если сцена 3D?
Потому что элементы стоят на полу ящика. Задача размещения — планировка площади, а не полёт в пространстве.

Можно ли на этом стеке вырасти до production?
Да: добавить backend, синхронизацию каталога, auth и более детальные ассеты. Архитектура store + utils + scene к этому готова.