Про начало разработки я писал в предыдущей статье. Напомню — я разрабатываю простенький 3D-редактор для моделирования под 3D-печать. С простым интерфейсом и, самое главное, работой прямо в браузере. Естественно, это будет не полноценная САПР, но для обучения и простенького проектирования функционала должно хватать.
Целился я в нечто среднее между Tinkercad и Fusion360. Одной из задач было обойтись без сервера, т.е. работа на стороне клиента, а также быстрая работа. Поэтому в качестве основы я выбрал популярную библиотеку 3D-графики Three.js.

Изначально проект планировался как простенький 3D-редактор, а-ля Tinkercad, но на стероидах, с чертежами, фасками и другими продвинутыми операциями.
После предыдущей статьи вектор разработки немного сменился. Народ захотел полноценный САПР, прямо в браузере, прям как onshape. Правда onshape (и большинство подобных решений) работает не совсем в браузере, это тонкий клиент, который работает на серверах, а пользователю выводит просто картинку.
У меня на данный момент сервера нет. Для работы моего редактора он практически не нужен. Но об этом чуть позже.
В общем, вектор развития из «сделано на коленке» перешел к «народ начал пользоваться, надо сделать нормально». Поэтому я решил сделать несколько глобальных изменений, чтобы обеспечить моему редактору будущее.
❯ Архитектура редактора
КонтрБагCAD работает целиком на клиенте, со всеми преимуществами и недостатками. В качестве геометрии, в отличии от большинства САПР, используются сетки, а не BREP. Это сделано в угоду легкости и скорости работы (у Tinkercad, кстати, тоже сетки). Благодаря этому STL и прочие сеточные форматы поддерживаются напрямую, и нет никаких проблем их редактировать (в отличии от того же Fusion 360). Ядро работает напрямую на Three.js. Начиная с версии 0.8, для бинарных операций внедрена библиотека manifold, а начиная с 0.9 ядро переписано на параметрическую работу.
Итак, после предыдущей статьи многое произошло...
Для начала, я занялся поиском проблемы дырявых моделей. Я долгое время думал, что дело в экспорте, но оказалось, беда в той самой «крутой» библиотеке THREE_BVH_CSG, которую я в прошлый раз расхваливал. Проблема в том, что при применении бинарной операции она гарантированно строит сломанную модель из несвязанных треугольников, в редакторе этого не видно, но на экспорте проявляется. И алгоритм обводки граней из-за этого правильно не работает.

Проблема решилась использованием уже по-настоящему крутой библиотеки Manifold.

Manifold — это высокопроизводительная библиотека для создания и обработки трёхмерной геометрии, ориентированная на твердотельное моделирование.
Основные особенности:
Ядро на C++ с WebAssembly-сборкой, что обеспечивает скорость работы в браузере и Node.js.
Гарантия манифолдности — все модели всегда замкнуты (watertight) и корректны с топологической точки зрения.
Булевы операции (объединение, пересечение, вычитание) с высокой надёжностью.
Построение геометрии: экструзия, вращение (revolve), создание примитивов.
Работа с mesh — импорт/экспорт, редактирование, упрощение.
На данный момент — это быстрейшая библиотека для бинарных операций над сеточной геометрией. Она значительно быстрее OpenSCAD и большинства аналогичных библиотек. При этом гарантированно строит водонепроницаемую геометрию. У меня она пока используется только для бинарных операций. Благодаря этому скорость бинарных операций значительно выросла и заметно обходит Tinkercad.
Из минусов: библиотека требует манифольдные (водонепроницаемые) меши для работы, а множество stl в сети такими не являются. Для решения этой проблемы я занялся написанием инструмента для ремонта геометрии, но пока он чинит только простые случаи.
❯ Про параметрическую работу
Итак, до версии 0.9 история у меня хранилась слепками сцены. Это было сложнее, чем сейчас (скрипты были здоровыми, и с проблемами), и жрало много памяти. Проект сохранялся по сути полной геометрией сцены. А из-за того, что история хранила слепки сцены, в сохранении она занимала какие-то неадекватные размеры. Я даже добавил опцию «не сохранять историю», дабы файлы сохранений меньше занимали.
Оценив все недостатки этого подхода, я решил всё-таки перейти на параметрическую работу, и для каждой операции использовать отдельный исполнитель, который совершает эту операцию по переданным параметрам. Это потребовало переписывания практически всего проекта, но зато история у меня теперь хранится просто списком операций с параметрами. А для сохранения, по сути, этот список просто экспортируется. Благодаря этому, файлы проекта похудели в десятки раз (на самом деле все немного сложнее, но в целом так как я описал :)
А бонусом появилась куча дополнительных возможностей, вроде изменения параметров уже сделанных операций, вставка и удаление операций, простого объединения проектов или вообще совместной работы нескольких пользователей. Но это все ещё в будущем, а пока только можно просто удалить любую операцию. Ещё можно вставлять операции в любое место истории, но это пока выключено.
Подумаю, как лучше реализовать изменения параметров операций и надо ли оно вообще.
❯ Изменения
Переход на новую архитектуру, естественно, вызвал кучу багов (большинство которых уже были решены в прошлом), и занял полную неделю работы (даже более, на самом деле я их до сих пор фикшу).
Определение регионов вытягивания переехало в скетч, и теперь происходит сразу после добавления элементов чертежей. А заодно появилась подсветка этих регионов, и был доработан алгоритм определения (но над этой задачей я все ещё бьюсь).

