vibe-openscad

tier-2-offset-handle-mug / gpt-5-nano-2025-08-07

7 run / 累計 936.1s / 累計 $0.0375

openai gpt 5 nano 2025-08-07 bare

bare (provider default effort)

run detail →
render
no render
render_error 209.1s · 273/26029t · $0.0104
openscad stl render failed (exit 1): ERROR: Parser error: syntax error in file ../../../../../tmp/render-22F3kd/input.scad, line 6
Can't parse file '/tmp/render-22F3kd/input.scad'!

SCAD (62 lines)
$fn = 100;

// Main cup (outer cylinder with inner hollow bottom 6 mm)
module mug_body() {
    outer = cylinder(h = 90, r = 40, $fn = $fn);
    inner = translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
    difference() {
        outer;
        inner;
    }
}

// D-shaped handle cross-section (2D, to be extruded then rotated into place)
module handle_cross_section() {
    Th = 12;       // thickness into +X direction (before rotation)
    Hh = 60;       // height of cross-section (maps to mug height after rotation)
    hole_w = 25;   // inner space width
    hole_h = 30;   // inner space height
    hole_x = 0;    // inner hole touches left boundary
    hole_y = (Hh - hole_h)/2; // center vertically within cross-section

    r = Hh/2; // radius for the semicircular outer part

    pts = [];
    // left-bottom to left-top and then to right-bottom
    pts = concat(pts, [[0, 0]]);
    pts = concat(pts, [[Th, 0]]);
    // semicircular arc on the right side (center at (Th, Hh/2), from -90° to +90°)
    for (a = [-90:5:90]) {
        ang = a * PI / 180;
        pts = concat(pts, [ [ Th + r * cos(ang), Hh/2 + r * sin(ang) ] ]);
    }
    // top-left corner to close the shape
    pts = concat(pts, [[0, Hh]]);

    difference() {
        polygon(points = pts);
        translate([hole_x, hole_y]) square([hole_w, hole_h], center = false);
    }
}

// 3D handle: extrude the 2D cross-section and rotate to align height with mug
module handle3d() {
    // After rotating -90° around X, the cross-section's height (Y) maps to Z (height)
    rotate([-90, 0, 0]) {
        linear_extrude(height = 18) {
            handle_cross_section();
        }
    }
}

// Assemble mug with handle on the +X side.
// The handle is positioned to slightly overlap the mug wall to ensure union (no gaps).
union() {
    mug_body();

    // Position the handle:
    // - Place so its left face is near the mug's outer surface at x ≈ 40 (we use 39 for slight overlap)
    // - Center the handle vertically around z = 45 mm (mug height is 90 mm)
    //   After rotation, vertical alignment maps accordingly; we translate in Z to center at 45.
    translate([39, 0, 15]) handle3d();
}

prompt

OpenSCAD で、向きが指定されたマグカップを作ってください。

本体:
- 外径 80mm、内径 70mm(肉厚 5mm)、高さ 90mm の円筒形マグ
- 底面の厚みは 6mm
- 内側は飲み物を入れられるよう中空

取手(handle):
- マグの **+X 軸方向の側面のみ** に付ける(他の方向には付けない)
- 取手は D 字形状(外側が半円、本体側が直線)で、本体外周にしっかり接続する
- 取手の内側の空間は高さ 30mm × 幅 25mm(指 3 本ぐらい入る)
- 取手はマグの高さ方向の中央付近に付ける
- 本体と取手は確実に union され、マニフォールド(隙間や宙吊りなし)を保つ

完成したコード全体を ```openscad ... ``` のフェンスで囲んで出力してください。コードのみで、追加の説明は不要です。

variant: effort

low render_error render
render_error
26.8s · 273/3389t · $0.0014
openscad stl render failed (exit 1): ERROR: Parser error: syntax error in file ../../../../../tmp/render-GohV8G/input.scad, line 30
Can't parse file '/tmp/render-GohV8G/input.scad'!

SCAD (137 lines)
// OpenSCAD: 向き指定のマグカップ with D字形取手 (+X 側面のみ)

// ===== 設定 =====
outer_r = 40;            // 外径 / 半径
inner_r = 35;            // 内径 / 半径
height_total = 90;       // 高さ
bottom_thickness = 6;      // 底厚
wall_thickness = outer_r - inner_r; // 5 mm

