FluidCAD Hub

@fluidcad/fasteners

1.0.0LatestPublished 0 comments

Fasteners: screws and bolts with every common head and drive, set screws, shoulder screws, nuts, washers, threaded rods, standoffs and pins, metric and inch, with plain or helical threads

@fluidcad/fasteners

Fasteners for FluidCAD, built on the custom-features SDK (fluidcad/sdk): screws and bolts with every common head and drive, set screws, shoulder screws, nuts, washers, threaded rods, standoffs and pins, in metric (ISO) and inch (ASME) sizes. Each is a body of its own, and its thread is plain or modeled as a true helix.

npx fluidcad install @fluidcad/fasteners
import { screw, nut, washer } from '@fluidcad/fasteners';
featureidwhat it makes
screwscrewa screw or bolt: socket cap (standard, low, ultra low), hex, hex flange, rounded (button, pan, truss, round), flat or oval countersunk, or cheese head; hex, Torx, Phillips, Pozidriv, slotted, square or combination drive; fully or partly threaded
setScrewsetScrewa headless set screw: hex, Torx or slot drive; cup, flat, cone, dog or oval point
shoulderScrewshoulderScrewa shoulder screw: socket head, precision shoulder, undercut neck, shorter thread
nutnuta hex, jam, nylon insert, flange, acorn, square, coupling or castle nut
washerwashera flat, wide, split lock, or external or internal tooth lock washer
threadedRodthreadedRoda threaded rod or stud, both ends chamfered
standoffstandoffa hex or round standoff, female or male at each end
pinpina dowel pin, or a slotted spring pin
partwhat it is
screwedCover (parts/screwed-cover.part.js)a round cover held by screws picked at its holes: four M5 socket cap screws from one statement in counterbored holes, an M4 countersunk screw flush in the middle
boltedFlange (parts/bolted-flange.part.js)two flanges bolted together on a bolt circle: six hex bolts, each with a washer under its head, a washer and a nylon-insert nut below, the washers' bores chamfered
metricScrew (parts/metric-screw.part.js)a metric screw with Size, Length, Head and Modeled threads parameters, and a seat connector where its head bears, for an assembly to insert and mate
metricNut (parts/metric-nut.part.js)a metric nut, its Size and Style parameters, its seat connector
metricWasher (parts/metric-washer.part.js)a metric washer, its Size and Style parameters, its seat and top connectors

Using them

// On the top face over a hole: a washer, and a bolt on it, raised by the
// washer's thickness (a connector 1.6 up). Below the lower plate, whose
// face points down: a washer, and a locknut 1.6 further down.
washer(connector("top", upper.endFaces()).offset(35, 0, 0), { size: "M8" });
screw(connector("onWasher", upper.endFaces()).offset(35, 0, 1.6), { head: "hex", size: "M8", drive: "none", length: 35, threading: "partial" });
washer(connector("under", lower.startFaces()).offset(-35, 0, 0), { size: "M8" });
nut(connector("underWasher", lower.startFaces()).offset(-35, 0, 1.6), { size: "M8", style: "nylon" });

// A countersunk Torx screw flush in a lid, its thread modeled.
screw(lid.endFaces().center(), { head: "flat", drive: "torx", size: "M4", length: 12, threads: true });

// Screws picked at a hole: one in each of the hole's placements, sized by
// the hole (M5, socket head for its counterbore), seated on the
// counterbore's floor. Only the length is the statement's to say.
const bores = hole("M5", a.center(), b.center(), c.center(), d.center()).counterbore();
screw(bores, { length: 12 });

