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, 500 x 100 x 100 mm by default. Three GU10 spots point straight down through openings in a recessed bottom plate. The front fascia runs 15 mm past that plate, so from the front you see a clean bar and no lamps: the light washes down over the mirror. The back is flat and sits flush against the wall, but its top corners are rounded on the same radius as the front, so the corner rounding carries through from the wall to the front face without tapering to a point. The top front edge and the vertical front edges share that radius and meet in spherical corners; the bottom edge is sharp. Behind each spot the back wall has a large service window: the wall hides them, and they give full access to mount and wire the sockets. The bottom opening follows the outline at a constant offset set by rim. The GU10 holder cups are the ones from mick/lamp-fittings, built into the body. The bar is split into three segments with dowel joints: at the defaults each segment is 167 x 100 x 100 mm, within an A1 Mini.

The image shows the solid OpenSCAD renders at part all · segment_index 1 · cutaway false · total_width 500 · height 100 · depth 100 · rounding 14 · spots 3 · lip 15 · rim 2.5 · segments 3 · wall 2.5 · plate_t 3 · gu10_hole_span 40 · smoothness 96 · color_body White.

MIT

Bathroom mirror light bar

mick/mirror-light@1.7.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
300800, steps of 10
70140, steps of 5
70140, steps of 5
240, steps of 1
25, steps of 1

Showing the render for these values.

Description

What is this

A modern wall mounted light bar for above a bathroom mirror, 500 x 100 x 100 mm by default. Three GU10 spots point straight down through openings in a recessed bottom plate. The front fascia runs 15 mm past that plate, so from the front you see a clean bar and no lamps: the light washes down over the mirror. The back is flat and sits flush against the wall, but its top corners are rounded on the same radius as the front, so the corner rounding carries through from the wall to the front face without tapering to a point. The top front edge and the vertical front edges share that radius and meet in spherical corners; the bottom edge is sharp. Behind each spot the back wall has a large service window: the wall hides them, and they give full access to mount and wire the sockets. The bottom opening follows the outline at a constant offset set by rim. The GU10 holder cups are the ones from mick/lamp-fittings, built into the body. The bar is split into three segments with dowel joints: at the defaults each segment is 167 x 100 x 100 mm, within an A1 Mini.

What you use it for

Print all segments and glue them on 4 mm dowels or filament pins. Through the service windows in the back, screw a store bought GU10 socket on top of each cup and wire the sockets in parallel on the bench. Feed the mains from the wall through the nearest window, connect it, and hang the bar on two screws through the keyhole slots. The lamp twists in from below and sits flush with the bottom plate. Use LED GU10 lamps only, print in PETG or ASA for a bathroom, keep the fixture out of the shower zones and have the mains connection checked if you are not certain of it.

Design notes

The shell is a single convex hull: a flat back plate shaped as a rectangle with rounded top corners, vertical cylinders on the front corners, a horizontal cylinder along the top front edge and a sphere in each top front corner, all on one radius. The hull blends the rounded back corners into the front corner spheres, so the top corners are soft along their whole depth while the back plane itself stays flush with the wall. The cavity is the same construction inset by one wall and the bottom opening is the plan outline offset inward by the rim thickness. One service window sits behind each spot, leaving a stiff frame: a full border, solid columns between the windows and solid strips at the segment cuts where the dowels run. The keyholes sit in the columns between the first and last pair of windows, offset from the cuts so no keyhole lands on a glue line. Each cup is a tube with a top cap that has the pin pass-through and two fixing holes for the socket, the same construction as the parent model. part = segment exports one segment on its back for printing; some support is needed inside. Choose spots and segments so the cuts miss the cups: three and three is safe.

Parameters

total_width, height and depth size the bar, lip sets how far the fascia drops past the lamp faces and rim sets the thickness of the visible bottom rim around the opening. rounding is the single radius for the top front edge, the vertical front edges, the corner blends and the top corners of the back outline; the back plane is always flat and the bottom edge always sharp. spots and segments set the count of lights and print sections, segment_index picks which section part = segment shows. wall and plate_t shape the shell, gu10_hole_span matches the socket, cutaway opens the display view and color_body sets the display colour.

