Building a CSWP Sample Exam Part

In this tutorial, you'll build the parametric part from the SolidWorks CSWP Sample Exam. The CSWP (Certified SolidWorks Professional) exam tests your ability to build parts from engineering drawings, then modify parameters and recalculate. It covers parametric variables, arc/offset sketch geometry, reference planes, hollow cylinders with chamfers, counterbore holes, face projection, and edge selection filters.
The tutorial is split into two parts matching the exam stages:
- Part 1 — Build the initial part from the exam drawings
- Part 2 — Modify the part with additional features
:::tip Checking mass properties In the CSWP exam, each question asks you to calculate the mass of the part for a given set of parameters. To check the mass of your model in FluidCAD, click the info button in the bottom-right corner of the 3D viewer, then select the shape. The mass properties panel will display the volume and mass of the selected shape. Use this to verify your answers against the exam answer key. :::
Create a new file called cswp-sample-exam.fluid.js in your project.
Setup
Start with imports and the exam parameters. Using variables makes the model fully parametric — change a value and the entire part updates, just like in the real exam.
import {
arc, chamfer, circle, cut, extrude, fillet, hLine, hMove,
line, move, offset, plane, project, rect, select, sketch,
subtract, tArc, vLine, vMove
} from 'fluidcad/core';
import { edge, face } from 'fluidcad/filters';
// CSWP Exam Parameters — Stage 1
const A = 213; // height
const B = 200; // width
const C = 170; // support size
const D = 130; // pipe length
const E = 41; // inner bore diameter
const X = A / 3; // front pipe diameter
const Y = B / 3 + 10; // right pipe diameter
const leftOffset = B - C;
AandB— overall height and width of the base plateC— determines the size of the L-shaped support (the support spans fromB - CtoBhorizontally and from0toCvertically)D— length of the cylindrical pipesE— inner bore diameter of the pipesXandY— outer diameters of the front and right pipes, derived fromAandBleftOffset— the horizontal position where the support starts, computed asB - C
Part 1: Build the Initial Part
Step 1: Base Plate
Sketch a rounded rectangle on the XY plane and extrude it to create the base plate.
sketch("xy", () => {
rect(B, A).radius(10);
})
const base = extrude(25);
rect(B, A) creates a rectangle of width B (200) and height A (213). The .radius(10) rounds all four corners with a 10mm radius. The base is extruded 25mm thick.

Step 2: L-Shaped Support
The L-shaped support sits on top of the base. Its profile is made of two perpendicular lines connected by an arc, then offset inward and closed with straight lines.
Sketch the profile
sketch("xy", () => {
move([leftOffset, 0]);
const l1 = vLine(80)
move([B, C]);
const l2 = hLine(-80)
arc(l1.end(), l2.end()).center([leftOffset, C])
const o = offset(15)
line(l1.start(), o.start())
line(l2.start(), o.end())
});
move([leftOffset, 0])positions the cursor at the left edge of the supportvLine(80)draws an 80mm vertical line upwardmove([B, C])jumps to the top-right corner, thenhLine(-80)draws 80mm to the leftarc(l1.end(), l2.end()).center([leftOffset, C])connects the two line endpoints with an arc, using[leftOffset, C]as the center point — this creates the curved corner of the Loffset(15)offsets the arc inward by 15mm to give the support wall thickness- The two
line()calls close the profile by connecting the vertical and horizontal lines to the offset arc

Extrude the support
const support = extrude(95)
The support is extruded 95mm upward from the base plane. Since it shares the same XY sketch plane as the base, it rises from ground level and extends well above the 25mm base plate.

Step 3: Cylindrical Pipes
Two hollow pipes extend from the support — one from the front face and one from the right face. Each is created by extruding a circle on an offset reference plane, then cutting a smaller bore through it.
Pipe 1 — Sketch on offset plane
First, create a reference plane offset 10mm from the front of the support. Then sketch a circle for the pipe's outer profile:
const p1 = plane("front", 10);
sketch(p1, () => {
move([leftOffset, 95]);
hMove(7.5)
circle(X)
});
plane("front", 10)creates a reference plane 10mm in front of the support facemove([leftOffset, 95])positions the cursor at the support's left edge, at the top of the support (95mm high)hMove(7.5)shifts 7.5mm to the right to center the pipe on the support wallcircle(X)draws the outer circle with diameterX(= A/3)
Pipe 1 — Extrude, bore, and chamfer
const cylBody1 = extrude(-D)
circle(E, cylBody1.startFaces())
const cylCut1 = cut()
chamfer(2, cylCut1.startEdges(), cylCut1.endEdges())
extrude(-D)extends the pipe backward (away from the viewer) byD(130mm) — the negative direction pushes it into and through the supportcircle(E, cylBody1.startFaces())sketches a smaller circle of diameterE(41mm) on the pipe's far end facecut()bores through the entire pipe, making it hollowchamfer(2, ...)adds a 2mm chamfer to both the start and end edges of the bore

