Created
October 5, 2025 13:51
-
-
Save erdesigns-eu/57ad3b68385f559e759421e33782aeed to your computer and use it in GitHub Desktop.
Gira Plate Nintendo Connectors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * One-Piece Gira System 55 Frame + Integrated Dual NES/SNES Classic Plate | |
| * (Hollow Shell, Solid Outer Wall) + Configurable Labels + Front Bezel + Rear Collar | |
| * | |
| * - Solid, full-height outer perimeter wall (no inset at the edge) | |
| * - Hollow interior with thin top skin (web) + localized ribs (plate ring, connector boss rings) | |
| * - Rear connector collar (deep sleeve into the hollow back) | |
| * - Front bezel recess around each connector (2D annulus, depth + optional chamfer via scale) | |
| * - True through-cut connector holes with bottom INSET notch | |
| * - Equal margins on the 55×55 plate area | |
| * | |
| * FIX: Front bezel recess now respects the bottom inset notch (does NOT clip it). | |
| * FIX: Replaced ternary module-call with if/else to satisfy OpenSCAD parser. | |
| * | |
| * Author: ERDesigns — License: MIT | |
| */ | |
| $fn = 128; // rendering quality | |
| //=============================== Public API ==================================// | |
| /** | |
| * Builds a one-piece Gira System 55 style part: | |
| * - Full-height solid outer wall of width `outer_wall_w` (continuous side wall). | |
| * - Hollow interior capped by thin top skin (`top_skin_t`). | |
| * - Localized ribs: plate ring & connector boss rings. | |
| * - Two Wii-extension (NES/SNES Classic) through cutouts (with bottom inset notch). | |
| * - Optional labels above the left/right connector (emboss or inset). | |
| * - Rear connector collars (deep sleeves) and front bezel recesses. | |
| * | |
| * Z layout: | |
| * z = 0 .................................. open back (hollow) | |
| * 0 .. rib heights ........................ ribs (plate ring / boss rings / rear collars) | |
| * rib_max .. rib_max+top_skin_t ........... thin top skin (web) | |
| * outer wall .............................. extruded from z=0 to z=top(front) (full-height) | |
| */ | |
| module system55_shell_onepiece( | |
| // Outer frame (Gira) | |
| outer_w = 80.8, | |
| outer_corner_r = 2.0, | |
| outer_roundover_r = 1.0, | |
| outer_wall_w = 10.0, // full-height solid perimeter wall width | |
| // Integrated plate zone (System 55) | |
| plate_w = 55.0, | |
| plate_corner_r = 2.0, | |
| plate_recess = 0.0, // set >0 to recess the whole 55×55 area | |
| // Shell & ribs | |
| top_skin_t = 1.6, // thin web thickness | |
| plate_ring_w = 4.0, // ring width around 55×55 zone | |
| plate_ring_h = 2.0, // ring height | |
| boss_ring_w = 2.0, // radial boss width around each connector profile | |
| boss_ring_h = 2.0, // boss height | |
| // Rear deep collar around each connector | |
| rear_collar_w = 2.5, // radial width of the rear sleeve | |
| rear_collar_h = 4.0, // depth into the hollow | |
| // Front bezel recess around each connector | |
| front_bezel_w = 2.0, // radial width (≈ “rand 2 mm”) | |
| front_bezel_depth = 1.0, // recess depth (≈ 1 mm) | |
| front_bezel_ch_h = 0.4, // chamfer/taper height (0 disables) | |
| front_bezel_ch_scale = 1.08, // taper scale (top slightly wider) | |
| // Connectors | |
| cutout_cfg = make_connector(), | |
| y_offset = 0.0, | |
| add_pilots = false, | |
| // Safety for spacing math | |
| min_wall = 3.0, | |
| // Labels | |
| label_enable = true, | |
| label_left = "Player 1", | |
| label_right = "Player 2", | |
| label_font = "DejaVu Sans:style=Bold", | |
| label_size = 6.0, | |
| label_height = 0.8, // used when label_mode="emboss" | |
| label_depth = 0.6, // used when label_mode="inset" | |
| label_gap = 1.6, | |
| label_mode = "emboss", // "emboss" | "inset" | |
| label_dx_left = 0.0, | |
| label_dx_right = 0.0 | |
| ){ | |
| // ---------- Equal horizontal margins on the 55×55 plate ---------- | |
| w_open = get(cutout_cfg,"w") + 2*get(cutout_cfg,"bezel_extra"); | |
| M_nominal = (plate_w - 2*w_open) / 3; // left = mid = right | |
| M = max(M_nominal, min_wall); | |
| // ---------- Z-stack parameters ---------- | |
| rib_max = max(plate_ring_h, max(boss_ring_h, rear_collar_h)); // include rear collar in rib_max | |
| skin_z0 = rib_max; // bottom of the top skin | |
| skin_z1 = rib_max + top_skin_t; // top/front surface | |
| // ---------- Through-cut parameters (guaranteed through-hole) ---------- | |
| cut_start_z = -0.6; // start slightly below the back plane | |
| cut_depth = skin_z1 - cut_start_z + 0.6; | |
| // ---------- Inner opening size bounded by the outer wall ---------- | |
| inner_w = outer_w - 2*outer_wall_w; | |
| inner_r = max(outer_corner_r - outer_wall_w, 0); | |
| // ---------- Connector vertical geometry (for labels & bezels) ---------- | |
| h_open = get(cutout_cfg,"h") + 2*get(cutout_cfg,"bezel_extra"); | |
| // Front top surface where labels/bezel start | |
| front_top_z = (plate_recess > 0) ? (skin_z1 - plate_recess) : skin_z1; | |
| // Label baseline Y position (above connector) | |
| label_baseline_y = y_offset + (h_open/2) + label_gap; | |
| difference(){ | |
| // ---------------- SOLID: wall + ribs + top skin + (emboss labels) + (rear collars) ---------------- | |
| union(){ | |
| // (A) Full-height solid outer wall | |
| linear_extrude(height=skin_z1) | |
| difference(){ | |
| rounded_rect2d(outer_w, outer_w, outer_corner_r); | |
| rounded_rect2d(inner_w, inner_w, inner_r); | |
| } | |
| // (B) Top skin over interior area | |
| translate([0,0,skin_z0]) | |
| linear_extrude(height=top_skin_t) | |
| rounded_rect2d(inner_w, inner_w, inner_r); | |
| // (C) Plate ring rib | |
| if (plate_ring_h > 0 && plate_ring_w > 0) | |
| translate([0,0,0]) | |
| linear_extrude(height=plate_ring_h) | |
| difference(){ | |
| rounded_rect2d(plate_w + 2*plate_ring_w, plate_w + 2*plate_ring_w, plate_corner_r + plate_ring_w); | |
| rounded_rect2d(plate_w, plate_w, plate_corner_r); | |
| } | |
| // (D) Connector boss rings (inside, below the skin) | |
| if (boss_ring_h > 0 && boss_ring_w > 0){ | |
| boss_ring_at(cutout_cfg, - (w_open + M)/2, y_offset, boss_ring_w, boss_ring_h); | |
| boss_ring_at(cutout_cfg, + (w_open + M)/2, y_offset, boss_ring_w, boss_ring_h); | |
| } | |
| // (E) Rear deep collars (extend further inward into the hollow back) | |
| if (rear_collar_h > 0 && rear_collar_w > 0){ | |
| rear_collar_at(cutout_cfg, - (w_open + M)/2, y_offset, rear_collar_w, rear_collar_h); | |
| rear_collar_at(cutout_cfg, + (w_open + M)/2, y_offset, rear_collar_w, rear_collar_h); | |
| } | |
| // (F) Emboss labels (if chosen) | |
| if (label_enable && label_size > 0 && label_mode == "emboss" && label_height > 0){ | |
| x_left = - (w_open + M)/2 + label_dx_left; | |
| x_right = + (w_open + M)/2 + label_dx_right; | |
| embossed_label(label_left, x_left, label_baseline_y, front_top_z, label_size, label_height, label_font); | |
| embossed_label(label_right, x_right, label_baseline_y, front_top_z, label_size, label_height, label_font); | |
| } | |
| } | |
| // ---------------- OPTIONAL: recess into the top skin (plate area) ---------------- | |
| if (plate_recess > 0){ | |
| recess_h = min(plate_recess, top_skin_t - 0.2); // keep ≥0.2 mm skin floor | |
| if (recess_h > 0) | |
| translate([0,0,skin_z1 - recess_h]) | |
| linear_extrude(height=recess_h) | |
| rounded_rect2d(plate_w, plate_w, plate_corner_r); | |
| } | |
| // ---------------- CONNECTOR CUTOUTS (true through) ---------------- | |
| translate([-(w_open + M)/2, y_offset, cut_start_z]) | |
| connector_cutout(cutout_cfg, cut_depth, add_pilots); | |
| translate([ +(w_open + M)/2, y_offset, cut_start_z]) | |
| connector_cutout(cutout_cfg, cut_depth, add_pilots); | |
| // ---------------- INSET LABELS (engrave) ---------------- | |
| if (label_enable && label_size > 0 && label_mode == "inset" && label_depth > 0){ | |
| x_left = - (w_open + M)/2 + label_dx_left; | |
| x_right = + (w_open + M)/2 + label_dx_right; | |
| engraved_label(label_left, x_left, label_baseline_y, front_top_z, label_size, label_depth, label_font); | |
| engraved_label(label_right, x_right, label_baseline_y, front_top_z, label_size, label_depth, label_font); | |
| } | |
| // ---------------- FRONT BEZEL RECESS (notch-safe) ---------------- | |
| if (front_bezel_depth > 0 && front_bezel_w > 0){ | |
| // Clamp recess to skin thickness to avoid punching through the skin | |
| bezel_h = min(front_bezel_depth, top_skin_t - 0.2); // keep ≥0.2 mm floor | |
| if (bezel_h > 0){ | |
| // Main recess annulus (inner boundary follows the REAL hole incl. bottom notch) | |
| front_bezel_at(cutout_cfg, - (w_open + M)/2, y_offset, front_top_z, front_bezel_w, bezel_h, 1.0, notch_safe=true); | |
| front_bezel_at(cutout_cfg, + (w_open + M)/2, y_offset, front_top_z, front_bezel_w, bezel_h, 1.0, notch_safe=true); | |
| // Optional chamfer/taper (scaled recess) directly at the top, also notch-safe | |
| if (front_bezel_ch_h > 0 && front_bezel_ch_scale > 1.0){ | |
| ch_h = min(front_bezel_ch_h, top_skin_t - 0.2); | |
| if (ch_h > 0){ | |
| front_bezel_at(cutout_cfg, - (w_open + M)/2, y_offset, front_top_z, front_bezel_w, ch_h, front_bezel_ch_scale, notch_safe=true); | |
| front_bezel_at(cutout_cfg, + (w_open + M)/2, y_offset, front_top_z, front_bezel_w, ch_h, front_bezel_ch_scale, notch_safe=true); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| //==================== Helpers: boss ring / collars / labels / bezel ==========// | |
| /** Creates one connector boss ring at (xc, yc) with given ring width/height. */ | |
| module boss_ring_at(cfg, xc, yc, ring_w, ring_h){ | |
| translate([xc, yc, 0]) | |
| linear_extrude(height=ring_h) | |
| connector_ring_annulus_2d(cfg, ring_w); | |
| } | |
| /** Rear deep collar (longer sleeve) at (xc, yc) extending deeper into the hollow back. */ | |
| module rear_collar_at(cfg, xc, yc, collar_w, collar_h){ | |
| translate([xc, yc, 0]) | |
| linear_extrude(height=collar_h) | |
| connector_ring_annulus_2d(cfg, collar_w); | |
| } | |
| /** | |
| * Front bezel recess around the connector hole. | |
| * Subtracts an annular region starting at the top surface (front_top_z) downward by `bezel_h`. | |
| * If `scale_factor` > 1, a slight taper is created (wider at the top). | |
| * If `notch_safe` is true, the inner boundary follows the REAL hole incl. bottom notch, | |
| * so the notch is preserved. | |
| */ | |
| module front_bezel_at(cfg, xc, yc, front_top_z, bezel_w, bezel_h, scale_factor=1.0, notch_safe=true){ | |
| translate([xc, yc, front_top_z - bezel_h]) | |
| linear_extrude(height=bezel_h + 0.02, scale=scale_factor) | |
| if (notch_safe) | |
| connector_ring_annulus_with_notch_2d(cfg, bezel_w); | |
| else | |
| connector_ring_annulus_2d(cfg, bezel_w); | |
| } | |
| /** 2D ring helper: offset(+ring_w) of connector profile (WITHOUT notch) minus base profile. */ | |
| module connector_ring_annulus_2d(cfg, ring_w){ | |
| difference(){ | |
| offset(delta=ring_w) connector_profile_2d(cfg); | |
| connector_profile_2d(cfg); | |
| } | |
| } | |
| /** 2D ring helper using the REAL hole profile INCLUDING the bottom inset notch. */ | |
| module connector_ring_annulus_with_notch_2d(cfg, ring_w){ | |
| difference(){ | |
| offset(delta=ring_w) connector_profile_with_notch_2d(cfg); | |
| connector_profile_with_notch_2d(cfg); | |
| } | |
| } | |
| /** Adds raised text at (xc, y_base) on top surface z=text_z. */ | |
| module embossed_label(txt, xc, y_base, text_z, size, height, font_name){ | |
| if (txt != "" && height > 0 && size > 0) | |
| translate([xc, y_base, text_z]) | |
| linear_extrude(height=height) | |
| text(text=txt, size=size, font=font_name, halign="center", valign="baseline", $fn=64); | |
| } | |
| /** Subtracts (engraves) text into the top surface by `depth`. */ | |
| module engraved_label(txt, xc, y_base, text_z, size, depth, font_name){ | |
| if (txt != "" && depth > 0 && size > 0) | |
| translate([xc, y_base, text_z - depth]) | |
| linear_extrude(height=depth + 0.02) | |
| text(text=txt, size=size, font=font_name, halign="center", valign="baseline", $fn=64); | |
| } | |
| //=========================== Connector profile ===============================// | |
| /** | |
| * NES/SNES Classic (Wii-extension) connector opening config. | |
| * (Your latest values are used in the preset below.) | |
| * | |
| * @param w,h,r,bezel_extra Body size and clearance. | |
| * @param bottom_slot_* Bottom INSET notch (bites upward into the opening). | |
| */ | |
| function make_connector( | |
| w=15.5, h=10.5, r=1.0, bezel_extra=0.30, | |
| left_notch_w=2.2, left_notch_h=1.8, left_notch_y=0.0, | |
| right_notch_w=2.2, right_notch_h=1.8, right_notch_y=0.0, | |
| notch_r=0.6, | |
| chamfer=0.6, | |
| bottom_slot_w=3.1, | |
| bottom_slot_h=2.5, | |
| bottom_slot_r=0.6 | |
| ) = [ | |
| ["w", w], ["h", h], ["r", r], ["bezel_extra", bezel_extra], | |
| ["left_notch_w", left_notch_w], ["left_notch_h", left_notch_h], ["left_notch_y", left_notch_y], | |
| ["right_notch_w", right_notch_w], ["right_notch_h", right_notch_h], ["right_notch_y", right_notch_y], | |
| ["notch_r", notch_r], | |
| ["chamfer", chamfer], | |
| ["bottom_slot_w", bottom_slot_w], | |
| ["bottom_slot_h", bottom_slot_h], | |
| ["bottom_slot_r", bottom_slot_r] | |
| ]; | |
| /** 2D union of the connector opening WITHOUT the bottom inset notch. */ | |
| module connector_profile_2d(cfg){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| } | |
| /** | |
| * 2D union of the REAL connector opening INCLUDING the bottom inset notch. | |
| * This matches the actual through-hole outline at the top surface (so bezel doesn’t clip the notch). | |
| */ | |
| module connector_profile_with_notch_2d(cfg){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| bsw = get(cfg,"bottom_slot_w"); | |
| bsh = get(cfg,"bottom_slot_h"); | |
| bsr = get(cfg,"bottom_slot_r"); | |
| difference(){ | |
| // Base opening (union of main + side key enlargements) | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| // Subtract the bottom inset notch (the “bite” into the opening) | |
| if (bsw > 0 && bsh > 0) | |
| translate([0, -(h/2 + bezel) + bsh/2]) | |
| rounded_rect2d(bsw, bsh, bsr); | |
| } | |
| } | |
| /** Subtracts the connector profile with an INSET bottom notch (true through-hole). */ | |
| module connector_cutout(cfg, depth, pilots=false){ | |
| w = get(cfg,"w"); h = get(cfg,"h"); rr = get(cfg,"r"); | |
| bezel = get(cfg,"bezel_extra"); | |
| lnw = get(cfg,"left_notch_w"); lnh = get(cfg,"left_notch_h"); lny = get(cfg,"left_notch_y"); | |
| rnw = get(cfg,"right_notch_w"); rnh = get(cfg,"right_notch_h"); rny = get(cfg,"right_notch_y"); | |
| nr = get(cfg,"notch_r"); | |
| chamfer = get(cfg,"chamfer"); | |
| bsw = get(cfg,"bottom_slot_w"); | |
| bsh = get(cfg,"bottom_slot_h"); | |
| bsr = get(cfg,"bottom_slot_r"); | |
| difference(){ | |
| // 3D extrusion of composite hole (base + side enlargements) MINUS bottom notch | |
| linear_extrude(height=depth) | |
| difference(){ | |
| union(){ | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| if (lnw > 0 && lnh > 0) | |
| translate([-(w/2 + bezel - 0.01), lny]) | |
| translate([-lnw/2, 0]) | |
| rounded_rect2d(lnw, lnh, nr); | |
| if (rnw > 0 && rnh > 0) | |
| translate([(w/2 + bezel - 0.01), rny]) | |
| translate([+rnw/2, 0]) | |
| rounded_rect2d(rnw, rnh, nr); | |
| } | |
| if (bsw > 0 && bsh > 0) | |
| translate([0, -(h/2 + bezel) + bsh/2]) | |
| rounded_rect2d(bsw, bsh, bsr); | |
| } | |
| if (pilots){ | |
| linear_extrude(height=depth) square([w, 0.2], center=true); | |
| linear_extrude(height=depth) square([0.2, h], center=true); | |
| } | |
| } | |
| // Cosmetic micro-chamfer at the very front edge of the hole | |
| if (chamfer > 0){ | |
| translate([0,0,-0.01]) | |
| linear_extrude(height=chamfer) | |
| offset(delta=+chamfer) | |
| rounded_rect2d(w + 2*bezel, h + 2*bezel, rr); | |
| } | |
| } | |
| //============================= Geometry helpers ==============================// | |
| /** 2D rounded rectangle helper. */ | |
| module rounded_rect2d(w, h, r){ | |
| offset(r=r) offset(r=-r) square([w-2*r, h-2*r], center=true); | |
| } | |
| /** 3D rounded rectangle helper (straight sides). */ | |
| module rounded_rect3d(w, h, t, r){ | |
| linear_extrude(height=t) rounded_rect2d(w, h, r); | |
| } | |
| /** | |
| * Builds a slab with a TRUE round-over on the outer top front edge. | |
| * Implemented via minkowski() then clipped to height t. | |
| */ | |
| module rounded_face3d(w, h, t, corner_r_2d, roundover_r){ | |
| if (roundover_r <= 0){ | |
| rounded_rect3d(w, h, t, corner_r_2d); | |
| } else { | |
| intersection(){ | |
| translate([0,0,t/2]) cube([w*2, h*2, t], center=true); | |
| minkowski(){ | |
| linear_extrude(height = max(t - roundover_r, 0.01)) | |
| rounded_rect2d(w, h, corner_r_2d); | |
| sphere(r = roundover_r); | |
| } | |
| } | |
| } | |
| } | |
| /** Tiny key-value getter for our struct-like vectors. */ | |
| function get(cfg, key, default_val=0) = | |
| let(idx = search([key], [ for (i=[0:len(cfg)-1]) cfg[i][0] ])[0]) | |
| (idx==[]) ? default_val : cfg[idx][1]; | |
| //============================= PRESET & RENDER ===============================// | |
| /** Gira System 55 shell preset incl. labels, rear collars and front bezels (notch-safe). */ | |
| module gira_system55_shell_preset(){ | |
| system55_shell_onepiece( | |
| // Outer aesthetics | |
| outer_w = 80.8, | |
| outer_corner_r = 2.0, | |
| outer_roundover_r = 1.0, | |
| outer_wall_w = 10.0, | |
| // Plate zone | |
| plate_w = 55.0, | |
| plate_corner_r = 2.0, | |
| plate_recess = 0.0, | |
| // Shell & ribs | |
| top_skin_t = 1.6, | |
| plate_ring_w = 4.0, | |
| plate_ring_h = 2.0, | |
| boss_ring_w = 2.0, | |
| boss_ring_h = 2.0, | |
| // Rear collars | |
| rear_collar_w = 2.5, | |
| rear_collar_h = 4.0, | |
| // Front bezel recess (+ optional chamfer) | |
| front_bezel_w = 2.0, | |
| front_bezel_depth = 1.0, | |
| front_bezel_ch_h = 0.4, | |
| front_bezel_ch_scale = 1.08, | |
| // Connectors (your current params) | |
| cutout_cfg = connector_cfg, | |
| y_offset = 0.0, | |
| add_pilots = false, | |
| min_wall = 3.0, | |
| // Labels | |
| label_enable = true, | |
| label_left = "Player 1", | |
| label_right = "Player 2", | |
| label_font = "DejaVu Sans:style=Bold", | |
| label_size = 4.0, | |
| label_height = 0.8, | |
| label_depth = 0.6, | |
| label_gap = 3.5, | |
| label_mode = "inset", | |
| label_dx_left = 0.0, | |
| label_dx_right = 0.0 | |
| ); | |
| } | |
| // --- Connector tuning (your latest values) --- | |
| connector_cfg = make_connector( | |
| w=17.0, h=12.0, r=1.0, bezel_extra=0.30, | |
| left_notch_w=2.2, left_notch_h=1.8, left_notch_y=0.0, | |
| right_notch_w=2.2, right_notch_h=1.8, right_notch_y=0.0, | |
| notch_r=0.6, | |
| chamfer=0.6, | |
| bottom_slot_w=3.1, | |
| bottom_slot_h=2.5, | |
| bottom_slot_r=0.6 | |
| ); | |
| // ---------------------- RENDER ---------------------- | |
| gira_system55_shell_preset(); |
Comments are disabled for this gist.