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 lip. 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 flush, or the printed variants. The printed cup and tilt cartridge are seats that hold the lamp by its own 50 mm face rim: it rests on a solid bottom ring and two sprung snap bumps sit directly on the thin rim with light preload, clamping it so it can move neither down nor up, yet pops free with a firm pull for relamping. The hinge of the tilting cartridge sits low, just above the lamp face, which keeps the swing at the plate small, the plate hole compact and the bore transition shallow. Squircle rounding with exact superellipsoid corners; past the physical cap the exponent relaxes toward an ellipse and the bar height compensates for the roof curvature. Flat back, sharp bottom edge, service windows, dovetail joints. The printed cups descend from mick/lamp-fittings.
The image shows the solid OpenSCAD renders at part all · segment_number 1 · cutaway false · show_fixtures false · fixture cartridges · saw_diameter 74 · ring_diameter 93 · ring_thickness 4 · sink_rings_flush true · fixture_depth 120 · width 460 · depth 85 · height 100 · spots 3 · corner_rounding 86 · front_lip 25 · bottom_rim 7.5 · body_color White · print_segments 3 · wall_thickness 2.5 · tilt_range 15 · preview_tilt 0.
Bathroom mirror light bar
mick/mirror-light@3.4.1
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.
Parameters
from sourceDescription
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 lip. 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 flush, or the printed variants. The printed cup and tilt cartridge are seats that hold the lamp by its own 50 mm face rim: it rests on a solid bottom ring and two sprung snap bumps sit directly on the thin rim with light preload, clamping it so it can move neither down nor up, yet pops free with a firm pull for relamping. The hinge of the tilting cartridge sits low, just above the lamp face, which keeps the swing at the plate small, the plate hole compact and the bore transition shallow. Squircle rounding with exact superellipsoid corners; past the physical cap the exponent relaxes toward an ellipse and the bar height compensates for the roof curvature. Flat back, sharp bottom edge, service windows, dovetail joints. The printed cups descend from mick/lamp-fittings.
What you use it for
For recessed fixtures: set saw_diameter, ring_diameter, ring_thickness and fixture_depth from the fixture; the bar height follows automatically. For the printed cartridge: press the socket onto the lamp pins, drop the lamp into the cartridge from the open top; it clicks past the two bumps and is clamped between them and the bottom ring. Insert the loaded cartridge from below into its pivot ring and push the filament hinge pins in through the service window. To relamp, pull the lamp firmly upward out of the clips. Print the segments; each cut carries one dovetail key with a 0.15 mm allowance. Glue the mating faces and slide the segments together from the front. Wire in parallel through the service windows and hang the bar on the keyholes. 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 clip fingers are formed by four relief slots and sit at ninety degrees from the hinge pins, so the pins always run through solid wall. The spherical bumps sit low, their underside at the top of the thin lamp rim, and protrude only lightly from the bore, so the rim is clamped precisely between ring and bumps with a gentle snap; the spheres cam both ways so a firm pull releases. The hinge at seven millimetres above the face shrinks the swing envelope, so the round plate hole and the conical bore transition are compact and the bore reads as one continuous surface from the underside up. Corners are exact superellipsoid polyhedra, the shell is clipped to its bounding box, the cavity to the plate, and the bottom opening is a true inward offset of the outer footprint. part = segment exports one segment on its back, part = cartridge the seat collar print ready.
Parameters
fixture picks the spot mounting; saw_diameter, ring_diameter, ring_thickness, sink_rings_flush and fixture_depth describe a recessed fixture. width, depth, height and spots size the bar; height grows automatically when too small for the fixtures. corner_rounding, front_lip, bottom_rim and body_color set the look, print_segments and wall_thickness the print, segment_number picks the exported section, and cutaway plus show_fixtures control the preview. tilt_range and preview_tilt only matter for the printed cartridges.
Use with your agent
{
"mcpServers": {
"remixcad": {
"type": "http",
"url": "https://remix-cad.vercel.app/api/mcp"
}
}
}get_model("mick/mirror-light@3.4.1")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| Name | Default | Range | Unit | Description |
|---|---|---|---|---|
| part | "all" | all, segment, cartridge | ||
| segment_number | 1 | 1 to 6 step 1 | ||
| cutaway | false | |||
| show_fixtures | false | |||
| fixture | "cartridges" | recessed, cups, cartridges | ||
| saw_diameter | 74 | 50 to 90 step 1 | ||
| ring_diameter | 93 | 60 to 110 step 1 | ||
| ring_thickness | 4 | 2 to 8 step 0.5 | ||
| sink_rings_flush | true | |||
| fixture_depth | 120 | 60 to 150 step 5 | ||
| width | 460 | 300 to 800 step 10 | ||
| depth | 85 | 70 to 140 step 5 | ||
| height | 100 | 70 to 160 step 5 | ||
| spots | 3 | 2 to 5 step 1 | ||
| corner_rounding | 86 | 2 to 120 step 1 | ||
| front_lip | 25 | 8 to 30 step 1 | ||
| bottom_rim | 7.5 | 2 to 12 step 0.5 | ||
| body_color | "White" | White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod | ||
| print_segments | 3 | 1 to 6 step 1 | ||
| wall_thickness | 2.5 | 2 to 4 step 0.25 | ||
| tilt_range | 15 | 5 to 20 step 1 | ||
| preview_tilt | 0 | -20 to 20 step 1 |
Lineage
0 models depend on this oneOnly what this model came from and what came from it.
License
Whoever downloads this takes these obligations along- mick/mirror-light@3.4.1 is MIT
Source
main.scad is the entrypointmain.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 seats holding the lamp by its own face rim: a solid bottom ring
// below and two low, lightly protruding snap bumps clamping the thin rim,
// releasable with a firm pull. Low hinge for a compact swing. Dovetail joints.
/* [Model] */
// The whole bar, one print segment laid flat, or the seat cartridge print ready.
part = "all"; // [all, segment, cartridge]
// Which segment when part = segment.
segment_number = 1; // [1:1:6]
// Slice the display view open through the spots.
cutaway = false;
// Show the grey lamp and fixture dummies in the preview. Printed parts always show. Display only, never part of a print.
show_fixtures = false;
/* [Fixture] */
// How the spots are held: store bought recessed GU10 fixtures in round cutouts, or printed seats, fixed (cups) or tilting (cartridges).
fixture = "cartridges"; // [recessed, cups, cartridges]
// Saw diameter of the recessed fixture, the hole cut in the plate.
saw_diameter = 74; // [50:1:90]
// Outer diameter of the fixture trim ring.
ring_diameter = 93; // [60:1:110]
// Thickness of the fixture trim ring, for the flush seat. Measure yours.
ring_thickness = 4; // [2:0.5:8]
// Sink the fixture rings flush with the underside of the plate.
sink_rings_flush = true;
// Recess depth the fixture needs behind the plate. The bar grows automatically to fit it.
fixture_depth = 120; // [60:5:150]
/* [Size] */
// Width of the bar in mm.
width = 460; // [300:10:800]
// Depth from the wall in mm.
depth = 85; // [70:5:140]
// Height of the bar in mm. Grows automatically when too small for the fixtures.
height = 100; // [70:5:160]
// Number of GU10 spots.
spots = 3; // [2:1:5]
/* [Style] */
// One value for all rounded edges, squircle style. Past the physical cap of the bar the curve automatically relaxes toward an ellipse, so higher values keep looking rounder.
corner_rounding = 86; // [2:1:120]
// How far the front drops past the lamp faces, hiding them from view.
front_lip = 25; // [8:1:30]
// Thickness of the visible rim around the bottom opening.
bottom_rim = 7.5; // [2:0.5:12]
// Display colour of the body.
body_color = "White"; // [White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod]
/* [Print] */
// Number of print segments. Keep width / print_segments under your printer bed size.
print_segments = 3; // [1:1:6]
// Wall thickness of the shell.
wall_thickness = 2.5; // [2:0.25:4]
/* [Printed spot variants only, ignore for recessed] */
// Tilt range of the printed cartridges, degrees to either side.
tilt_range = 15; // [5:1:20]
// Tilt of the cartridges in the preview only, degrees. Positive tilts forward.
preview_tilt = 0; // [-20:1:20]
/* [Hidden] */
total_width = width;
rounding = corner_rounding;
lip = front_lip;
rim = bottom_rim;
wall = wall_thickness;
cutout_d = saw_diameter;
bezel_d = ring_diameter;
bezel_t = ring_thickness;
flush_bezels = sink_rings_flush;
recess_depth = fixture_depth;
segments = print_segments;
segment_index = segment_number;
color_body = body_color;
max_tilt = tilt_range;
tilt_angle = preview_tilt;
$fn = 128;
eps = 0.01;
clearance = 0.3;
plate_t = 3;
n_sq = 4;
sq_step = 3;
ball_step = 3;
seat_od = 61;
seat_bore = 51;
ring_t = 2;
ring_ap = 45;
cart_h = 14;
cup_h = 14;
plate_bot = lip;
plate_top = lip + plate_t;
flush_ = fixture == "recessed" && flush_bezels;
H0 = fixture == "recessed"
? max(height, lip + recess_depth + wall + (flush_ ? bezel_t : 0))
: height;
rm0 = min(H0 - 12, depth - 8, total_width / 4);
r0 = min(rounding, rm0);
ne0 = max(2, n_sq - max(rounding - rm0, 0) / 14);
ri0 = max(r0 - wall, 1);
dd0 = max(0, depth / 2 + cutout_d / 2 - (depth - wall - ri0));
sag0 = dd0 > 0
? ri0 * (1 - pow(max(1 - pow(min(dd0 / ri0, 0.999), ne0), 0.0001), 1 / ne0))
: 0;
H = fixture == "recessed" ? max(height, H0 + min(sag0, 80)) : height;
seg_w = total_width / segments;
r_max = min(H - 12, depth - 8, total_width / 4);
r_ = min(rounding, r_max);
n_eff = max(2, n_sq - max(rounding - r_max, 0) / 14);
r_i = max(r_ - wall, 1);
r_back = 3;
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_z = (lip + H) / 2;
cart_od = seat_od;
pivot_rel = 7;
pivot_z = lip + pivot_rel;
ring_wall = 2.5;
swing_hole_d = cart_od + 2.4 + 2 * sin(max_tilt) * (pivot_rel + ring_t + 1);
ring_od = swing_hole_d + 2 * ring_wall;
ring_top = pivot_z + 8;
tilt_show = max(-max_tilt, min(max_tilt, tilt_angle));
// ---- Squircle primitives ----
function sqpt(r, a) = [r * sign(cos(a)) * pow(abs(cos(a)), 2 / n_eff),
r * sign(sin(a)) * pow(abs(sin(a)), 2 / n_eff)];
module sq2d(r)
polygon([for (a = [0:sq_step:360 - sq_step]) sqpt(r, a)]);
function sqw(t) = pow(abs(cos(t)), 2 / n_eff);
function sqz(r, t) = r * sign(sin(t)) * pow(abs(sin(t)), 2 / n_eff);
module sqball(r) {
na = floor(360 / sq_step);
lats = [for (t = [-90 + ball_step:ball_step:90 - ball_step]) t];
nl = len(lats);
pts = concat(
[[0, 0, -r]],
[for (t = lats, a = [0:sq_step:360 - sq_step])
let (s = r * sqw(t))
[s * sign(cos(a)) * pow(abs(cos(a)), 2 / n_eff),
s * sign(sin(a)) * pow(abs(sin(a)), 2 / n_eff),
sqz(r, t)]],
[[0, 0, r]]
);
faces = concat(
[for (i = [0:na - 1]) [0, 1 + (i + 1) % na, 1 + i]],
[for (j = [0:nl - 2], i = [0:na - 1])
[1 + j * na + i,
1 + j * na + (i + 1) % na,
1 + (j + 1) * na + (i + 1) % na,
1 + (j + 1) * na + i]],
[for (i = [0:na - 1])
[len(pts) - 1,
1 + (nl - 1) * na + i,
1 + (nl - 1) * na + (i + 1) % na]]
);
polyhedron(points = pts, faces = faces, convexity = 4);
}
module sqrod(r, len)
rotate([0, 90, 0]) linear_extrude(len) sq2d(r);
// ---- Shell ----
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]) sq2d(r);
translate([x1 - r, z1 - r]) sq2d(r);
}
module bar_solid()
intersection() {
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]) linear_extrude(1) sq2d(r_);
translate([px, depth - r_, H - r_]) sqball(r_);
}
translate([r_, depth - r_, H - r_]) sqrod(r_, total_width - 2 * r_);
}
cube([total_width, depth, H]);
}
module cavity()
intersection() {
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]) linear_extrude(1) sq2d(r_i);
translate([px, depth - wall - r_i, H - wall - r_i]) sqball(r_i);
}
translate([wall + r_i, depth - wall - r_i, H - wall - r_i])
sqrod(r_i, total_width - 2 * (wall + r_i));
}
translate([0, wall, plate_top]) cube([total_width, depth, H]);
}
module bottom_plan_2d()
intersection() {
hull() {
square([total_width, 1]);
for (px = [r_, total_width - r_])
translate([px, depth - r_]) sq2d(r_);
}
square([total_width, depth]);
}
module plan_in()
offset(r = r_back)
offset(delta = -(rim + r_back))
bottom_plan_2d();
module trough()
translate([0, 0, -1]) linear_extrude(lip + 1) plan_in();
module spot_cut_guard()
translate([-1, wall, -50])
cube([total_width + 2, depth - 2 * wall, H + 100]);
// ---- Service windows ----
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);
// ---- Seat: bottom ring below, low snap bumps clamping the thin lamp rim ----
module seat_cuts(top) {
translate([0, 0, -ring_t - eps]) cylinder(d1 = 49, d2 = ring_ap, h = 1.5);
translate([0, 0, -ring_t - eps]) cylinder(d = ring_ap, h = ring_t + 2 * eps);
cylinder(d = seat_bore, h = top + 1);
for (a = [65, 115, 245, 295])
rotate(a)
translate([-1.5, seat_od / 2 - 8, 2.5])
cube([3, 10, top]);
}
// Low bumps, half sunk into the wall: the underside sits at the top of the
// thin lamp rim, clamping it against the ring with light preload.
module seat_bumps()
for (a = [90, 270])
rotate(a) translate([25.5, 0, 4.2]) sphere(d = 2.6);
// ---- Fixed cups: integral seats on the plate ----
module cups()
for (i = [0:spots - 1])
translate([sx(i), depth / 2, plate_bot - ring_t])
cylinder(d = seat_od, h = cup_h + ring_t);
module cup_bores()
for (i = [0:spots - 1])
translate([sx(i), depth / 2, plate_bot])
seat_cuts(cup_h);
module cup_bumps()
for (i = [0:spots - 1])
translate([sx(i), depth / 2, plate_bot])
seat_bumps();
// ---- Tilting cartridge: the same seat on a low filament hinge ----
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 - ring_t - 1])
cylinder(d = cart_od + 2.4, h = cart_h + ring_t + 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]) {
translate([0, 0, -ring_t - 2])
cylinder(d = swing_hole_d, h = plate_t + ring_t + 2 + eps);
translate([0, 0, plate_t - eps])
cylinder(d1 = swing_hole_d, d2 = cart_od + 2.4,
h = pivot_rel - plate_t + 2 * eps);
intersection() {
cart_sweep();
translate([-60, -60, plate_t - eps]) cube([120, 120, cart_h + 20]);
}
}
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() {
union() {
translate([0, 0, -ring_t + 1]) cylinder(d = seat_od, h = cart_h + ring_t - 1);
translate([0, 0, -ring_t]) cylinder(d1 = seat_od - 2, d2 = seat_od, h = 1);
}
seat_cuts(cart_h);
translate([0, 0, pivot_rel])
rotate([0, 90, 0])
cylinder(d = 1.7, h = cart_od + 2, center = true);
}
seat_bumps();
}
// ---- Store bought recessed fixtures ----
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);
}
// ---- Dovetail segment cuts ----
module bmask2d(j, grow) {
xi = j * seg_w;
translate([-10, -10]) square([xi + 10, H + 20]);
if (j > 0)
offset(delta = grow)
polygon([[xi - 1, tooth_z - 8], [xi + 8, tooth_z - 12],
[xi + 8, tooth_z + 12], [xi - 1, tooth_z + 8]]);
}
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()
union() {
difference() {
union() {
difference() {
bar_solid();
cavity();
trough();
}
intersection() {
union() {
if (fixture == "cups") cups();
if (fixture == "cartridges") rings();
if (fixture == "recessed") bezel_bosses();
}
bar_solid();
}
}
if (fixture == "cups")
intersection() { cup_bores(); spot_cut_guard(); }
if (fixture == "cartridges")
intersection() {
union() { ring_carve(); pivot_holes(); }
spot_cut_guard();
}
if (fixture == "recessed")
intersection() {
union() { recessed_openings(); bezel_pockets(); }
spot_cut_guard();
}
keyholes();
service_windows();
}
if (fixture == "cups") cup_bumps();
}
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("Silver") cartridge_part();
if (show_fixtures) spot_mock();
}
} else if (fixture == "cups") {
if (show_fixtures) spot_mock();
} else {
if (show_fixtures) recessed_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.
