vibe-openscad

tier-3-butt-hinge / gpt-6-astra

6 run / 累計 429.3s / 累計 $1.24

openai gpt 6 astra bare

bare (provider default effort)

run detail →
render
bare render of tier-3-butt-hinge
loading STL…
success 27.6s · 592/1569t · $0.0844
SCAD (128 lines)
$fn = 96;

// 寸法(mm)
leaf_length = 30;
leaf_width = 25;
leaf_thickness = 2;

pin_diameter = 4;
pin_length = 32;

knuckle_od = 8;
pin_radial_clearance = 0.3;
knuckle_id = pin_diameter + 2 * pin_radial_clearance;
knuckle_count = 5;
knuckle_length = leaf_length / knuckle_count;

screw_diameter = 3.2;
countersink_diameter = 6;
countersink_depth = 1;
hole_pitch = 8;
hole_edge_distance = 5;

eps = 0.01;

// 相手側の筒部と板が干渉しないための隙間
leaf_barrel_clearance = 0.2;
leaf_root = knuckle_od / 2 + leaf_barrel_clearance;
connector_overlap = 0.5;

// 両板の上面は Z=0、下面は Z=-2。
// 軸中心線は X=0, Z=0、筒部は Y=0~30。

module cylinder_y(d, h) {
    rotate([-90, 0, 0])
        cylinder(d = d, h = h);
}

module screw_hole(x, y) {
    // 直径3.2mmの貫通穴
    translate([x, y, -leaf_thickness - eps])
        cylinder(
            d = screw_diameter,
            h = leaf_thickness + 2 * eps
        );

    // 上面側:直径6mm、深さ1mmのテーパ
    translate([x, y, -countersink_depth])
        cylinder(
            d1 = screw_diameter,
            d2 = countersink_diameter,
            h = countersink_depth
        );

    // 上面のブーリアン演算を安定させる延長
    translate([x, y, 0])
        cylinder(d = countersink_diameter, h = eps);
}

// +X側を基準にした板と筒部の一体部品
module leaf_with_knuckles(segment_indices) {
    difference() {
        union() {
            // 25 × 30 × 2 mm の板
            translate([leaf_root, 0, -leaf_thickness])
                cube([leaf_width, leaf_length, leaf_thickness]);

            for (i = segment_indices) {
                // 各筒部:外径8mm、長さ6mm
                translate([0, i * knuckle_length, 0])
                    cylinder_y(
                        d = knuckle_od,
                        h = knuckle_length
                    );

                // 筒部と板を体積的に接続する根元
                translate([
                    0,
                    i * knuckle_length,
                    -leaf_thickness
                ])
                    cube([
                        leaf_root + connector_overlap,
                        knuckle_length,
                        leaf_thickness
                    ]);
            }
        }

        // 接続部分も含めて直径4.6mmの軸穴を開ける
        translate([0, -eps, 0])
            cylinder_y(
                d = knuckle_id,
                h = leaf_length + 2 * eps
            );

        // 遠端側に3穴:Y=7,15,23(8mmピッチ)
        for (j = [-1, 0, 1])
            screw_hole(
                x = leaf_root + leaf_width - hole_edge_distance,
                y = leaf_length / 2 + j * hole_pitch
            );
    }
}

module left_leaf() {
    mirror([1, 0, 0])
        leaf_with_knuckles([0, 2, 4]);
}

module right_leaf() {
    leaf_with_knuckles([1, 3]);
}

module hinge_pin() {
    // Y=-1~31:筒部の両端から1mmずつ突出
    translate([0, -(pin_length - leaf_length) / 2, 0])
        cylinder_y(d = pin_diameter, h = pin_length);
}

// 完成組立:180°開いた状態の3部品
color([0.62, 0.65, 0.69])
    left_leaf();

color([0.72, 0.75, 0.79])
    right_leaf();

color([0.38, 0.40, 0.43])
    hinge_pin();
パラメータ (16) —
スライダを動かすと openscad-wasm で再レンダリング

prompt

OpenSCAD で、家具用の小型バット蝶番(butt hinge)を作ってください。
3 つのパーツ(左板、右板、ピン軸)が組み合わさって動作する完成品を、
「開いた状態(180°)」で 1 つの SCAD ファイルに配置して出力します。

寸法と配置:
- 板(leaf)2 枚: 30mm × 25mm × 厚さ 2mm の鉄板形状
  - 縦 30mm の辺がピン軸に沿う(ヒンジ軸方向)
  - 横 25mm の辺が回転で開く方向に伸びる
