Open8
Script-based CADをLLMと一緒に色々試す

OpenSCAD
公式ドキュメント
ここで試せる
Claude 3.7-sonnet (think)
下記openscad viewerでのexampleを参考に、ビールジョッキのopenscadを作って。
---
//openSCAD サンプルコード
Output
// Beer Mug Design in OpenSCAD
// Global resolution settings
$fs = $preview ? 1 : 0.1;
$fa = $preview ? 5 : 1;
// Parameters for customization
mug_height = 130; // Height of the mug
mug_diameter = 85; // Outer diameter of the mug
wall_thickness = 4; // Thickness of the mug wall
base_height = 15; // Height of the base
rim_height = 15; // Height of the rim at top
rim_thickness = 4; // How much wider the rim is than the body
handle_thickness = 14; // Thickness of the handle
handle_width = 40; // Width of the handle (distance from mug)
handle_top_pos = 95; // Position of top of handle from bottom
handle_bottom_pos = 35; // Position of bottom of handle from bottom
ridges = 20; // Number of ridges around the mug
ridge_height = 70; // Height of the ridged section
ridge_depth = 1.5; // Depth of the ridges
taper_ratio = 0.92; // Taper ratio for the main body (bottom/top)
add_beer = true; // Add beer and foam to the mug
module mug_body() {
difference() {
union() {
// Base
cylinder(h=base_height, r1=mug_diameter/2 * 1.1, r2=mug_diameter/2 * 1.05, center=false);
// Main body with taper
translate([0, 0, base_height])
cylinder(h=mug_height-base_height-rim_height,
r1=mug_diameter/2,
r2=mug_diameter/2 * taper_ratio, center=false);
// Rim
translate([0, 0, mug_height-rim_height])
cylinder(h=rim_height,
r1=mug_diameter/2 * taper_ratio,
r2=(mug_diameter/2 * taper_ratio) + rim_thickness, center=false);
// Add decorative ridges
translate([0, 0, base_height + 5])
for(i = [0:ridges-1]) {
rotate([0, 0, i * (360/ridges)])
translate([mug_diameter/2 - ridge_depth/2, 0, 0])
scale([1, 0.25, 1])
cylinder(h=ridge_height, r=ridge_depth, center=false);
}
// Decorative band at base
translate([0, 0, base_height - 5])
difference() {
cylinder(h=5, r=mug_diameter/2 * 1.05 + 1, center=false);
translate([0, 0, -1])
cylinder(h=7, r=mug_diameter/2 * 1.05 - 1, center=false);
}
}
// Hollow out the inside - with taper
translate([0, 0, base_height])
cylinder(h=mug_height,
r1=mug_diameter/2 - wall_thickness,
r2=(mug_diameter/2 * taper_ratio) - wall_thickness, center=false);
}
}
module handle() {
// Create a handle with thicker attachments
// Top attachment
hull() {
// Top attachment to mug
translate([0, -mug_diameter/2 + wall_thickness/2, handle_top_pos])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 2, r=handle_thickness/2 * 1.2, center=true);
// Outer top curve
translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_top_pos - handle_thickness/2])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
}
// Middle section
hull() {
// Outer top curve
translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_top_pos - handle_thickness/2])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
// Outer bottom curve
translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_bottom_pos + handle_thickness/2])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
}
// Bottom attachment
hull() {
// Outer bottom curve
translate([0, -mug_diameter/2 - handle_width + handle_thickness/2, handle_bottom_pos + handle_thickness/2])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 1.5, r=handle_thickness/2, center=true);
// Bottom attachment to mug
translate([0, -mug_diameter/2 + wall_thickness/2, handle_bottom_pos])
rotate([0, 90, 0])
cylinder(h=wall_thickness * 2, r=handle_thickness/2 * 1.2, center=true);
}
}
module beer_and_foam() {
beer_height = mug_height - base_height - wall_thickness - 25;
foam_height = 20;
// Beer liquid
color([0.8, 0.4, 0.0, 0.8]) // Amber beer color
translate([0, 0, base_height + wall_thickness])
cylinder(h=beer_height,
r1=mug_diameter/2 - wall_thickness - 1,
r2=(mug_diameter/2 * taper_ratio) - wall_thickness - 1, center=false);
// Beer foam
color([1, 0.98, 0.94, 0.9]) // Off-white foam
translate([0, 0, base_height + wall_thickness + beer_height])
difference() {
cylinder(h=foam_height, r=(mug_diameter/2 * taper_ratio) - wall_thickness - 1, center=false);
// Add foam bubbles/irregularities
for(i = [0:16]) {
rotate([0, 0, i * 22.5])
translate([(mug_diameter/4) * 0.8, 0, foam_height * 0.6])
scale([1, 1, 0.7])
sphere(r=foam_height/3);
}
}
}
// Complete mug with options
module beer_mug() {
// Glass mug
color([0.7, 0.8, 0.9, 0.6]) { // Blue-tinted glass color
mug_body();
handle();
}
if (add_beer) {
beer_and_foam();
}
}
// Create the model
beer_mug();

