What it is
A shrink calculator that refuses to give you a scale factor smaller than your measurement error, plus the tool that turns a drop-in fit into a 20 mm progressive lock taper. 40 mm cube, 0.050 % measured shrink, 0.065 mm noise floor, verdict: slicer stays at 100 %.
Version history
Straight from the project’s own card data — what each version added.
Four constant-clearance fits with a live SVG cross-section.
Multi-reading axes with the minima datum, lock-taper fit, insertion-ramp chart, auto-set on Lock.
Separate shrink-only page: preset, nominal, readings, four numbers out. Fit tool left intact.
Files on the site
By the numbers
Measured from the real working folder ~/.hermes/scripts/ — not a claim, a count.
Mostly: Python ×201 · Shell ×73 · binary assets ×16 · JSON ×5 · JavaScript ×3 · HTML ×3
What broke, and what I’d change
Not written yet. This is the part only I can write — what actually went wrong, and what I’d do differently. It lives in builds/reflections/shrink-calculator.md (see _TEMPLATE.md); as soon as that file has words in it, this section fills in on the next build.
Everything else on this page — the spec, the version history, the file counts — is generated from the project’s own build notes and files, so nothing here is guesswork.
Build spec
The project’s own build notes, rendered. Open the raw .md ↗
Show the spec
Build spec — Shrinkage & fit calculators (shrink-only page + lock-taper pocket)
Goal. Two single-file HTML tools and one CLI around a single honest claim: a 40 mm printed cube cannot resolve the shrinkage it is meant to measure, so a shrink calculator must be allowed to answer “no change, leave the slicer at 100 %”. The second tool answers the question that shrinkage cannot — how to make a part go in slowly and smoothly instead of dropping in or needing a mallet.
Hard requirements
- Zero network requests in both pages: no CDN, no webfonts, no raster assets, no
fetch. Must run from - Shrink page does one job. Preset material, nominal size, three reading boxes, and four outputs
- Multiple readings per axis, accepted space/comma/newline separated. Per-axis datum is the
- A noise floor derived from the user's own data:
max(0.05, max_spread/2 + 0.02)mm. A deviation - Verdict precedence, fixed and testable: preset → nothing parseable → under noise → oversized →
- Never emit a dishonest number: no
NaN, noInfinity, no0.000 %from junk input, and no - Lock fit: gap ramps from mouth to floor instead of being constant. Defaults
- Every number on screen is re-derivable in one line of arithmetic shown on the analysis page.
- CLI parity:
dt filament shrink <nominal> <reading…>prints shrink only (--pocketopts into geometry);
file://, from a USB stick, and inside a portfolio iframe. (Verified: 0 matches for src=/href= to anything external in the shrink page.)
(shrink %, slicer scale %, measured mm, off nominal mm) plus a per-axis table. No pocket geometry, no lead-in controls, no diagrams. The fit tool stays separate so neither page compromises the other.
minimum (a tilted caliper only ever reads big); measured size is the mean of the axis minima. Spread is reported separately so noise never hides inside an average.
at or below it must produce 100.00 % scale, with the raw arithmetic shown greyed underneath as evidence — never as the instruction.
real shrink. Coverage warnings (“only one axis”) are notes, never the verdict, or they mask the oversized branch.
sub-100 % scale offered as the fix for a part that printed oversized.
−0.04 mm/side land clearance, 0.20 mm/side mouth opening, taper length equal to pocket depth. Report free travel, bite-zone length and bite rate (µm per mm of push); warn below 1.5 mm of bite zone, above 0.09 mm/side interference, and when the mouth is so wide the first millimetres fall in loose.
dt filament fit <envelope> --fit lock --clearance -0.04 --hole-bias 0 --lead taper --lead-allow 0.20 --taper-len 20 prints the pocket and the insertion ramp. --json on both.
Verification contract
- Headless Chrome at 390 / 768 / 1440 px, narrow widths via iframe (Chrome clamps a headless window to
- Assertions:
document.documentElement.scrollWidth <= innerWidth, min tap target ≥ 44 px, table - Every displayed value recomputed independently in Python and compared to the rendered DOM — 9 maths
- Both harnesses live in
~/.hermes/scripts/(verify-shrink.py,verify-shrinkfit.py) and exit non-zero
~500 px, so a “390 px” screenshot at window width is a lie).
overflow = 0, no clipped SVG text (via getBBox()), 0 console errors.
checks, 8 UI states (empty, measured, real shrink, oversized, one axis, junk, zero nominal, after reset).
on any failed assertion.
Pitfalls worth carrying forward
- A scale factor is not a fit knob. It multiplies the gap along with the parts: scaling both to
- 40 mm is too short a witness. One caliper tick (0.01 mm) is 0.025 % on 40 mm — half the effect.
- Elephant's foot is not shrinkage. A 40.09 mm bottom against a 40.05 mm mid-face is a first-layer
dtmust be a symlink, not a copy — a copied launcher resolvesDT_DIRto/usr/local/binand- The stiffest bug found in testing was a correct-looking one: the single-axis warning was promoted to
100.3 % turns a 0.16 mm mouth gap into 0.1605 mm. Shrink correction preserves fits by design; only pocket mouth/floor/taper change how entry feels.
Use a 100 mm+ bar before believing any material constant; the preset table exists for the rest.
flare (+0.02 mm/side). Use the mid-face minima for shrink, the bottom maximum for entry clearance.
every sub-app dies with exit 2. Fixed with resolve_root().
the verdict, which silently hid the oversized message. Test states in pairs, not one at a time.
Files
~/Desktop/Shrink-Calculator.html | shrink-only page, 18,556 B, self-contained |~/Desktop/Shrink-Fit-Calculator.html | pocket / lock-taper calculator, 48,434 B |~/DTApps/filament-calc/filament | CLI: shrink, fit, shrinklist |~/.hermes/scripts/verify-shrink.py | shrink-page harness |~/.hermes/scripts/verify-shrinkfit.py | fit-page harness |