Rendering these values. This takes a few seconds.
Download STL
Read this model as text

A modern wall mounted light bar for above a bathroom mirror. Three GU10 spots point down through the recessed bottom plate, hidden behind the front fascia so you see a clean bar and the light washes over the mirror. The fixture parameter picks how the spots are held: store bought recessed GU10 fixtures that clamp into round cutouts with their own spring clips and tilt mechanism, optionally counterbored so the bezel sits flush with the plate, or the printed variants, fixed cups or tilt cartridges on filament hinge pins. The bar automatically grows tall enough for the recess depth. The back is flat against the wall with rounded top corners that blend into the spherical front corners; one rounding radius, sharp bottom edge, service windows behind the spots, and a bottom opening that follows the outline with rounded front corners and a very subtle 3 mm ease on the back corners. Segments join with printed dovetail keys and glue: no dowels or other hardware. The printed cups descend from mick/lamp-fittings.

The image shows the solid OpenSCAD renders at part all · segment_index 1 · cutaway false · show_fixtures true · fixture recessed · cutout_d 75 · bezel_d 93 · bezel_t 4 · flush_bezels true · recess_depth 120 · total_width 500 · depth 100 · height 100 · spots 3 · rounding 14 · lip 15 · rim 2.5 · color_body White · segments 3 · wall 2.5 · max_tilt 15 · tilt_angle 0 · gu10_hole_span 40.

MIT

Bathroom mirror light bar

mick/mirror-light@2.5.0

Remix this
Report

For a legal or policy problem: a license violation, personal data, somebody else’s work republished as their own. A model that prints badly is a comment, not a report.

Sign in to report

0reused0 remixes · 0 imports7downloads3.4.1latest

Parameters

from source
16, steps of 1
5090, steps of 1
60110, steps of 1
28, steps of 0.5

Showing the render for these values.

Description

What is this

A modern wall mounted light bar for above a bathroom mirror. Three GU10 spots point down through the recessed bottom plate, hidden behind the front fascia so you see a clean bar and the light washes over the mirror. The fixture parameter picks how the spots are held: store bought recessed GU10 fixtures that clamp into round cutouts with their own spring clips and tilt mechanism, optionally counterbored so the bezel sits flush with the plate, or the printed variants, fixed cups or tilt cartridges on filament hinge pins. The bar automatically grows tall enough for the recess depth. The back is flat against the wall with rounded top corners that blend into the spherical front corners; one rounding radius, sharp bottom edge, service windows behind the spots, and a bottom opening that follows the outline with rounded front corners and a very subtle 3 mm ease on the back corners. Segments join with printed dovetail keys and glue: no dowels or other hardware. The printed cups descend from mick/lamp-fittings.

What you use it for

For recessed fixtures: set cutout_d, bezel_d, bezel_t and recess_depth from the fixture; the bar height follows automatically. The preview draws a grey dummy of each fixture at full recess depth; show_fixtures toggles the dummies and they are never part of a print. Print the segments; each cut carries three dovetail keys with a 0.15 mm fitting allowance, so the parts align themselves. Apply glue to the mating faces and slide the segments together from the front. Push the fixtures into their counterbored cutouts from below until the clips grab, wire them in parallel through the service windows, feed the mains through the nearest window and hang the bar on the keyholes. For the printed variants: cups are fixed, cartridges tilt on 1.75 mm filament pins secured with glue or a melted head, and gu10_hole_span must match your bare socket. LED GU10 lamps only, PETG or ASA for a bathroom, out of the shower zones, and have the mains connection checked if you are not certain of it.

Design notes

The segment cut is not a flat plane but a comb: three dovetail keys extruded through the depth, one running through the glue boss on the plate, one through the walls at mid height and one through the boss under the top wall. The flare of the keys locks the joint in width and height, the only free direction is the sliding one, and the glue closes that. Sockets are grown by 0.15 mm so printed parts actually fit. The flush seat for a recessed fixture works with a local boss: the plate stays 3 mm, a ring one bezel thickness tall sits on top and the counterbore leaves 3 mm above the pocket floor, so the spring clips clamp the same thickness as a plain plate. The shell is one convex hull with a flat back plate with rounded top corners blending into the front corner spheres. Keyholes sit in the columns between the service windows, offset from the cuts. part = segment exports one segment on its back; part = cartridge exports the tilt cartridge.

