vibe-openscad

tier-2-offset-handle-mug / claude-fable-5

9 run / 累計 438.0s / 累計 $1.73

claude fable 5 bare

bare (provider default effort)

run detail →
render
bare render of tier-2-offset-handle-mug
loading STL…
success 64.7s · 343/4779t · $0.2424
SCAD (62 lines)
// 取手付きマグカップ(取手は +X 方向のみ)
$fn = 120;

// ===== パラメータ =====
outer_r   = 40;    // 外半径(外径 80mm)
inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
mug_h     = 90;    // 高さ
bottom_t  = 6;     // 底面の厚み

handle_t  = 8;     // 取手の棒の太さ
handle_d  = 12;    // 取手の奥行き(Y方向の幅)
open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
open_h    = 30;    // 取手内側空間の高さ(Z方向)
open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)

// ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
module handle_opening_2d() {
    hull() {
        // 本体側の直線部分
        translate([open_x0, -open_h/2])
            square([0.01, open_h]);
        // 外側の半円部分
        translate([open_x0 + open_w - open_h/2, 0])
            circle(r = open_h/2);
    }
}

// ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
module handle_2d() {
    difference() {
        offset(r = handle_t) handle_opening_2d();
        handle_opening_2d();
    }
}

// ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
// 内側の縁は本体外壁より内側まで食い込ませており、
// 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
module handle() {
    translate([0, 0, handle_z])
        rotate([90, 0, 0])
            linear_extrude(height = handle_d, center = true)
                handle_2d();
}

// ===== マグ全体 =====
module mug() {
    difference() {
        // 本体外形と取手を先に union → マニフォールドを保証
        union() {
            cylinder(r = outer_r, h = mug_h);
            handle();
        }
        // 飲み物用の中空(底厚 6mm を残す)
        // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
        translate([0, 0, bottom_t])
            cylinder(r = inner_r, h = mug_h);
    }
}

mug();
パラメータ (9)
スライダを動かすと openscad-wasm で再レンダリング

prompt

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

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

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

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

variant: effort

low success
low
22.3s · 343/1502t · $0.0785
SCAD (55 lines)
$fn = 120;

// パラメータ
outer_d  = 80;
inner_d  = 70;
height   = 90;
bottom_t = 6;

handle_h = 30;   // 取手内側の高さ
handle_w = 25;   // 取手内側の幅
handle_t = 8;    // 取手の太さ
embed    = 5;    // 本体への食い込み量

// マグ本体
module body() {
    difference() {
        cylinder(d = outer_d, h = height);
        translate([0, 0, bottom_t])
            cylinder(d = inner_d, h = height);
    }
}

// D字形 2D 断面(x=0 が本体外壁位置、+x が外側)
module handle_2d() {
    difference() {
        // 外形 D
        hull() {
            translate([-embed, -(handle_h/2 + handle_t)])
                square([0.1, handle_h + 2*handle_t]);
            translate([handle_w - handle_h/2, 0])
                circle(r = handle_h/2 + handle_t);
        }
        // 内側の空間(壁側まで貫通)
        hull() {
            translate([-embed - 1, -handle_h/2])
                square([0.1, handle_h]);
            translate([handle_w - handle_h/2, 0])
                circle(r = handle_h/2);
        }
    }
}

// 取手(+X 側、高さ中央)
module handle() {
    translate([outer_d/2, 0, height/2])
        rotate([90, 0, 0])
            linear_extrude(height = handle_t, center = true)
                handle_2d();
}

// 組み立て
union() {
    body();
    handle();
}
mediumnot run
high (default) success
high
64.7s · 343/4779t · $0.2424
SCAD (62 lines)
// 取手付きマグカップ(取手は +X 方向のみ)
$fn = 120;

// ===== パラメータ =====
outer_r   = 40;    // 外半径(外径 80mm)
inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
mug_h     = 90;    // 高さ
bottom_t  = 6;     // 底面の厚み