- ピン軸: 直径 4mm の円柱、長さ 32mm(両端 1mm ずつ knuckle から飛び出す)
- knuckle(筒部): 縦 30mm を 5 等分(各 6mm)に区切り、左板に 3 個・右板に 2 個を
  互い違いに配置(左板は外側 2 個 + 中央 1 個、右板は中間 2 個)
- knuckle 外径 8mm、内径はピン軸 + 0.3mm クリアランス(= 4.6mm 穴)
- 左板と右板はピン軸を共有して回転可能。180° 開いた状態で、両板の
  平らな面が同一平面に来るように配置する
- 各板の knuckle から離れた側に、M3 用の皿穴を 3 個ずつ
  (穴ピッチは板の縦方向に 8mm 間隔、皿穴は表面から見て直径 6mm × 深さ 1mm
  のテーパ + 直径 3.2mm の貫通穴)

座標系:
- ピン軸の中心線を Y 軸に重ねる(ピン軸は +Y 方向)
- 板の平らな面は Z 軸に直交し、左板が x<0 側、右板が x>0 側に伸びる(180° 開)
- knuckle は X=0 を中心とし、Y 方向に 6mm ずつ並ぶ

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

variant: effort

low success →
low
20.3s · 592/1158t · $0.0638
SCAD (106 lines)
// 単位: mm。Y=0~30 が筒部、Y=-1~31 がピン。
// 左右の板は Z=-4~-2 に配置し、180°開いた状態とする。
$fn = 96;

leaf_length = 30;
leaf_width  = 25;
leaf_thick  = 2;

pin_d       = 4;
pin_length  = 32;
knuckle_od  = 8;
bore_d      = 4.6;

segment     = leaf_length / 5;
leaf_inner  = knuckle_od / 2;
leaf_bottom = -knuckle_od / 2;
leaf_top    = leaf_bottom + leaf_thick;

screw_d     = 3.2;
sink_d      = 6;
sink_depth  = 1;
hole_pitch  = 8;
hole_x      = leaf_inner + leaf_width - 6;

eps = 0.01;

// ローカルZ軸の円柱を、+Y方向へ向ける。
module cylinder_y(d, h) {
    rotate([-90, 0, 0])
        cylinder(d = d, h = h);
}

// 右側を原型とし、左側はX方向に鏡映する。
module place_side(side) {
    if (side < 0)
        mirror([1, 0, 0]) children();
    else
        children();
}

module screw_hole(x, y) {
    translate([x, y, leaf_bottom - eps])
        cylinder(d = screw_d, h = leaf_thick + 2 * eps);

    // +Z側表面から深さ1mmの皿穴。
    translate([x, y, leaf_top - sink_depth])
        cylinder(d1 = screw_d, d2 = sink_d, h = sink_depth);

    translate([x, y, leaf_top - eps])
        cylinder(d = sink_d, h = 2 * eps);
}

module leaf(side, knuckle_indices) {
    place_side(side)
        difference() {
            union() {
                // 板本体: 幅25 × 長さ30 × 厚さ2。
                translate([leaf_inner, 0, leaf_bottom])
                    cube([leaf_width, leaf_length, leaf_thick]);

                for (i = knuckle_indices) {
                    translate([0, i * segment, 0])
                        cylinder_y(d = knuckle_od, h = segment);

                    // 各筒部のみに接続する一体の根元。
                    // 相手側の筒部がある区間には張り出さない。
                    translate([0, i * segment, leaf_bottom])
                        cube([
                            leaf_inner + 0.5,
                            segment,
                            leaf_thick
                        ]);
                }
            }

            // 根元も含めて穴を抜き、ピンとの隙間を確保。
            translate([0, -eps, 0])
                cylinder_y(
                    d = bore_d,
                    h = leaf_length + 2 * eps
                );

            for (y = [
                leaf_length / 2 - hole_pitch,
                leaf_length / 2,
                leaf_length / 2 + hole_pitch
            ])
                screw_hole(hole_x, y);
        }
}

module pin() {
    translate([0, -(pin_length - leaf_length) / 2, 0])
        cylinder_y(d = pin_d, h = pin_length);
}

// 完成組立: 独立した左板・右板・ピンの3パーツ。
// 筒部は各6mmで交互に配置し、端面同士は接触する。
color([0.66, 0.69, 0.73])
    leaf(-1, [0, 2, 4]);