Parameters

fixture picks the spot mounting; cutout_d, bezel_d, bezel_t, flush_bezels and recess_depth describe a recessed fixture. total_width, depth, height and spots size the bar; height grows automatically when too small for the fixtures. rounding, lip, rim and color_body set the look, segments and wall the print, and cutaway plus show_fixtures the preview. The last group only matters for the printed spot variants.

Use with your agent
{
  "mcpServers": {
    "remixcad": {
      "type": "http",
      "url": "https://remix-cad.vercel.app/api/mcp"
    }
  }
}
get_model("mick/mirror-light@2.5.0")

Returns the manifest, the source, the import closure and the license obligations. Full MCP setup.

Parameter table

Parsed from the Customizer annotations in main.scad
Parameters of Bathroom mirror light bar, with the ranges the source declares
NameDefaultRangeUnitDescription
part"all"all, segment, cartridge
segment_index11 to 6 step 1
cutawayfalse
show_fixturestrue
fixture"recessed"recessed, cups, cartridges
cutout_d7550 to 90 step 1
bezel_d9360 to 110 step 1
bezel_t42 to 8 step 0.5
flush_bezelstrue
recess_depth12060 to 150 step 5
total_width500300 to 800 step 10
depth10070 to 140 step 5
height10070 to 160 step 5
spots32 to 5 step 1
rounding142 to 60 step 1
lip158 to 30 step 1
rim2.52 to 12 step 0.5
color_body"White"White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod
segments31 to 6 step 1
wall2.52 to 4 step 0.25
max_tilt155 to 20 step 1
tilt_angle0-20 to 20 step 1
gu10_hole_span4024 to 50 step 1

Lineage

0 models depend on this one

Only what this model came from and what came from it.

Remix, the code changed Import, used unchanged and pinned The version you are on Withdrawn, still recorded

License

Whoever downloads this takes these obligations along
  • mick/mirror-light@2.5.0 is MIT

Source

main.scad is the entrypoint
main.scad
// Bathroom mirror light bar. Remix of mick/lamp-fittings. Spots point down
// behind a front lip. Fixture options: store bought recessed GU10 fixtures in
// round cutouts (optionally counterbored flush, bar height auto-grows), or
// printed fixed cups or tilt cartridges on filament hinge pins. Flat back with
// rounded top corners blending into spherical front corners, sharp bottom edge,
// service windows behind the spots. Segments join with printed dovetail keys
// and glue: no dowels or hardware.

/* [Model] */
// The whole bar, one print segment laid flat, or one tilt cartridge print ready.
part = "all"; // [all, segment, cartridge]
// Which segment when part = segment.
segment_index = 1; // [1:1:6]
// Slice the display view open through the spots.
cutaway = false;
// Show the grey fixture dummies in the preview. Display only, never part of a print.
show_fixtures = true;

/* [Fixture] */
// How the spots are held: store bought recessed GU10 fixtures in round cutouts, or printed cups or tilting cartridges.
fixture = "recessed"; // [recessed, cups, cartridges]
// Saw diameter of the recessed fixture, the cutout in the plate.
cutout_d = 75; // [50:1:90]
// Outer bezel diameter of the recessed fixture.
bezel_d = 93; // [60:1:110]
// Thickness of the bezel ring, for the flush seat. Measure yours.
bezel_t = 4; // [2:0.5:8]
// Sink the bezels flush with the underside of the plate.
flush_bezels = true;
// Required recess depth of the fixture. The bar grows automatically to fit it.
recess_depth = 120; // [60:5:150]

/* [Size] */
// Width of the bar in mm.
total_width = 500; // [300:10:800]
// Depth from the wall in mm.
depth = 100; // [70:5:140]
// Height of the front fascia in mm. With recessed fixtures the bar grows automatically when this is too small for the fixture.
height = 100; // [70:5:160]
// Number of GU10 spots.
spots = 3; // [2:1:5]

