Writes the bill of materials as a KISS file for fabrication software: quantities, sizes, lengths, weights and plate areas.
How the precision is kept
Lengths and labor sizes are written in millimeters with two decimals, which the file's header says the standard asks for. Imperial files convert weight and area with decimal constants rounded to 12 significant digits, and plate and bolt sizes to the nearest 1/16 inch. Quantities are whole-number counts.
Open item. Divide by 0.45359237 and by 0.09290304 instead of multiplying by the rounded constants, so the factors are the exact definitions.
Calculations under this policy
6 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
The pound and inch factors and the helper that writes two decimals.
lb = kg × 2.20462262185; in = mm ÷ 25.4; f2(v) = round(v × 100) ÷ 100
25.4 is exact. 2.20462262185 is the pound factor rounded to 12 significant digits; the exact value is 1 ÷ 0.45359237. f2 rounds with Math.round and then prints two decimals.
The weight and area written on a line, in metric or imperial units.
weight = kg, or kg × 2.20462262185 lb; area = m², or m² × 10.7639104167 sq ft
10.7639104167 is 1 ÷ 0.09290304 rounded to 12 significant digits. The relative error of each constant is below 1 × 10⁻¹², and both results are then rounded to two decimals.
kiss.js
lines 84 to 85
DetailCraft 0.8.1
const W = (kg) => f2(metric ? kg : kg * KG_LB);
const area = (m2) => f2(metric ? m2 : m2 * 10.7639104167);
Inches as a fraction to 1/16
64-bit
Writes a plate or bolt size in inches and sixteenths.
n = round(inches × 16); whole = ⌊n ÷ 16⌋; fraction reduced by halving
Rounds to the nearest 1/16 with Math.round, then reduces the fraction with whole-number steps. A size that is not a multiple of 1/16 inch is changed by up to 1/32 inch in the size text.
kiss.js
lines 39 to 47
DetailCraft 0.8.1
/** Inches to a fraction string to 1/16: 12.375 → "12-3/8", 0.5 → "1/2", 3 → "3". */
export function inchFraction(inches, denom = 16) {
let n = Math.round(inches * denom);
const whole = Math.floor(n / denom);
let num = n - whole * denom, den = denom;
while (num && num % 2 === 0) { num /= 2; den /= 2; }
if (!num) return String(whole);
return (whole ? whole + '-' : '') + num + '/' + den;
}
Size designation
64-bit
The type code and size text of a part's profile.
Metric plates are written as thickness × width, each rounded to two decimals. Imperial plates divide by 25.4 and go through inchFraction. Rolled shapes keep their designation; an HSS wall given as a fraction is written as a 3-decimal number.
kiss.js
lines 54 to 70
DetailCraft 0.8.1
/** [type code, size string] for a part's profile. */
export function kissShape(profile, metric) {
const p = profile, name = String(p.name).toUpperCase();
if (p.kind === 'PL') {
const t = p.t, w = p.b;
return ['PL', metric ? f2c(t) + 'X' + f2c(w) : inchFraction(t / IN) + 'X' + inchFraction(w / IN)];
}
if (p.source === 'aisc') {
const m = name.match(/^(W|S|C|L|HSS)(.*)$/);
if (m) {
if (m[1] === 'HSS') { const parts = m[2].split('X'); parts[parts.length - 1] = decWall(parts[parts.length - 1]); return ['HSS', parts.join('X')]; }
return [m[1], m[2]];
}
}
if (p.source === 'en') return [p.kind === 'C' ? 'C' : 'W', name]; // UPN is a channel
return [{ I: 'MI', C: 'MI', L: 'MI', RHS: 'MI', CHS: 'MI' }[p.kind] || 'MI', name];
}
Detail line: quantity, length, weight, area
64-bit
One D line of the file for a part mark.
plate area m² = width × length ÷ 10⁶
The quantity is rounded to a whole number and the length is written in mm with two decimals. Plate area is width × length from 64-bit millimeters. The header notes that net weight is left empty because holes are not taken off.
The labor lines that count a part's holes by diameter and thickness.
Holes are grouped by diameter and thickness after both are rounded to two decimals, so holes whose sizes round to the same two decimals are counted together. For a hole in the web of a rectangular hollow section the thickness written is twice the wall.
kiss.js
lines 90 to 99
DetailCraft 0.8.1
const labor = (part) => {
const holes = new Map();
for (const h of part.holes) {
const t = part.profile.kind === 'PL' ? part.profile.t : h.face === 'web' ? (part.profile.kind === 'RHS' ? part.profile.t * 2 : part.profile.tw) : (part.profile.kind === 'RHS' ? part.profile.t : part.profile.tf);
const k = f2(h.d) + '|' + f2(t);
holes.set(k, (holes.get(k) || 0) + 1);
}
for (const [k, n] of holes) { const [dd, t] = k.split('|'); put('L', 'Holes', n, dd, t, 'Round'); }
for (const c of part.cuts.filter((x) => x.kind === 'cope')) put('L', 'Copes', 1, f2(c.depth), f2(c.length), clean('Cope ' + c.side + ' at ' + c.end, 40));
};
In detail
Method
The KISS standard version 1.1 as described in the file's header: comma-delimited lines, D lines per part mark with quantity, size, length, weight and area, and L lines for holes, copes and welds.
Number types
64-bit numbers; text with two decimals; whole-number quantities.
Limits
kg to lb uses 2.20462262185 where 1 ÷ 0.45359237 = 2.2046226218487757…, and m² to sq ft uses 10.7639104167 where 1 ÷ 0.09290304 = 10.763910416709722…. Each differs from the exact factor by less than 1 part in 10¹². Imperial sizes are rounded to 1/16 inch.
Approach: 64-bit, stated limit
The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.