中文说明 · Live workbench · Example project · Equations
A transparent fan-curve × duct-route solver for one-gate-at-a-time woodshop dust collection.
DustRoute takes your collector fan curve, explicit duct segments, and per-tool constraints. It calculates each route's operating point, pressure-loss breakdown, transport velocity, and pass/fail margin in a local CLI and a no-login browser workbench powered by the same core.
Single-number CFM calculators hide the relationship that matters: the collector supplies pressure according to its fan curve while the route consumes pressure according to airflow. Layout tools can draw a duct without proving where those two curves meet.
DustRoute keeps that relationship visible:
- piecewise-linear interpolation of the fan curve you supplied;
- Darcy–Weisbach wall loss plus explicit fitting K values per segment;
- deterministic bisection of the fan/system intersection;
- route airflow and every segment's velocity compared with your stated limits;
- terminal, JSON, Markdown, and browser results from one calculation core.
It does not invent a fan curve, universal safety threshold, fitting allowance, or equipment recommendation.
Requires Node.js 22 or 24.
git clone https://github.com/KanadeK/dustroute.git
cd dustroute
npm ci
npm run checkExpected result:
PASS 3/3 routes
PASS Table saw 619.1 CFM @ 9.55 in. wg
PASS Planer 629.0 CFM @ 9.50 in. wg
PASS Miter saw 428.1 CFM @ 10.55 in. wg
Start the local browser workbench:
npm startOpen http://127.0.0.1:4173. The static app has no backend, account, telemetry, or third-party script.
# Human-readable analysis
node bin/dustroute.js analyze examples/garage-shop.json
# Machine-readable result
node bin/dustroute.js analyze examples/garage-shop.json --format json
# Markdown report
node bin/dustroute.js analyze examples/garage-shop.json --format markdown
# CI gate: exits 1 when a stated route constraint fails
node bin/dustroute.js check examples/garage-shop.jsonExit codes are stable:
| Code | Meaning |
|---|---|
0 |
Analysis completed; for check, every route passed |
1 |
check completed and at least one route missed a stated constraint |
2 |
Usage, file, JSON, or project-validation error |
See usage and project format for every input field and output mode.
The live/static app can:
- load the passing three-tool example;
- import or paste a project JSON file up to 1 MiB;
- switch routes with pointer or arrow keys;
- plot the fan and route system curves;
- show per-segment velocity, pressure loss, and effective K;
- download the complete analysis as JSON or a Markdown report;
- keep analyzing after the page has loaded and the network is offline.
Imported labels are validated and rendered as text nodes. Browser data is never sent to a server.
Copy examples/garage-shop.json, then replace every physical value with manufacturer data, measurements, or a value you explicitly chose:
{
"schemaVersion": 1,
"project": { "name": "My shop" },
"air": {
"densityKgM3": 1.204,
"kinematicViscosityM2S": 0.00001506
},
"fanCurve": [
{ "cfm": 0, "pressureInWg": 8.2 },
{ "cfm": 900, "pressureInWg": 4.1 },
{ "cfm": 1400, "pressureInWg": 0 }
],
"segments": [
{
"id": "main",
"label": "Main duct",
"lengthFt": 20,
"diameterIn": 5,
"roughnessIn": 0.0006,
"lossMultiplier": 1,
"fittings": [
{ "label": "Long-radius elbow", "lossCoefficient": 0.2, "quantity": 2 }
]
}
],
"routes": [
{
"id": "planer",
"label": "Planer",
"targetCfm": 500,
"minTransportFpm": 3500,
"segmentIds": ["main"]
}
]
}The example values demonstrate the workflow; they are not design recommendations.
Run the complete local release gate from a clean checkout:
npm ci
npm test
npm run test:coverage
npm run lint
npm run build
npm run check
npm audit --audit-level=high
npm pack --dry-runVerify the real failure path separately. This command is expected to print both failed constraints and exit 1:
node bin/dustroute.js check examples/undersized-route.jsonUse the exit code and first concrete message; do not edit values merely to make the badge green.
- Exit
2, field path shown — fix that exact JSON field. Fan points must start at0 CFM, increase in CFM, never rise in pressure, and end at0 in. wg. Segment and route IDs must be unique and referenced segments must exist. - Exit
2, calculation error — one or more finite JSON numbers overflowed or underflowed after unit conversion. Re-check the named segment for impossible magnitudes or wrong units; DustRoute refuses to serializeNaN/infinity as a result. - Exit
1, airflow below target — inspect the route's largest pressure-loss segments, then verify the real fan curve, length, diameter, roughness, fitting K, and loss multiplier. Change only inputs that differ in the real system. - Exit
1, velocity below minimum — inspect the named segment and re-check its diameter and the minimum you explicitly selected. DustRoute does not choose a replacement threshold for you. - Build or test failure — run
node --version(22/24 required), remove only the generateddist/directory if it is stale, runnpm ci, and retry the single failing command before the full gate. - Result still looks implausible — stop using the output as a decision basis. Re-check units and source data, compare against equipment documentation or measurements, and obtain qualified review where the consequence warrants it.
More cases are in troubleshooting.
DustRoute converts the public imperial inputs to SI, calculates Reynolds number and Darcy friction factor, combines wall and explicit minor losses, and solves the curve intersection. The exact equations, constants, transition rule, numeric anchors, and primary technical source are documented in docs/equations.md.
This is a planning estimate from user-supplied values. It is not CFD, particle-capture modeling, simultaneous multi-gate balancing, code compliance, certification, or professional acceptance. Local exhaust guidance and equipment instructions still apply.
project JSON ──> validate ──> shared calculation core ──> analysis object
│ ├─ terminal
│ ├─ JSON
│ ├─ Markdown
└───────────────────────└─ browser/SVG
There are no runtime or development dependencies. The CLI and browser import the same ECMAScript modules under src/core/; the static build copies them unchanged into dist/core/. See ADR-0001.
v0.1 intentionally supports one open blast gate at a time. It does not solve branched simultaneous flow, model capture efficiency or particles, design a floor plan, recommend equipment, or store projects in the cloud. Those are different products with different evidence requirements.
Start with CONTRIBUTING.md. Please report vulnerabilities using SECURITY.md, not a public issue.
MIT © KanadeK. See LICENSE.