Every feature takes the same first argument and placement:

  • Where it stands: at is a connector, a point, an anchor on a face or an edge (a hole's rim centres it on the hole) — or a hole() itself, picked in the timeline: the fastener stands in every placement of the hole. Left out, it's the origin, with its axis along Z. The fastener's axis is the location's Z, which points out of the material. A head bears on the location with its shank going down into the material. A nut, a washer, a standoff, a threaded rod and a pin stand on it. To stack one on another (a bolt on a washer), place it at a connector offset along the face's normal by the thickness below it.
  • At a hole, a screw is what the hole was drilled for: its system and size are the hole's (hole("M6", …)), its pitch a tapped hole's (or the one a clearance hole .fasten()s), its head the recess's — flat at the countersink's angle in a countersunk hole, socket in a counterbored one — and it seats in the recess: on a counterbore's floor, flush in a countersink. The dialog shows those rows locked; a value the statement passes for one of them is ignored, with a warning on the row. A hole drilled to a plain diameter fixes only what its recess says.
  • system narrows the dialog's sizes to metric or inch. A hand-written call may pass any size.
  • Modeled threads (threads: true) is off by default. Off, a thread is plain at its major diameter and a tapped bore at its minor diameter (how a drawing shows them), and it builds in milliseconds. On, a 60° thread with the basic ISO profile is wound on as a helix, right- or left-handed (hand), and takes a second or more to build. Every dialog previews from the start (no Preview toggle); the preview keeps threads plain.
  • Units. The size tables are in millimetres. In a model written in another unit, a fastener's lengths are read in that unit and its standard sizes are converted, so a 1/4-20 bolt is 0.25" in an inch model.
  • New bodies only. Each statement keeps its fastener as a separate solid (new is its only operation).

The values, their defaults and the buckets (startFaces is where the fastener bears, plus named ones such as headFaces, driveFaces, threadFaces and boreFaces) are on each feature's page in docs/.

Geometry

The fasteners are planned as plain data (features/lib/spec.js), then built in OpenCascade (features/lib/occ-build.js, occ-thread.js):

  • Bodies are half-sections revolved about the axis (heads, shanks, points, domes, collars), with outlines swept along it and booleans where a shape isn't round: a hex or a square chamfered at 30° by a revolved cone, the slots of a castle nut, the teeth of a lock washer.
  • Drives are cut last. A hex or Torx socket is the outline swept down to a 118° drill point. Phillips, Pozidriv and square recesses are lofts that narrow as they go down, and a slot runs across the head. The faces the cut makes are the drive's bucket, read from the cut's own history.
  • Threads are a ridge wound between two helical strips: one on the root cylinder, one on the crest cylinder. Each strip is bounded by exact helices, drawn as straight lines in the cylinder's parameters. The two are lofted with ruled faces, so the flanks are straight at 60° in every half-plane through the axis. The ridge is trimmed to an envelope (45° chamfers, a runout cone, a nut's countersinks), fused onto the core at the minor diameter (or into a bore at the major), and mended with ShapeFix. If a ridge trims to nothing, it is started a little lower and tried again (the thread's phase is free). A castle nut's modeled thread stops under its slots.

Layout

fluidcad.json   the package block (@fluidcad/fasteners)
features/       one module per fastener, its icon (icons/) and its dialog pictures (img/)
  lib/            plain ES modules the features import
    data.js         the size tables: ISO, DIN and ASME dimensions by size
    profile.js      plane outlines: hexagons, Torx lobes, crosses, teeth, domes
    spec.js         what a fastener is made of: its solids, threads, drive, buckets
    dialog.js       the dialog rows and choices the features share
    fastener.js     the shared build: made, sorted into buckets, placed
    occ-build.js    OpenCascade: revolves, prisms, lofts, booleans, the drive's cut
    occ-thread.js   OpenCascade: the thread's helical ridge
parts/          the example parts: a bolted flange, a metric screw, nut and washer
docs/           a page per feature

These stay in the workspace and never ship: sandbox.part.js, a bench with one of each head, drive, point and style; tests/ (vitest unit tests for features/lib); tools/ (the icon and picture scripts); and the npm files.

Development

npm install
npm test            # unit tests
npm run typecheck   # checkJs over the workspace (needs fluidcad linked: npm link fluidcad)
npx fluidcad pack   # → fluidcad-fasteners-<version>.fluidpkg

Icons are rendered in Blender in the FluidCAD pack's 3D language, each fastener in the family accent #E08A1E (amber); the washer sits under a white bolt's head and the threaded rod carries a white nut. To render them, run flatpak run org.blender.Blender -b --python-expr "exec(open('tools/icons/generate_fastener_icons.py').read()); main()" (or exec(…); main() through the Blender MCP), then python3 tools/icons/sheet.py (needs Pillow) for the contact sheet. The dialog pictures are SVG, drawn from the features' own geometry: node tools/svg/generate_svg.mjs.

Lengths are millimetres.