/* [Style] */
// One radius for all rounded edges: top front edge, vertical front edges, their corner blends and the top corners of the back outline. Back stays flat, bottom edge stays sharp.
rounding = 14; // [2:1:60]
// How far the front fascia drops past the lamp faces, hiding them from view.
lip = 15; // [8:1:30]
// Thickness of the visible rim around the bottom opening.
rim = 2.5; // [2:0.5:12]
// Display colour of the body.
color_body = "White"; // [White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod]

/* [Print] */
// Number of print segments. Keep total_width / segments under your printer bed size.
segments = 3; // [1:1:6]
// Wall thickness of the shell.
wall = 2.5; // [2:0.25:4]

/* [Printed spot variants only, ignore for recessed] */
// Designed tilt range of the printed cartridges, degrees to either side.
max_tilt = 15; // [5:1:20]
// Tilt of the cartridges in the preview only, degrees. Positive tilts forward.
tilt_angle = 0; // [-20:1:20]
// Centre distance of the two fixing holes of a bare GU10 socket.
gu10_hole_span = 40; // [24:1:50]

/* [Hidden] */
$fn = 96;
eps = 0.01;
clearance = 0.3;
plate_t = 3;                   // bottom plate thickness
spot_len = 46;                 // GU10 lamp length without pins
cup_id = 50 + 2 * clearance;   // bore for the 50 mm lamp face
cup_od = cup_id + 2 * wall;
plate_bot = lip;
plate_top = lip + plate_t;
cap_bot = lip + spot_len;
flush_ = fixture == "recessed" && flush_bezels;
H = fixture == "recessed"
  ? max(height, lip + recess_depth + wall + (flush_ ? bezel_t : 0))
  : height;
seg_w = total_width / segments;
r_ = min(rounding, H / 2 - 2, depth / 2 - 2, total_width / 4);
r_i = max(r_ - wall, 1);
r_rim = max(r_ - rim, 1);
r_back = 3;                    // subtle ease on the back corners of the opening
spacing = total_width / spots;
win_w = max(spacing - 56, 40);
win_z0 = plate_top + 4;
win_z1 = H - 14;
function sx(i) = (i + 0.5) * spacing;
kx1 = (sx(0) + sx(1)) / 2 - 12;
kx2 = (sx(spots - 2) + sx(spots - 1)) / 2 + 12;
tooth_zs = [plate_top + 6, (lip + H) / 2, H - wall - 6];
// Printed tilting geometry
cart_od = cup_id + 2 * wall;
cart_h = spot_len + plate_t;
pivot_rel = 15;
pivot_z = lip + pivot_rel;
gap_t = 1.5;
ring_wall = 2.5;
ring_od = cart_od + 2 * gap_t + 2 * ring_wall;
ring_top = pivot_z + 8;
tilt_show = max(-max_tilt, min(max_tilt, tilt_angle));

// ---- Shell: flat back with rounded top corners, rounded front, sharp bottom ----

module back_face_2d(x0, x1, z0, z1, r)
  hull() {
    translate([x0, z0]) square([x1 - x0, max(z1 - z0 - r, 0.1)]);
    translate([x0 + r, z1 - r]) circle(r);
    translate([x1 - r, z1 - r]) circle(r);
  }

module bar_solid()
  hull() {
    translate([0, 1, 0]) rotate([90, 0, 0])
      linear_extrude(1) back_face_2d(0, total_width, 0, H, r_);
    for (px = [r_, total_width - r_]) {
      translate([px, depth - r_, 0]) cylinder(r = r_, h = 1);
      translate([px, depth - r_, H - r_]) sphere(r = r_);
    }
    translate([r_, depth - r_, H - r_])
      rotate([0, 90, 0]) cylinder(r = r_, h = total_width - 2 * r_);
  }

module cavity()
  hull() {
    translate([0, wall + 1, 0]) rotate([90, 0, 0])
      linear_extrude(1)
        back_face_2d(wall, total_width - wall, plate_top, H - wall, r_i);
    for (px = [wall + r_i, total_width - wall - r_i]) {
      translate([px, depth - wall - r_i, plate_top]) cylinder(r = r_i, h = 1);
      translate([px, depth - wall - r_i, H - wall - r_i]) sphere(r = r_i);
    }
    translate([wall + r_i, depth - wall - r_i, H - wall - r_i])
      rotate([0, 90, 0]) cylinder(r = r_i, h = total_width - 2 * (wall + r_i));
  }