CadQuery
公式ドキュメント
awesomeなやつ
ここで試せる。が、結構制約あり。
VScode dev container 環境
Claude 3.7-sonnet (think)

build123d
公式ドキュメント
「view page souce」からtxt表示にできるのはLLMフレンドリー
awesomeなやつ
Claude 3.7-sonnet (think)

OpenCascade.js
ここで試せる
Claude 3.7-sonnet (think)
下記cascade studio viewerでのexampleを参考に、ビールジョッキのcascade studioのコードを作って。
---
// cascade studioのexample
---
コンテキスト雑だとあまり得意でないかも
Output
// Beer Mug in Cascade Studio
// Interactive parameters
let mugHeight = Slider("Mug Height", 120, 80, 160);
let mugRadius = Slider("Mug Radius", 40, 30, 60);
let wallThickness = Slider("Wall Thickness", 5, 2, 10);
let handleThickness = Slider("Handle Thickness", 8, 4, 15);
// Create the outer body of the mug
let outerBody = Cylinder(mugRadius, mugHeight, true);
// Create the inner cavity by subtracting a smaller cylinder
let innerBody = Translate([0, 0, wallThickness],
Cylinder(mugRadius - wallThickness, mugHeight, true));
// Create the main body with hollow interior
let mugBody = Difference(outerBody, innerBody);
// Create handle with three cylinders in a C shape
// Distance from mug to handle
let handleDistance = 15;
// Top horizontal part of handle
let handleTop = Translate([0, mugRadius + handleDistance/2, mugHeight * 0.7],
Rotate([1, 0, 0], 90,
Cylinder(handleThickness/2, handleDistance, true)));
// Bottom horizontal part of handle
let handleBottom = Translate([0, mugRadius + handleDistance/2, mugHeight * 0.3],
Rotate([1, 0, 0], 90,
Cylinder(handleThickness/2, handleDistance, true)));
// Vertical part of handle connecting top and bottom
let handleSide = Translate([0, mugRadius + handleDistance, mugHeight * 0.5],
Cylinder(handleThickness/2, mugHeight * 0.4, true));
// Combine all handle parts
let handle = Union([handleTop, handleBottom, handleSide]);
// Combine the mug body and handle
let mug = Union(mugBody, handle);
// Add a beer label
let addLabel = Checkbox("Add Label", true);
if (addLabel) {
let beerText = Text3D("BEER", 20, 0.15, 'Arial');
beerText = Translate([-15, -mugRadius+1, mugHeight/2],
Rotate([0, 0, 1], 180, Rotate([1, 0, 0], 90, beerText)));
mug = Union(mug, beerText);
}
// Optional: Add some froth
let addFroth = Checkbox("Add Froth", true);
if (addFroth) {
let frothHeight = 10;
let froth = Translate([0, 0, mugHeight - frothHeight],
Cylinder(mugRadius - wallThickness, frothHeight, true));
mug = Union(mug, froth);
}
// Display the final mug
mug;

Replicad
ここで試せる
Claude 3.7-sonnet (think)
下記replicad viewerでのexampleを参考に、ビールジョッキのreplicadのコードを作って。
---
// replicadのexample
エラーを貼り付けて3ターンで完成
Output
const { makePlane, makeCylinder, draw, drawCircle } = replicad;
const defaultParams = {};
const main = () => {
// Define dimensions for a simple beer mug
const baseRadius = 30; // Radius at the base
const topRadius = 32; // Radius at the top
const height = 100; // Total height of the mug
const thickness = 3; // Wall thickness
// Building a simple beer mug profile
const profile = draw()
.hLine(baseRadius) // Bottom radius
.line(topRadius - baseRadius, height * 0.8) // Slightly widen as we go up
.vLine(height * 0.2) // Straight wall at the top
.hLine(-thickness) // Top rim thickness
.vLine(-(height * 0.2)) // Inner wall top section
.line(-(topRadius - thickness - baseRadius + thickness), -(height * 0.8)) // Inner wall tapered section
.hLine(-(baseRadius - thickness)) // Bottom inner wall
.close(); // Close the profile
// Revolve the profile around the Z-axis to create the mug body
const mugBody = profile.sketchOnPlane("XZ").revolve([0, 0, 1]);
// Create a simple handle
// Create two circles that we'll loft to make a handle
const topHandlePlane = makePlane().translate([baseRadius, 0, height * 0.75]);
const topHandle = drawCircle(4).sketchOnPlane(topHandlePlane);
const middleHandlePlane = makePlane().translate([baseRadius + 20, 0, height * 0.5]);
const middleHandle = drawCircle(4).sketchOnPlane(middleHandlePlane);
const bottomHandlePlane = makePlane().translate([baseRadius, 0, height * 0.25]);
const bottomHandle = drawCircle(4).sketchOnPlane(bottomHandlePlane);
// Loft the circles to create the handle
const handle = topHandle.loftWith([middleHandle, bottomHandle]);
// Combine the mug body and handle
const beerMug = mugBody.fuse(handle);
return {
shape: beerMug,
name: "Simple Beer Mug",
};
};