handle_t  = 8;     // 取手の棒の太さ
handle_d  = 12;    // 取手の奥行き(Y方向の幅)
open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
open_h    = 30;    // 取手内側空間の高さ(Z方向)
open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)

// ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
module handle_opening_2d() {
    hull() {
        // 本体側の直線部分
        translate([open_x0, -open_h/2])
            square([0.01, open_h]);
        // 外側の半円部分
        translate([open_x0 + open_w - open_h/2, 0])
            circle(r = open_h/2);
    }
}

// ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
module handle_2d() {
    difference() {
        offset(r = handle_t) handle_opening_2d();
        handle_opening_2d();
    }
}

// ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
// 内側の縁は本体外壁より内側まで食い込ませており、
// 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
module handle() {
    translate([0, 0, handle_z])
        rotate([90, 0, 0])
            linear_extrude(height = handle_d, center = true)
                handle_2d();
}

// ===== マグ全体 =====
module mug() {
    difference() {
        // 本体外形と取手を先に union → マニフォールドを保証
        union() {
            cylinder(r = outer_r, h = mug_h);
            handle();
        }
        // 飲み物用の中空(底厚 6mm を残す)
        // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
        translate([0, 0, bottom_t])
            cylinder(r = inner_r, h = mug_h);
    }
}

mug();
max success
max
90.3s · 343/7626t · $0.3847
SCAD (66 lines)
// ============================================
// マグカップ(取手は +X 軸方向の側面のみ)
// ============================================
$fn = 120;

/* ---- 本体パラメータ ---- */
mug_height   = 90;    // 全高
outer_dia    = 80;    // 外径
inner_dia    = 70;    // 内径(肉厚 5mm)
bottom_thick = 6;     // 底面の厚み

/* ---- 取手パラメータ ---- */
grip_w       = 25;    // 取手内側空間の幅(X方向)
grip_h       = 30;    // 取手内側空間の高さ(Z方向)
bar_thick    = 8;     // 取手の棒の太さ(断面)
handle_depth = 12;    // 取手の奥行き(Y方向)
embed        = 4;     // 本体壁への埋め込み量(肉厚5mm未満 → 内側へ貫通しない)

body_r   = outer_dia / 2;
handle_z = mug_height / 2;   // 高さ方向の中央に配置

/* ---- 本体:底付き中空円筒 ---- */
module mug_body() {
    difference() {
        cylinder(h = mug_height, d = outer_dia);
        // 内側をくり抜く(底 6mm を残し、上面は開口)
        translate([0, 0, bottom_thick])
            cylinder(h = mug_height - bottom_thick + 1, d = inner_dia);
    }
}

/* ---- D字形 取手断面(2D: x = 本体から外向き, y = 上下方向) ---- */
module handle_profile_2d() {
    r_in  = grip_h / 2;              // 内側半円の半径 (15)
    r_out = grip_h / 2 + bar_thick;  // 外側半円の半径 (23)
    difference() {
        // 外形:本体側(x負方向)は直線、外側(+x)は半円 → D字
        union() {
            translate([-embed, -r_out])
                square([embed + grip_w - r_in, 2 * r_out]);
            translate([grip_w - r_in, 0])
                circle(r = r_out);
        }
        // 内側の開口:高さ 30mm × 幅 25mm
        union() {
            translate([0, -r_in])
                square([grip_w - r_in, 2 * r_in]);
            translate([grip_w - r_in, 0])
                circle(r = r_in);
        }
    }
}

/* ---- 取手:+X 側面のみ、壁に embed 分食い込ませて確実に接続 ---- */
module handle() {
    translate([body_r, 0, handle_z])      // 外周面 (x = 40) に配置
        rotate([90, 0, 0])                // 断面を X-Z 平面に立てる
            linear_extrude(height = handle_depth, center = true)
                handle_profile_2d();
}