Pipe 2 — Right
The right pipe follows the same pattern on the right side of the support:
const p2 = plane("right", B + 10)
sketch(p2, () => {
move([C - 7.5, 95]);
circle(Y)
});
const cylBody2 = extrude(-D)
circle(E, cylBody2.startFaces())
const cylCut2 = cut()
chamfer(2, cylCut2.startEdges(), cylCut2.endEdges())
plane("right", B + 10)creates a reference plane 10mm beyond the right edge of the basemove([C - 7.5, 95])centers the pipe on the support wall on the right side- The extrude, bore, cut, and chamfer steps are identical to Pipe 1, but with diameter
Y(= B/3 + 10) for the outer circle

Step 4: Corner Block & Counterbore
A rectangular block is added at the front-right corner of the base, with a through-all hole and a counterbore on top.
Corner sketch
sketch("xy", () => {
move([B, 0])
rect(-60, 60).radius(10, 0, 15, 0);
});
move([B, 0]) positions at the right edge, then rect(-60, 60) draws a 60x60 rectangle extending to the left and upward. The .radius(10, 0, 15, 0) rounds two of the four corners — 10mm on the top-left and 15mm on the bottom-left.

Corner extrusion
const corner = extrude(35);
The block is extruded 35mm, taller than the 25mm base plate.

Through-all hole and counterbore
circle(15, corner.endFaces())
cut()
circle(30, corner.endFaces())
cut(10)
circle(15, corner.endFaces())sketches a 15mm radius circle on the top face of the corner block, andcut()with no depth argument cuts through the entire blockcircle(30, corner.endFaces())adds a larger 30mm radius circle on the same face, andcut(10)cuts only 10mm deep — creating the counterbore recess

Step 5: Face Pocket
The final feature of Part 1 is a pocket cut into the top of the base plate. It's created by projecting the L-shaped support's footprint, offsetting it inward, and cutting down.
Select and project the face
const topFace = select(face().onPlane("xy", 25).hasEdge(edge().line(45)));
sketch(base.endFaces(), () => {
project(topFace);
offset(-9, true)
});
face().onPlane("xy", 25)finds faces at the top of the base plate (25mm height).hasEdge(edge().line(45))narrows it to the face that has a 45mm long line edge — this is the L-shaped support's footprintproject(topFace)projects the outline of that face onto the sketchoffset(-9, true)shrinks the projected outline inward by 9mm, and thetrueflag discards the original projection, keeping only the offset

Cut the pocket
const c = cut(20)
cut(20) removes material 20mm deep, creating the pocket.

Fillet the pocket edges
fillet(10, c.internalEdges())
c.internalEdges() selects the internal edges of the pocket (the edges at the bottom where the cut meets the base), and fillet(10, ...) rounds them with a 10mm fillet.