color([0.73, 0.76, 0.80])
    leaf(1, [1, 3]);

color([0.40, 0.43, 0.48])
    pin();
medium (default) success →
medium
27.6s · 592/1569t · $0.0844
SCAD (128 lines)
$fn = 96;

// 寸法(mm)
leaf_length = 30;
leaf_width = 25;
leaf_thickness = 2;

pin_diameter = 4;
pin_length = 32;

knuckle_od = 8;
pin_radial_clearance = 0.3;
knuckle_id = pin_diameter + 2 * pin_radial_clearance;
knuckle_count = 5;
knuckle_length = leaf_length / knuckle_count;

screw_diameter = 3.2;
countersink_diameter = 6;
countersink_depth = 1;
hole_pitch = 8;
hole_edge_distance = 5;

eps = 0.01;

// 相手側の筒部と板が干渉しないための隙間
leaf_barrel_clearance = 0.2;
leaf_root = knuckle_od / 2 + leaf_barrel_clearance;
connector_overlap = 0.5;

// 両板の上面は Z=0、下面は Z=-2。
// 軸中心線は X=0, Z=0、筒部は Y=0~30。

module cylinder_y(d, h) {
    rotate([-90, 0, 0])
        cylinder(d = d, h = h);
}

module screw_hole(x, y) {
    // 直径3.2mmの貫通穴
    translate([x, y, -leaf_thickness - eps])
        cylinder(
            d = screw_diameter,
            h = leaf_thickness + 2 * eps
        );

    // 上面側:直径6mm、深さ1mmのテーパ
    translate([x, y, -countersink_depth])
        cylinder(
            d1 = screw_diameter,
            d2 = countersink_diameter,
            h = countersink_depth
        );

    // 上面のブーリアン演算を安定させる延長
    translate([x, y, 0])
        cylinder(d = countersink_diameter, h = eps);
}

// +X側を基準にした板と筒部の一体部品
module leaf_with_knuckles(segment_indices) {
    difference() {
        union() {
            // 25 × 30 × 2 mm の板
            translate([leaf_root, 0, -leaf_thickness])
                cube([leaf_width, leaf_length, leaf_thickness]);

            for (i = segment_indices) {
                // 各筒部:外径8mm、長さ6mm
                translate([0, i * knuckle_length, 0])
                    cylinder_y(
                        d = knuckle_od,
                        h = knuckle_length
                    );

                // 筒部と板を体積的に接続する根元
                translate([
                    0,
                    i * knuckle_length,
                    -leaf_thickness
                ])
                    cube([
                        leaf_root + connector_overlap,
                        knuckle_length,
                        leaf_thickness
                    ]);
            }
        }

        // 接続部分も含めて直径4.6mmの軸穴を開ける
        translate([0, -eps, 0])
            cylinder_y(
                d = knuckle_id,
                h = leaf_length + 2 * eps
            );

        // 遠端側に3穴:Y=7,15,23(8mmピッチ)
        for (j = [-1, 0, 1])
            screw_hole(
                x = leaf_root + leaf_width - hole_edge_distance,
                y = leaf_length / 2 + j * hole_pitch
            );
    }
}

module left_leaf() {
    mirror([1, 0, 0])
        leaf_with_knuckles([0, 2, 4]);
}

module right_leaf() {
    leaf_with_knuckles([1, 3]);
}

module hinge_pin() {
    // Y=-1~31:筒部の両端から1mmずつ突出
    translate([0, -(pin_length - leaf_length) / 2, 0])
        cylinder_y(d = pin_diameter, h = pin_length);
}

// 完成組立:180°開いた状態の3部品
color([0.62, 0.65, 0.69])
    left_leaf();

color([0.72, 0.75, 0.79])
    right_leaf();

color([0.38, 0.40, 0.43])
    hinge_pin();
high success →
high
66.8s · 592/3781t · $0.1950
SCAD (157 lines)
// 小型バット蝶番:180°開いた組立状態
// 単位:mm。ピン中心線はY軸、左板は-X側、右板は+X側。
$fn = 96;

leaf_length    = 30;
leaf_width     = 25;
leaf_thickness = 2;

pin_diameter = 4;
pin_length   = 32;

knuckle_outer_diameter = 8;
pin_radial_clearance   = 0.3;
knuckle_inner_diameter = pin_diameter + 2 * pin_radial_clearance;

knuckle_count = 5;
knuckle_pitch = leaf_length / knuckle_count;