/* ---- 組み立て(本体と取手をオーバーラップさせて union → マニフォールド) ---- */
union() {
    mug_body();
    handle();
}
xhigh success
xhigh
59.3s · 343/4422t · $0.2245
SCAD (64 lines)
// ===============================
// マグカップ(取手は +X 方向のみ)
// ===============================
$fn = 128;

// ---- 本体パラメータ ----
outer_d  = 80;   // 外径
inner_d  = 70;   // 内径(肉厚 5mm)
mug_h    = 90;   // 高さ
bottom_t = 6;    // 底面の厚み

// ---- 取手パラメータ ----
grip_h       = 30;  // 取手内側の空間 高さ
grip_w       = 25;  // 取手内側の空間 幅
handle_t     = 8;   // 取手の材料厚(リングの太さ)
handle_depth = 12;  // 取手の奥行き(Y 方向)
embed        = 4;   // 本体壁への食い込み量(マニフォールド確保)
handle_z     = mug_h / 2;  // 高さ方向中央に配置

R = outer_d / 2;  // 外半径 40

// ---- 本体(中空マグ) ----
module mug_body() {
    difference() {
        cylinder(h = mug_h, d = outer_d);
        // 内側をくり抜く(底は bottom_t 残す)
        translate([0, 0, bottom_t])
            cylinder(h = mug_h, d = inner_d);
    }
}

// ---- 2D D字形状 ----
// straight_x : 直線辺(本体側)の X 位置
// width      : 直線辺から外端までの幅
// half_h     : 高さの半分(半円の半径)
module d_shape(straight_x, width, half_h) {
    hull() {
        // 本体側の直線辺
        translate([straight_x, -half_h])
            square([0.01, 2 * half_h]);
        // 外側の半円
        translate([straight_x + width - half_h, 0])
            circle(r = half_h);
    }
}

// ---- 取手(D字リング、+X 方向) ----
module handle() {
    rotate([90, 0, 0])
        linear_extrude(height = handle_depth, center = true)
            difference() {
                // 外側 D(本体壁内 x = R - embed まで食い込ませる)
                d_shape(R - embed, grip_w + handle_t + embed, grip_h / 2 + handle_t);
                // 内側 D(指の入る空間: 幅 25 × 高さ 30)
                d_shape(R, grip_w, grip_h / 2);
            }
}

// ---- 組み立て ----
union() {
    mug_body();
    translate([0, 0, handle_z])
        handle();
}

variant: thinking

offnot run
adaptive (default) success
adaptive
59.3s · 343/4422t · $0.2245
SCAD (64 lines)
// ===============================
// マグカップ(取手は +X 方向のみ)
// ===============================
$fn = 128;

// ---- 本体パラメータ ----
outer_d  = 80;   // 外径
inner_d  = 70;   // 内径(肉厚 5mm)
mug_h    = 90;   // 高さ
bottom_t = 6;    // 底面の厚み

// ---- 取手パラメータ ----
grip_h       = 30;  // 取手内側の空間 高さ
grip_w       = 25;  // 取手内側の空間 幅
handle_t     = 8;   // 取手の材料厚(リングの太さ)
handle_depth = 12;  // 取手の奥行き(Y 方向)
embed        = 4;   // 本体壁への食い込み量(マニフォールド確保)
handle_z     = mug_h / 2;  // 高さ方向中央に配置

R = outer_d / 2;  // 外半径 40

// ---- 本体(中空マグ) ----
module mug_body() {
    difference() {
        cylinder(h = mug_h, d = outer_d);
        // 内側をくり抜く(底は bottom_t 残す)
        translate([0, 0, bottom_t])
            cylinder(h = mug_h, d = inner_d);
    }
}

// ---- 2D D字形状 ----
// straight_x : 直線辺(本体側)の X 位置
// width      : 直線辺から外端までの幅
// half_h     : 高さの半分(半円の半径)
module d_shape(straight_x, width, half_h) {
    hull() {
        // 本体側の直線辺
        translate([straight_x, -half_h])
            square([0.01, 2 * half_h]);
        // 外側の半円
        translate([straight_x + width - half_h, 0])
            circle(r = half_h);
    }
}