Part 1 — Full Code
// @screenshot waitForInput
import { arc, chamfer, circle, cut, extrude, fillet, hLine, hMove, line, move, offset, plane, project, rect, select, sketch, subtract, tArc, vLine, vMove } from 'fluidcad/core';
import { edge, face } from 'fluidcad/filters';
// CSWP Exam Parameters — Stage 1
const A = 213;
const B = 200;
const C = 170;
const D = 130;
const E = 41;
const X = A / 3;
const Y = B / 3 + 10;
const leftOffset = B - C;
// Base plate
sketch("xy", () => {
rect(B, A).radius(10);
})
const base = extrude(25);
// L-shaped support
sketch("xy", () => {
move([leftOffset, 0]);
const l1 = vLine(80)
move([B, C]);
const l2 = hLine(-80)
arc(l1.end(), l2.end()).center([leftOffset, C])
const o = offset(15)
line(l1.start(), o.start())
line(l2.start(), o.end())
});
const support = extrude(95)
// Pipe 1 — front
const p1 = plane("front", 10);
sketch(p1, () => {
move([leftOffset, 95]);
hMove(7.5)
circle(X)
});
const cylBody1 = extrude(-D)
circle(E, cylBody1.startFaces())
const cylCut1 = cut()
chamfer(2, cylCut1.startEdges(), cylCut1.endEdges())
// Pipe 2 — right
const p2 = plane("right", B + 10)
sketch(p2, () => {
move([C - 7.5, 95]);
circle(Y)
});
const cylBody2 = extrude(-D)
circle(E, cylBody2.startFaces())
const cylCut2 = cut()
chamfer(2, cylCut2.startEdges(), cylCut2.endEdges())
// Corner block
sketch("xy", () => {
move([B, 0])
rect(-60, 60).radius(10, 0, 15, 0);
});
const corner = extrude(35);
// Through-all hole
circle(15, corner.endFaces())
cut()
// Counterbore
circle(30, corner.endFaces())
cut(10)
// Face pocket
const topFace = select(face().onPlane("xy", 25).hasEdge(edge().line(45)));
sketch(base.endFaces(), () => {
project(topFace);
offset(-9, true)
});
const c = cut(20)
fillet(10, c.internalEdges())
Verify with exam answers
With the Stage 1 test 1 parameters above (A=213, B=200, C=170, D=130, E=41), the mass should be 14207.34 grams (using Alloy Steel with density 0.0077 g/mm^3). Try changing the parameters to test 2 (A=225, B=210, C=176, D=137, E=39) and test 3 (A=209, B=218, C=169, D=125, E=41) to verify you get 16490.45 g and 15100.47 g respectively.
Part 2: Modify the Part
Stage 2 of the CSWP exam modifies the initial part. The key changes are:
- Remove corner radii from the base plate
- Change Y formula from
B/3 + 10toB/3 + 15 - Change chamfers to angled (2mm x 30 degrees)
- Remove the corner block (no counterbore hole)
- Add a second pocket cut into the base
- Add a key slot on the front pipe
- Add fillets on the base plate side edges
Update the parameters at the top of your file:
// CSWP Exam Parameters — Stage 2
const A = 221;
const B = 211;
const C = 165;
const D = 121;
const E = 37;
const X = A / 3;
const Y = B / 3 + 15; // changed from B/3 + 10
const leftOffset = B - C;
Step 6: Angled Chamfers & Second Pocket
Base plate and chamfer changes
The base plate no longer has rounded corners:
sketch("xy", () => {
rect(B, A); // no .radius(10)
})
The pipe chamfers change from equal-distance to angled. Instead of chamfer(2, ...), use:
chamfer(2, 30, true, cylCut1.startEdges(), cylCut1.endEdges())
The three arguments (2, 30, true) specify a 2mm distance at a 30-degree angle, with true indicating the angle is measured from the face rather than the edge.
First pocket — different face selection
Since the corner block is removed, the face selector changes. Instead of matching a face with a 45-degree edge, use edge count:
const topFace1 = select(face().onPlane("xy", 25).edgeCount(5));
sketch(base.endFaces(), () => {
project(topFace1);
offset(-9, true)
});
let c1 = cut(20)
fillet(10, c1.internalEdges())
edgeCount(5) selects the face with exactly 5 edges — the L-shaped footprint without the corner block interfering. The rest follows the same project-offset-cut-fillet pattern as Part 1.

Second pocket — sketch
A second pocket is cut on the opposite side of the base, using a manually constructed profile that mirrors the L-shape:
sketch(base.endFaces(), () => {
const outerOffset = 9;
move([0, 0])
vMove(A - outerOffset)
hMove(outerOffset)
const l1 = hLine(B - 80 - outerOffset * 2)
const l2 = vLine(l1.start(), -A + 80 + outerOffset * 2)
const l3 = hLine(l2.end(), B - C - outerOffset)
const l4 = vLine(l1.end(), -A + C + outerOffset)
tArc(l4.end(), l3.end(), l4.tangent())
});
- The sketch starts near the top-left corner of the base, offset 9mm inward from the edges
- Four lines trace the pocket boundary, following the L-shape in reverse
tArc(l4.end(), l3.end(), l4.tangent())creates a tangent arc connecting the two open endpoints — the arc is tangent tol4, creating a smooth curved corner that mirrors the support's arc

Second pocket — cut and fillet
const c2 = cut(20)
fillet(10, c2.internalEdges())
The pocket is cut 20mm deep and its internal edges are filleted with a 10mm radius, matching the first pocket.