// 取手のパラメータ
handle_thickness = 12;     // 取手の奥行き(+X方向の厚さ感)
handle_height = 60;        // 取手の高さ(全体の目安)
handle_slot_h = 30;        // 取手内側空間の高さ(y方向)
handle_slot_w = 25;        // 取手内側空間の幅(x方向の内側空間をY,Zで表現する想定)

// 取手の取り付け位置
attach_x = outer_r + 1.5;    // 本体側から取手の付け根までのX位置
attach_y = 0;                   // 垂直中心に取り付け
attach_z = 0;

// ===== マグ本体(中空マグ) =====
module mug_body() {
    // 外側円筒
    outer = cylinder(h = height_total, r = outer_r, $fn=200);

    // 内部空間(中空化)
    // 内部空洞は高さ height_total - bottom_thickness、底は6mm
    inner_h = height_total - bottom_thickness;
    translate([0,0,bottom_thickness])
        inner = cylinder(h = inner_h, r = inner_r, $fn=200);

    difference() {
        outer;
        translate([0,0,bottom_thickness])
            inner;
    }
}

// ===== 取手(D字形) =====
module handle() {
    // 2D D形断面を作成し、X方向に押し出して3D化
    // ここでは、左端を本体の外周面に接する「平な直線端」を作成し、
    // 右端を半円状にしてD字の形状とする。
    // 2D_PROFILE: 左辺が直線、右辺が半円(外側が半円、内側は直線的)
    // Y軸方向に高さ handle_height、Z方向に後退する形で厚みを付与
    module d_profile() {
        points = [
            [0, -handle_height/2],           // 左下
            [0,  handle_height/2],           // 左上
            [handle_slot_w, handle_height/2], // 右上(平面部)
            [handle_slot_w, handle_height/2 - (handle_height/2 - 5)], // 微調整
            // ここから半円状の外縁(右側を丸く)
            // 追加の点は円弧として後で補完
        ];
        // 代替的に、左直線・右半円の形状をパスで実装
        // 2D path を円弧で近似
        // 実質的には以下の単純な形でD字風にします
        polygon(points = [
            [0, -handle_height/2],
            [0,  handle_height/2],
            [handle_slot_w,  handle_height/2],
            [handle_slot_w, -handle_height/2],
            // 半円の円弧を近似するための補助点を追加
            // (右端で丸くつなぐ)
        ], paths = [
            [0,1,2,3,0]
        ]);
    }

    // より実用的な D 字形の実装(2D profileを用意して押し出し)
    module d_shape() {
        // 左端を垂直に直線、右端を半円にするためのパスを構成
        // 左直線の幅を handle_slot_w とし、右端を半径 handle_height/2 の半円で連結
        // ここでは見た目を整えるため、シンプルなD字断面を用意
        difference() {
            // 外形(D字の外側)
            union() {
                translate([0, -handle_height/2])
                    rounded_rectangle(h = handle_height, w = handle_slot_w, r = handle_height/2);
                // 右半円の外側を作るための閉じ領域
            }
            // 内側空間(指3本分の空間)
            translate([10, -handle_slot_h/2])
                square([handle_slot_w - 20, handle_slot_h], center = true);
        }
    }

    // 代用として、実装を簡略化した厚みのあるD字風の取手を作成
    // 外形を丸みを帯びた長方形+半円の組み合わせ
    difference() {
        // 外形
        translate([0, -handle_height/2, -handle_thickness/2])
            rotate([90,0,0])
                linear_extrude(height = handle_thickness)
                    // D字風の断面(長方形+半円の組み合わせ)
                    // 簡易実装: 左を直線、右を半円で結ぶ形に近い
                    union() {
                        // 直線部
                        translate([0, -handle_height/2])
                            square([handle_slot_w, handle_height], center = false);
                        // 右側の半円
                        translate([handle_slot_w, 0])
                            circle(r = handle_height/2, $fn=100);
                    }

        // 内部空間をくり抜く(指が入る空間)
        translate([6, -handle_slot_h/2, -handle_thickness/2])
            rotate([90,0,0])
                linear_extrude(height = handle_thickness)
                    // 内部空間は幅 handle_slot_w-12、高さ handle_slot_h
                    square([handle_slot_w - 12, handle_slot_h], center = true);
    }
}