// ---- 取手(D字リング、+X 方向) ----
module handle() {
    rotate([90, 0, 0])
        linear_extrude(height = handle_depth, center = true)
            difference() {
                // 外側 D(本体壁内 x = R - embed まで食い込ませる)
                d_shape(R - embed, grip_w + handle_t + embed, grip_h / 2 + handle_t);
                // 内側 D(指の入る空間: 幅 25 × 高さ 30)
                d_shape(R, grip_w, grip_h / 2);
            }
}

// ---- 組み立て ----
union() {
    mug_body();
    translate([0, 0, handle_z])
        handle();
}
dynamicnot run

iteration: iter-png

i1 success
iter 1
21.3s · 2008/1471t · $0.0936
diff vs bare: +0/-0
  // 取手付きマグカップ(取手は +X 方向のみ)
  $fn = 120;
  
  // ===== パラメータ =====
  outer_r   = 40;    // 外半径(外径 80mm)
  inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
  mug_h     = 90;    // 高さ
  bottom_t  = 6;     // 底面の厚み
  
  handle_t  = 8;     // 取手の棒の太さ
  handle_d  = 12;    // 取手の奥行き(Y方向の幅)
  open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
  open_h    = 30;    // 取手内側空間の高さ(Z方向)
  open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
  handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)
  
  // ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
  module handle_opening_2d() {
      hull() {
          // 本体側の直線部分
          translate([open_x0, -open_h/2])
              square([0.01, open_h]);
          // 外側の半円部分
          translate([open_x0 + open_w - open_h/2, 0])
              circle(r = open_h/2);
      }
  }
  
  // ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
  module handle_2d() {
      difference() {
          offset(r = handle_t) handle_opening_2d();
          handle_opening_2d();
      }
  }
  
  // ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
  // 内側の縁は本体外壁より内側まで食い込ませており、
  // 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
  module handle() {
      translate([0, 0, handle_z])
          rotate([90, 0, 0])
              linear_extrude(height = handle_d, center = true)
                  handle_2d();
  }
  
  // ===== マグ全体 =====
  module mug() {
      difference() {
          // 本体外形と取手を先に union → マニフォールドを保証
          union() {
              cylinder(r = outer_r, h = mug_h);
              handle();
          }
          // 飲み物用の中空(底厚 6mm を残す)
          // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
          translate([0, 0, bottom_t])
              cylinder(r = inner_r, h = mug_h);
      }
  }
  
  mug();
SCAD (62 lines)
// 取手付きマグカップ(取手は +X 方向のみ)
$fn = 120;

// ===== パラメータ =====
outer_r   = 40;    // 外半径(外径 80mm)
inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
mug_h     = 90;    // 高さ
bottom_t  = 6;     // 底面の厚み

handle_t  = 8;     // 取手の棒の太さ
handle_d  = 12;    // 取手の奥行き(Y方向の幅)
open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
open_h    = 30;    // 取手内側空間の高さ(Z方向)
open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)

// ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
module handle_opening_2d() {
    hull() {
        // 本体側の直線部分
        translate([open_x0, -open_h/2])
            square([0.01, open_h]);
        // 外側の半円部分
        translate([open_x0 + open_w - open_h/2, 0])
            circle(r = open_h/2);
    }
}

// ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
module handle_2d() {
    difference() {
        offset(r = handle_t) handle_opening_2d();
        handle_opening_2d();
    }
}

// ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
// 内側の縁は本体外壁より内側まで食い込ませており、
// 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
module handle() {
    translate([0, 0, handle_z])
        rotate([90, 0, 0])
            linear_extrude(height = handle_d, center = true)
                handle_2d();
}