Use with your agent
{
  "mcpServers": {
    "remixcad": {
      "type": "http",
      "url": "https://remix-cad.vercel.app/api/mcp"
    }
  }
}
get_model("mick/mirror-light@1.7.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
segment_index11 to 6 step 1
cutawayfalse
total_width500300 to 800 step 10
height10070 to 140 step 5
depth10070 to 140 step 5
rounding142 to 40 step 1
spots32 to 5 step 1
lip158 to 30 step 1
rim2.52 to 12 step 0.5
segments31 to 6 step 1
wall2.52 to 4 step 0.25
plate_t32 to 5 step 0.5
gu10_hole_span4024 to 50 step 1
smoothness9624 to 160 step 8
color_body"White"White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod

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@1.7.0 is MIT

Source

main.scad is the entrypoint
main.scad
// Bathroom mirror light bar. Remix of mick/lamp-fittings: the GU10 holder cups
// from that model are built into a wall mounted bar. Spots point down behind a
// front lip, so the lamps are hidden from the front. The back plane is flat
// against the wall with rounded top corners that blend into the spherical front
// corners. Behind each spot a large service window in the back wall gives access
// to mount and wire the sockets; the wall hides the windows once hung. Split
// into segments that fit a small printer bed and join on 4 mm dowels.

/* [Model] */
// The whole bar, or one print segment laid flat.
part = "all"; // [all, segment]
// Which segment when part = segment.
segment_index = 1; // [1:1:6]
// Slice the display view open through the spots.
cutaway = false;

/* [Size] */
// Width of the bar in mm.
total_width = 500; // [300:10:800]
// Height of the front fascia in mm.
height = 100; // [70:5:140]
// Depth from the wall in mm.
depth = 100; // [70:5:140]

/* [Rounding] */
// One radius for all rounded edges: the top front edge, the vertical front edges, the corner blends and the top corners of the back outline. The back plane always stays flat against the wall and the bottom edge always stays sharp.
rounding = 14; // [2:1:40]

/* [Light] */
// Number of GU10 spots.
spots = 3; // [2:1:5]
// 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]

/* [Build] */
// 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]
// Thickness of the bottom plate that carries the spots.
plate_t = 3; // [2:0.5:5]

/* [GU10 socket, measure yours] */
// Centre distance of the two fixing holes of your GU10 socket.
gu10_hole_span = 40; // [24:1:50]

/* [Quality] */
// Facets on round surfaces.
smoothness = 96; // [24:8:160]

/* [Colour] */
// Display colour of the body.
color_body = "White"; // [White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod]

/* [Hidden] */
$fn = smoothness;
eps = 0.01;
clearance = 0.3;
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;      // lamp sits flush with the plate underside
seg_w = total_width / segments;
r_ = min(rounding, height / 2 - 2, depth / 2 - 2, total_width / 4);
r_i = max(r_ - wall, 1);
r_rim = max(r_ - rim, 1);
spacing = total_width / spots;
win_w = max(spacing - 56, 40);       // service window width
win_z0 = plate_top + 4;              // service window bottom
win_z1 = height - 14;                // service window top
function sx(i) = (i + 0.5) * spacing;
// Keyholes in the solid columns between the outermost window pairs, offset from the segment cuts.
kx1 = (sx(0) + sx(1)) / 2 - 12;
kx2 = (sx(spots - 2) + sx(spots - 1)) / 2 + 12;

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

// A rectangle in the wall plane with rounded top corners.
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, height, r_);
    for (px = [r_, total_width - r_]) {
      translate([px, depth - r_, 0]) cylinder(r = r_, h = 1);
      translate([px, depth - r_, height - r_]) sphere(r = r_);
    }
    translate([r_, depth - r_, height - 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, height - 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, height - wall - r_i]) sphere(r = r_i);
    }
    translate([wall + r_i, depth - wall - r_i, height - wall - r_i])
      rotate([0, 90, 0]) cylinder(r = r_i, h = total_width - 2 * (wall + r_i));
  }

// Bottom opening: the plan outline inset by the rim thickness, front corners following the rounding.
module plan_in()
  hull() {
    translate([rim, rim]) square([total_width - 2 * rim, 1]);
    for (px = [rim + r_rim, total_width - rim - r_rim])
      translate([px, depth - rim - r_rim]) circle(r = r_rim);
  }

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);

// ---- Spot 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);
    }

// ---- Segment joints ----

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, height - wall - 12]) cube([24, 12, 12]);
    }

module dowel_holes()
  if (segments > 1)
    for (j = [1:segments - 1]) {
      xi = j * seg_w;
      for (p = [[wall + 6, plate_top + 6],
                [depth - wall - 6, plate_top + 6],
                [depth / 2, height - wall - 6]])
        translate([xi, p[0], p[1]])
          rotate([0, 90, 0])
            cylinder(d = 4.2, h = 24, center = true);
    }

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

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

// ---- Body ----

module body()
  difference() {
    union() {
      difference() {
        bar_solid();
        cavity();
        trough();
      }
      intersection() {
        union() {
          cups();
          join_blocks();
        }
        bar_solid();
      }
    }
    cup_bores();
    cap_holes();
    dowel_holes();
    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]) spot_mock();
}

// ---- Layout ----

if (part == "segment") {
  si = min(segment_index, segments);
  rotate([90, 0, 0])
    translate([-(si - 1) * seg_w, 0, 0])
      intersection() {
        color(color_body) body();
        translate([(si - 1) * seg_w, -10, -10])
          cube([seg_w, depth + 20, height + 20]);
      }
} else {
  if (cutaway)
    difference() {
      display();
      translate([-10, -10, -10])
        cube([total_width + 20, depth / 2 + 10, height + 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