// シンプルな丸み付き長方形を作るサポート
module rounded_rectangle(h, w, r) {
    // h: 高さ, w: 幅, r: 角の半径
    // 2Dの丸み付き長方形を近似
    minkowski() {
        square([w, h], center = true);
        circle(r = r);
    }
}

// ===== 組み立て =====
union() {
    // 本体
    mug_body();

    // 取手を +X 側面の外側に配置
    // mug の外周表面に沿って取り付け
    translate([attach_x, attach_y, 0])
        // 取手は3D形状として作成
        // ここでは薄肉のD字風に近い形状を押し出し
        // 実体として結合させる
        handle();
}
medium (default) render_error render
render_error
209.1s · 273/26029t · $0.0104
openscad stl render failed (exit 1): ERROR: Parser error: syntax error in file ../../../../../tmp/render-22F3kd/input.scad, line 6
Can't parse file '/tmp/render-22F3kd/input.scad'!

SCAD (62 lines)
$fn = 100;

// Main cup (outer cylinder with inner hollow bottom 6 mm)
module mug_body() {
    outer = cylinder(h = 90, r = 40, $fn = $fn);
    inner = translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
    difference() {
        outer;
        inner;
    }
}

// D-shaped handle cross-section (2D, to be extruded then rotated into place)
module handle_cross_section() {
    Th = 12;       // thickness into +X direction (before rotation)
    Hh = 60;       // height of cross-section (maps to mug height after rotation)
    hole_w = 25;   // inner space width
    hole_h = 30;   // inner space height
    hole_x = 0;    // inner hole touches left boundary
    hole_y = (Hh - hole_h)/2; // center vertically within cross-section

    r = Hh/2; // radius for the semicircular outer part

    pts = [];
    // left-bottom to left-top and then to right-bottom
    pts = concat(pts, [[0, 0]]);
    pts = concat(pts, [[Th, 0]]);
    // semicircular arc on the right side (center at (Th, Hh/2), from -90° to +90°)
    for (a = [-90:5:90]) {
        ang = a * PI / 180;
        pts = concat(pts, [ [ Th + r * cos(ang), Hh/2 + r * sin(ang) ] ]);
    }
    // top-left corner to close the shape
    pts = concat(pts, [[0, Hh]]);

    difference() {
        polygon(points = pts);
        translate([hole_x, hole_y]) square([hole_w, hole_h], center = false);
    }
}

// 3D handle: extrude the 2D cross-section and rotate to align height with mug
module handle3d() {
    // After rotating -90° around X, the cross-section's height (Y) maps to Z (height)
    rotate([-90, 0, 0]) {
        linear_extrude(height = 18) {
            handle_cross_section();
        }
    }
}

// Assemble mug with handle on the +X side.
// The handle is positioned to slightly overlap the mug wall to ensure union (no gaps).
union() {
    mug_body();

    // Position the handle:
    // - Place so its left face is near the mug's outer surface at x ≈ 40 (we use 39 for slight overlap)
    // - Center the handle vertically around z = 45 mm (mug height is 90 mm)
    //   After rotation, vertical alignment maps accordingly; we translate in Z to center at 45.
    translate([39, 0, 15]) handle3d();
}
high no_code nocode
no_code
218.2s
model returned empty response (stopReason=in_progress)
SCAD (1 lines)

no SCAD

maxnot run
xhighnot run

iteration: iter-png

i1 render_error render
render_error
110.5s · 1010/17005t · $0.0069
openscad stl render failed (exit 1): ERROR: Parser error: syntax error in file ../../../../../tmp/render-DdIUix/input.scad, line 6
Can't parse file '/tmp/render-DdIUix/input.scad'!

diff vs bare: +15/-23
  $fn = 100;
  
- // Main cup (outer cylinder with inner hollow bottom 6 mm)
+ // Main mug body: outer cylinder with hollow inner bottom (6 mm)
  module mug_body() {
      outer = cylinder(h = 90, r = 40, $fn = $fn);
      inner = translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
      difference() {
          outer;
          inner;
      }
  }
  