// ===== マグ全体 =====
module mug() {
    difference() {
        // 本体外形と取手を先に union → マニフォールドを保証
        union() {
            cylinder(r = outer_r, h = mug_h);
            handle();
        }
        // 飲み物用の中空(底厚 6mm を残す)
        // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
        translate([0, 0, bottom_t])
            cylinder(r = inner_r, h = mug_h);
    }
}

mug();
i2 success
iter 2
23.7s · 2008/1563t · $0.0982
diff vs i1: +0/-0
  // 取手付きマグカップ(取手は +X 方向のみ)
  $fn = 120;
  
  // ===== パラメータ =====
  outer_r   = 40;    // 外半径(外径 80mm)
  inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
  mug_h     = 90;    // 高さ
  bottom_t  = 6;     // 底面の厚み
  
  handle_t  = 8;     // 取手の棒の太さ
  handle_d  = 12;    // 取手の奥行き(Y方向の幅)
  open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
  open_h    = 30;    // 取手内側空間の高さ(Z方向)
  open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
  handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)
  
  // ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
  module handle_opening_2d() {
      hull() {
          // 本体側の直線部分
          translate([open_x0, -open_h/2])
              square([0.01, open_h]);
          // 外側の半円部分
          translate([open_x0 + open_w - open_h/2, 0])
              circle(r = open_h/2);
      }
  }
  
  // ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
  module handle_2d() {
      difference() {
          offset(r = handle_t) handle_opening_2d();
          handle_opening_2d();
      }
  }
  
  // ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
  // 内側の縁は本体外壁より内側まで食い込ませており、
  // 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
  module handle() {
      translate([0, 0, handle_z])
          rotate([90, 0, 0])
              linear_extrude(height = handle_d, center = true)
                  handle_2d();
  }
  
  // ===== マグ全体 =====
  module mug() {
      difference() {
          // 本体外形と取手を先に union → マニフォールドを保証
          union() {
              cylinder(r = outer_r, h = mug_h);
              handle();
          }
          // 飲み物用の中空(底厚 6mm を残す)
          // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
          translate([0, 0, bottom_t])
              cylinder(r = inner_r, h = mug_h);
      }
  }
  
  mug();
SCAD (62 lines)
// 取手付きマグカップ(取手は +X 方向のみ)
$fn = 120;

// ===== パラメータ =====
outer_r   = 40;    // 外半径(外径 80mm)
inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
mug_h     = 90;    // 高さ
bottom_t  = 6;     // 底面の厚み

handle_t  = 8;     // 取手の棒の太さ
handle_d  = 12;    // 取手の奥行き(Y方向の幅)
open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
open_h    = 30;    // 取手内側空間の高さ(Z方向)
open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)

// ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
module handle_opening_2d() {
    hull() {
        // 本体側の直線部分
        translate([open_x0, -open_h/2])
            square([0.01, open_h]);
        // 外側の半円部分
        translate([open_x0 + open_w - open_h/2, 0])
            circle(r = open_h/2);
    }
}

// ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
module handle_2d() {
    difference() {
        offset(r = handle_t) handle_opening_2d();
        handle_opening_2d();
    }
}

// ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
// 内側の縁は本体外壁より内側まで食い込ませており、
// 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
module handle() {
    translate([0, 0, handle_z])
        rotate([90, 0, 0])
            linear_extrude(height = handle_d, center = true)
                handle_2d();
}

// ===== マグ全体 =====
module mug() {
    difference() {
        // 本体外形と取手を先に union → マニフォールドを保証
        union() {
            cylinder(r = outer_r, h = mug_h);
            handle();
        }
        // 飲み物用の中空(底厚 6mm を残す)
        // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
        translate([0, 0, bottom_t])
            cylinder(r = inner_r, h = mug_h);
    }
}