// Bottom opening: rounded front corners following the outline, a subtle 3 mm ease at the back.
module plan_in()
  hull() {
    for (px = [rim + r_rim, total_width - rim - r_rim])
      translate([px, depth - rim - r_rim]) circle(r = r_rim);
    for (px = [rim + r_back, total_width - rim - r_back])
      translate([px, rim + r_back]) circle(r = r_back);
  }

module trough()
  translate([0, 0, -1]) linear_extrude(lip + 1) plan_in();

// ---- Service windows: one behind each spot, hidden by the wall ----

module rrect2(w, h, r)
  hull()
    for (dx = [r, w - r], dz = [r, h - r])
      translate([dx, dz]) circle(r);

module service_windows()
  for (i = [0:spots - 1])
    translate([sx(i) - win_w / 2, wall + 1, win_z0])
      rotate([90, 0, 0])
        linear_extrude(wall + 2)
          rrect2(win_w, win_z1 - win_z0, 6);

// ---- Fixed printed cups (construction from mick/lamp-fittings) ----

module cups()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, plate_bot])
      cylinder(d = cup_od, h = spot_len + plate_t);

module cup_bores()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, -1])
      cylinder(d = cup_id, h = cap_bot + 1);

module cap_holes()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, cap_bot - 1]) {
      cylinder(d = 30, h = plate_t + 2);
      for (s = [-1, 1])
        translate([s * gu10_hole_span / 2, 0, 0])
          cylinder(d = 2.8, h = plate_t + 2);
    }

// ---- Printed tilting: pivot rings, swept clearance and the cartridge ----

module cart_sweep()
  hull()
    for (a = [-max_tilt, 0, max_tilt])
      translate([0, 0, pivot_rel])
        rotate([a, 0, 0])
          translate([0, 0, -pivot_rel - 1])
            cylinder(d = cart_od + 2.4, h = cart_h + 2);

module rings()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, plate_bot])
      cylinder(d = ring_od, h = ring_top - plate_bot);

module ring_carve()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, plate_bot])
      cart_sweep();

module pivot_holes()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, pivot_z]) {
      rotate([0, 90, 0])
        cylinder(d = 2.0, h = ring_od + 8, center = true);
      for (s = [-1, 1])
        translate([s * (ring_od / 2 - 0.6), 0, 0])
          rotate([0, 90, 0])
            cylinder(d = 4.5, h = 1.4, center = true);
    }

module cartridge_part()
  difference() {
    cylinder(d = cart_od, h = cart_h);
    translate([0, 0, -1]) cylinder(d = cup_id, h = spot_len + 1);
    translate([0, 0, spot_len - 1]) cylinder(d = 30, h = plate_t + 2);
    for (s = [-1, 1])
      translate([s * gu10_hole_span / 2, 0, spot_len - 1])
        cylinder(d = 2.8, h = plate_t + 2);
    translate([0, 0, pivot_rel])
      rotate([0, 90, 0])
        cylinder(d = 1.7, h = cart_od + 2, center = true);
  }

// ---- Store bought recessed fixtures: round cutouts, clip mounted ----

module recessed_openings()
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, plate_bot - 1])
      cylinder(d = cutout_d, h = plate_t + bezel_t + 2);

module bezel_bosses()
  if (flush_)
    for (i = [0:spots - 1])
      translate([sx(i), depth / 2, plate_top])
        cylinder(d = bezel_d + 6, h = bezel_t);

module bezel_pockets()
  if (flush_)
    for (i = [0:spots - 1])
      translate([sx(i), depth / 2, plate_bot - eps])
        cylinder(d = bezel_d + 1, h = bezel_t + eps);