// 各6mm区画の内部境界に設ける回転用の軸方向すきま。
// 最外端はY=0、Y=30を維持する。
axial_clearance = 0.10;

// 板本体と、相手側の筒部との接触を避けるすきま。
leaf_barrel_clearance = 0.20;

screw_diameter       = 3.2;
countersink_diameter = 6;
countersink_depth    = 1;
screw_pitch          = 8;
screw_edge_distance  = 5;

outer_radius = knuckle_outer_diameter / 2;
leaf_inner_x = outer_radius + leaf_barrel_clearance;

// 両板の裏面を筒部下面に合わせ、閉じる方向の回転を可能にする。
leaf_bottom_z = -outer_radius;
leaf_top_z    = leaf_bottom_z + leaf_thickness;

eps = 0.02;
neck_overlap = 0.25;

function section_start(i) =
    i * knuckle_pitch
    + (i == 0 ? 0 : axial_clearance / 2);

function section_end(i) =
    (i + 1) * knuckle_pitch
    - (i == knuckle_count - 1 ? 0 : axial_clearance / 2);

// ローカルの+Z方向を、組立座標の+Y方向へ向ける。
module cylinder_y(diameter, length, y_start) {
    translate([0, y_start, 0])
        rotate([-90, 0, 0])
            cylinder(d = diameter, h = length);
}

module plate_body(side) {
    x_start = side < 0
        ? -leaf_inner_x - leaf_width
        :  leaf_inner_x;

    translate([x_start, 0, leaf_bottom_z])
        cube([leaf_width, leaf_length, leaf_thickness]);
}

// 筒部と板本体を、体積のあるネックで一体化する。
module knuckle_and_neck(side, index) {
    y_start = section_start(index);
    length  = section_end(index) - y_start;
    neck_width = leaf_inner_x + neck_overlap;

    union() {
        cylinder_y(knuckle_outer_diameter, length, y_start);

        translate([
            side < 0 ? -neck_width : 0,
            y_start,
            leaf_bottom_z
        ])
            cube([neck_width, length, leaf_thickness]);
    }
}

// 皿穴は+Z側の板表面から深さ1mm。
// 板表面で直径6mm、テーパ底で直径3.2mm。
module countersunk_hole(x, y) {
    translate([x, y, leaf_bottom_z - eps])
        cylinder(
            d = screw_diameter,
            h = leaf_thickness + 2 * eps
        );

    translate([x, y, leaf_top_z - countersink_depth])
        cylinder(
            h  = countersink_depth + eps,
            d1 = screw_diameter,
            d2 = countersink_diameter
                 + (countersink_diameter - screw_diameter)
                   * eps / countersink_depth
        );
}

module hinge_leaf(side, indices) {
    hole_x = side * (
        leaf_inner_x + leaf_width - screw_edge_distance
    );

    difference() {
        union() {
            plate_body(side);

            for (i = indices)
                knuckle_and_neck(side, i);
        }

        // ネックを含めて直径4.6mmの軸穴を通す。
        cylinder_y(
            knuckle_inner_diameter,
            leaf_length + 2 * eps,
            -eps
        );

        // Y=7,15,23:縦方向8mmピッチ。
        for (offset = [-1, 0, 1])
            countersunk_hole(
                hole_x,
                leaf_length / 2 + offset * screw_pitch
            );
    }
}

module left_leaf() {
    hinge_leaf(-1, [0, 2, 4]);
}

module right_leaf() {
    hinge_leaf(1, [1, 3]);
}

module hinge_pin() {
    // Y=-1~31:筒部の両端から各1mm突出。
    cylinder_y(
        pin_diameter,
        pin_length,
        -(pin_length - leaf_length) / 2
    );
}

// 3パーツを共有軸上に組み立て、180°開いた状態で配置。
color([0.60, 0.63, 0.67])
    left_leaf();

color([0.70, 0.73, 0.77])
    right_leaf();

color([0.82, 0.84, 0.87])
    hinge_pin();
max success →
max
163.3s · 592/9159t · $0.4639
SCAD (157 lines)
// 単位: mm
// ピン中心線: X=0, Z=0(+Y方向)
// 180°開いたとき、両板の表面は Z=-2、裏面は Z=-4。
$fn = 128;

leaf_length    = 30;
leaf_width     = 25;
leaf_thickness = 2;

pin_diameter = 4;
pin_length   = 32;