- // D-shaped handle cross-section (2D, to be extruded then rotated into place)
+ // 2D cross-section for the D-shaped handle (in YZ plane), to be extruded along X
  module handle_cross_section() {
-     Th = 12;       // thickness into +X direction (before rotation)
-     Hh = 60;       // height of cross-section (maps to mug height after rotation)
-     hole_w = 25;   // inner space width
-     hole_h = 30;   // inner space height
-     hole_x = 0;    // inner hole touches left boundary
-     hole_y = (Hh - hole_h)/2; // center vertically within cross-section
+     Th = 30;       // thickness into +X direction (cross-section width)
+     Hh = 70;       // overall cross-section height
+     hole_w = 25;   // inner hollow width
+     hole_h = 30;   // inner hollow height
+     hole_x = Th - hole_w; // inner hole left edge (keeps hole inside from the left boundary)
+     hole_y = (Hh - hole_h) / 2;
  
-     r = Hh/2; // radius for the semicircular outer part
- 
+     // Build D-shape: left straight boundary (x = 0), right semi-circular boundary
      pts = [];
-     // left-bottom to left-top and then to right-bottom
      pts = concat(pts, [[0, 0]]);
      pts = concat(pts, [[Th, 0]]);
-     // semicircular arc on the right side (center at (Th, Hh/2), from -90° to +90°)
      for (a = [-90:5:90]) {
          ang = a * PI / 180;
-         pts = concat(pts, [ [ Th + r * cos(ang), Hh/2 + r * sin(ang) ] ]);
+         pts = concat(pts, [ [ Th + Th * cos(ang), Hh/2 + Th * sin(ang) ] ]);
      }
-     // top-left corner to close the shape
      pts = concat(pts, [[0, Hh]]);
  
      difference() {
          polygon(points = pts);
          translate([hole_x, hole_y]) square([hole_w, hole_h], center = false);
      }
  }
  
- // 3D handle: extrude the 2D cross-section and rotate to align height with mug
+ // 3D handle by extruding the 2D cross-section along the X axis
  module handle3d() {
-     // After rotating -90° around X, the cross-section's height (Y) maps to Z (height)
      rotate([-90, 0, 0]) {
          linear_extrude(height = 18) {
              handle_cross_section();
          }
      }
  }
  
- // Assemble mug with handle on the +X side.
- // The handle is positioned to slightly overlap the mug wall to ensure union (no gaps).
+ // Assemble mug with handle on the +X side
  union() {
      mug_body();
  
-     // Position the handle:
-     // - Place so its left face is near the mug's outer surface at x ≈ 40 (we use 39 for slight overlap)
-     // - Center the handle vertically around z = 45 mm (mug height is 90 mm)
-     //   After rotation, vertical alignment maps accordingly; we translate in Z to center at 45.
-     translate([39, 0, 15]) handle3d();
+     // Position the handle near the outer surface on the +X side
+     // Z offset centers the handle around the mug height
+     translate([40, 0, 10]) handle3d();
  }
SCAD (54 lines)
$fn = 100;

// Main mug body: outer cylinder with hollow inner bottom (6 mm)
module mug_body() {
    outer = cylinder(h = 90, r = 40, $fn = $fn);
    inner = translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
    difference() {
        outer;
        inner;
    }
}

// 2D cross-section for the D-shaped handle (in YZ plane), to be extruded along X
module handle_cross_section() {
    Th = 30;       // thickness into +X direction (cross-section width)
    Hh = 70;       // overall cross-section height
    hole_w = 25;   // inner hollow width
    hole_h = 30;   // inner hollow height
    hole_x = Th - hole_w; // inner hole left edge (keeps hole inside from the left boundary)
    hole_y = (Hh - hole_h) / 2;

    // Build D-shape: left straight boundary (x = 0), right semi-circular boundary
    pts = [];
    pts = concat(pts, [[0, 0]]);
    pts = concat(pts, [[Th, 0]]);
    for (a = [-90:5:90]) {
        ang = a * PI / 180;
        pts = concat(pts, [ [ Th + Th * cos(ang), Hh/2 + Th * sin(ang) ] ]);
    }
    pts = concat(pts, [[0, Hh]]);