mug();
i3 success
iter 3
32.5s · 2008/2335t · $0.1368
diff vs i2: +0/-0
  // 取手付きマグカップ(取手は +X 方向のみ)
  $fn = 120;
  
  // ===== パラメータ =====
  outer_r   = 40;    // 外半径(外径 80mm)
  inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
  mug_h     = 90;    // 高さ
  bottom_t  = 6;     // 底面の厚み
  
  handle_t  = 8;     // 取手の棒の太さ
  handle_d  = 12;    // 取手の奥行き(Y方向の幅)
  open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
  open_h    = 30;    // 取手内側空間の高さ(Z方向)
  open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
  handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)
  
  // ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
  module handle_opening_2d() {
      hull() {
          // 本体側の直線部分
          translate([open_x0, -open_h/2])
              square([0.01, open_h]);
          // 外側の半円部分
          translate([open_x0 + open_w - open_h/2, 0])
              circle(r = open_h/2);
      }
  }
  
  // ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
  module handle_2d() {
      difference() {
          offset(r = handle_t) handle_opening_2d();
          handle_opening_2d();
      }
  }
  
  // ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
  // 内側の縁は本体外壁より内側まで食い込ませており、
  // 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
  module handle() {
      translate([0, 0, handle_z])
          rotate([90, 0, 0])
              linear_extrude(height = handle_d, center = true)
                  handle_2d();
  }
  
  // ===== マグ全体 =====
  module mug() {
      difference() {
          // 本体外形と取手を先に union → マニフォールドを保証
          union() {
              cylinder(r = outer_r, h = mug_h);
              handle();
          }
          // 飲み物用の中空(底厚 6mm を残す)
          // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
          translate([0, 0, bottom_t])
              cylinder(r = inner_r, h = mug_h);
      }
  }
  
  mug();
SCAD (62 lines)
// 取手付きマグカップ(取手は +X 方向のみ)
$fn = 120;

// ===== パラメータ =====
outer_r   = 40;    // 外半径(外径 80mm)
inner_r   = 35;    // 内半径(内径 70mm、肉厚 5mm)
mug_h     = 90;    // 高さ
bottom_t  = 6;     // 底面の厚み

handle_t  = 8;     // 取手の棒の太さ
handle_d  = 12;    // 取手の奥行き(Y方向の幅)
open_w    = 25;    // 取手内側空間の幅(X方向、指3本分)
open_h    = 30;    // 取手内側空間の高さ(Z方向)
open_x0   = 42;    // 内側開口の開始X位置(外壁のすぐ外)
handle_z  = mug_h / 2;  // 取手の中心高さ(マグ中央)

// ===== 取手の内側開口(D字の内側): 平らな辺 + 半円 =====
module handle_opening_2d() {
    hull() {
        // 本体側の直線部分
        translate([open_x0, -open_h/2])
            square([0.01, open_h]);
        // 外側の半円部分
        translate([open_x0 + open_w - open_h/2, 0])
            circle(r = open_h/2);
    }
}

// ===== D字リング断面(内側開口を太さ handle_t で囲む) =====
module handle_2d() {
    difference() {
        offset(r = handle_t) handle_opening_2d();
        handle_opening_2d();
    }
}

// ===== 取手本体(XZ平面のD字をY方向に押し出し、+X側面へ配置) =====
// 内側の縁は本体外壁より内側まで食い込ませており、
// 後段で飲み物用キャビティを差し引くことで内壁面はきれいに保たれる
module handle() {
    translate([0, 0, handle_z])
        rotate([90, 0, 0])
            linear_extrude(height = handle_d, center = true)
                handle_2d();
}

// ===== マグ全体 =====
module mug() {
    difference() {
        // 本体外形と取手を先に union → マニフォールドを保証
        union() {
            cylinder(r = outer_r, h = mug_h);
            handle();
        }
        // 飲み物用の中空(底厚 6mm を残す)
        // 取手の食い込み部分も同時にトリムされ、内壁は滑らか
        translate([0, 0, bottom_t])
            cylinder(r = inner_r, h = mug_h);
    }
}

mug();