Download

The MechPilot file format

A drawing is one JSON text file, name.mechpilot.json. It is yours: open, documented, versioned, and written in a stable order so it diffs well in Git (product rule 3). Nothing is rounded on save or load: numbers are IEEE doubles written by JSON.stringify, which round-trips every value exactly (product rule 1).

Reference implementation: shared/doc/types.ts (shapes), shared/doc/file.ts (serialize, parse, validate, migrations). Tests: tests/file-format.test.ts.

Top level (format 1)

{
  "format": "mechpilot",
  "version": 1,
  "unit": "mm",
  "name": "Mounting bracket",
  "description": "optional",
  "standard": "iso",
  "projection": "first",
  "layerOrder": ["0", "hidden", "centre"],
  "activeLayer": "0",
  "layers": { "0": { "id": "0", "name": "0", "color": "auto", "lineType": "01.2", "lineWidth": 0.5, "visible": true, "locked": false } },
  "entityOrder": ["e1", "e2"],
  "entities": { "e1": { "id": "e1", "type": "line", "layer": "0", "a": { "x": 0, "y": 0 }, "b": { "x": 120, "y": 0 } } }
}
FieldMeaning
formatalways "mechpilot"
versionthe format version; older files are migrated on open, newer ones are refused with a plain message
unitalways "mm": every length in the file is millimetres
standard"iso" (default) or "asme": which drawing conventions the checker and the dimension styles follow
projection"first" (ISO 5456-2 default) or "third"
layerOrder / layerslayers bottom to top; the map is keyed by id and written in that order
activeLayerwhere new entities go
entityOrder / entitiesdrawing order; the map is keyed by id and written in that order

Ids are short strings, unique within the file. Keys inside a layer or an entity are written with id, type and layer first and the rest alphabetically.

Layers

FieldMeaning
colora hex colour, or "auto": the canvas foreground (white on a dark canvas, black on a white one)
lineTypea line type id from library/line-types/iso-128-2.json, e.g. "01.2" continuous wide
lineWidthmm, from the ISO 128-2 series (0.13, 0.18, 0.25, 0.35, 0.5, 0.7, 1, 1.4, 2)
visible, lockedbooleans; a locked layer cannot be edited

Entities (format 2)

Angles are radians, counter-clockwise, y up.

typeFields
linea, b: points
circlecenter: point; radius > 0
arccenter, radius, start, end: from start to end counter-clockwise
polylinepoints (2 or more), closed; optional bulges[i] for segment i as in DXF: tan(θ/4), positive counter-clockwise, 0 straight. A rectangle is a closed polyline of four points.
ellipsecenter; major: vector from the centre to the major-axis end; ratio minor/major in (0, 1]; start, end parameters (0 and 2π = full)
splinenon-rational B-spline as in DXF: degree, controlPoints, clamped knots (controlPoints + degree + 1 values, non-decreasing), closed; optional fitPoints the user picked
textposition (baseline left), text, height in mm, rotation

Format 1 (M0) had line, circle and arc only; a format-1 file is upgraded to format 2 unchanged.

Annotations (format 3)

typeFields
dimensionkind (linear, aligned, angular, radius, diameter, ordinate), a, b (measured points; for radius/diameter a is the centre and b a point on the curve; for ordinate a is the origin), position (the dimension line passes through it, or the leader ends there), rotation (direction of a linear or ordinate dimension), center (angular: the vertex); optional text (override, <> = measured value), prefix, suffix, decimals, tolerance
tolerance{ kind: "deviation", upper, lower } in mm, { kind: "symmetric", value }, { kind: "limits", upper, lower }, or { kind: "fit", cls: "H7" } (ISO 286 class; the deviations come from the library)
noteposition, text (lines separated by \n), height, rotation; optional leader: points from the arrow tip to the text
balloonposition (circle centre), text, leader (arrow tip)
surfaceposition (tip on the surface), rotation, removal (any, required, prohibited); optional ra (µm), text, leader
gdtposition, rotation, characteristic (id from library/gdt/iso-1101.json), tolerance (text), datums (up to three letters); optional leader
datumposition (triangle on the feature), rotation, label

Annotations are drawn from the document's dimStyle (paper mm: textHeight, arrowSize, extensionOvershoot, extensionGap, textGap, decimals, annotationScale, arrowhead). The measured value is computed from the geometry when the drawing is shown, never stored, so a dimension can never disagree with what it measures.

Sheets (format 3)

sheetOrder / sheets: each sheet has name, size (A0 to A4), orientation, titleBlock (ISO 7200 field id → text) and views: windows onto the model placed on the paper, each with scale (ratio: 0.5 for 1:2), center (model point at the centre of the viewport), position, width, height (paper mm) and label (draw "SCALE 1:2" under it). A format-2 file gets the default dimension style and no sheets.

Sketch constraints (format 4)

constraintOrder / constraints: each constraint has an id and a kind, and refers to entities by id and to their points by a PointRef { "entity": "e1", "point": "a" } (a/b of a line, center of a circle or arc, start/end of an arc, or a vertex index of a polyline). Values are mm, angles radians.

kindFields
coincidentp1, p2
pointOnLinep, line
horizontal, verticalentity (a line)
parallel, perpendiculara, b (lines)
anglea, b, value (radians, counter-clockwise from a to b)
tangent, equala, b (lines, circles, arcs)
symmetricp1, p2, line
fixedentity
distancep1, p2, value
pointLineDistancep, line, value
radiusentity, value

A dimension with driving set (a number: mm, or degrees for angular) also constrains the geometry it measures. The solver (planegcs in a worker) moves the entities; the solved geometry is what the file stores, so a file opens exactly as it was saved even without solving. Deleting an entity deletes the constraints that refer to it (undo brings both back).

Parts (format 5)

partOrder / parts: a part has name, an optional material (id from library/materials) and features, an ordered list built one after the other by OpenCascade (through replicad) in a worker. Each feature has id, name, kind and optionally suppressed.

kindFields
sketchplane (XY, XZ, YZ), offset along the plane normal, entities: ids of 2D entities in model space that form closed loops (outer loop and holes)
extrudesketch (id of an earlier sketch feature), distance > 0, direction (normal, reverse, both), op (add, cut)
revolvesketch, axis { a, b } in sketch coordinates, angle in degrees (0, 360], op
holesketch (its circle centres, line ends and polyline vertices are hole positions), spec ({ kind: "simple", diameter }, { kind: "clearance", thread, series } ISO 273, { kind: "tapped", thread } tap drill), depth in mm or "through"
filletedges selector, radius
chamferedges selector, distance
shellthickness, faces to remove (selectors)
mirrorplane, offset
patternmode: "linear" with counts, spacing, axes, or mode: "circular" with axis, count, angle
importformat: "step", data (base64 of the STEP text), sourceName

Edge selectors: { kind: "all" }, { kind: "parallelTo", axis }, { kind: "inPlane", plane, offset }, { kind: "ofLength", length }, { kind: "inBox", min, max }. Face selectors: { kind: "normal", direction: "Z+" } or { kind: "inPlane", plane, offset }. The built solid is never stored: a file rebuilds from its features, so it stays small and diffable; meshes and mass properties are computed when the part is shown.

Each addition bumps version and ships a migration.

Migrations

shared/doc/file.ts keeps one function per version step. Opening a file of version n runs the steps n → n+1 → … → current, then validates. A file that fails validation is refused with the field that is wrong, never silently repaired.

Source of this page on GitHub