В старом инструменте вращения неправильно формировались крышки фигуры и отверстия, это тоже было доработано. Но надо ещё поработать над спаиванием.

В выдавливании появилось визуальное отображение операции: красный — вырезать, желтый — добавить, зелёный — новый объект. Как светофор.

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

А, да, появилась смена языка. Причём локализации являются просто json-файлом и нет никакой проблемы добавить в редактор любой язык (даже русский матерный, или старославянский).

❯ ES6 архитектура
Я не фронтендер — за современное развитие js не шарил. Поэтому начал писать проект на старом стеке с подключением всех файлов глобально. Когда этих файлов стало больше 120, это стало уже неудобно, и развивать проект в таком виде было не рационально. К тому же, все современные библиотеки поддерживают подключение только модулями (кто бы мог подумать).
Короче, я решил переписать проект на ES6 модельную архитектуру, заодно сделать рефакторинг и ещё немного приблизить его к принципам SOLID.
В целом это было не особо сложно, проект уже был модульным (неспроста было 120+ файлов). Оставалось просто дописать все подключения, и переписать пару скриптов. С этим я справился за пару дней.
Пожалуй, больше заморочек вызвало обновление с three150 на three182. Возникло несколько проблем:
Cмена цветового пространства с linearRGB на sRGB в three 152, из за этого все цвета стали темными и блеклыми, пришлось долго играться с настройками.
Многие библиотеки вынесли из основной сборки Three, в отдельные библиотеки, что в целом логично.
И в 3D-тексте они зачем-то переименовали параметр толщины, с heights на depth. Из-за чего перестало работать изменение толщины, а я с этим долго разбирался.
❯ Инструменты
Чертеж теперь можно строить сразу на гранях объектов.

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

Пока над распознаванием регионов я ещё работаю, это не самый простой алгоритм, в котором надо слишком много всего учесть. Кстати, при вытягивании надо наоборот правильно соединить фигуры, и там тоже довольно сложный алгоритм (может про это когда-нибудь напишу отдельную статью).
Еще я заморочился над инструментом бинарных операций. У старого варианта не было предпросмотра, для объединения и пересечения это приемлемо, но с вычитанием не особо понятно, что из чего вычитается.
Теперь получилось прям круто, включить инструмент можно без выделенных объектов, кликом на ЛКМ фигура добавляется в операцию, повторным кликом исключается.

В вычитании ещё задействована ПКМ для добавления вычитаемых фигур.

Прокачал библиотеку, теперь каждая категория грузится только при переходе на нее и из отдельного каталога. В каждом каталоге лежит json со списком моделей, а каталоги и категории прописаны в отдельном «главном» json.

Поддерживается работа с удаленными каталогами, и объединение несколько категорий в одну (собственно, категория «все» так и сделана. Но она временная, пока моделей не много). Заодно подтянул немного дизайн, теперь на экран помещается больше моделей и библиотека немного больше напоминает Tinkercad.
Также, специально по просьбам пользователей Tinkercad, добавил инструмент выравнивания.

И доработал параметрическую операцию создания примитивов. Раньше половина примитивов были обычными stl, теперь для них написаны отдельные параметрические генераторы. Заодно добавил в параметрическую модель метод изменения параметров операции. Правда пока это работает только для примитивов.

На этом все изменения за февраль и начало марта, на самом деле ещё куча всяких мелких изменений, про которые я не написал. В тг-канале сообщения об обновлениях выходят практически каждый день.
Была проделана действительно большая работа, особенно в части основ редактора.
Редактор доступен online, без регистрации и совершенно бесплатно.
Обратите внимание! Редактор находится на стадии активной разработки, постоянно становится лучше и пополняется новыми функциями.
Буду благодарен за обратную связь, сообщения об ошибках и предложения по развитию :)
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩

Комментарии (14)

Arhammon
25.03.2026 22:13Отличная работа, вспоминаю первые дни с принтером, тинкеркадом.
Единственное конечно чем быстрее начнешь переходить на взрослый уровень типа Фьюженов, Солидов тем лучше... И других людей надо туда как-то тащить, потому что миры мешей и тел плохо пересекаются.