knuckle_od       = 8;
radial_clearance = 0.3;
knuckle_id       = pin_diameter + 2 * radial_clearance; // 4.6
knuckle_count    = 5;
knuckle_pitch    = leaf_length / knuckle_count;        // 6

// 6mm区画の内側境界に可動用の隙間を設ける。
// 最外端は Y=0,30 に保ち、ピンの突出量を両端1mmにする。
axial_gap = 0.10;

screw_hole_diameter = 3.2;
countersink_diameter = 6;
countersink_depth    = 1;
screw_pitch          = 8;
screw_edge_inset     = 5;

eps = 0.01;

knuckle_radius = knuckle_od / 2;
leaf_inner_x   = knuckle_radius;
leaf_bottom_z  = -knuckle_radius;
leaf_top_z     = leaf_bottom_z + leaf_thickness;


// +Y方向の円柱
module cylinder_y(diameter, length, y_start = 0) {
    translate([0, y_start, 0])
        rotate([-90, 0, 0])
            cylinder(d = diameter, h = length);
}


// +Z側の表面から加工する皿穴
module countersunk_hole() {
    translate([0, 0, leaf_bottom_z - eps])
        cylinder(
            d = screw_hole_diameter,
            h = leaf_thickness + 2 * eps
        );

    // 表面で直径6mm、深さ1mmで直径3.2mmとなるテーパ。
    // 上端のみ延長し、表面位置での指定径を維持する。
    translate([0, 0, leaf_top_z - countersink_depth])
        cylinder(
            h  = countersink_depth + eps,
            d1 = screw_hole_diameter,
            d2 = countersink_diameter
               + (countersink_diameter - screw_hole_diameter)
               * eps / countersink_depth
        );
}


// 筒部と、その筒部を板につなぐ一体のウェブ
module knuckle_with_web(index, side) {
    y0 = index * knuckle_pitch
       + (index == 0 ? 0 : axial_gap / 2);

    y1 = (index + 1) * knuckle_pitch
       - (index == knuckle_count - 1 ? 0 : axial_gap / 2);

    web_x = side < 0 ? -leaf_inner_x - eps : 0;

    union() {
        cylinder_y(
            diameter = knuckle_od,
            length   = y1 - y0,
            y_start  = y0
        );

        translate([web_x, y0, leaf_bottom_z])
            cube([
                leaf_inner_x + eps,
                y1 - y0,
                leaf_thickness
            ]);
    }
}


// side=-1: 左板(区画0,2,4)
// side=+1: 右板(区画1,3)
module leaf(side) {
    body_x = side < 0
           ? -leaf_inner_x - leaf_width
           :  leaf_inner_x;

    screw_x = side
            * (leaf_inner_x + leaf_width - screw_edge_inset);

    difference() {
        union() {
            // 25×30×2の平板本体。
            // 筒部の外側に置き、相手側の筒部との干渉を防ぐ。
            translate([body_x, 0, leaf_bottom_z])
                cube([leaf_width, leaf_length, leaf_thickness]);

            for (i = [0 : knuckle_count - 1])
                if (i % 2 == (side < 0 ? 0 : 1))
                    knuckle_with_web(i, side);
        }

        // ウェブを含めて貫通させ、軸穴を完全に開ける。
        cylinder_y(
            diameter = knuckle_id,
            length   = leaf_length + 2 * eps,
            y_start  = -eps
        );

        // Y=7,15,23、8mmピッチ
        for (n = [-1 : 1])
            translate([
                screw_x,
                leaf_length / 2 + n * screw_pitch,
                0
            ])
                countersunk_hole();
    }
}


module pin() {
    cylinder_y(
        diameter = pin_diameter,
        length   = pin_length,
        y_start  = -(pin_length - leaf_length) / 2
    );
}


// 0°で閉、180°で開。回転中心は共通のY軸。
module hinge(open_angle = 180) {
    color([0.62, 0.65, 0.68])
        leaf(-1);

    color([0.72, 0.75, 0.78])
        rotate([0, open_angle - 180, 0])
            leaf(1);

    color([0.42, 0.45, 0.48])
        pin();
}


hinge(open_angle = 180);
xhigh success →
xhigh
123.7s · 592/6938t · $0.3528
SCAD (153 lines)
// 単位: mm
$fn = 96;

// ---------- 基本寸法 ----------
leaf_length    = 30;
leaf_width     = 25;
leaf_thickness = 2;

pin_diameter   = 4;
pin_overhang   = 1;
pin_length     = leaf_length + 2 * pin_overhang;

