Verified CNC toolpath strategies and the small motion IR they compose onto — the reusable core extracted from the ShopBot Labs step-toolpath app.
Each strategy is a self-contained function that turns a geometric feature (a pocket, a profile, an edge chamfer, a bored hole, a 3D relief surface) into machine moves on a shared rail, checked by an independent verifier before it becomes G-code or ShopBot SBP. The idea is that you can lift one file — say the chamfer strategy — understand it on its own, and reuse the concept in your own CAM code.
Grab a strategy. Want the chamfer logic? It's
strategies/chamfer.js. The strategies depend only on each other, their/rail, and a bundled copy of Clipper — no framework, no build step.
feature (pocket / profile / chamfer / bore / relief)
│
strategies/*.js ← the "how to cut it" — geometry → toolpath
▼
ir/moves.js ← the canonical motion rail (the neck): every
strategy emits the SAME move vocabulary
│
ir/job.js ← compose ops into one multi-tool job
ir/verify.js ← admission gate: refuses gouges / cut-throughs /
bad plunges BEFORE anything posts
▼
G-code · ShopBot SBP
Strategies never post directly and never trust themselves — they emit moves, and
ir/verify.js re-derives the safety constraints independently. That separation
(a wide set of strategies above a narrow verified rail) is the whole point.
strategies/ — the toolpath generators:
| file | what it does |
|---|---|
chamfer.js | Edge-break / bevel along a feature edge with a V-bit. |
pocket.js | Pocket clearing — the core area-clearing primitive. |
profile.js | Cut the part free (profile/perimeter, with tabs). |
bore.js | A circular hole cut by a bit near its own diameter. |
rest.js | Rest machining — a smaller bit cleans what the bulk bit couldn't reach. |
surface-raster.js | Ballnose-compensated 3D raster over a heightmap (reliefs, dishes, textures). |
tool-select.js | Which bit machines which feature, and when to add a smaller one. |
ir/ — the composition IR the strategies share:
| file | what it does |
|---|---|
moves.js | The canonical motion rail — the common move vocabulary. |
job.js | Compose ops into one multi-tool job. |
verify.js | The verifier — the admission gate (gouge / depth / plunge checks). |
tools.js | Shared tool drawer + a deterministic feeds/speeds engine. |
placement.js | Transform op-local moves into job coordinates. |
arc-fit.js | Optional arc-fitting pass on the moves rail. |
vendor/clipper.js — Clipper 6.4.2 (Angus
Johnson), polygon offsetting/clipping, wrapped as an ES module. Boost Software
License; see NOTICE.
Pure ES modules — browser or Node, no build step, no dependencies to install
(Clipper is vendored). Clone it and run the example below with node.
This cuts a rectangular part free from a board and posts ShopBot .sbp. The
shape of every job is the same: run a strategy → compose → verify → post.
import{generateProfile}from'./strategies/profile.js';import{composeJob,postJobToSbp}from'./ir/job.js';import{verifyJob}from'./ir/verify.js';// 1. A feature — a 3" x 2" part outline. Points are { x, y } in inches, placed// with clearance inside the stock so an outside cut stays on the board.constregion={outer: [{x: 0.5,y: 0.5},{x: 3.5,y: 0.5},{x: 3.5,y: 2.5},{x: 0.5,y: 2.5}]};// 2. A tool — a 1/4" flat endmill, carrying the machine's real &Tool number.consttool={number: 1,diameter: 0.25,kind: 'flat',flutes: 2};// 3. Run a strategy — profile-cut the part free, tool OUTSIDE the line, with// hold-down tabs so the part doesn't break loose mid-cut.constprof=generateProfile(region,tool,{side: 'outside',totalDepth: 0.5,depthPerPass: 0.25,safeZ: 0.25,tabs: {height: 0.08,length: 0.3},});// 4. Wrap it as a one-operation job over a piece of stock.constjob={units: 'in',stock: {w: 4,h: 3,thickness: 0.5},safeZ: 0.25,spindleSpeed: 16000,tools: {1: {name: '1/4" endmill',diameter: 0.25,kind: 'flat',rpm: 16000}},operations: [{name: 'Cut out',tool: 1,feedRate: 120,plungeRate: 40,moves: prof.moves},],};// 5. Compose → verify → post. verifyJob MEASURES the real motion (stock// envelope, cut depth, plunge) and refuses anything unsafe before it// becomes machine code — the strategy is never trusted to police itself.constmoves=composeJob(job);constreport=verifyJob(job,moves);if(!report.ok)thrownewError('refused: '+report.errors.join('; '));constsbp=postJobToSbp(job,moves,{title: 'quickstart'});// ShopBot .sbp// const gcode = postJobToGcode(job, moves, { title: 'quickstart' }); // or G-codeconsole.log(sbp);The verifier is real. Move the part flush to the corner — { x: 0, y: 0 } —
and verifyJob returns ok: false, because an outside cut with a 1/4" tool
would run off the stock. Nothing posts until the motion checks out.
Swap generateProfile for generatePocket, generateChamfer, generateBore,
or generateSurfaceRaster to cut a different feature — same compose/verify/post
loop, same job shape.
The strategies are written to be read, not just called — each file opens with a comment explaining the geometry and the reasoning, because the goal is to share the toolpathing concepts, not just an API.
This is an extracted, reusable subset — the strategy + IR core. The surrounding application (STEP-file feature detection, the UI, the LLM intent layer, the hosting) is not included here. Interfaces may still change; treat it as a reference and a starting point rather than a frozen library.
Apache License 2.0 — permissive, with an explicit patent grant. See
NOTICE for third-party attributions.