    difference() {
        polygon(points = pts);
        translate([hole_x, hole_y]) square([hole_w, hole_h], center = false);
    }
}

// 3D handle by extruding the 2D cross-section along the X axis
module handle3d() {
    rotate([-90, 0, 0]) {
        linear_extrude(height = 18) {
            handle_cross_section();
        }
    }
}

// Assemble mug with handle on the +X side
union() {
    mug_body();

    // Position the handle near the outer surface on the +X side
    // Z offset centers the handle around the mug height
    translate([40, 0, 10]) handle3d();
}
i2 render_error render
render_error
99.0s · 869/12516t · $0.0050
openscad stl render failed (exit 1): ERROR: Parser error: syntax error in file ../../../../../tmp/render-yabiDC/input.scad, line 20
Can't parse file '/tmp/render-yabiDC/input.scad'!

diff vs i1: +22/-25
  $fn = 100;
  
- // Main mug body: outer cylinder with hollow inner bottom (6 mm)
+ // Mug body: outer cylinder and hollow inner with bottom thickness 6
  module mug_body() {
-     outer = cylinder(h = 90, r = 40, $fn = $fn);
-     inner = translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
      difference() {
-         outer;
-         inner;
+         cylinder(h = 90, r = 40, $fn = $fn);
+         translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
      }
  }
  
- // 2D cross-section for the D-shaped handle (in YZ plane), to be extruded along X
+ // Handle cross-section (D-shape) in XY plane with inner hollow
  module handle_cross_section() {
-     Th = 30;       // thickness into +X direction (cross-section width)
-     Hh = 70;       // overall cross-section height
-     hole_w = 25;   // inner hollow width
-     hole_h = 30;   // inner hollow height
-     hole_x = Th - hole_w; // inner hole left edge (keeps hole inside from the left boundary)
+     Th = 30;        // thickness into +X direction
+     Hh = 70;        // total height
+     hole_w = 25;    // inner hollow width
+     hole_h = 30;    // inner hollow height
+     hole_x = Th - hole_w;
      hole_y = (Hh - hole_h) / 2;
  
-     // Build D-shape: left straight boundary (x = 0), right semi-circular boundary
-     pts = [];
-     pts = concat(pts, [[0, 0]]);
-     pts = concat(pts, [[Th, 0]]);
-     for (a = [-90:5:90]) {
-         ang = a * PI / 180;
-         pts = concat(pts, [ [ Th + Th * cos(ang), Hh/2 + Th * sin(ang) ] ]);
-     }
-     pts = concat(pts, [[0, Hh]]);
+     outer = union() {
+         // D-shape: left straight edge, right semicircular edge
+         square([Th, Hh], center = false);
+         translate([Th, Hh/2]) circle(r = Th, $fn = $fn);
+     };
  
+     inner_hole = translate([hole_x, hole_y])
+         square([hole_w, hole_h], center = false);
+ 
      difference() {
-         polygon(points = pts);
-         translate([hole_x, hole_y]) square([hole_w, hole_h], center = false);
+         outer;
+         inner_hole;
      }
  }
  
