Skip to main content

Slider

A slider mate leaves one degree of freedom: translation along the shared Z axis. Everything else — the other two translations and all three rotations — is locked. It is the joint of a carriage on a rail, a drawer in a cabinet, a key in a keyway.

Free motiontravel along Z

In the viewport

  1. Click Slider on the assembly toolbar and pick the two connectors — the rail's first, then the carriage's.
  2. The carriage snaps onto the rail. Drag it in the viewport: it moves along the rail and nowhere else.
  3. Offset takes a Z value only (the two frames share their axis, so an X or Y offset would contradict the joint); it sets where the carriage rests. Limits bound the travel in document units.
  4. Click Apply. Right-click the joint's row in the Joints panel and choose Animate… to drive it back and forth.

Carriage part-way along its rail

The code behind it

Both connectors point Z along the direction of travel. Each is a face frame — the rail's top face, the carriage's groove ceiling — given X across the rail with xDirection: 'y' and then turned 90° about that X. Built the same way, the two frames meet face-to-face with their X axes agreeing, so the carriage lands upright on the rail with no further options:

rail.part.js
rail.part.js
import { part, sketch, line, extrude, chamfer, select, connector } from 'fluidcad/core';
import { face } from 'fluidcad/filters';
import { coincident, distance, fix, horizontal, vertical } from 'fluidcad/constraints';

// A 120 mm linear rail: a 20 × 12 bar along X with chamfered top edges.
export const rail = part('Rail', () => {
sketch('xy', () => {
const b = line([-60, -10], [60, -10]);
const r = line([60, -10], [60, 10]);
const t = line([60, 10], [-60, 10]);
const l = line([-60, 10], [-60, -10]);
coincident(b.end(), r.start());
coincident(r.end(), t.start());
coincident(t.end(), l.start());
coincident(l.end(), b.start());
horizontal(b);
horizontal(t);
vertical(r);
vertical(l);
fix(b.start(), [-60, -10]);
distance(b.start(), b.end(), 120);
distance(r.start(), r.end(), 20);
});
const body = extrude(12);
chamfer(1.5, body.endEdges());
// The track frame, on the top face: X across the rail (world Y), then
// turned 90° about that X so Z runs along the rail. The carriage's
// frame is built the same way, so the two meet face-to-face with their
// X axes agreeing, and a slider mate frees exactly the shared Z.
connector('track', select(face().planar().onPlane('xy', 12)), { xDirection: 'y' }).rotate('x', 90);
});
carriage.part.js
carriage.part.js
import { part, sketch, line, extrude, color, select, connector } from 'fluidcad/core';
import { face } from 'fluidcad/filters';
import { coincident, distance, fix, horizontal, vertical } from 'fluidcad/constraints';

// A 30 mm carriage that straddles the rail: a U profile on the YZ plane —
// 30 wide, 20 tall, with a 20.4 × 12 groove that rests on the rail's top
// and clears its sides by 0.2 — extruded along X.
export const carriage = part('Carriage', () => {
sketch('yz', () => {
const l1 = line([-15, 0], [-10.2, 0]);
const l2 = line([-10.2, 0], [-10.2, 12]);
const l3 = line([-10.2, 12], [10.2, 12]);
const l4 = line([10.2, 12], [10.2, 0]);
const l5 = line([10.2, 0], [15, 0]);
const l6 = line([15, 0], [15, 20]);
const l7 = line([15, 20], [-15, 20]);
const l8 = line([-15, 20], [-15, 0]);
coincident(l1.end(), l2.start());
coincident(l2.end(), l3.start());
coincident(l3.end(), l4.start());
coincident(l4.end(), l5.start());
coincident(l5.end(), l6.start());
coincident(l6.end(), l7.start());
coincident(l7.end(), l8.start());
coincident(l8.end(), l1.start());
horizontal(l1);
horizontal(l3);
horizontal(l5);
horizontal(l7);
vertical(l2);
vertical(l4);
vertical(l6);
vertical(l8);
fix(l8.start(), [-15, 20]);
distance(l7.start(), l7.end(), 30);
distance(l8.start(), l8.end(), 20);
distance(l3.start(), l3.end(), 20.4);
distance(l2.start(), l2.end(), 12);
});
extrude(30);
color('steelblue');
// The groove ceiling, built like the rail's `track` frame: X across the
// carriage (world Y), then turned 90° about that X so Z runs along it.
connector('slide', select(face().planar().onPlane('xy', 12)), { xDirection: 'y' }).rotate('x', 90);
});
linear-stage.assembly.js
import { assembly, insert, mate } from 'fluidcad/core';
import { rail } from './asm-rail.part.js';
import { carriage } from './asm-carriage.part.js';

export const linearStage = assembly('linear-stage', () => {
const track = insert(rail).grounded();
const slide = insert(carriage).translate(0, 0, 40);

// Slider leaves one degree of freedom: travel along the shared Z, which
// both parts' frames point along their length. The carriage sits over
// the rail and slides; .offset(0, 0, d) sets where it rests and
// .limits() bounds the travel, both in document units (mm here).
mate('slider', track.connectors.track, slide.connectors.slide).offset(0, 0, 25).limits(-45, 45);
});

Options

mate('slider', track.connectors.track, slide.connectors.slide)
.offset(0, 0, 25) // rest 25 along the rail (Z only)
.limits(-45, 45) // travel bounds, in document units
.flip() // reverse which way the carriage faces along the rail

.offset(x, y, z) with a non-zero x or y is refused on a slider.

Choosing the connectors

The free axis is the connectors' Z, so the connectors must point along the direction of travel. A face connector points out of its face; turn it with .rotate() on the connector, or pick a straight edge, whose frame already has Z along the edge.

The mate also lines up the two frames' X axes, and on a slider that fixes the roll about the rail. Two face frames on facing faces get opposite default X directions, so turning each about its own Y leaves the second part rolled half a turn. Give both connectors the same xDirection (the rail and carriage use 'y', across the rail) and turn both about that X instead — they then meet face-to-face as they are. .rotate(180) on the mate spins a part that still lands upside down.