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. 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, fixed cups or tilt cartridges on filament hinge pins. The printed variants include a snap in trim ring whose shoulder locks the lamp captive in the cup or cartridge. All rounding is squircle style with continuous curvature and true superellipsoid corners; the shell is clipped to its bounding box so the rounding can run far past half the bar depth. The bottom opening is a true offset of the outer footprint, so the visible rim stays exactly one rim width at any rounding. Flat back, sharp bottom edge, service windows behind the spots. Segments join with one printed dovetail key per joint and glue. 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.
Bathroom mirror light bar
mick/mirror-light@2.10.0
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 fascia. 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, fixed cups or tilt cartridges on filament hinge pins. The printed variants include a snap in trim ring whose shoulder locks the lamp captive in the cup or cartridge. All rounding is squircle style with continuous curvature and true superellipsoid corners; the shell is clipped to its bounding box so the rounding can run far past half the bar depth. The bottom opening is a true offset of the outer footprint, so the visible rim stays exactly one rim width at any rounding. Flat back, sharp bottom edge, service windows behind the spots. Segments join with one printed dovetail key per joint and glue. 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. For the printed cups or cartridges: twist the GU10 lamp into its socket, then press the trim ring (part = trimring, one per spot) into the bore until the four fingers click into the groove; the lamp is then held between the socket and the ring shoulder and cannot fall out. Pry the ring out to relamp. 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, feed the mains through the nearest window 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 squircle is a superellipse with exponent four and the corners are superellipsoids built from stacked squircle slices, so faces, edges and corners share continuous curvature. The hull is clipped to the bounding box, so large radii truncate at the flat back and bottom instead of breaking; the slider runs to 120 and is capped internally by depth and height. The bottom opening is computed as an inward offset of the actual outer bottom outline with a subtle rounding at the back corners, which guarantees a uniform rim at every rounding value. The printed bores carry a 56 mm counterbore with a snap groove around the 50 mm lamp face for the trim ring; the ring has eight flex fingers and four snap bumps. Mesh resolution runs at 128 facets with fine squircle sampling. part = segment exports one segment on its back, part = cartridge the tilt cartridge, part = trimring the snap ring.
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.10.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| Name | Default | Range | Unit | Description |
|---|---|---|---|---|
| part | "all" | all, segment, cartridge, trimring | ||
| segment_index | 1 | 1 to 6 step 1 | ||
| cutaway | false | |||
| show_fixtures | true | |||
| fixture | "recessed" | recessed, cups, cartridges | ||
| cutout_d | 75 | 50 to 90 step 1 | ||
| bezel_d | 93 | 60 to 110 step 1 | ||
| bezel_t | 4 | 2 to 8 step 0.5 | ||
| flush_bezels | true | |||
| recess_depth | 120 | 60 to 150 step 5 | ||
| total_width | 500 | 300 to 800 step 10 | ||
| depth | 100 | 70 to 140 step 5 | ||
| height | 100 | 70 to 160 step 5 | ||
| spots | 3 | 2 to 5 step 1 | ||
| rounding | 14 | 2 to 120 step 1 | ||
| lip | 15 | 8 to 30 step 1 | ||
| rim | 2.5 | 2 to 12 step 0.5 | ||
| color_body | "White" | White, Silver, Gainsboro, DimGray, Black, SlateGray, FireBrick, SteelBlue, ForestGreen, Goldenrod | ||
| segments | 3 | 1 to 6 step 1 | ||
| wall | 2.5 | 2 to 4 step 0.25 | ||
| max_tilt | 15 | 5 to 20 step 1 | ||
| tilt_angle | 0 | -20 to 20 step 1 | ||
| gu10_hole_span | 40 | 24 to 50 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@2.10.0 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 fixed cups or tilt cartridges on filament hinge pins, both with a
// snap in trim ring that locks the lamp captive. Squircle rounding with
// continuous curvature and superellipsoid corners, clipped to the bounding box.
// The bottom opening is a true offset of the outer footprint, so the rim stays
// uniform at any rounding. Segments join with one dovetail key and glue.
/* [Model] */
// The whole bar, one print segment laid flat, the tilt cartridge, or the snap trim ring.
part = "all"; // [all, segment, cartridge, trimring]
// 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 value for all rounded edges, squircle style with continuous curvature. Large values truncate against the flat back and bottom; capped internally by depth and height.
rounding = 14; // [2:1:120]
// 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 = 128;
eps = 0.01;
clearance = 0.3;
plate_t = 3;
n_sq = 4;
sq_step = 3; // squircle polygon step, degrees
ball_step = 6; // superellipsoid slice step, degrees
spot_len = 46;
cup_id = 50 + 2 * clearance;
cbore_d = cup_id + 5.4;
cbore_h = 6;
groove_d = cbore_d + 2.4;
ring_aperture = 44;
cup_od = cbore_d + 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 - 12, depth - 8, total_width / 4);
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;
// Printed tilting geometry
cart_od = cup_od;
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));
// ---- Squircle primitives ----
function sqpt(r, a) = [r * sign(cos(a)) * pow(abs(cos(a)), 2 / n_sq),
r * sign(sin(a)) * pow(abs(sin(a)), 2 / n_sq)];
module sq2d(r)
polygon([for (a = [0:sq_step:360 - sq_step]) sqpt(r, a)]);
function sqw(t) = pow(abs(cos(t)), 2 / n_sq);
function sqz(r, t) = r * sign(sin(t)) * pow(abs(sin(t)), 2 / n_sq);
module sqball(r) {
ts = [for (t = [-90:ball_step:90]) t];
for (i = [0:len(ts) - 2])
hull() {
translate([0, 0, sqz(r, ts[i])])
linear_extrude(0.02) sq2d(max(r * sqw(ts[i]), 0.05));
translate([0, 0, sqz(r, ts[i + 1])])
linear_extrude(0.02) sq2d(max(r * sqw(ts[i + 1]), 0.05));
}
}
module sqrod(r, len)
rotate([0, 90, 0]) linear_extrude(len) sq2d(r);
// ---- Shell: clipped to the bounding box so large radii stay valid ----
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, 0]) cube([total_width, depth, H]);
}
// The outer footprint at the bottom, in the plan view.
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]);
}
// Bottom opening: a true inward offset of the outer footprint, so the rim is
// exactly one rim width everywhere at any rounding. Back corners eased subtly.
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();
// ---- 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 with snap ring groove ----
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, 0]) {
translate([0, 0, -1]) cylinder(d = cup_id, h = cap_bot + 1);
translate([0, 0, -1]) cylinder(d = cbore_d, h = plate_bot + cbore_h + 1);
translate([0, 0, plate_bot + cbore_h - 2]) cylinder(d = groove_d, h = 2);
}
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, -1]) cylinder(d = cbore_d, h = cbore_h + 1);
translate([0, 0, cbore_h - 2]) cylinder(d = groove_d, h = 2);
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);
}
// ---- Snap trim ring: locks the lamp captive, finishes the opening ----
module trimring_part() {
rb = (cbore_d - 0.3) / 2;
difference() {
union() {
cylinder(d = cup_od, h = 1.5);
cylinder(d = cbore_d - 0.3, h = 1.5 + cbore_h - 0.5);
for (a = [0, 90, 180, 270])
rotate(a) translate([rb, 0, 1.5 + cbore_h - 2.5]) sphere(d = 2.6);
}
translate([0, 0, -1]) cylinder(d = ring_aperture, h = 20);
for (a = [0:45:315])
rotate(a + 22.5) translate([-1.5, rb - 6, 3]) cube([3, 10, 12]);
}
}
// ---- 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);
}
// ---- Dovetail segment cuts: one key per joint, through both walls ----
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()
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") {
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 == "trimring") {
color(color_body) trimring_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.