knuckle_count    = 5;
knuckle_pitch    = leaf_length / knuckle_count; // 6 mm
knuckle_diameter = 8;
knuckle_radius   = knuckle_diameter / 2;

radial_clearance = 0.3;
bore_diameter   = pin_diameter + 2 * radial_clearance; // 4.6 mm

// 6 mm区画の境界に可動用隙間を設ける。
// 筒部全体の外端はY=0とY=30を維持する。
axial_gap = 0.10;

// 平板部は25×30×2。筒部との接続部を各担当区画に追加する。
leaf_inner_x = knuckle_radius + 0.15;
leaf_bottom_z = -knuckle_radius;
leaf_top_z    = leaf_bottom_z + leaf_thickness;

// ---------- M3皿穴 ----------
hole_diameter         = 3.2;
countersink_diameter  = 6;
countersink_depth     = 1;
hole_pitch            = 8;
hole_outer_edge_margin = 5;
hole_first_y          = (leaf_length - 2 * hole_pitch) / 2;

// 180°で左右の板が同一平面。0°へ変更すると右板が閉じる。
opening_angle = 180;

eps = 0.01;

function knuckle_start(i) =
    i * knuckle_pitch + (i == 0 ? 0 : axial_gap / 2);

function knuckle_end(i) =
    (i + 1) * knuckle_pitch
    - (i == knuckle_count - 1 ? 0 : axial_gap / 2);

function owns_knuckle(side, i) =
    side < 0 ? (i % 2 == 0) : (i % 2 == 1);

// +Y方向の円柱。中心線はX=Z=0。
module cylinder_y(diameter, length, start_y = 0) {
    translate([0, start_y, 0])
        rotate([-90, 0, 0])
            cylinder(d = diameter, h = length);
}

module screw_hole(x, y) {
    // 直径3.2 mmの貫通穴
    translate([x, y, leaf_bottom_z - eps])
        cylinder(
            d = hole_diameter,
            h = leaf_thickness + 2 * eps
        );

    // +Z側表面で直径6 mm、深さ1 mmのテーパ
    // 表面より上へ延長しても、表面位置の直径は正確に6 mm。
    translate([x, y, leaf_top_z - countersink_depth])
        cylinder(
            h = countersink_depth + eps,
            d1 = hole_diameter,
            d2 = countersink_diameter
                 + (countersink_diameter - hole_diameter)
                   * eps / countersink_depth
        );
}

// side=-1: 左板、side=+1: 右板
module hinge_leaf(side) {
    difference() {
        union() {
            // 25×30×2 mmの平板
            translate([
                side < 0
                    ? -leaf_inner_x - leaf_width
                    : leaf_inner_x,
                0,
                leaf_bottom_z
            ])
                cube([leaf_width, leaf_length, leaf_thickness]);

            // 左: 0,2,4区画 / 右: 1,3区画
            for (i = [0 : knuckle_count - 1]) {
                if (owns_knuckle(side, i)) {
                    let(
                        y0 = knuckle_start(i),
                        h  = knuckle_end(i) - knuckle_start(i)
                    ) {
                        cylinder_y(knuckle_diameter, h, y0);

                        // 筒部と平板を確実に一体化する接続部
                        translate([
                            side < 0 ? -leaf_inner_x - eps : 0,
                            y0,
                            leaf_bottom_z
                        ])
                            cube([
                                leaf_inner_x + eps,
                                h,
                                leaf_thickness
                            ]);
                    }
                }
            }
        }

        // 接続部も含めて軸穴を貫通させる
        cylinder_y(
            bore_diameter,
            leaf_length + 2 * eps,
            -eps
        );

        for (j = [0 : 2])
            screw_hole(
                side * (
                    leaf_inner_x
                    + leaf_width
                    - hole_outer_edge_margin
                ),
                hole_first_y + j * hole_pitch
            );
    }
}

module hinge_pin() {
    // Y=-1~31:筒部の両端から各1 mm突出
    cylinder_y(pin_diameter, pin_length, -pin_overhang);
}

// ---------- 完成アセンブリ:独立した3パーツ ----------
// 開いた状態では両板の表面がZ=-2、裏面がZ=-4。
color([0.66, 0.68, 0.71])
    hinge_leaf(-1);

color([0.72, 0.74, 0.77])
    rotate([0, opening_angle - 180, 0])
        hinge_leaf(1);

color([0.43, 0.45, 0.48])
    hinge_pin();