Bug Report: Tool diameter input rejects decimal values, silently rounds to integers
Summary
The Tool diameter (mm) field in the G‑code Toolbox silently rounds any decimal input to an integer when the stepper + / − buttons are used (or when any code path re‑enters the shared stepper logic). Entering 12.7 and pressing + yields 14, not 13.7. Under some sequences of interaction the value can end up looking corrupted (e.g. 712), which is what surfaced this bug.
The raw accepts decimals fine — the bug lives in the custom +/− stepper JS that shares a single rounding routine across all numeric fields.
Environment
• App: Gcode Toolbox (fabianoh130/GcodeToolbox)
• Files affected: main.js, index.html
• Unit mode: mm (also affects inch mode indirectly via clamping)
• Browser: Reproducible in Chromium / Firefox / Edge (framework‑agnostic; pure DOM)
Steps to reproduce
- Open the app in Advanced mode, unit = mm
- In the Tool diameter (mm) field, clear the value and type 12.7 (often fails when the period is pressed)
- Click the + (or −) stepper button next to the field once
- Observe the value in the input
Expected: 13.7 (or 12.2 for −, assuming default step of 1). Actual: 14 (decimals discarded). Repeated interactions and the auto‑fired input listeners on the field can produce further mangled values.
A related repro: type 12.7, then click into Stepover and back — depending on the unit toggle path, updateStepoverMaxWhenMm() clamps stepover against a stale/rounded tool diameter, which cascades into user‑visible weirdness on the tool diameter row.
Root cause
In main.js (~L9151, inside the .input-with-stepper[data-step] wiring loop):
function applyDelta(delta) {
const { step, min, max } = getStepMinMax();
const decimals = step < 1
? (String(step).split(".")[1]?.length || 2)
: 0; // ← forced to 0 when step ≥ 1
const roundValue = (v) => decimals
? Math.round(v * 10**decimals) / 10**decimals
: Math.round(v); // ← Math.round() destroys .7
const current = toNumber(input.value) || 0;
const next = roundValue(current + delta);
const clamped = Math.min(max, Math.max(min, next));
input.value = String(clamped);
…
}
The Tool diameter row in index.html is defined as:
<div class="input-with-stepper" data-step="1" data-min="0.1">
<input type="number" id="tool-diameter" min="0.1" step="any" required value="4" />
Because the wrapper carries data-step="1", the branch decimals = 0 is taken and Math.round(current + delta) snaps the user's 12.7 to an integer. The underlying is fine — the custom stepper is overriding user precision.
This is inconsistent with the input's own step="any" attribute, which explicitly opts out of integer stepping.
Why "712" appeared
Two mechanisms combine to make this look worse than a plain rounding bug:
- applyDelta is invoked from click, but the shared handler also touches the value through change/input cascades from updateStepoverHint() / updateStepoverMaxWhenMm() and the stepover-unit radio's change handler (which reads tool diameter and rewrites the stepover input). During a partial edit, this can concatenate/clamp against stale state.
- Locale handling: toNumber() accepts , or ., but the browser‑native type=number rejects , in some locales, so a keypress may momentarily produce a non‑numeric value that then round‑trips through applyDelta and gets clamped/rewritten oddly.
Impact
• Correctness: Users cannot enter common metric tool diameters (3.175 for 1/8″, 6.35 for 1/4″, 12.7 for 1/2″, 1.5, 2.5, etc.) if they touch the +/− steppers. Tool diameter directly drives offset math, pocket ring stepping, stepover clamping, and engraving guards — a silently truncated value produces incorrect G‑code with no error surfaced.
• Safety: The generated toolpath will be geometrically wrong (e.g. under‑sized offsets on a contour) and the operator may not notice before running material.
• Consistency: The behavior contradicts the input's own step="any" and the app's inch mode, which relies on sub‑mm precision.
Proposed fix
Change applyDelta in main.js to respect (a) the precision the user typed and (b) a per‑input minimum precision, instead of hard‑rounding when step ≥ 1:
function applyDelta(delta) {
const { step, min, max } = getStepMinMax();
// Precision implied by the configured step
const stepDecimals = String(step).includes(".")
? String(step).split(".")[1].length
: 0;
// Precision the user already typed – never destroy it
const currentStr = String(input.value ?? "").trim().replace(",", ".");
const typedDecimals = currentStr.includes(".")
? currentStr.split(".")[1].length
: 0;
// Absolute floor for fields explicitly opted into fractional input
const minDecimals = (input.step === "any") ? 1 : 0;
const decimals = Math.max(stepDecimals, typedDecimals, minDecimals);
const factor = Math.pow(10, decimals);
const current = toNumber(input.value) || 0;
const next = decimals > 0
? Math.round((current + delta) * factor) / factor
: Math.round(current + delta);
const clamped = Math.min(max, Math.max(min, next));
input.value = String(clamped);
if (input.id === "tool-diameter" || input.id === "stepover") updateStepoverHint();
if (["patterned-holes-spacing-x","patterned-holes-spacing-y",
"patterned-holes-count-x","patterned-holes-count-y"].includes(input.id)) {
if (typeof updatePatternedHolesTotalHint === "function") updatePatternedHolesTotalHint();
}
if (typeof updateRegenerateIndicator === "function") updateRegenerateIndicator();
}
Secondary hardening (recommended)
- Loosen the wrapper step for tool diameter so bumps aren't jarring for common metric sizes:
o index.html:
o main.js (STEP_MM_BY_INPUT): change "tool-diameter": 1 → "tool-diameter": 0.5.
- Locale safety. Consider switching Tool diameter to a locale‑tolerant text input, since toNumber() already handles both separators:
- Guard downstream writers. Audit callers that read tool diameter and immediately write back (updateStepoverMaxWhenMm, stepover‑unit radio change) so they never touch the tool diameter input itself.
Suggested regression tests
After patching, verify in both mm and inch modes:
Action Field starts at Expected after
Type 12.7, blur 4 12.7
Type 12.7, click + 12.7 13.7 (or 13.2 with data-step=0.5)
Type 12.7, click − twice 12.7 10.7 (or 11.7 with data-step=0.5)
Type 3.175, blur, toggle stepover unit to mm and back 3.175 3.175 (unchanged)
Type 0.5, click − 0.5 0.1 (clamped to data-min)
Inch mode: type 0.125, click + 0.125 0.135 (or 0.126 depending on inch step)
Also worth adding: a unit test around applyDelta (extract it from the closure) that asserts precision preservation for a matrix of (step, typedValue, delta).
Additional notes
• The same rounding bug affects any other field where data-step ≥ 1 but users may legitimately enter decimals (total-depth, stepdown, feedrate, safe-height, lead-in-above, z-offset, origin-offset-*). The proposed fix resolves all of them in one place because they share applyDelta.
This was generated by Microsoft Copilot AI
Bug Report: Tool diameter input rejects decimal values, silently rounds to integers
Summary
The Tool diameter (mm) field in the G‑code Toolbox silently rounds any decimal input to an integer when the stepper + / − buttons are used (or when any code path re‑enters the shared stepper logic). Entering 12.7 and pressing + yields 14, not 13.7. Under some sequences of interaction the value can end up looking corrupted (e.g. 712), which is what surfaced this bug.
The raw accepts decimals fine — the bug lives in the custom +/− stepper JS that shares a single rounding routine across all numeric fields.
Environment
• App: Gcode Toolbox (fabianoh130/GcodeToolbox)
• Files affected: main.js, index.html
• Unit mode: mm (also affects inch mode indirectly via clamping)
• Browser: Reproducible in Chromium / Firefox / Edge (framework‑agnostic; pure DOM)
Steps to reproduce
Expected: 13.7 (or 12.2 for −, assuming default step of 1). Actual: 14 (decimals discarded). Repeated interactions and the auto‑fired input listeners on the field can produce further mangled values.
A related repro: type 12.7, then click into Stepover and back — depending on the unit toggle path, updateStepoverMaxWhenMm() clamps stepover against a stale/rounded tool diameter, which cascades into user‑visible weirdness on the tool diameter row.
Root cause
In main.js (~L9151, inside the .input-with-stepper[data-step] wiring loop):
The Tool diameter row in index.html is defined as:
Because the wrapper carries data-step="1", the branch decimals = 0 is taken and Math.round(current + delta) snaps the user's 12.7 to an integer. The underlying is fine — the custom stepper is overriding user precision.
This is inconsistent with the input's own step="any" attribute, which explicitly opts out of integer stepping.
Why "712" appeared
Two mechanisms combine to make this look worse than a plain rounding bug:
Impact
• Correctness: Users cannot enter common metric tool diameters (3.175 for 1/8″, 6.35 for 1/4″, 12.7 for 1/2″, 1.5, 2.5, etc.) if they touch the +/− steppers. Tool diameter directly drives offset math, pocket ring stepping, stepover clamping, and engraving guards — a silently truncated value produces incorrect G‑code with no error surfaced.
• Safety: The generated toolpath will be geometrically wrong (e.g. under‑sized offsets on a contour) and the operator may not notice before running material.
• Consistency: The behavior contradicts the input's own step="any" and the app's inch mode, which relies on sub‑mm precision.
Proposed fix
Change applyDelta in main.js to respect (a) the precision the user typed and (b) a per‑input minimum precision, instead of hard‑rounding when step ≥ 1:
Secondary hardening (recommended)
o index.html:
o main.js (STEP_MM_BY_INPUT): change "tool-diameter": 1 → "tool-diameter": 0.5.
Suggested regression tests
After patching, verify in both mm and inch modes:
Action Field starts at Expected after
Type 12.7, blur 4 12.7
Type 12.7, click + 12.7 13.7 (or 13.2 with data-step=0.5)
Type 12.7, click − twice 12.7 10.7 (or 11.7 with data-step=0.5)
Type 3.175, blur, toggle stepover unit to mm and back 3.175 3.175 (unchanged)
Type 0.5, click − 0.5 0.1 (clamped to data-min)
Inch mode: type 0.125, click + 0.125 0.135 (or 0.126 depending on inch step)
Also worth adding: a unit test around applyDelta (extract it from the closure) that asserts precision preservation for a matrix of (step, typedValue, delta).
Additional notes
• The same rounding bug affects any other field where data-step ≥ 1 but users may legitimately enter decimals (total-depth, stepdown, feedrate, safe-height, lead-in-above, z-offset, origin-offset-*). The proposed fix resolves all of them in one place because they share applyDelta.
This was generated by Microsoft Copilot AI