{
  "openapi": "3.1.1",
  "info": {
    "title": "Ohmforge PCB Enclosure Generator (STL) API",
    "version": "1.0.0",
    "summary": "Board outline, holes, parts and connectors in – a verified, printable base and lid STL out.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://ohmforgeenclosuregenerator.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Board outline, holes, parts and connectors in – a verified, printable base and lid STL out.",
        "description": "Describe a circuit board as JSON – outline, mounting holes, component boxes, edge connectors and keep-outs – and get a two-part 3D-printable enclosure: base with standoffs for heat-set inserts or self-tapping screws, connector cut-outs, and a lid with a snap-fit or friction lip or corner screws, optional vents and windows. Both STL files are checked to be watertight and manifold, cut-outs and standoffs are probed on the final mesh, and every part is tested for collisions. Includes a dimensioned drawing and an OBJ assembly.\n\nMethodology:\n- The cavity is the board's bounding box plus the gap on every side; the outer shell adds the wall. With lid screws the cavity grows until the corner posts (overlapping the walls) clear the board. Heights: floor, standoff, board, the tallest part or connector plus the space above it (at least the lip height plus 0.5 mm above the board), then the lid.\n- Base and lid are each built as one layered solid: ordered add and subtract polygons over height ranges (shell, cavity, standoffs with blind holes, posts, connector cut-outs = connector box + clearance extended through the wall, snap grooves; lid plate, lip, snap bumps, vents, windows, notches where parts reach the lip). All polygon edges form one planar arrangement split at every crossing; a trapezoidal decomposition gives convex cells that share whole edges, and the surface consists of the cell faces between filled and empty prisms. This yields closed, consistently oriented meshes without mesh booleans.\n- Verification on the final meshes: watertight, manifold, positive volume and a single shell (shared Renderloom mesh engine), again after a binary-STL round trip through the mesh analyzer; surface volume (divergence theorem) equal to the volume of the filled prisms; generalised winding numbers 0.005 mm inside and outside every opening edge and around every standoff hole and ring; every part, connector and the board tested as boxes against every material prism of base and lid.\n- Typical sizes: clearance holes per ISO 273 (medium: M2 2.4, M2.5 2.9, M3 3.4 mm); pilot holes for self-tapping screws in printed plastic about 0.8 × d (1.6, 2.0, 2.5 mm); common short brass heat-set inserts need 3.2, 3.6 and 4.0 mm holes and are 3–4 mm long. Holes are polygons whose flats lie on the nominal diameter; bosses are inscribed polygons.\n- Snap fit: bumps on the outside of the lip reach the snap depth past the lip, so they catch (snap depth − lip gap) in grooves cut 0.1 mm deeper into the wall, in the middle of each straight wall that has room and no opening. The lid STL is turned over for printing (plate on the bed); the base prints as it stands.\n\nScrew, insert and boss sizes are typical values, and connector dimensions in the catalogue are generic. Check them against your parts' datasheets. Printability and fit are not guaranteed: tolerances depend on your printer, material and slicer, so print a test piece first.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ohmforge_enclosure_generator",
        "x-owner-app": "ohmforge",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OhmforgeEnclosureGeneratorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Sensor node with USB-C, barrel jack and header – snap-fit lid",
                  "value": {
                    "board": "{\n \"format\": \"ohmforge-board\",\n \"version\": 1,\n \"name\": \"Sensor node 70 × 50 mm\",\n \"thickness\": 1.6,\n \"outline\": {\n  \"shape\": \"rect\",\n  \"width\": 70,\n  \"height\": 50\n },\n \"holes\": [\n  {\n   \"id\": \"H1\",\n   \"x\": 3.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H2\",\n   \"x\": 66.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H3\",\n   \"x\": 66.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H4\",\n   \"x\": 3.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  }\n ],\n \"parts\": [\n  {\n   \"id\": \"U1\",\n   \"kind\": \"radio-module\",\n   \"x\": 50,\n   \"y\": 34,\n   \"width\": 18,\n   \"depth\": 25.5,\n   \"height\": 3.2,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"U2\",\n   \"kind\": \"smd-ic\",\n   \"x\": 30,\n   \"y\": 20,\n   \"width\": 7,\n   \"depth\": 7,\n   \"height\": 1.8,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"C1\",\n   \"kind\": \"electrolytic\",\n   \"x\": 18,\n   \"y\": 36,\n   \"width\": 8,\n   \"depth\": 8,\n   \"height\": 12,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"SW1\",\n   \"kind\": \"tactile-button\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 6,\n   \"depth\": 6,\n   \"height\": 5,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"D1\",\n   \"kind\": \"led-5mm\",\n   \"x\": 44,\n   \"y\": 10,\n   \"width\": 5.8,\n   \"depth\": 5.8,\n   \"height\": 8.7,\n   \"side\": \"top\"\n  }\n ],\n \"connectors\": [\n  {\n   \"id\": \"J1\",\n   \"kind\": \"usb-c\",\n   \"edge\": \"left\",\n   \"position\": 25,\n   \"width\": 8.94,\n   \"height\": 3.26,\n   \"depth\": 7.35,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J2\",\n   \"kind\": \"barrel-jack\",\n   \"edge\": \"top\",\n   \"position\": 25,\n   \"width\": 9,\n   \"height\": 11,\n   \"depth\": 14,\n   \"overhang\": 0,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J3\",\n   \"kind\": \"header-right-angle\",\n   \"edge\": \"right\",\n   \"position\": 20,\n   \"width\": 15.24,\n   \"height\": 2.54,\n   \"depth\": 8.5,\n   \"overhang\": 3,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  }\n ],\n \"keepouts\": [\n  {\n   \"id\": \"K1\",\n   \"label\": \"Button access\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 8,\n   \"depth\": 8,\n   \"heightAbove\": 30,\n   \"lidOpening\": true\n  }\n ]\n}"
                  }
                },
                "example2": {
                  "summary": "Same board with lid screws and ventilation slots",
                  "value": {
                    "board": "{\n \"format\": \"ohmforge-board\",\n \"version\": 1,\n \"name\": \"Sensor node 70 × 50 mm\",\n \"thickness\": 1.6,\n \"outline\": {\n  \"shape\": \"rect\",\n  \"width\": 70,\n  \"height\": 50\n },\n \"holes\": [\n  {\n   \"id\": \"H1\",\n   \"x\": 3.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H2\",\n   \"x\": 66.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H3\",\n   \"x\": 66.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H4\",\n   \"x\": 3.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  }\n ],\n \"parts\": [\n  {\n   \"id\": \"U1\",\n   \"kind\": \"radio-module\",\n   \"x\": 50,\n   \"y\": 34,\n   \"width\": 18,\n   \"depth\": 25.5,\n   \"height\": 3.2,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"U2\",\n   \"kind\": \"smd-ic\",\n   \"x\": 30,\n   \"y\": 20,\n   \"width\": 7,\n   \"depth\": 7,\n   \"height\": 1.8,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"C1\",\n   \"kind\": \"electrolytic\",\n   \"x\": 18,\n   \"y\": 36,\n   \"width\": 8,\n   \"depth\": 8,\n   \"height\": 12,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"SW1\",\n   \"kind\": \"tactile-button\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 6,\n   \"depth\": 6,\n   \"height\": 5,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"D1\",\n   \"kind\": \"led-5mm\",\n   \"x\": 44,\n   \"y\": 10,\n   \"width\": 5.8,\n   \"depth\": 5.8,\n   \"height\": 8.7,\n   \"side\": \"top\"\n  }\n ],\n \"connectors\": [\n  {\n   \"id\": \"J1\",\n   \"kind\": \"usb-c\",\n   \"edge\": \"left\",\n   \"position\": 25,\n   \"width\": 8.94,\n   \"height\": 3.26,\n   \"depth\": 7.35,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J2\",\n   \"kind\": \"barrel-jack\",\n   \"edge\": \"top\",\n   \"position\": 25,\n   \"width\": 9,\n   \"height\": 11,\n   \"depth\": 14,\n   \"overhang\": 0,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J3\",\n   \"kind\": \"header-right-angle\",\n   \"edge\": \"right\",\n   \"position\": 20,\n   \"width\": 15.24,\n   \"height\": 2.54,\n   \"depth\": 8.5,\n   \"overhang\": 3,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  }\n ],\n \"keepouts\": [\n  {\n   \"id\": \"K1\",\n   \"label\": \"Button access\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 8,\n   \"depth\": 8,\n   \"heightAbove\": 30,\n   \"lidOpening\": true\n  }\n ]\n}",
                    "lid": "screws",
                    "vents": true
                  }
                },
                "example3": {
                  "summary": "Slim 65 × 30 mm board, M2.5 self-tapping screws, friction lip",
                  "value": {
                    "board": "{\n \"format\": \"ohmforge-board\",\n \"version\": 1,\n \"name\": \"Slim board 65 × 30 mm\",\n \"thickness\": 1.6,\n \"outline\": {\n  \"shape\": \"rounded\",\n  \"width\": 65,\n  \"height\": 30,\n  \"radius\": 3\n },\n \"holes\": [\n  {\n   \"id\": \"H1\",\n   \"x\": 3.5,\n   \"y\": 3.5,\n   \"diameter\": 2.75\n  },\n  {\n   \"id\": \"H2\",\n   \"x\": 61.5,\n   \"y\": 3.5,\n   \"diameter\": 2.75\n  },\n  {\n   \"id\": \"H3\",\n   \"x\": 61.5,\n   \"y\": 26.5,\n   \"diameter\": 2.75\n  },\n  {\n   \"id\": \"H4\",\n   \"x\": 3.5,\n   \"y\": 26.5,\n   \"diameter\": 2.75\n  }\n ],\n \"parts\": [\n  {\n   \"id\": \"U1\",\n   \"kind\": \"smd-ic\",\n   \"x\": 30,\n   \"y\": 15,\n   \"width\": 12,\n   \"depth\": 12,\n   \"height\": 1.2,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J5\",\n   \"kind\": \"pin-header\",\n   \"x\": 32.5,\n   \"y\": 26.5,\n   \"width\": 50.8,\n   \"depth\": 5.08,\n   \"height\": 8.5,\n   \"side\": \"top\"\n  }\n ],\n \"connectors\": [\n  {\n   \"id\": \"J1\",\n   \"kind\": \"micro-usb\",\n   \"edge\": \"bottom\",\n   \"position\": 41.4,\n   \"width\": 7.5,\n   \"height\": 2.6,\n   \"depth\": 5,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J2\",\n   \"kind\": \"micro-usb\",\n   \"edge\": \"bottom\",\n   \"position\": 54,\n   \"width\": 7.5,\n   \"height\": 2.6,\n   \"depth\": 5,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J3\",\n   \"kind\": \"micro-sd\",\n   \"edge\": \"left\",\n   \"position\": 15,\n   \"width\": 14,\n   \"height\": 1.9,\n   \"depth\": 15,\n   \"overhang\": 1.5,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  }\n ],\n \"keepouts\": []\n}",
                    "screw": "M2.5",
                    "fixing": "self-tap",
                    "lid": "lip",
                    "vents": true,
                    "cornerRadius": 2
                  }
                },
                "example4": {
                  "summary": "Notched polygon board with a relay and a screw terminal",
                  "value": {
                    "board": "{\n \"format\": \"ohmforge-board\",\n \"version\": 1,\n \"name\": \"Polygon board with a notch\",\n \"thickness\": 1.6,\n \"outline\": {\n  \"shape\": \"polygon\",\n  \"width\": 60,\n  \"height\": 45,\n  \"points\": [\n   [\n    0,\n    0\n   ],\n   [\n    60,\n    0\n   ],\n   [\n    60,\n    45\n   ],\n   [\n    40,\n    45\n   ],\n   [\n    40,\n    35\n   ],\n   [\n    20,\n    35\n   ],\n   [\n    20,\n    45\n   ],\n   [\n    0,\n    45\n   ]\n  ]\n },\n \"holes\": [\n  {\n   \"id\": \"H1\",\n   \"x\": 4,\n   \"y\": 4,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H2\",\n   \"x\": 56,\n   \"y\": 4,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H3\",\n   \"x\": 56,\n   \"y\": 41,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H4\",\n   \"x\": 4,\n   \"y\": 41,\n   \"diameter\": 3.2\n  }\n ],\n \"parts\": [\n  {\n   \"id\": \"K1\",\n   \"kind\": \"relay\",\n   \"x\": 30,\n   \"y\": 17,\n   \"width\": 19,\n   \"depth\": 15.5,\n   \"height\": 15.5,\n   \"side\": \"top\"\n  }\n ],\n \"connectors\": [\n  {\n   \"id\": \"J1\",\n   \"kind\": \"screw-terminal\",\n   \"edge\": \"right\",\n   \"position\": 20,\n   \"width\": 10.16,\n   \"height\": 10,\n   \"depth\": 7.6,\n   \"overhang\": 0,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J2\",\n   \"kind\": \"usb-c\",\n   \"edge\": \"bottom\",\n   \"position\": 12,\n   \"width\": 8.94,\n   \"height\": 3.26,\n   \"depth\": 7.35,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  }\n ],\n \"keepouts\": []\n}",
                    "cornerRadius": 5,
                    "wall": 2.4
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OhmforgeEnclosureGeneratorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "OhmforgeEnclosureGeneratorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "board": {
            "title": "Board model (JSON)",
            "description": "Fields: name, thickness, outline {shape: rect | rounded | polygon, width, height, radius, points}, holes [{id, x, y, diameter}], parts [{id, kind, x, y, width, depth, height, side}], connectors [{id, kind, edge: left | right | bottom | top, position, width, height, depth, overhang, offsetZ, side}], keepouts [{id, label, x, y, width, depth, heightAbove, lidOpening}]. Millimetres; part x and y are centres. Part kinds: smd-ic, dip-ic, electrolytic, pin-header, tactile-button, led-5mm, relay, radio-module, display-module, power-inductor, custom. Connector kinds: usb-c, micro-usb, usb-a, barrel-jack, header-right-angle, rj45, screw-terminal, micro-sd, custom. An Ohmforge project with a saved board also works.",
            "type": "string",
            "maxLength": 200000,
            "default": "{\n \"format\": \"ohmforge-board\",\n \"version\": 1,\n \"name\": \"Sensor node 70 × 50 mm\",\n \"thickness\": 1.6,\n \"outline\": {\n  \"shape\": \"rect\",\n  \"width\": 70,\n  \"height\": 50\n },\n \"holes\": [\n  {\n   \"id\": \"H1\",\n   \"x\": 3.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H2\",\n   \"x\": 66.5,\n   \"y\": 3.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H3\",\n   \"x\": 66.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  },\n  {\n   \"id\": \"H4\",\n   \"x\": 3.5,\n   \"y\": 46.5,\n   \"diameter\": 3.2\n  }\n ],\n \"parts\": [\n  {\n   \"id\": \"U1\",\n   \"kind\": \"radio-module\",\n   \"x\": 50,\n   \"y\": 34,\n   \"width\": 18,\n   \"depth\": 25.5,\n   \"height\": 3.2,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"U2\",\n   \"kind\": \"smd-ic\",\n   \"x\": 30,\n   \"y\": 20,\n   \"width\": 7,\n   \"depth\": 7,\n   \"height\": 1.8,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"C1\",\n   \"kind\": \"electrolytic\",\n   \"x\": 18,\n   \"y\": 36,\n   \"width\": 8,\n   \"depth\": 8,\n   \"height\": 12,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"SW1\",\n   \"kind\": \"tactile-button\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 6,\n   \"depth\": 6,\n   \"height\": 5,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"D1\",\n   \"kind\": \"led-5mm\",\n   \"x\": 44,\n   \"y\": 10,\n   \"width\": 5.8,\n   \"depth\": 5.8,\n   \"height\": 8.7,\n   \"side\": \"top\"\n  }\n ],\n \"connectors\": [\n  {\n   \"id\": \"J1\",\n   \"kind\": \"usb-c\",\n   \"edge\": \"left\",\n   \"position\": 25,\n   \"width\": 8.94,\n   \"height\": 3.26,\n   \"depth\": 7.35,\n   \"overhang\": 0.6,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J2\",\n   \"kind\": \"barrel-jack\",\n   \"edge\": \"top\",\n   \"position\": 25,\n   \"width\": 9,\n   \"height\": 11,\n   \"depth\": 14,\n   \"overhang\": 0,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  },\n  {\n   \"id\": \"J3\",\n   \"kind\": \"header-right-angle\",\n   \"edge\": \"right\",\n   \"position\": 20,\n   \"width\": 15.24,\n   \"height\": 2.54,\n   \"depth\": 8.5,\n   \"overhang\": 3,\n   \"offsetZ\": 0,\n   \"side\": \"top\"\n  }\n ],\n \"keepouts\": [\n  {\n   \"id\": \"K1\",\n   \"label\": \"Button access\",\n   \"x\": 58,\n   \"y\": 10,\n   \"width\": 8,\n   \"depth\": 8,\n   \"heightAbove\": 30,\n   \"lidOpening\": true\n  }\n ]\n}"
          },
          "wall": {
            "title": "Wall thickness",
            "type": "number",
            "minimum": 0.8,
            "maximum": 6,
            "default": 2,
            "x-unit": "mm"
          },
          "floor": {
            "title": "Floor thickness",
            "type": "number",
            "minimum": 0.8,
            "maximum": 6,
            "default": 2,
            "x-unit": "mm"
          },
          "lidThickness": {
            "title": "Lid thickness",
            "type": "number",
            "minimum": 0.8,
            "maximum": 6,
            "default": 2,
            "x-unit": "mm"
          },
          "clearance": {
            "title": "Gap between board and wall",
            "description": "Around the board's bounding box.",
            "type": "number",
            "minimum": 0.1,
            "maximum": 10,
            "default": 1,
            "x-unit": "mm"
          },
          "topClearance": {
            "title": "Space above the tallest part",
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "default": 2,
            "x-unit": "mm"
          },
          "cornerRadius": {
            "title": "Outer corner radius",
            "description": "Drawn with straight facets on the arc.",
            "type": "number",
            "minimum": 0,
            "maximum": 30,
            "default": 3,
            "x-unit": "mm"
          },
          "standoffHeight": {
            "title": "Standoff height (under the board)",
            "description": "Also the depth of the screw or insert holes.",
            "type": "number",
            "minimum": 1,
            "maximum": 40,
            "default": 5,
            "x-unit": "mm"
          },
          "screw": {
            "title": "Screw size",
            "type": "string",
            "enum": [
              "M2",
              "M2.5",
              "M3"
            ],
            "default": "M3"
          },
          "fixing": {
            "title": "Board fixing",
            "type": "string",
            "enum": [
              "insert",
              "self-tap"
            ],
            "default": "insert"
          },
          "lid": {
            "title": "Lid",
            "type": "string",
            "enum": [
              "snap",
              "lip",
              "screws"
            ],
            "default": "snap"
          },
          "lipHeight": {
            "title": "Lip height",
            "type": "number",
            "minimum": 1,
            "maximum": 15,
            "default": 3,
            "x-unit": "mm"
          },
          "lipWidth": {
            "title": "Lip width",
            "type": "number",
            "minimum": 0.6,
            "maximum": 5,
            "default": 1.2,
            "x-unit": "mm"
          },
          "lipGap": {
            "title": "Gap between lip and wall",
            "description": "Per side; 0.15–0.3 mm suits most FDM printers.",
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 0.2,
            "x-unit": "mm"
          },
          "snapDepth": {
            "title": "Snap bump depth",
            "description": "How far the bumps reach beyond the lip; the catch is this minus the lip gap.",
            "type": "number",
            "minimum": 0.1,
            "maximum": 1.5,
            "default": 0.4,
            "x-unit": "mm"
          },
          "connectorClearance": {
            "title": "Clearance around connectors",
            "type": "number",
            "minimum": 0,
            "maximum": 5,
            "default": 0.5,
            "x-unit": "mm"
          },
          "vents": {
            "title": "Ventilation slots in the lid",
            "type": "boolean",
            "default": false
          },
          "ventWidth": {
            "title": "Vent slot width",
            "type": "number",
            "minimum": 1,
            "maximum": 10,
            "default": 2,
            "x-unit": "mm"
          },
          "ventPitch": {
            "title": "Vent slot pitch",
            "type": "number",
            "minimum": 2,
            "maximum": 30,
            "default": 4,
            "x-unit": "mm"
          },
          "circleSegments": {
            "title": "Facets per circle",
            "description": "Holes are drawn with their flats at the nominal diameter.",
            "type": "integer",
            "minimum": 12,
            "maximum": 96,
            "default": 32
          },
          "stlFormat": {
            "title": "STL format",
            "type": "string",
            "enum": [
              "binary",
              "ascii"
            ],
            "default": "binary"
          }
        },
        "required": []
      },
      "OhmforgeEnclosureGeneratorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "ok",
              "board",
              "sizeMm",
              "heights",
              "screw",
              "base",
              "lid",
              "checks",
              "cutouts",
              "warnings",
              "files"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "board": {
                "type": "string"
              },
              "sizeMm": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "outer": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "x0": {
                    "type": "number"
                  },
                  "x1": {
                    "type": "number"
                  },
                  "y0": {
                    "type": "number"
                  },
                  "y1": {
                    "type": "number"
                  }
                }
              },
              "cavity": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "x0": {
                    "type": "number"
                  },
                  "x1": {
                    "type": "number"
                  },
                  "y0": {
                    "type": "number"
                  },
                  "y1": {
                    "type": "number"
                  }
                }
              },
              "cornerRadius": {
                "type": "number"
              },
              "heights": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "floorTop": {
                    "type": "number"
                  },
                  "boardBottom": {
                    "type": "number"
                  },
                  "boardTop": {
                    "type": "number"
                  },
                  "wallTop": {
                    "type": "number"
                  },
                  "lidTop": {
                    "type": "number"
                  },
                  "lipBottom": {
                    "type": "number"
                  }
                }
              },
              "screw": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "size": {
                    "type": "string"
                  },
                  "fixing": {
                    "type": "string"
                  },
                  "holeDiameter": {
                    "type": "number"
                  },
                  "bossDiameter": {
                    "type": "number"
                  },
                  "holeDepth": {
                    "type": "number"
                  },
                  "insertLength": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                }
              },
              "settings": {
                "type": "object"
              },
              "base": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "triangles": {
                    "type": "integer"
                  },
                  "vertices": {
                    "type": "integer"
                  },
                  "watertight": {
                    "type": "boolean"
                  },
                  "nonManifoldEdges": {
                    "type": "integer"
                  },
                  "nonManifoldVertices": {
                    "type": "integer"
                  },
                  "boundaryEdges": {
                    "type": "integer"
                  },
                  "components": {
                    "type": "integer"
                  },
                  "volumeMm3": {
                    "type": "number"
                  },
                  "cellVolumeMm3": {
                    "type": "number"
                  },
                  "areaMm2": {
                    "type": "number"
                  },
                  "sizeMm": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "stlPrintReady": {
                    "type": "boolean"
                  }
                }
              },
              "lid": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "triangles": {
                    "type": "integer"
                  },
                  "vertices": {
                    "type": "integer"
                  },
                  "watertight": {
                    "type": "boolean"
                  },
                  "nonManifoldEdges": {
                    "type": "integer"
                  },
                  "nonManifoldVertices": {
                    "type": "integer"
                  },
                  "boundaryEdges": {
                    "type": "integer"
                  },
                  "components": {
                    "type": "integer"
                  },
                  "volumeMm3": {
                    "type": "number"
                  },
                  "cellVolumeMm3": {
                    "type": "number"
                  },
                  "areaMm2": {
                    "type": "number"
                  },
                  "sizeMm": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "stlPrintReady": {
                    "type": "boolean"
                  }
                }
              },
              "bosses": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    }
                  }
                }
              },
              "posts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    },
                    "diameter": {
                      "type": "number"
                    },
                    "holeDiameter": {
                      "type": "number"
                    },
                    "holeDepth": {
                      "type": "number"
                    },
                    "lidHole": {
                      "type": "number"
                    }
                  }
                }
              },
              "cutouts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "edge": {
                      "type": "string"
                    },
                    "x0": {
                      "type": "number"
                    },
                    "x1": {
                      "type": "number"
                    },
                    "y0": {
                      "type": "number"
                    },
                    "y1": {
                      "type": "number"
                    },
                    "z0": {
                      "type": "number"
                    },
                    "z1": {
                      "type": "number"
                    },
                    "viewLeft": {
                      "type": "number"
                    },
                    "viewWidth": {
                      "type": "number"
                    },
                    "bottom": {
                      "type": "number"
                    },
                    "top": {
                      "type": "number"
                    },
                    "notch": {
                      "type": "boolean"
                    }
                  }
                }
              },
              "snaps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "edge": {
                      "type": "string"
                    },
                    "from": {
                      "type": "number"
                    },
                    "to": {
                      "type": "number"
                    }
                  }
                }
              },
              "vents": {
                "type": "integer"
              },
              "openings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "x0": {
                      "type": "number"
                    },
                    "x1": {
                      "type": "number"
                    },
                    "y0": {
                      "type": "number"
                    },
                    "y1": {
                      "type": "number"
                    }
                  }
                }
              },
              "checks": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "kind": {
                      "type": "string"
                    },
                    "ok": {
                      "type": "boolean"
                    },
                    "text": {
                      "type": "string"
                    }
                  }
                }
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "files": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "baseStl",
                  "lidStl",
                  "assemblyObj",
                  "drawingSvg",
                  "project"
                ],
                "properties": {
                  "baseStl": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "lidStl": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "assemblyObj": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "drawingSvg": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  "project": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}