module recessed_mock() {
  bz = flush_ ? 0 : -bezel_t;
  color("Gainsboro") {
    translate([0, 0, bz]) cylinder(d = bezel_d, h = bezel_t);
    translate([0, 0, bz + bezel_t]) cylinder(d = cutout_d - 3, h = recess_depth - bezel_t - 2);
    translate([0, 0, bz + recess_depth - 2]) cylinder(d = 24, h = 5);
  }
  color("WhiteSmoke") translate([0, 0, bz + 0.4]) cylinder(d = 50, h = 3);
}

// ---- Glue bosses at the cuts: the dovetail keys run through these ----

module join_blocks()
  if (segments > 1)
    for (j = [1:segments - 1]) {
      xi = j * seg_w;
      translate([xi - 12, wall, plate_top]) cube([24, 12, 12]);
      translate([xi - 12, depth - wall - 12, plate_top]) cube([24, 12, 12]);
      translate([xi - 12, depth / 2 - 6, H - wall - 12]) cube([24, 12, 12]);
    }

// ---- Dovetail segment cuts: the cut is a comb, not a plane ----

module bmask2d(j, grow) {
  xi = j * seg_w;
  translate([-10, -10]) square([xi + 10, H + 20]);
  if (j > 0)
    offset(delta = grow)
      for (zc = tooth_zs)
        polygon([[xi - 1, zc - 5], [xi + 8, zc - 8],
                 [xi + 8, zc + 8], [xi - 1, zc + 5]]);
}

module bmask(j, grow)
  translate([0, depth + 5, 0])
    rotate([90, 0, 0])
      linear_extrude(depth + 10)
        bmask2d(j, grow);

// ---- Wall mount ----

module keyholes()
  for (kx = [kx1, kx2])
    translate([kx, -1, 0]) rotate([-90, 0, 0]) {
      translate([0, -(H - 35), 0]) cylinder(d = 9, h = wall + 2);
      hull()
        for (dz = [0, 12])
          translate([0, -(H - 35) - dz, 0])
            cylinder(d = 4.5, h = wall + 2);
    }

// ---- Body ----

module body()
  difference() {
    union() {
      difference() {
        bar_solid();
        cavity();
        trough();
      }
      intersection() {
        union() {
          if (fixture == "cups") cups();
          if (fixture == "cartridges") rings();
          if (fixture == "recessed") bezel_bosses();
          join_blocks();
        }
        bar_solid();
      }
    }
    if (fixture == "cups") {
      cup_bores();
      cap_holes();
    }
    if (fixture == "cartridges") {
      ring_carve();
      pivot_holes();
    }
    if (fixture == "recessed") {
      recessed_openings();
      bezel_pockets();
    }
    keyholes();
    service_windows();
  }

module spot_mock()
  color("Gainsboro") {
    cylinder(d = 50, h = 6);
    translate([0, 0, 6]) cylinder(d1 = 50, d2 = 24, h = 32);
    translate([0, 0, 38]) cylinder(d = 24, h = 8);
  }

module display() {
  color(color_body) body();
  for (i = [0:spots - 1])
    translate([sx(i), depth / 2, plate_bot])
      if (fixture == "cartridges") {
        translate([0, 0, pivot_rel])
          rotate([tilt_show, 0, 0])
            translate([0, 0, -pivot_rel]) {
              color(color_body) cartridge_part();
              if (show_fixtures) spot_mock();
            }
      } else if (fixture == "recessed") {
        if (show_fixtures) recessed_mock();
      } else {
        if (show_fixtures) spot_mock();
      }
}

// ---- Layout ----

if (part == "cartridge") {
  translate([0, 0, cart_h]) rotate([180, 0, 0])
    color(color_body) cartridge_part();
} else if (part == "segment") {
  si = min(segment_index, segments);
  rotate([90, 0, 0])
    translate([-(si - 1) * seg_w, 0, 0])
      intersection() {
        color(color_body) body();
        difference() {
          bmask(si, 0);
          bmask(si - 1, 0.15);
        }
      }
} else {
  if (cutaway)
    difference() {
      display();
      translate([-10, -10, -10])
        cube([total_width + 20, depth / 2 + 10, H + 20]);
    }
  else
    display();
}

Comments

Context, not a score. Comments never move a model up or down the results.

No comments yet

Printed it? A note about your material and the clearance you landed on saves the next person a failed print.

Sign in to comment