ponikrf
25.03.2026 22:13Ваше желание догнать людей и причинить им добро это конечно похвально, но пожалуй так делать не надо.
Тот же blender пока закрывает мои задачи на 100%. Хоть я и понимаю о чем вы говорите, переходить на проприетарные решения в моем случае не вижу никакого смысла.

Arhammon
25.03.2026 22:13Тут скорее корыстно-альтруистический момент - текущая хоббийная база открытых моделей это меши, в итоге человек потратил с мышкой и штангенциркулем пол дня и тебе еще надо час заново перерисовывать по контуру меш в тело.
Проипетарные форматы зло, тот же Фьюжен помоему с Солидом не дружит, но есть же STEP? Собственно и приходилось солидовский файл импортировать в Оншейп, оттуда степ. Но все равно это на порядок лучше, чем перерисовывать.
А с ростом сложности, многокомпонентными устройствами проипетарные CADы увы необходимость...

EnvalidGamer Автор
25.03.2026 22:13Поэтому я просто решил сразу с мешем работать :)
Вся хоббийная база поддерживается нативно, прям из загрузок забрасывай в окно редактора и работай.
Arhammon
25.03.2026 22:13Что-такое из 5 деталей и 10ка макетов в меше разве что на спор делать... А это просто продвинутая печатная коробка для электроники...


EnvalidGamer Автор
25.03.2026 22:13Меш это просто способ хранения и визуализации геометрии. Подходы к проектированию разные бывают.
Как-раз такую коробку в моём редакторе не особо сложно сделать.

aamonster
25.03.2026 22:13Я правильно понимаю, что ведущее бесплатное решение для "взрослого мира" – FreeCAD с его адом зависимостей между частями?

Arhammon
25.03.2026 22:13Бесплатное, в том числе и для ограниченного коммерческого использования - Фьюжен, а вот открытое, свободное... даже не скажу Фрикад я в ужасе закрыл через минут 5...
Если кто подскажет какой есть запасной аэродром буду рад...
Хотя подозреваю опции или "параллельно импортировать" солид или Компас за 1500

Plushevy_Nosok
25.03.2026 22:13Да назовите уже программу по-человечески. Контр, да еще и баг. Слова изначально отталкивающие от использования. Термин "баг" связан с ошибками в коде, это термин программистов. Вы же делаете инженерную программу, зачем нужен "баг"? Название больше похоже на подростковую шутку, чем на какой-то серьёзный софт.
Спросите нейросеть, если совсем туго с фантазией. У вас очень неудачное название программы. Мало того, что название длинное, так ещё и англицизмы написанные кириллицей.
Думаю я далеко не первый, кто говорит о неудачном названии.
Да хоть конкурс устройте, вам тут быстро накидают варианты.
А в целом удачи и терпения в создании программы.
aamonster
Респект и уважуха.
Кстати, свежий OpenSCAD (не релиз 22 года, а современные билды) тоже на manifold, благодаря чему им можно пользоваться на мало-мальски сложной геометрии (render не тормозит, как на старом движке, можно даже использовать voronoi()).
Типовая проблема с бинарными операциями там – что если у двух объектов в difference одинаковая толщина, то стенка то ли есть, то ли нет – приходится добавлять/вычитать что-то типа epsilon (2*epsilon, 3*epsilon) или явно вызывать render, чтобы избежать этого. Вы в своём CAD сталкивались с такой проблемой? Решали?
Про параметрическое представление: а нет случаем интероперабельности с OpenSCAD? Или хотя бы импорта/экспорта какого-то простого текстового формата для возможной конверсии? В эпоху текстового "ИИ", который легко может набросать или поправить OpenSCAD модель (пусть и с ошибками) было бы очень полезно. Классические кады типа FreeCAD огорчают тем, что по сути можешь или обмениваться STL, или интегрировать в модель scad как есть, бесшовный переход недостижим.
EnvalidGamer Автор
Проблема со стенками аналогичная (она и на старой библиотеке была). Пришлось решать небольшим расширением контура при вычитании. (В общем тоже костыли какие-то, особенно в фаске мне это жизнь подпортило).
Интероперабельности с OpenSCAD нет, но файлы сохранений теперь это просто json файлик с набором операций. Можно и в ручную поправить, и ИИ подключить.
aamonster
Т.е. это расширение для вычитаний в итоге сделали на своём уровне, пользователю о нём думать не надо?
Простой json – это прекрасно. Может даже чатгпт освоит его перевод.
EnvalidGamer Автор
Эта проблема в основном возникала в операции extrude. Там я просто добавил микроскопическое расширение контуров через clipper.
Правда, как оказалось, при переходе на отдельные исполнители я эту фичу потерял :D
Хорошо что заметил, вернул в сегодняшнем обновлении.
В снятии фаски конечно все посложнее.