LuaCAD — это движок для написания параметрических 2D и 3D CAD-моделей на языке Lua. Готовые модели экспортируются в форматы 3MF, STL, OBJ, PLY, OFF, AMF или SCAD, либо сразу рендерятся в PNG.

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

LuaCAD встраивает Lua 5.4 в движок на Rust, который либо напрямую вычисляет CSG-операции (через Manifold), либо генерирует код OpenSCAD для внешнего рендеринга.

LuaCAD Studio с превью модели гоночной машины MuSHR — сборки из 43 деталей и 490 802 треугольников, рядом со скриптом на Lua, который её строит

Почему Lua?

  • Синтаксис похож на язык OpenSCAD, но лучше:
    • Мощнее
    • Более последователен
    • Быстрее
    • Легко встраивается
  • Перегрузка операторов для естественного синтаксиса CSG (a + b, a - b, a * b)
  • Уже используется в другом CAD-софте, например в LibreCAD и Autodesk Netfabb

Пример

LuaCAD:

my_cube = cube { size = { 1, 2, 3 } }

function my_sphere(radius)
  return sphere({ r = radius }):translate(5, 0, 0)
end

model = my_cube + my_sphere(2)

render(model)

Эквивалент на OpenSCAD:

module my_cube() {
  cube(size=[1,2,3]);
}

module my_sphere(radius) {
  translate([5,0,0]) sphere(r = radius);
}

union() {
  my_cube();
  my_sphere(2);
}

Начало работы

cargo install luacad         # CLI for running and converting LuaCAD scripts
cargo install luacad-studio  # GUI desktop app with live 3D preview

Либо сборка из исходников, для которой понадобится Rust:

git clone https://github.com/ad-si/LuaCAD.git
cd LuaCAD
make install

Оба крейта включают свои C/C++ зависимости, поэтому системные библиотеки устанавливать не нужно — но для их сборки требуются компилятор C++ и CMake. luacad собирает Manifold и Clipper2; luacad-studio дополнительно собирает OpenCSG, для которого нужны заголовки разработки OpenGL (на Debian/Ubuntu: libgl1-mesa-dev, libx11-dev, libxcb1-dev, libxkbcommon-dev, libxrandr-dev, libwayland-dev).

Использование CLI

luacad convert model.lua output.3mf   # Convert to 3MF
luacad convert model.lua output.stl   # Convert to STL
luacad convert model.lua output.scad  # Export as OpenSCAD
luacad watch model.lua output.3mf     # Rebuild on file changes
luacad render model.lua preview.png   # Render to a PNG image
luacad info model.lua                 # Print triangle counts and bounding box
luacad lint model.lua                 # Lint with selene (also takes directories)
luacad run model.lua                  # Execute (side-effects only)

convert и watch определяют формат по расширению выходного файла; флаг --format <fmt> позволяет задать его вручную, а --via-openscad передаёт экспорт установленному бинарнику OpenSCAD вместо построения меша через Manifold.

BOSL2

LuaCAD полностью поддерживает библиотеку Belfry OpenSCAD Library v2, переработанную и реализованную заново внутри самого LuaCAD, — так что рендеринг, превью и экспорт в меш работают без установленных OpenSCAD или BOSL2:

bosl.cuboid { {40, 40, 40}, rounding = 2 }
bosl.regular_prism { 5, r = 10, h = 25 }
bosl.spur_gear { circ_pitch = 5, teeth = 20, thickness = 5 }

При экспорте в .scad в файл записывается сам вызов BOSL2, благодаря чему экспортированный файл остаётся таким же коротким, как и исходный скрипт.

Текст и импорт

text() преобразует системный шрифт в контур на эскизе, а text3d() сразу выдавливает его в объём, — так текст становится настоящей геометрией, а не просто выводом в формате SCAD:

render(text("LuaCAD", { size = 12, halign = "center" }):linear_extrude(2))

import() читает любой из форматов мешей, которые умеет записывать LuaCAD, и возвращает твёрдое тело, которое можно трансформировать и комбинировать как любой примитив; SVG и DXF вместо этого возвращают 2D-эскиз, готовый к выдавливанию.

Поддерживаемые форматы экспорта

  • SCAD — формат OpenSCAD
  • 3MF — 3D Manufacturing Format
  • STL — Standard Triangle Language для 3D-печати
  • OBJ — формат Wavefront 3D object
  • PLY — Polygon File Format
  • OFF — Object File Format
  • AMF — Additive Manufacturing File Format

Каждое значение, возвращаемое скриптом, становится отдельным объектом 3MF, поэтому слайсеры загружают их как отдельно перемещаемые детали. Пометить их можно с помощью :name(…), чтобы управлять тем, как они отображаются в списке объектов. Остальные форматы не умеют выражать отдельные объекты, поэтому сводят всё в единый меш.