Step 7: Key Slot & Base Fillets
Key slot on front pipe
A key slot is cut into the front pipe by projecting the pipe face, offsetting it, then subtracting a rectangular notch:
sketch(plane(cylBody1.startFaces(), -30), () => {
let p = project(cylBody1.startFaces());
let o = offset(-10)
move(p.end())
let r = rect(15).centered('horizontal')
const s = subtract(p, r)
subtract(s, o)
});
cut(30);
plane(cylBody1.startFaces(), -30)creates a sketch plane 30mm behind the pipe's far endproject(cylBody1.startFaces())projects the pipe's circular face onto the sketchoffset(-10)creates a smaller concentric circle (the bore)rect(15).centered('horizontal')draws a 15mm square centered horizontally at the top of the circle- Two
subtract()calls remove the inner circle and the rectangle from the outer circle, leaving a ring with a rectangular notch — the key slot profile cut(30)cuts this profile 30mm deep into the pipe
Base side fillets
fillet(10, base.sideEdges())
base.sideEdges() selects all vertical edges of the base plate, and fillet(10, ...) rounds them with a 10mm radius.

Part 2 — Full Code
// @screenshot waitForInput
import { arc, chamfer, circle, cut, extrude, fillet, hLine, hMove, line, move, offset, plane, project, rect, select, sketch, subtract, tArc, vLine, vMove } from 'fluidcad/core';
import { edge, face } from 'fluidcad/filters';
// CSWP Exam Parameters — Stage 2
const A = 221;
const B = 211;
const C = 165;
const D = 121;
const E = 37;
const X = A / 3;
const Y = B / 3 + 15;
const leftOffset = B - C;
// Base plate (no corner radii in Stage 2)
sketch("xy", () => {
rect(B, A);
})
const base = extrude(25);
// L-shaped support
sketch("xy", () => {
move([leftOffset, 0]);
const l1 = vLine(80)
move([B, C]);
const l2 = hLine(-80)
arc(l1.end(), l2.end()).center([leftOffset, C])
const o = offset(15)
line(l1.start(), o.start())
line(l2.start(), o.end())
});
const support = extrude(95)
// Pipe 1 — front (angled chamfer)
const p1 = plane("front", 10);
sketch(p1, () => {
move([leftOffset, 95]);
hMove(7.5)
circle(X)
});
const cylBody1 = extrude(-D)
circle(E, cylBody1.startFaces())
const cylCut1 = cut()
chamfer(2, 30, true, cylCut1.startEdges(), cylCut1.endEdges())
// Pipe 2 — right (angled chamfer)
const p2 = plane("right", B + 10)
sketch(p2, () => {
move([C - 7.5, 95]);
circle(Y)
});
const cylBody2 = extrude(-D)
circle(E, cylBody2.startFaces())
const cylCut2 = cut()
chamfer(2, 30, true, cylCut2.startEdges(), cylCut2.endEdges())
// First pocket
const topFace1 = select(face().onPlane("xy", 25).edgeCount(5));
sketch(base.endFaces(), () => {
project(topFace1);
offset(-9, true)
});
let c1 = cut(20)
fillet(10, c1.internalEdges())
// Second pocket
sketch(base.endFaces(), () => {
const outerOffset = 9;
move([0, 0])
vMove(A - outerOffset)
hMove(outerOffset)
const l1 = hLine(B - 80 - outerOffset * 2)
const l2 = vLine(l1.start(), -A + 80 + outerOffset * 2)
const l3 = hLine(l2.end(), B - C - outerOffset)
const l4 = vLine(l1.end(), -A + C + outerOffset)
tArc(l4.end(), l3.end(), l4.tangent())
});
const c2 = cut(20)
fillet(10, c2.internalEdges())
// Key slot on pipe 1
sketch(plane(cylBody1.startFaces(), -30), () => {
let p = project(cylBody1.startFaces());
let o = offset(-10)
move(p.end())
let r = rect(15).centered('horizontal')
const s = subtract(p, r)
subtract(s, o)
});
cut(30);
// Base side fillets
fillet(10, base.sideEdges())
Verify with exam answers
With the Stage 2 test 4 parameters above (A=221, B=211, C=165, D=121, E=37), the mass should be 13206.40 grams. Try changing to test 5 (A=229, B=217, C=163, D=119, E=34) to verify you get 14208.00 g.
What you practiced
rect().radius()— creating rectangles with selectively rounded cornersarc()— connecting two endpoints with an arc through a center pointoffset()— offsetting sketch geometry inward or outward to create wall thicknessplane()— creating offset reference planes for sketching on non-standard surfaceschamfer()— adding equal-distance and angled chamfers to edgescircle()on faces — sketching circles on existing faces for holes and borescut()with and without depth — through-all cuts vs. depth-limited counterboresselect()withface()filters — selecting specific faces usingonPlane(),hasEdge(), andedgeCount()project()+offset()— projecting face outlines and offsetting them to create pocket profilesfillet()— rounding internal pocket edges and base side edgessubtract()— boolean subtraction of sketch geometry to create complex profiles like key slotstArc()— creating tangent arcs for smooth profile transitions