Factory MBOM
Schema Reference
The scalarcut.factory_bom.v1.1 document, field by field: header, pieces, cut types, recipes, pack rounding, consumables, totals, and stable IDs.
The Factory MBOM document is versioned by a top-level schema string. The current version is scalarcut.factory_bom.v1.1. Treat the schema field as the contract: if a constant or field meaning changes, the version bumps.
Dual units, one truth
The planner's internal lattice is in metres, but the exported document is millimetres:
- Cut sizes and export fields are integer millimetres (
round(m × 1000)). - The document states
unit_system: "metric"andlattice_unit: "mm". - Canonical piece sizes are always
w_mm/h_mm. - Inch/foot display in the planner converts from the millimetre lattice and is never written back into the cut keys. This export emits no inch columns.
Document header
| Field | Meaning |
|---|---|
schema |
scalarcut.factory_bom.v1.1 |
scene_id |
Planner scene id, or null if unsaved |
project_id |
Same as scene_id this round (one tiling scene = one ERP key) |
title |
Scene display label |
unit_system / lattice_unit / unit_policy |
metric / mm / policy string |
rates |
Frozen consumable constants (below) |
totals |
Room rollup across surfaces |
surfaces / pieces / recipes |
Per-surface BOM, cut list, and CRE recipes |
Pieces
A piece describes a cut group — a size repeated qty times. Key fields:
| Field | Meaning |
|---|---|
surface_id |
wall-a … wall-d, or floor |
letter |
Legend letter matching the PDF cut list (A, B, …) |
group_id |
Stable group id derived from location + size |
sku |
Catalog SKU, or empty on the first-party planner |
w_mm / h_mm |
Canonical millimetre size |
cut_type |
The cut class for this piece |
qty |
Number of identical pieces |
fragile |
True when the cut is below the 50 mm fragility floor |
cre_recycled |
True when the piece is recycled by the Cut Recycling Engine |
cre_parent |
Parent blank size key (tileW×tileH mm) when recycled, else empty |
is_l_cut |
True for L-shaped cuts |
Cut types
cut_type classifies how the piece is produced. An integrator can key cutting-table behaviour off it. Fragile pieces are flagged separately so they can be routed for special handling rather than dropped onto a machine that will shatter them.
L-cuts
L-shaped pieces are flagged with is_l_cut and carry their arm dimensions in the piece geometry. CRE nesting still treats each piece as its w_mm × h_mm bounding rectangle.
Optional leftover polygon (geometry)
A piece may include an additive geometry object:
"geometry": {
"frame": "tile_local_mm",
"vertices_mm": [[0, 0], [180, 0], [180, 600], [0, 600]]
}
- The
frameis wall-aligned millimetres translated so the nominal unclipped tile AABB minimum is(0, 0). - Present when the leftover is a single convex/simple ring (a 45° diagonal or herringbone fragment, or an axis-aligned rectangular leftover).
- Omitted for L-cuts, multi-fragment leftovers, and qty groups whose members do not share the same ring.
- It is not a CNC toolpath and does not introduce arbitrary blade angles — CRE still nests
w_mm × h_mmrectangles. - Unknown fields are additive: an ERP that ignores
geometrykeepsw_mm/h_mm/cut_type/is_l_cut.
Box and pack rounding
When the total piece count (totalPieces) is known:
orderPieces = ceil(totalPieces × (1 + wastage) − 1e-12)- With a pack quantity (
pack_qty, tiles per box) of 1 or more:fullBoxes = floor(orderPieces / pack_qty)looseTiles = orderPieces % pack_qtyboxes_to_order = fullBoxes— leftover tiles are not rounded into an extra box.pack_mode = "full_boxes_plus_loose"
- With no pack quantity:
pack_mode = "pack_unset",boxes_to_order = null; the tile line is stillorderPieces.
When totalPieces is unknown: pack_mode = "area_ceil_boxes", boxes_to_order = ceil(grossTileAreaSqm / sqmPerBox − 1e-12).
Surface packing fields: pack_qty, pack_mode, order_pieces, full_boxes, loose_tiles, boxes_to_order, and the deprecated boxes alias (equal to boxes_to_order).
Consumables (frozen rates)
Consumables are emitted as a rates formula version and as kg/L per surface and in totals. These constants are frozen with the schema; if they change between builds, the contract has changed and the schema bumps.
| Constant | Value | Use |
|---|---|---|
adhesive_kg_per_sqm |
4.5 |
adhesiveKg = grossTileAreaSqm × 4.5 |
adhesive_bag_kg |
25 |
adhesiveBags = ceil(adhesiveKg / 25 − 1e-12) |
primer_l_per_sqm |
0.2 |
primerL = grossTileAreaSqm × 0.2 |
grout_density_kg_m3 |
1200 |
CAD grout mass |
grout_compaction_factor |
1.05 |
CAD grout mass |
Grout mass is computed from pattern geometry with density × compaction. Display rounding (0.1 steps) is for the human sheets only; the factory JSON stores the engine value before display rounding.
Totals rollup
totals sums the surface BOM fields, plus:
cut_qty— sum of pieceqty(must match the blueprint cut-list header when audited).boxes_to_order(and deprecatedboxes) — sum of surface carton counts where set.
Stable IDs
- Surfaces:
wall-a,wall-b,wall-c,wall-d,floor. - Cut groups:
group_idfrom location key + size (w×hmm or L-arm key). - Legend letters: A, B, … from group array order, identical to the PDF cut list.
The same lattice always yields the same group_id and letters on re-export.
SKU
- An empty
skuis allowed on the first-party planner (demo, no catalog). - A catalog / widget embed must populate
skufor a live factory feed. - An empty SKU does not block the export.
CSV piece list
The CSV is the piece list only (same columns as v1). Packing, ids, rates, totals, and the optional geometry live in JSON.
Columns: surface_id, letter, group_id, sku, w_mm, h_mm, cut_type, qty, fragile, cre_recycled, cre_parent, is_l_cut.