- // 3D handle by extruding the 2D cross-section along the X axis
+ // Extrude the 2D handle cross-section along the X axis
  module handle3d() {
-     rotate([-90, 0, 0]) {
+     // Move the cross-section into the YZ plane, then extrude along X by rotating
+     rotate([0, -90, 0]) {
          linear_extrude(height = 18) {
              handle_cross_section();
          }
      }
  }
  
  // Assemble mug with handle on the +X side
  union() {
      mug_body();
  
      // Position the handle near the outer surface on the +X side
-     // Z offset centers the handle around the mug height
      translate([40, 0, 10]) handle3d();
  }
SCAD (51 lines)
$fn = 100;

// Mug body: outer cylinder and hollow inner with bottom thickness 6
module mug_body() {
    difference() {
        cylinder(h = 90, r = 40, $fn = $fn);
        translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
    }
}

// Handle cross-section (D-shape) in XY plane with inner hollow
module handle_cross_section() {
    Th = 30;        // thickness into +X direction
    Hh = 70;        // total height
    hole_w = 25;    // inner hollow width
    hole_h = 30;    // inner hollow height
    hole_x = Th - hole_w;
    hole_y = (Hh - hole_h) / 2;

    outer = union() {
        // D-shape: left straight edge, right semicircular edge
        square([Th, Hh], center = false);
        translate([Th, Hh/2]) circle(r = Th, $fn = $fn);
    };

    inner_hole = translate([hole_x, hole_y])
        square([hole_w, hole_h], center = false);

    difference() {
        outer;
        inner_hole;
    }
}

// Extrude the 2D handle cross-section along the X axis
module handle3d() {
    // Move the cross-section into the YZ plane, then extrude along X by rotating
    rotate([0, -90, 0]) {
        linear_extrude(height = 18) {
            handle_cross_section();
        }
    }
}

// Assemble mug with handle on the +X side
union() {
    mug_body();

    // Position the handle near the outer surface on the +X side
    translate([40, 0, 10]) handle3d();
}
i3 success
iter 3
63.6s · 774/8389t · $0.0034
diff vs i2: +9/-13
  $fn = 100;
  
  // Mug body: outer cylinder and hollow inner with bottom thickness 6
  module mug_body() {
      difference() {
          cylinder(h = 90, r = 40, $fn = $fn);
          translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
      }
  }
  
  // Handle cross-section (D-shape) in XY plane with inner hollow
  module handle_cross_section() {
      Th = 30;        // thickness into +X direction
      Hh = 70;        // total height
      hole_w = 25;    // inner hollow width
      hole_h = 30;    // inner hollow height
      hole_x = Th - hole_w;
      hole_y = (Hh - hole_h) / 2;
  
-     outer = union() {
-         // D-shape: left straight edge, right semicircular edge
-         square([Th, Hh], center = false);
-         translate([Th, Hh/2]) circle(r = Th, $fn = $fn);
-     };
- 
-     inner_hole = translate([hole_x, hole_y])
-         square([hole_w, hole_h], center = false);
- 
      difference() {
-         outer;
-         inner_hole;
+         union() {
+             // D-shape: left straight edge, right semicircular edge
+             square([Th, Hh], center = false);
+             translate([Th, Hh/2]) circle(r = Th, $fn = $fn);
+         }
+         translate([hole_x, hole_y])
+             square([hole_w, hole_h], center = false);
      }
  }
  
  // Extrude the 2D handle cross-section along the X axis
  module handle3d() {
      // Move the cross-section into the YZ plane, then extrude along X by rotating
      rotate([0, -90, 0]) {
          linear_extrude(height = 18) {
              handle_cross_section();
          }
      }
  }
  
  // Assemble mug with handle on the +X side
  union() {
      mug_body();
  
-     // Position the handle near the outer surface on the +X side
-     translate([40, 0, 10]) handle3d();
+     // Position the handle near the outer surface on the +X side, at mid-height
+     translate([40, 0, 45]) handle3d();
  }
SCAD (47 lines)
$fn = 100;

// Mug body: outer cylinder and hollow inner with bottom thickness 6
module mug_body() {
    difference() {
        cylinder(h = 90, r = 40, $fn = $fn);
        translate([0, 0, 6]) cylinder(h = 84, r = 35, $fn = $fn);
    }
}

// Handle cross-section (D-shape) in XY plane with inner hollow
module handle_cross_section() {
    Th = 30;        // thickness into +X direction
    Hh = 70;        // total height
    hole_w = 25;    // inner hollow width
    hole_h = 30;    // inner hollow height
    hole_x = Th - hole_w;
    hole_y = (Hh - hole_h) / 2;

    difference() {
        union() {
            // D-shape: left straight edge, right semicircular edge
            square([Th, Hh], center = false);
            translate([Th, Hh/2]) circle(r = Th, $fn = $fn);
        }
        translate([hole_x, hole_y])
            square([hole_w, hole_h], center = false);
    }
}

// Extrude the 2D handle cross-section along the X axis
module handle3d() {
    // Move the cross-section into the YZ plane, then extrude along X by rotating
    rotate([0, -90, 0]) {
        linear_extrude(height = 18) {
            handle_cross_section();
        }
    }
}

// Assemble mug with handle on the +X side
union() {
    mug_body();

    // Position the handle near the outer surface on the +X side, at mid-height
    translate([40, 0, 45]) handle3d();
}