OpenJSCAD
ここで試せる
Claude 3.7-sonnet (think)
下記openjscad viewerでのexampleを参考に、ビールジョッキのopenjscadのコードを作って。
---
// OpenJSCADのexample
エラー貼り付けて4ターンで完成
Output
/**
* Basic Beer Mug in OpenJSCAD
* @category Creating Shapes
* @description A very basic beer mug closely following the example structure
* @tags mug, beer
* @licence MIT License
*/
const jscad = require('@jscad/modeling')
const { cylinder } = jscad.primitives
const { subtract, union } = jscad.booleans
const { colorize } = jscad.colors
const { translate } = jscad.transforms
const options = {
mugHeight: 100, // Height of the mug in mm
mugRadius: 40, // Radius of the mug in mm
wallThickness: 4, // Wall thickness in mm
handleThickness: 8, // Thickness of the handle in mm
segments: 32 // Number of segments for circular shapes
}
const main = () => {
return [
colorize([0.95, 0.9, 0.8], beerMug(options))
]
}
// Create the beer mug
const beerMug = (options) => {
// Create outer cylinder
const outer = cylinder({
height: options.mugHeight,
radius: options.mugRadius,
segments: options.segments,
center: [0, 0, options.mugHeight/2]
})
// Create inner cylinder (hollow part)
const inner = cylinder({
height: options.mugHeight - options.wallThickness,
radius: options.mugRadius - options.wallThickness,
segments: options.segments,
center: [0, 0, options.mugHeight/2 + options.wallThickness/2]
})
// Basic mug body
const body = subtract(outer, inner)
// Create handle using cylinder primitives
const handle = createSimpleHandle(options)
return union(body, handle)
}
// Create a simple handle made of cylinders
const createSimpleHandle = (options) => {
const { mugRadius, mugHeight, handleThickness } = options
// Vertical cylinder for the handle
const verticalPart = cylinder({
height: mugHeight * 0.6,
radius: handleThickness / 2,
segments: options.segments,
center: [mugRadius + handleThickness/2, 0, mugHeight * 0.5]
})
// Top horizontal cylinder
const topPart = cylinder({
height: handleThickness,
radius: handleThickness / 2,
segments: options.segments,
center: [mugRadius - handleThickness/2, 0, mugHeight * 0.7]
})
// Bottom horizontal cylinder
const bottomPart = cylinder({
height: handleThickness,
radius: handleThickness / 2,
segments: options.segments,
center: [mugRadius - handleThickness/2, 0, mugHeight * 0.3]
})
// Rotate horizontal cylinders to connect to vertical part
const rotatedTop = translate([handleThickness, 0, 0],
cylinder({
height: handleThickness * 2,
radius: handleThickness / 2,
segments: options.segments,
center: [mugRadius, 0, mugHeight * 0.7]
})
)
const rotatedBottom = translate([handleThickness, 0, 0],
cylinder({
height: handleThickness * 2,
radius: handleThickness / 2,
segments: options.segments,
center: [mugRadius, 0, mugHeight * 0.3]
})
)
// Combine all parts
return union(
verticalPart,
topPart,
bottomPart,
rotatedTop,
rotatedBottom
)
}
module.exports = { main }

各ツールの系統
※o1 Pro & Claude3.7-sonnetに整理してもらったもののマージ
Open CASCADE (OCCT, C++ライブラリ)
│
├─ OpenCascade.js (OCCT をブラウザ向けに WASM 化したもの)
│ ├─ CascadeStudio(Web アプリとして動作する簡易な CAD 環境)
│ └─ replicad(OpenCascade.js を使った JS/TS ライブラリ)
│
├─ CadQuery(Python から OCCT を扱いやすくしたライブラリ)
│ └─ build123d(CadQuery の開発者コミュニティによる別プロジェクト)
│
└─ (他にも pythonOCC / OCP ベースのプロジェクトが存在)
OpenSCAD(OCCT とは独立した独自言語ベースのスクリプトCAD)
└─ OpenJSCAD(JavaScript ベースの同様のアプローチ)

番外
なお,chatGPT advanced data analysisで単体でstl出力も可能。
trimesh × numpyなので簡単な形状のみ