{
  "openapi": "3.1.1",
  "info": {
    "title": "Premium apps API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "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://apps.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "kerfwise-cabinet-builder",
                "kerfwise-cut-list",
                "kerfwise-sheet-nesting",
                "kinetica-collision-check",
                "kinetica-forward-kinematics",
                "kinetica-inverse-kinematics",
                "kinetica-trajectory-planner",
                "ohmforge-ac-sweep",
                "ohmforge-dc-operating-point",
                "ohmforge-led-resistor",
                "ohmforge-transient",
                "threadsmith-design-stats",
                "threadsmith-digitize",
                "threadsmith-stitch-file",
                "twinworks-bottleneck-analysis",
                "twinworks-buffer-sweep",
                "twinworks-simulate",
                "twinworks-line-balance",
                "twinworks-queue-formulas"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/kerfwise-cabinet-builder/calculate": {
      "post": {
        "operationId": "calculateKerfwiseCabinetBuilder",
        "summary": "Parametric cabinet → every part with cut sizes, edge banding, drilling and hardware.",
        "description": "Give a cabinet type (base, wall, tall, drawer bank, blind corner, open shelf, wardrobe, bookshelf, desk, table, bed frame) with its size, back panel, doors, drawers, shelves and joinery, and get the complete parts list with finished and cut sizes, grain direction, edge banding per edge, hinge and shelf-pin drilling, hardware and a front view. The same engine powers the Kerfwise app.\n\nMethodology:\n- Carcass: sides run full height, so side height = cabinet height − plinth height; top, bottom and fixed shelves sit between the sides (length = inner width = width − 2 × panel thickness), plus 2 × dado depth (T/3) for dado joints or 2 × rabbet depth (T/2) for rabbets.\n- Back panels: grooved = (inner width + 2 × groove depth) × (inner height + 2 × groove depth) and the shelves lose groove set-back + back thickness of depth; inset = inner width × inner height; nailed = outer size − 2 mm, and the carcass depth includes the back.\n- Doors: full overlay = width / n − gap by carcass height − gap (gap 3 mm = 1.5 mm reveal per edge); inset = (opening − (n + 1) × gap) / n. Hinges per door by height: ≤ 900 mm → 2, ≤ 1600 → 3, ≤ 2000 → 4, else 5, placed 100 mm from the ends; Ø35 × 13 mm cup 22.5 mm from the edge with two Ø8 dowel holes 45 mm apart, mounting plates on the side 37 mm from the front.\n- Drawers: slide length = largest standard length ≤ inner depth − 10 mm; box length = nominal slide length; box width = opening − 25.4 mm (side-mount, 12.7 mm per side) or opening − 42 mm + 2 × side thickness (undermount); box height = front height − 40 mm (side) / − 47 mm (undermount). Front/back length: butt or dowel = box width − 2t, dado = + t, dovetail = full box width.\n- Adjustable shelves: inner width − 2 mm, 20 mm set back, on Ø5 holes at 32 mm pitch in two rows (37 mm from the front, rear row on the 32 mm grid). Fasteners: 50 mm from each end, ≤ 150 mm apart (dowels, confirmat, screws, pocket screws), cams 2–3 per joint.\n- Cut size = finished size − edge-banding thickness on each banded edge (L1/L2 run along the length and reduce the width; W1/W2 reduce the length) when deduction is on.\n\nDimensions follow common European frameless practice and the stated rules. Always check hardware manufacturers’ planning data for the exact hinges and slides you buy, and verify critical sizes before cutting expensive material.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kerfwise_cabinet_builder",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KerfwiseCabinetBuilderInput"
              },
              "examples": {
                "example1": {
                  "summary": "Kitchen base cabinet 600, grooved back, legs, 1 door",
                  "value": {
                    "type": "base",
                    "width": 600,
                    "height": 870,
                    "depth": 560,
                    "backType": "groove",
                    "grooveDepth": 8,
                    "plinthType": "legs",
                    "plinthHeight": 150,
                    "doorCount": 1,
                    "shelfCount": 1,
                    "carcassJoint": "dowel",
                    "topType": "rails"
                  }
                },
                "example2": {
                  "summary": "Drawer bank 800 with undermount slides and dovetails",
                  "value": {
                    "type": "drawer",
                    "width": 800,
                    "height": 870,
                    "depth": 560,
                    "drawerCount": 4,
                    "slideType": "under",
                    "drawerJoint": "dovetail",
                    "carcassJoint": "confirmat"
                  }
                },
                "example3": {
                  "summary": "Wardrobe 1000 × 2200, cam joints, 2 doors",
                  "value": {
                    "type": "wardrobe",
                    "width": 1000,
                    "height": 2200,
                    "depth": 600,
                    "carcassJoint": "cam",
                    "plinthType": "board",
                    "plinthHeight": 80
                  }
                },
                "example4": {
                  "summary": "Dining table 1600 × 900 with mortise & tenon aprons",
                  "value": {
                    "type": "table",
                    "width": 1600,
                    "depth": 900,
                    "height": 750,
                    "materialId": "oakpanel-27",
                    "frameJoint": "mortise-tenon"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KerfwiseCabinetBuilderResult"
                }
              }
            }
          },
          "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/tools/kerfwise-cut-list/calculate": {
      "post": {
        "operationId": "calculateKerfwiseCutList",
        "summary": "Cabinets or a Kerfwise project → cut list, edge banding, hardware, sheets and costs.",
        "description": "Paste a Kerfwise project (.kerfwise.json) or list cabinets by type and size, and get the complete grouped cut list with edge banding per edge, banding metres, hardware list, optimised sheet count and yield per material, worktops, labour minutes and a full cost estimate with markup and tax. CSV export included.\n\nMethodology:\n- Every cabinet is generated with the Kerfwise cabinet engine (see kerfwise-cabinet-builder for the joinery rules); identical cut pieces (same material, size, grain and banding) are grouped into one row with all their labels.\n- Edge banding metres = sum of banded finished edge lengths × (1 + banding waste %, default 10 %), rounded up to 0.1 m.\n- Sheets: parts of each sheet material are nested with the kerfwise-sheet-nesting optimiser (kerf, trim margins, grain locked for grained materials); solid stock and worktops use first-fit-decreasing 1D optimisation.\n- Cost = materials (full sheets or used area × (1 + waste %)) + banding + hardware + labour (cut minutes per part, banding minutes per metre, drilling minutes per hole, assembly minutes per cabinet) + worktop cut-outs, then markup and tax.\n\nPrices are editable defaults, not quotes. Labour times are rough workshop averages — adjust them to your shop. Check the cut list against your drawings before cutting.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kerfwise_cut_list",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KerfwiseCutListInput"
              },
              "examples": {
                "example1": {
                  "summary": "Three kitchen cabinets (base, drawer bank, wall)",
                  "value": {
                    "cabinets": [
                      {
                        "type": "base",
                        "width": 600,
                        "doors": 1,
                        "shelves": 1
                      },
                      {
                        "type": "drawer",
                        "width": 600,
                        "drawers": 3
                      },
                      {
                        "type": "wall",
                        "width": 800,
                        "doors": 2
                      }
                    ],
                    "kerf": 4,
                    "trim": 10,
                    "labourRate": 45,
                    "currency": "EUR"
                  }
                },
                "example2": {
                  "summary": "Bookshelf ×2 and a desk, 19 % VAT",
                  "value": {
                    "cabinets": [
                      {
                        "type": "bookshelf",
                        "width": 800,
                        "qty": 2
                      },
                      {
                        "type": "desk",
                        "width": 1400,
                        "drawers": 2
                      }
                    ],
                    "materialId": "oak-18",
                    "frontMaterialId": "oak-18",
                    "taxPct": 19,
                    "markupPct": 15
                  }
                },
                "example3": {
                  "summary": "Project JSON: wall cabinet in walnut",
                  "value": {
                    "project": "{\"format\":\"kerfwise\",\"version\":1,\"name\":\"Walnut wall cabinet\",\"cabinets\":[{\"type\":\"wall\",\"params\":{\"width\":900,\"doorCount\":2,\"frontMaterialId\":\"walnut-19\",\"frontBandingId\":\"walnut-veneer-05\"}}]}"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KerfwiseCutListResult"
                }
              }
            }
          },
          "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/tools/kerfwise-sheet-nesting/calculate": {
      "post": {
        "operationId": "calculateKerfwiseSheetNesting",
        "summary": "Nest rectangular parts on sheets with kerf, trim and grain: layouts, yield, offcuts, SVG + DXF.",
        "description": "A cutting optimiser for panel saws and CNC routers: list rectangular parts with quantity and grain, choose the sheet size (e.g. 2800 × 2070), saw kerf and trim margin, and get guillotine-cuttable or MaxRects layouts, sheet count, yield per sheet, reusable offcuts, the guillotine cut sequence, SVG drawings and a DXF R12 file.\n\nMethodology:\n- Parts are inflated by one kerf and the usable sheet (sheet − 2 × trim) by one kerf, so neighbouring parts are exactly one kerf apart and the outer parts touch the trimmed edge.\n- Guillotine: free-rectangle packing with best-area-fit / best-short-side-fit and split rules (shorter-leftover-axis, longer-leftover-axis, min-area); every placement records its edge-to-edge cuts, giving a panel-saw cut sequence. MaxRects: maximal free rectangles with best-short-side, best-area or bottom-left fit (tighter, for CNC).\n- Each method runs a fixed set of strategies (4 sort orders × fit/split rules × rotation on/off) and keeps the best: fewest unplaced parts → fewest sheets → least sheet area → largest single offcut → guillotine preferred. Deterministic for identical input.\n- Grain: on a grained material, parts marked grain keep their length along the sheet length; other parts may rotate 90°. Yield = part area / full sheet area. Offcuts = non-overlapping free rectangles ≥ the minimum offcut size.\n\nHeuristic optimisation: good, fast layouts, not a proven optimum. Check that your saw can follow the cut sequence and measure your blade’s real kerf.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kerfwise_sheet_nesting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KerfwiseSheetNestingInput"
              },
              "examples": {
                "example1": {
                  "summary": "16 panels 600 × 500 on 2800 × 2070 (exactly one sheet)",
                  "value": {
                    "parts": [
                      {
                        "name": "Panel",
                        "length": 600,
                        "width": 500,
                        "qty": 16
                      }
                    ],
                    "sheetLength": 2800,
                    "sheetWidth": 2070,
                    "kerf": 4,
                    "trim": 10,
                    "method": "guillotine",
                    "grainedMaterial": false
                  }
                },
                "example2": {
                  "summary": "Base cabinet carcass parts, oak veneer with grain",
                  "value": {
                    "parts": [
                      {
                        "name": "Side",
                        "length": 720,
                        "width": 559,
                        "qty": 4,
                        "grain": true
                      },
                      {
                        "name": "Bottom",
                        "length": 564,
                        "width": 559,
                        "qty": 2,
                        "grain": true
                      },
                      {
                        "name": "Rail",
                        "length": 564,
                        "width": 99,
                        "qty": 4,
                        "grain": true
                      },
                      {
                        "name": "Shelf",
                        "length": 562,
                        "width": 515,
                        "qty": 2,
                        "grain": true
                      },
                      {
                        "name": "Door",
                        "length": 716,
                        "width": 596,
                        "qty": 2,
                        "grain": true
                      }
                    ],
                    "sheetLength": 2800,
                    "sheetWidth": 2070,
                    "sheetPrice": 148,
                    "kerf": 4,
                    "trim": 10,
                    "method": "auto",
                    "grainedMaterial": true
                  }
                },
                "example3": {
                  "summary": "Plywood 2440 × 1220, mixed parts, MaxRects",
                  "value": {
                    "parts": [
                      {
                        "name": "Top",
                        "length": 1200,
                        "width": 600,
                        "qty": 1
                      },
                      {
                        "name": "Side",
                        "length": 700,
                        "width": 580,
                        "qty": 2
                      },
                      {
                        "name": "Shelf",
                        "length": 1160,
                        "width": 300,
                        "qty": 3
                      },
                      {
                        "name": "Strip",
                        "length": 1160,
                        "width": 80,
                        "qty": 4
                      }
                    ],
                    "sheetLength": 2440,
                    "sheetWidth": 1220,
                    "sheetPrice": 74,
                    "kerf": 3.2,
                    "trim": 5,
                    "method": "maxrects",
                    "grainedMaterial": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KerfwiseSheetNestingResult"
                }
              }
            }
          },
          "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/tools/kinetica-collision-check/calculate": {
      "post": {
        "operationId": "calculateKineticaCollisionCheck",
        "summary": "Robot pose + obstacles → collisions, minimum clearance and self-collision between links.",
        "description": "Checks a robot configuration against box, sphere and capsule obstacles and against itself. Robot links are modelled as capsules and boxes; the tool reports every pair closer than the safety margin, the minimum clearance and the closest pair, using exact segment–segment distances and an exact convex search for capsule–box distances.\n\nMethodology:\n- Robot links are capsules (segment + radius) and oriented boxes attached to the link frames; library robots generate capsules along the kinematic skeleton, URDF boxes/cylinders/spheres are imported (cylinders become capsules with caps ending at the cylinder faces; flat discs become an equal-area square prism).\n- Capsule–capsule: closest points between two segments minus both radii. Capsule–box: the squared distance from the segment to the box is convex in the segment parameter, so a 64-step golden-section search finds the minimum. Box–box: separating-axis test for overlap, else the minimum of the 24 edge-to-box distances.\n- Self-collision skips adjacent links, user-listed pairs and pairs that already touch in the robot’s home pose (as in MoveIt’s allowed-collision matrix); the static base link is not checked against the environment.\n- A pair counts as a contact when its clearance is below the safety margin.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active. Geometry is a simplified envelope of the real robot.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_collision_check",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaCollisionCheckInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm above a table (clear)",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, 0, 0, 0, 90, 0",
                    "obstacles": [
                      {
                        "name": "Table",
                        "shape": "box",
                        "x": 900,
                        "y": 0,
                        "z": 350,
                        "sx": 700,
                        "sy": 900,
                        "sz": 700
                      }
                    ],
                    "margin": 10
                  }
                },
                "example2": {
                  "summary": "Arm reaching into a box (collision)",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, 40, 30, 0, 20, 0",
                    "obstacles": [
                      {
                        "name": "Machine",
                        "shape": "box",
                        "x": 1000,
                        "y": 0,
                        "z": 400,
                        "sx": 600,
                        "sy": 800,
                        "sz": 800
                      }
                    ],
                    "margin": 0
                  }
                },
                "example3": {
                  "summary": "Folded elbow: self-collision check",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, -90, 155, 0, 125, 0",
                    "self": true,
                    "margin": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaCollisionCheckResult"
                }
              }
            }
          },
          "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/tools/kinetica-forward-kinematics/calculate": {
      "post": {
        "operationId": "calculateKineticaForwardKinematics",
        "summary": "DH table or URDF + joint values → TCP pose, every joint frame, Jacobian and manipulability.",
        "description": "Computes the tool-centre-point pose of a serial robot from its Denavit–Hartenberg table (standard or modified), a URDF subset or a library robot and the joint values. Returns the 4×4 transform, position and roll/pitch/yaw, quaternion, all intermediate frames, the geometric Jacobian, manipulability and singularity status, and static payload torques.\n\nMethodology:\n- Each joint compiles to Fᵢ = Fᵢ₋₁ · Preᵢ · Motionᵢ(qᵢ) · Postᵢ. Standard DH: Rz(θ+q)·Tz(d)·Tx(a)·Rx(α); modified DH (Craig): Rx(α)·Tx(a)·Rz(θ+q)·Tz(d); URDF: origin(xyz, rpy) · rotation about / translation along the joint axis.\n- TCP = base mount · F_n · tool offset. Orientation is reported as fixed-axis roll-pitch-yaw (R = Rz(yaw)·Ry(pitch)·Rx(roll), the URDF convention) and as a unit quaternion [w, x, y, z].\n- Geometric Jacobian at the TCP: revolute column [zᵢ × (p − oᵢ); zᵢ], prismatic column [zᵢ; 0]. Rows vx, vy, vz in mm per rad (or per mm), wx, wy, wz in rad per unit.\n- Manipulability: Yoshikawa √det(J·Jᵀ) of the Jacobian with translation rows divided by a characteristic length (the arm’s skeleton length), and σmin/σmax as a 0–1 singularity indicator (< 0.001 singular, < 0.03 near-singular).\n- Payload loads: static holding torque τ = −Jᵀ(cog)·m·g for the tool mass at its centre of gravity (g = 9.80665 m/s², gravity along −z world).\n- Verified against hand-computed planar cases, the PUMA 560 qz pose (452.1, −150.05, 1103.63) mm of the Robotics Toolbox model and the UR5 zero pose (−817.25, −191.45, −5.491) mm.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_forward_kinematics",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaForwardKinematicsInput"
              },
              "examples": {
                "example1": {
                  "summary": "PUMA 560 at qz (all zeros) — textbook pose",
                  "value": {
                    "robot": "puma560",
                    "joints": "0, 0, 0, 0, 0, 0"
                  }
                },
                "example2": {
                  "summary": "UR5-style cobot at its upright home",
                  "value": {
                    "robot": "ur5-like",
                    "joints": "0, -90, 90, -90, -90, 0"
                  }
                },
                "example3": {
                  "summary": "Planar 2-link arm from a custom DH table (l1 = 300, l2 = 250)",
                  "value": {
                    "robot": "custom-dh",
                    "convention": "dh",
                    "dh": [
                      {
                        "type": "revolute",
                        "a": 300,
                        "alpha": 0,
                        "d": 0,
                        "theta": 0
                      },
                      {
                        "type": "revolute",
                        "a": 250,
                        "alpha": 0,
                        "d": 0,
                        "theta": 0
                      }
                    ],
                    "joints": "30, 60"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaForwardKinematicsResult"
                }
              }
            }
          },
          "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/tools/kinetica-inverse-kinematics/calculate": {
      "post": {
        "operationId": "calculateKineticaInverseKinematics",
        "summary": "Target TCP pose → all joint solutions found, residuals, joint limits and reachability.",
        "description": "Solves the inverse kinematics of a serial robot (DH table, URDF subset or library robot) for a target TCP pose with damped least squares from several deterministic seeds, plus closed-form solutions for planar 2-link arms and SCARAs. Lists every distinct solution with its residual, joint-limit and singularity status, and explains why a target is unreachable.\n\nMethodology:\n- Error e = [Δp / L; Δφ] with Δφ the rotation vector from current to target orientation and L the arm’s characteristic length, restricted to the task rows the robot can actually control (e.g. x, y, z, yaw for a SCARA; x, y for a planar arm).\n- Damped least squares step Δq = Jᵀ(J·Jᵀ + λ²I)⁻¹e with adaptive damping λ (decrease after an improving step, increase after a failed one), step-size limit 0.5 rad, and projection onto the joint limits (revolute joints wrap by 2π when the range allows).\n- Restarts: the preferred configuration, the home pose, then pseudo-random configurations from a seeded mulberry32 generator; distinct converged solutions (position residual ≤ 1e-6 mm, orientation ≤ 1e-8 rad) are kept and sorted by distance to the preferred configuration.\n- Closed forms: planar 2R and SCARA use the law of cosines (two elbow branches), then FK verifies and a short DLS polish removes any remaining residual.\n- Unreachable targets report the distance from the first joint versus the skeleton length (upper bound of reach) and the closest configuration found.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_inverse_kinematics",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaInverseKinematicsInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm, tool pointing down at (700, 200, 600) mm",
                  "value": {
                    "robot": "kx6-1400",
                    "x": 700,
                    "y": 200,
                    "z": 600,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 0
                  }
                },
                "example2": {
                  "summary": "SCARA closed form: (300, 250, 200) mm, yaw 45°",
                  "value": {
                    "robot": "scara-550",
                    "x": 300,
                    "y": 250,
                    "z": 200,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 45
                  }
                },
                "example3": {
                  "summary": "Planar arm: elbow-up and elbow-down for (350, 200)",
                  "value": {
                    "robot": "planar2",
                    "x": 350,
                    "y": 200,
                    "z": 50,
                    "roll": 0,
                    "pitch": 0,
                    "yaw": 0,
                    "mode": "position"
                  }
                },
                "example4": {
                  "summary": "Unreachable target (2 m away)",
                  "value": {
                    "robot": "ur5-like",
                    "x": 2000,
                    "y": 0,
                    "z": 300,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaInverseKinematicsResult"
                }
              }
            }
          },
          "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/tools/kinetica-trajectory-planner/calculate": {
      "post": {
        "operationId": "calculateKineticaTrajectoryPlanner",
        "summary": "Waypoints (PTP, LIN, CIRC) + limits → timed joint samples, cycle time and peak velocities.",
        "description": "Plans a robot motion program from waypoints: synchronous joint moves (PTP), straight TCP lines (LIN) and circular arcs (CIRC) with trapezoidal, quintic or jerk-limited S-curve profiles that respect the joint velocity and acceleration limits, blend radii and dwell times. Returns the cycle time, per-segment timing, peak joint velocities and accelerations, a sampled joint/TCP trajectory and a CSV.\n\nMethodology:\n- PTP: synchronous joint interpolation q(s) = q₀ + s·Δq with one profile on s ∈ [0, 1]; the limits on s are min over joints of vmaxᵢ/|Δqᵢ| (and the same for acceleration and jerk), so every joint starts and stops together and none exceeds its limits.\n- Trapezoid: if h ≥ v²/a then Ta = v/a and T = h/v + v/a, else triangular with Ta = √(h/a), T = 2√(h/a). Quintic: s = 10τ³ − 15τ⁴ + 6τ⁵ with T = max(1.875·h/v, √(5.7735·h/a)). S-curve: double-S with jerk limit (Biagiotti & Melchiorri §3.4).\n- LIN/CIRC: the TCP follows the line or the circle through start, via and end point, orientation by quaternion slerp; IK runs per sample seeded from the previous one. If a joint would exceed its velocity/acceleration limit the segment is slowed down uniformly and re-planned (reported as speed scale).\n- Blending: consecutive moves overlap by the time the TCP spends inside the blend radius (capped at half of each move) and are superposed in joint space, which rounds the corner without stopping.\n- Velocities/accelerations in the output are central differences of the sampled trajectory; the cycle time includes dwell times.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active. Real controllers add their own look-ahead, dynamics limits and servo lag, so measured cycle times differ.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_trajectory_planner",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaTrajectoryPlannerInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm: two PTP moves and a LIN line",
                  "value": {
                    "robot": "kx6-1400",
                    "profile": "trapezoid",
                    "waypoints": [
                      {
                        "name": "Home",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0"
                      },
                      {
                        "name": "Above",
                        "type": "PTP",
                        "target": "p: 800, -200, 700, 180, 0, 0",
                        "vel": 80,
                        "acc": 80,
                        "blend": 30
                      },
                      {
                        "name": "Line",
                        "type": "LIN",
                        "target": "p: 800, 200, 700, 180, 0, 0",
                        "vel": 250,
                        "acc": 1500
                      },
                      {
                        "name": "Home",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0",
                        "vel": 100,
                        "acc": 100
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Single joint, trapezoid timing check (90° at 156°/s, 400°/s²)",
                  "value": {
                    "robot": "kx6-1400",
                    "profile": "trapezoid",
                    "waypoints": [
                      {
                        "name": "A",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0"
                      },
                      {
                        "name": "B",
                        "type": "PTP",
                        "target": "j: 90, 0, 0, 0, 90, 0",
                        "vel": 100,
                        "acc": 100
                      }
                    ]
                  }
                },
                "example3": {
                  "summary": "SCARA pick with S-curve profile and CIRC",
                  "value": {
                    "robot": "scara-550",
                    "profile": "scurve",
                    "waypoints": [
                      {
                        "name": "Start",
                        "type": "PTP",
                        "target": "j: -30, 60, 50, 0"
                      },
                      {
                        "name": "P1",
                        "type": "LIN",
                        "target": "p: 350, -200, 250, 180, 0, 0",
                        "vel": 500,
                        "acc": 4000
                      },
                      {
                        "name": "Arc",
                        "type": "CIRC",
                        "target": "p: 350, 200, 250, 180, 0, 0",
                        "via": "450, 0, 250",
                        "vel": 500,
                        "acc": 4000
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaTrajectoryPlannerResult"
                }
              }
            }
          },
          "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/tools/ohmforge-ac-sweep/calculate": {
      "post": {
        "operationId": "calculateOhmforgeAcSweep",
        "summary": "Frequency response of a circuit: Bode magnitude/phase, −3 dB corner and unity gain.",
        "description": "Linearises the circuit at its DC operating point and solves the complex MNA equations across a logarithmic frequency sweep. Returns magnitude in dB and unwrapped phase of an output node (optionally relative to an input node), the peak gain, lower/upper −3 dB frequencies, the unity-gain frequency, a Bode chart and CSV.\n\nMethodology:\n- The DC operating point is solved first; every nonlinear device is replaced by its small-signal conductances at that point (diode gd, BJT gm/gπ/go, MOSFET gm/gds, op-amp output slope).\n- Capacitors become admittances jωC, inductors impedances jωL in their branch equations, coupled inductors jωM; the complex system is solved by dense LU with partial pivoting at every frequency.\n- Magnitude is 20·log10|H|, phase is unwrapped to be continuous. The −3 dB points are found 3.01 dB below the peak by logarithmic interpolation; unity gain is the 0 dB crossing.\n\nTeaching-grade simulation: device models are simplified (Ebers–Moll BJT, level-1 MOSFET, behavioural op-amps and 555) and part ratings are typical values. Verify real designs on the bench and against manufacturer data before building anything connected to mains voltage.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ohmforge_ac_sweep",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OhmforgeAcSweepInput"
              },
              "examples": {
                "example1": {
                  "summary": "RC low-pass (fc ≈ 1.59 kHz)",
                  "value": {
                    "netlist": "* RC low-pass, fc = 1/(2*pi*1k*100n) = 1591.5 Hz\nV1 in 0 DC 0 AC 1\nR1 in out 1k\nC1 out 0 100n\n.ac dec 20 10 1meg",
                    "output": "out",
                    "input": "V1"
                  }
                },
                "example2": {
                  "summary": "Inverting op-amp, gain −10",
                  "value": {
                    "netlist": "* Inverting amplifier, gain -10 (ideal op-amp as VCVS)\nV1 in 0 AC 1\nR1 in m 1k\nR2 m out 10k\nE1 out 0 0 m 100k\n.ac dec 10 10 10meg",
                    "output": "out",
                    "input": "V1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OhmforgeAcSweepResult"
                }
              }
            }
          },
          "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/tools/ohmforge-dc-operating-point/calculate": {
      "post": {
        "operationId": "calculateOhmforgeDcOperatingPoint",
        "summary": "SPICE netlist in, node voltages, branch currents, power and overload warnings out.",
        "description": "Solves the DC operating point of a circuit with Ohmforge's SPICE-style engine (Modified Nodal Analysis, Newton–Raphson with junction limiting, damping, gmin and source stepping). Returns every node voltage, the current and power of every element, total supply power, parts beyond their ratings and plain-language convergence diagnostics.\n\nMethodology:\n- The netlist is parsed (SPICE subset) and compiled into Modified Nodal Analysis unknowns: one voltage per node plus one current per voltage source, inductor and controlled-source output.\n- Nonlinear devices (Shockley diode with series resistance and breakdown, Ebers–Moll BJT with Early effect, Shichman–Hodges level-1 MOSFET) are linearised at each Newton–Raphson iteration; junction voltages are limited with the SPICE3 pnjlim rule.\n- If plain Newton–Raphson fails, the solver retries with damping (≤ 0.5 V per iteration), then gmin stepping (1e-2 S → 1e-12 S to ground on every node) and finally source stepping (all sources ramped 0 → 100 %). Every attempt is reported in plain words.\n- Topology checks run first: missing ground, loops of voltage sources/inductors (no unique solution) and nodes without a DC path to ground.\n- Element power is Σ(terminal current × node voltage); sources show negative power when delivering. Ratings (resistor watts, LED current, diode/transistor limits, capacitor voltage) are compared with the result.\n\nTeaching-grade simulation: device models are simplified (Ebers–Moll BJT, level-1 MOSFET, behavioural op-amps and 555) and part ratings are typical values. Verify real designs on the bench and against manufacturer data before building anything connected to mains voltage.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ohmforge_dc_operating_point",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OhmforgeDcOperatingPointInput"
              },
              "examples": {
                "example1": {
                  "summary": "Voltage divider (10 V, 1k/3k → 7.5 V)",
                  "value": {
                    "netlist": "* Voltage divider\nV1 in 0 DC 10\nR1 in out 1k\nR2 out 0 3k\n.op\n.end"
                  }
                },
                "example2": {
                  "summary": "Transistor switching an LED",
                  "value": {
                    "netlist": "* LED with series resistor and a 2N3904 switch\nVCC vcc 0 9\nRB vcc b 10k\nRC vcc a 470\nD1 a c LED_RED\nQ1 c b 0 2N3904\n.op"
                  }
                },
                "example3": {
                  "summary": "Diode forward drop (Shockley)",
                  "value": {
                    "netlist": "* Shockley diode check\nV1 in 0 5\nR1 in a 1k\nD1 a 0 DMOD\n.model DMOD D(IS=1e-14 N=1)\n.op"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OhmforgeDcOperatingPointResult"
                }
              }
            }
          },
          "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/tools/ohmforge-led-resistor/calculate": {
      "post": {
        "operationId": "calculateOhmforgeLedResistor",
        "summary": "Series resistor for LEDs, rounded to a standard value and checked with a real diode model.",
        "description": "Calculates the series resistor for one or more LEDs in series: R = (Vs − n·Vf) / I, rounds up to the next E6/E12/E24 value, and then verifies the actual current, LED voltage and resistor dissipation by simulating the circuit with Ohmforge's diode model. Suggests a power rating with 2× margin.\n\nMethodology:\n- Exact value R = (Vs − n·Vf) / I with the typical forward voltage of the chosen colour at 20 mA.\n- Rounded UP to the next preferred value of the chosen E-series so the current never exceeds the target.\n- The circuit (supply, resistor, n LEDs) is then simulated with Ohmforge's LED diode model (n = 2, Rs = 4 Ω, fitted to Vf at 20 mA) to report the real current, which is slightly different because Vf depends on current.\n- Resistor rating: next of 0.125/0.25/0.5/1/2/5 W at or above twice the dissipation.\n\nForward voltages vary by LED type and batch (±0.2 V is common); check the datasheet of your LED. Mains-powered LED circuits need proper isolation – do not build them from this calculation.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ohmforge_led_resistor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OhmforgeLedResistorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Red LED on 9 V at 20 mA",
                  "value": {
                    "supply": 9,
                    "colour": "red",
                    "current": 20,
                    "count": 1,
                    "series": "E12"
                  }
                },
                "example2": {
                  "summary": "Three white LEDs on 12 V at 15 mA",
                  "value": {
                    "supply": 12,
                    "colour": "white",
                    "current": 15,
                    "count": 3,
                    "series": "E24"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OhmforgeLedResistorResult"
                }
              }
            }
          },
          "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/tools/ohmforge-transient/calculate": {
      "post": {
        "operationId": "calculateOhmforgeTransient",
        "summary": "Simulate a circuit over time: waveforms, Vpp/RMS/frequency, CSV and a chart.",
        "description": "Runs a transient (time-domain) simulation of a SPICE netlist with trapezoidal or backward-Euler integration, adaptive time steps and breakpoints at source corners. Returns resampled waveforms of the chosen nodes, oscilloscope-style measurements (min, max, Vpp, mean, RMS, frequency, duty cycle, rise time), rating warnings, a chart and CSV.\n\nMethodology:\n- Starts from the DC operating point (or from initial conditions with \"uic\"), then integrates capacitors and inductors with companion models: trapezoidal (2C/h) or backward Euler (C/h); inductors and coupled inductors use branch currents.\n- Each time step is solved with Newton–Raphson. The step size adapts: the difference between the corrector and a linear predictor estimates the local truncation error; failed steps are retried with h/8.\n- Source corners (PULSE edges, PWL points) are breakpoints: the integrator lands on them and restarts with backward Euler to avoid trapezoidal ringing. Behavioural events (555 latch, relay pull-in, fuse, current limit) are localised by step bisection.\n- Returned samples are linearly interpolated onto a uniform grid (output step). Measurements: time-weighted mean and RMS, Vpp, frequency from mid-level crossings with 10 % hysteresis, 10–90 % rise time.\n\nTeaching-grade simulation: device models are simplified (Ebers–Moll BJT, level-1 MOSFET, behavioural op-amps and 555) and part ratings are typical values. Verify real designs on the bench and against manufacturer data before building anything connected to mains voltage.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ohmforge_transient",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OhmforgeTransientInput"
              },
              "examples": {
                "example1": {
                  "summary": "RC step response (τ = 1 ms)",
                  "value": {
                    "netlist": "* RC step response, tau = 1 ms\nV1 in 0 PULSE(0 1 0 1n 1n 10m 20m)\nR1 in out 1k\nC1 out 0 1u\n.tran 10u 5m\n.end",
                    "probes": [
                      "in",
                      "out"
                    ]
                  }
                },
                "example2": {
                  "summary": "Half-wave rectifier with smoothing",
                  "value": {
                    "netlist": "* Half-wave rectifier with reservoir capacitor\nV1 ac 0 SIN(0 12 50)\nD1 ac out 1N4007\nC1 out 0 470u\nRL out 0 1k\n.tran 50u 100m",
                    "probes": [
                      "ac",
                      "out"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OhmforgeTransientResult"
                }
              }
            }
          },
          "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/tools/threadsmith-design-stats/calculate": {
      "post": {
        "operationId": "calculateThreadsmithDesignStats",
        "summary": "Stitch count, colours, trims, thread, bobbin, sewing time and density of a DST/EXP file.",
        "description": "Reads a Tajima DST or Melco EXP file (or a stitch list) and reports stitches, jumps, trims, colour changes, size and hoop fit, thread length per colour with a bobbin estimate, sewing time at your machine speed and a thread-density check with the densest spots, plus a thread-look preview.\n\nMethodology:\n- DST records are decoded from balanced ternary (bits for ±1, ±3, ±9, ±27, ±81 per axis); runs of three or more jumps count as one trim, as on most machines. EXP bytes are two’s-complement 0.1 mm steps with 0x80 control codes.\n- Sewn length = sum of stitch lengths per colour; top thread = sewn length + 0.8 mm take-up per penetration + 5 % waste; bobbin ≈ 33 % of sewn length.\n- Sewing time = stitches ÷ speed + trims × trim time + colour changes × change time + 0.15 s per jump.\n- Density: each stitch deposits length × 0.4 mm thread width into the 1 mm cells it crosses; values are thread layers (1 ≈ fully covered once).\n\nThread and time figures are planning estimates; real consumption depends on tension, fabric, stabiliser and machine.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "threadsmith_design_stats",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThreadsmithDesignStatsInput"
              },
              "examples": {
                "example1": {
                  "summary": "Leaf template as DST, 850 stitches/min",
                  "value": {
                    "file": {
                      "filename": "leaf.dst",
                      "contentBase64": "TEE6TEVBRiAgICAgICAgICAgIA1TVDogICAyMjc5DUNPOiAgMg0rWDogIDE4OQ0tWDogIDE4OA0rWTogIDM4Mg0tWTogIDQ2OA1BWDorICAgNzgNQVk6LSAgNDUwDU1YOisgICAgMA1NWTorICAgIDANUEQ6KioqKioqDRogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAUQIcWQIcAAAOgQANQgAMCYQMCYQOCYAMCYAMAYgMCYgMIYQNKYQNJYANKYAOZogMYogNVqQNUqQMWKQOVaAOUaANVagOligOkmgOlmgNmmAMlGANlGAOkWQMqUgMqUgOJkgOIkAOJkAMKkQMJkQNCkgMBkgNCkANAkANCkQMCkQMBkQNEkgMFkgOFkgMEkANlUAOGkQMkUQNlUQOoVgOoVgNpFgMqFAOoFAOoFANZJAMYJAOYJANZpgNYpgMYpgOVoQOVoQNGYQMFYAMEYAMFYgOEYgOGYgOBYQOJEgNJkgNIkgNJkgOJEgNJkgNJkgNJkgOJEgNJkgNJkgNUCAMgGgMWSgNUaQOmQQNRJQMQJQNQJQMpBgOgJgNVCANVCAOiGgMgGgOgGgMWCQMUCQMVaQNphAMRJQNQJQMQJQNRJQMQJQMpBgNoZgMhmAMgGgOgGgMiGgOgGgMgGgOiGgNKQQOYYgNQZgMRJQNQJQMQJQNRJQMQJQNQJQMpBgMpBgOGIANVCANVCAOiGgMgGgOgGgMiGgOgGgMgGgOiGgNZggNZIgOQZANRJQMQJQNQJQMRJQNQJQMQJQNRJQNohAOoBANGIgNUCAOUSAOgGgMiGgOgGgMgGgOiGgMgGgOgGgMiGgNaggNYIAOQZAMRJQNQJQMQJQNRJQMQJQNQJQMRJQNQJQOqBAOqBAMCYQMUCQMWCQOgGgMgGgOiGgMgGgOgGgMiGgOgGgMgGgOiGgNZggMYIAMRZgNRJQMQJQNQJQMRJQNQJQMQJQNRJQMQJQNQJQOQZANAYANWSgOgGgMgGgOgGgMiGgOgGgMgGgOiGgMgGgOgGgMiGgNKQQOaIQMphANRJQMQJQNQJQMRJQNQJQMQJQNRJQMQJQNQJQMRJQNqBgORogNKQQMiGgOgGgMgGgOgGgMiGgOgGgMgGgOiGgMgGgOgGgMWCQMUCQNYoQMmQQMRJQNQJQMQJQNRJQMQJQNQJQMRJQNQJQMQJQNRJQNSJQNZoQOWSAOiGgMgGgOgGgMgGgOiGgMgGgOgGgMiGgOgGgMgGgMWSgMSogMpBgNoBgMQJQNQJQMRJQNQJQMQJQNRJQMQJQNQJQMRJQNQJQMkQAOYIQNimAMiGgOgGgMgGgOgGgMiGgOgGgMgGgOiGgMgGgOgGgOYgAORogMpBgNQJQMQJQNRJQMQJQNQJQMRJQNQJQMQJQNRJQMQJQMpBgOZIANVCAMWCQMiGgOgGgMgGgOgGgMiGgOgGgMgGgOiGgMgGgNWSgNAYAOQZAMQJQNRJQMQJQNQJQMRJQNQJQMQJQNRJQMQJQNphANaIANVCANVCAOiGgMgGgOgGgMgGgOiGgMgGgOgGgMiGgMUCQMWCQOAYQMpBgOqBAMRJQNQJQMQJQNRJQMQJQNQJQMRJQNQJQNphANYIgNWCQMWCQMiGgOgGgMgGgOgGgMiGgOgGgMgGgNUCANVCAMGIgMoBAOqBAMQJQNQJQMRJQNQJQMQJQNRJQMQJQMoBgMaYgNgmAOiGgMgGgOgGgMgGgOiGgMgGgMWCQMWCQMGoQMSZANQJQMRJQNQJQMQJQNRJQMQJQOFggNWaQNWCQOiGgMgGgOgGgMgGgOiGgNWCQNqJQMpBgMpBgMQJQNQJQMRJQNRZgOkiAMWCQNVCAOgGgNUCAOVSAOCRAMARAMARAOCRAMARAMARAOCRAMVQgOaFQOaFQOVQgOEkAMYogNlKgOlagNlKgMoAQNYYgNlEAMmEQNalQOaFQOaFQNKlgNmkgOGKQOlagNlKgNlKgOlagNEKQMoAAOlkgNalQOaFQNalQOaFQOaFQMJFgNQQQMGKQOlagNlKgNlKgOlagNlKgOlagOpQAOkUQOaFQNalQOaFQOaFQNalQOaFQMFkQOSQQOYogOlagNlKgNlKgOlagNlKgOlagNYogNZogMpQAMKlgOaFQOaFQNalQOaFQOaFQNalQOaFQMlEANRAAMZYAOlagNlKgOlagNlKgNlKgOlagNlKgNlKgNiAgOJgAOIFgOaFQNalQOaFQNalQOaFQOaFQNalQOaFQNUAgMRAANYogNZogNlKgOlagNlKgNlKgOlagNlKgNlKgOlagOoAQOAQgMkUQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQMlEAMlEAORAAMEqANlKgOlagNlKgNlKgOlagNlKgOlagNlKgMmaAMAQgMWAgNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQMKlgOQAAOZIgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNlKgNZogOCQgOZlAOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNVQgNQgAOiQgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagMpAQOCQgOkUQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQOaFQMlEAMlEANQgANFqANlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgOEqAOAQgORAQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOKlgNSgAOYYANlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNlKgOZIgMCQgMIVAOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQMWAgNSgAOaIAMZIgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgNYogMYogMAQgOlEAOaFQOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQOKVAMSgAOaogOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNGqQMAQgOmUQNkEQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMmkAMSgANiAgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNlKgMYYAOAQgMIFgOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMSgAMGKQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgMZIgOaIAMCQgNWQAOaFQOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQNmEQMSgANogQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgOFaQMAQgMlEAOlEAOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNmEQNmEQORggMFqAOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNlKgNogQMAQgNkUQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNlUQORggOpgANlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgNkaAMAQgOWAgOaFQOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOmUQOkUQMRggNkaANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgOZIgMAQgOKVAOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQOKlgORggMYYANlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNZogNYogMBQgNmkAOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOkUQMkUQORggNkaANlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOEaQMAQgMlEAMmEQOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQMKlgORggMYYANlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgMqgQNBQgMkUQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQOkUQOkUQORggNmaANlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNkaAMAQgOWAgOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQOFkQNBQgNZYAOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgNaIAMAQgNJFgOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOkUQOmUQORggOEqANlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagOZIgOaIANAQgMVQgOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQNlUQNBQgMqgQNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNKYgNAQgMZlANalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNmEQNmEQNBQgNFqAOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOiQgNAQgOlEAOaFQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNkEQOQggNpgQOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagMGKQNBQgMlEAMmEQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQMlEAMlEANBQgNEKQNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagNlKgNqgQNBQgMkUQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOlEANAQgOiQgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgMFqANBQgOmUQOkUQNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQOYlANBQgNKYgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagMZYAOQggOKlgOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNWQANAQgOZIgOZIgNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagMmaANBQgORAQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOKVAMAQgMaIANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOaYAORggNIlgNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQMWAgNAQgOmaAOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagORggOWAgOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMKlgMAQgNZYAOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgOlagMaIAOSgAOIFgOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOmUQNmEQNAQgNGqQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgORggMWAgNalQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQNmEQNAQgMpAQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNaIAOSgAOKFgNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMalQNAQgMKYgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgMlagOSgANRgQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNVQgMBQgMZIgOZIgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagOYYAMSgAOFkQOaFQOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQNJFgMAQgNaIANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNkaAMSgAOmUQNkEQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQNRgQNAQgNkaAOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgNlKgMqgQMRggOkUQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMkUQMAQgNogQOlagNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgMGKQMSgAOlEAMlEAOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQMlEAOmEQMAQgMFaQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNpAQMSgAMkkAOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQMmkAMAQgNZogOZIgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagNlKgOaogNQgANJFgOaFQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNJFgMAQgMaIAOlagNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgMaIAMaIANSgAOWAgOaFQNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQMkUQMmUQMBQgOEqANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNlKgNZYAOSAAOkUQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQMkUQMAQgOoAQNlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgOlagMEKQOQAAOYlAOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMalQMAQgNKYgOlagNlKgOlagNlKgNlKgOlagNlKgNlKgOlagOZIgOZIgOQAAMWAgNalQOaFQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQMVQgMAQgMZIgMaIANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNZYAMQAANmEQNalQOaFQOaFQNalQOaFQOaFQNalQOaFQNalQOIFgOAQgNYYANlKgOlagNlKgNlKgOlagNlKgNlKgOlagNlKgNKYgMQAANKFANalQOaFQOaFQNalQOaFQOaFQNalQOaFQNmEQNmEQMAQgOGKQOlagNlKgOlagNlKgNlKgOlagNlKgNlKgNmaAOSQQOlEAMlEANalQOaFQOaFQNalQOaFQOaFQNalQOaFQOlEAOAQgNYogNYogNlKgOlagNlKgNlKgOlagNlKgNlKgOZIgOZIgOSQQMkUQOmUQOaFQNalQOaFQOaFQNalQOaFQNalQMKlgNoAAMZIgOaIAOlagNlKgNlKgOlagNlKgNlKgOlagNpAQNQQQOWAgOaFQOaFQNalQOaFQOaFQNalQOaFQOmkANpggMFaQNlKgOlagNlKgNlKgOlagNlKgNpAQMmkgMmUQOkUQOaFQNalQOaFQOaFQNalQNaYgMYogNYogNlKgNlKgOlagOaIAMZIgOlUgMIVAOaFQOaFQNalQNWAgNGKANYogNZogOlagMZYAMQgQMgQgNCgYNCQoNCgYMAAMNSVqMAAAMEQgMIgQOYBANkCAOYBAMZBAMmCAMZBAOYBANkCAOYBAOYBANkCAOYBAMZBAMmCAMZBAOYBANkCAOYBAMKBYMAAANoBAOUCANoBAMpBAMWCAMpBANoBAOUCANoBANoBAOUCANoBAMpBAMWCAMpBANoBAOUCANoBAMIQQMEggNCgYNCQoNCgYORSqsAAAMEggMIQQNoBAOUCANoBAOqRANViAOqRANoBAOUCANoBAOqRANViAOqRANoBAOUCANoBAOqRANViAOqRANoBAOUCANoBAOqRANViAOqRAMIQQMEggNCgYNCQoNCgYNgkKNgkKMAAAMIQQMEggMVCAMqBAMVCAOUCANoBAOUCAMVCAMqBAMVCAMUCAMoBAMUCAMVCAMqBAMVCAOUCANoBAOUCAMVCAMqBAMVCAMUCAMoBAMUCAMFCoMAAAMlCAMaBAMlCAMkCAMYBAMkCANlCAOaBANlCAMkCAMYBAMkCAMlCAMaBAMlCAMkCAMYBAMkCANlCAOaBANlCAMkCAMYBAMkCAMEQgMIgQNCgYNCQoNCgYOQYJOQYJMAAAMEQgMIgQNYhAOkSANYhAOaBANlCAOaBANYhAOkSANYhAOaBANlCAOaBANYhAOkSANYhAOaBANlCAOaBANYhAOkSANYhAOaBANlCAOaBAMIgQMEQgNCgYNCQoNCgYMgoKMgoKMAAAOIgQNEQgNmiQOZRgNmiQMkiQMYRgMkiQNmiQOZRgNmiQMmiQMZRgMmiQNmiQOZRgNmiQMkiQMYRgMkiQNmiQOZRgNmiQNEQgOIgQNCgYNCQoNCgYNWWYdWWYcAAAOEggNIQQNphgOWSQNphgMohgMUSQMohgNphgOWSQNphgMphgMWSQMphgNphgOWSQNphgMohgMUSQMohgNphgOWSQNphgNIQQOEggNCgYNCQoNCgYMoWqsAAANRgAOiQANiUQORogNiUQMhUAMSoAMhUANiUQORogNiUQMiUQMRogMiUQNhUAOSoANhUANhUAOSoANhUAMiUQMRogMiUQNhUAOSoANhUANgUAOQoANgUAMhUAMSoAMhUANhUAOSoANhUANgUAOQoANgUANhUAOSoANhUAMgUAMQoAMgUANgUAOQoANgUANgUAOQoANgUAMgUAMQoAMgUANiUAORoANiUANgUAOQoANgUAMiUAMRoAMiUANgUAOQoANgUANiUAORoANiUAMiUAMRoAMiUANiUAORoANiUANhUgOSoQNhUgMiUAMRoAMiUANhUgOSoQNhUgNiUAORoANiUAMhUgMSoQMhUgNhUgOSoQNhUgOhQANSgANCgYNCQoNCgYMAAMOgUIMAAANSgQOhQgOFEgNFkANqVgOpVAOqFQNpQQOWggNCgYNCQoNCgYNBIqsAAAOFAgNKAQNAhANSCQNChANQCQMChAORSQOChAMQSQNiRANRSQMiRAOmmgNgBgOkmgMhBgNkmgMgBgNlmgMghgNmGAMihgMkGANZZQMlWAMZZQOlWAOYZQMkWQOYZQNkWQNaJQOKkgMZJAOKkgMZJAOZgQNmQgNCgYNCQoNCgYMAAPM="
                    },
                    "spm": 850,
                    "colors": [
                      "#0b7a4b",
                      "#1f5c3f",
                      "#6d4a33"
                    ],
                    "hoop": "100x100"
                  }
                },
                "example2": {
                  "summary": "Hand-written stitch list with a jump",
                  "value": {
                    "stitches": "[[0,0],[5,0],[10,0],[10,5],[10,10],[40,10,\"jump\"],[40,10],[45,12],[50,10]]",
                    "spm": 600
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadsmithDesignStatsResult"
                }
              }
            }
          },
          "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/tools/threadsmith-digitize/calculate": {
      "post": {
        "operationId": "calculateThreadsmithDigitize",
        "summary": "Turn shapes, SVG paths, text or a whole project into embroidery stitches with stats and preview.",
        "description": "Digitizes vector artwork into machine embroidery: running, bean, satin (with pull compensation, auto split and short stitches), tatami fill with stagger and graded density, contour fill and motif runs, plus underlay. Returns stitch counts, trims, colour changes, thread and bobbin estimates, sewing time, hoop fit, a density check and a thread-look SVG preview — the same engine as the Threadsmith app.\n\nMethodology:\n- Shapes are flattened to polygons (Bézier curves within 0.04 mm); closed shapes are regions (even-odd, holes allowed), open paths are lines.\n- Tatami: scanlines at the fill angle every row-spacing; intervals are split into blocks that can be sewn back and forth, ordered nearest-first, and penetrations sit on a staggered grid (1/3 offset by default) so no visible columns form.\n- Satin: zig-zag between the edges every density step (rows perpendicular to the shape’s principal axis); columns along lines measure spacing on the outer edge and shorten every other inner stitch on tight curves; stitches longer than the max width are split with interleaved penetrations.\n- Contour fill and edge-walk underlay use an exact Euclidean distance transform of the rasterised shape and marching-squares iso-lines, so insets stay valid for concave shapes and holes.\n- Sequencing: objects grouped by colour (first appearance) and visited nearest-first; gaps up to 1.2 mm are sewn, gaps below the trim distance are jumped, longer gaps get tie-off, trim, jump and tie-in.\n- Thread estimate = sewn length + 0.8 mm take-up per penetration + 5 % waste; bobbin ≈ ⅓ of the sewn length; time = stitches ÷ speed + 4 s per trim + 20 s per colour change.\n\nEstimates assume average fabric and settings; always test-stitch on the real fabric and stabiliser. Thread names are generic colours, not brand shade numbers.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "threadsmith_digitize",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThreadsmithDigitizeInput"
              },
              "examples": {
                "example1": {
                  "summary": "40 × 30 mm oval, automatic tatami with underlay",
                  "value": {
                    "source": "shape",
                    "shape": "ellipse",
                    "widthMm": 40,
                    "heightMm": 30,
                    "color": "ruby"
                  }
                },
                "example2": {
                  "summary": "Satin column along a curve",
                  "value": {
                    "source": "path",
                    "pathD": "M-30 10 C-15 -15 15 25 30 0",
                    "stitchType": "satin",
                    "satinWidth": 3.5,
                    "spacing": 0.4,
                    "color": "emerald"
                  }
                },
                "example3": {
                  "summary": "Name in single-line satin lettering",
                  "value": {
                    "source": "text",
                    "text": "Ada",
                    "textSize": 14,
                    "stitchType": "satin",
                    "satinWidth": 2,
                    "color": "navy",
                    "includeStitches": true
                  }
                },
                "example4": {
                  "summary": "SVG badge (circle + square)",
                  "value": {
                    "source": "svg",
                    "svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"60mm\" height=\"60mm\" viewBox=\"0 0 60 60\"><circle cx=\"30\" cy=\"30\" r=\"26\" fill=\"#0f4c81\"/><rect x=\"20\" y=\"20\" width=\"20\" height=\"20\" fill=\"#e4c13b\" stroke=\"#ffffff\" stroke-width=\"1.5\"/></svg>"
                  }
                },
                "example5": {
                  "summary": "Template project: botanical leaf",
                  "value": {
                    "source": "project",
                    "project": "{\"format\":\"threadsmith\",\"version\":1,\"name\":\"Botanical leaf\",\"hoop\":\"100x100\",\"palette\":[{\"id\":\"emerald\",\"name\":\"Emerald\",\"hex\":\"#0b7a4b\"},{\"id\":\"malachite\",\"name\":\"Malachite\",\"hex\":\"#1f5c3f\"},{\"id\":\"walnut\",\"name\":\"Walnut\",\"hex\":\"#6d4a33\"}],\"objects\":[{\"id\":\"leaf\",\"name\":\"Leaf\",\"kind\":\"path\",\"color\":\"emerald\",\"d\":\"M0 -38C24 -24 26 14 0 36C-26 14 -24 -24 0 -38Z\",\"stitch\":{\"type\":\"tatami\",\"angle\":60,\"spacing\":0.4,\"length\":4,\"stagger\":\"1/3\",\"pullComp\":0.2},\"underlay\":{\"edge\":true,\"tatami\":true,\"inset\":0.5}},{\"id\":\"vein\",\"name\":\"Centre vein\",\"kind\":\"path\",\"color\":\"malachite\",\"d\":\"M0 -32C2 -10 2 12 0 33\",\"stitch\":{\"type\":\"running\",\"length\":2.2,\"bean\":true}},{\"id\":\"veins\",\"name\":\"Side veins\",\"kind\":\"path\",\"color\":\"malachite\",\"d\":\"M1 -18L12 -26M1 -6L15 -13M1 6L15 0M1 18L12 13M-1 -18L-12 -26M-1 -6L-15 -13M-1 6L-15 0M-1 18L-12 13\",\"stitch\":{\"type\":\"running\",\"length\":2,\"bean\":true}},{\"id\":\"stem\",\"name\":\"Stem\",\"kind\":\"path\",\"color\":\"walnut\",\"d\":\"M0 35C1 40 3 43 7 46\",\"stitch\":{\"type\":\"satin\",\"width\":2.2,\"density\":0.35},\"underlay\":{\"center\":true}}]}"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadsmithDigitizeResult"
                }
              }
            }
          },
          "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/tools/threadsmith-stitch-file/calculate": {
      "post": {
        "operationId": "calculateThreadsmithStitchFile",
        "summary": "Write Tajima DST or Melco EXP machine files from a stitch list or a Threadsmith project.",
        "description": "Encodes stitches as a Tajima DST (512-byte header, balanced-ternary 3-byte records, jumps split to ≤ 12.1 mm, colour changes, trims as zero-sum jumps, END) or Melco EXP file. The file is decoded again to verify every stitch position before you download it.\n\nMethodology:\n- Coordinates are rounded to 0.1 mm on absolute positions, so rounding never accumulates; each move becomes the difference to the previous rounded position.\n- DST: each axis is written in balanced ternary with digits for 1, 3, 9, 27 and 81 (±121 max). Byte 3 = 0x03 | flags: 0x80 jump, 0xC0 colour change; END = 00 00 F3. Longer moves are split into equal records. Y is inverted (DST is y-up).\n- Trims are written as three jumps (+2,+2) (−4,−4) (+2,+2) that cancel out — the convention machines use to trigger a trim after a run of jumps.\n- Header: LA label, ST record count, CO colour changes, ±X/±Y extents in 0.1 mm, AX/AY end offset, MX/MY 0, PD ******, 0x1A, padded with spaces to 512 bytes.\n- EXP: 2 signed bytes per stitch (±127), 0x80 0x04 dx dy jump, 0x80 0x01 colour change; trims as three zero-sum jumps.\n\nDST and EXP carry no thread colours: set the needle/colour order on the machine using the colour list from Threadsmith. Test on scrap fabric first.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "threadsmith_stitch_file",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThreadsmithStitchFileInput"
              },
              "examples": {
                "example1": {
                  "summary": "Tiny square outline with a jump and a colour change → DST",
                  "value": {
                    "format": "dst",
                    "label": "SQUARE",
                    "stitches": "[[0,0],[10,0],[10,10],[0,10],[0,0],[30,0,\"jump\"],[30,0,\"color\"],[30,0],[40,5],[30,10]]"
                  }
                },
                "example2": {
                  "summary": "Template project (name tag) → Melco EXP",
                  "value": {
                    "format": "exp",
                    "project": "{\"format\":\"threadsmith\",\"version\":1,\"name\":\"Name tag\",\"hoop\":\"130x180\",\"palette\":[{\"id\":\"sapphire\",\"name\":\"Sapphire\",\"hex\":\"#0f4c81\"},{\"id\":\"coral\",\"name\":\"Coral\",\"hex\":\"#e8705a\"},{\"id\":\"ivory\",\"name\":\"Ivory\",\"hex\":\"#fffbf0\"}],\"objects\":[{\"id\":\"frame\",\"name\":\"Frame\",\"kind\":\"rect\",\"color\":\"sapphire\",\"x\":-45,\"y\":-22,\"w\":90,\"h\":44,\"r\":8,\"stitch\":{\"type\":\"satin\",\"mode\":\"border\",\"width\":3,\"density\":0.4},\"underlay\":{\"center\":true}},{\"id\":\"hello\",\"name\":\"Hello\",\"kind\":\"text\",\"color\":\"coral\",\"text\":\"Hello, my name is\",\"x\":0,\"y\":-7,\"size\":6,\"font\":\"single\",\"align\":\"center\",\"stitch\":{\"type\":\"running\",\"length\":1.8,\"bean\":true}},{\"id\":\"name\",\"name\":\"Name\",\"kind\":\"text\",\"color\":\"sapphire\",\"text\":\"Ada\",\"x\":0,\"y\":14,\"size\":16,\"font\":\"single\",\"align\":\"center\",\"spacing\":1,\"stitch\":{\"type\":\"satin\",\"width\":2.4,\"density\":0.36},\"underlay\":{\"center\":true}}]}"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadsmithStitchFileResult"
                }
              }
            }
          },
          "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/tools/twinworks-bottleneck-analysis/calculate": {
      "post": {
        "operationId": "calculateTwinworksBottleneckAnalysis",
        "summary": "Find the constraint of a production line and test fixes: ranked bottlenecks with what-if gains.",
        "description": "Ranks the stations of a Twinworks factory model by how often they constrain the line (active-period method: sole and shifting bottleneck shares), explains the dominant loss (working, breakdowns, setups, waiting for operators) and simulates typical improvements of the top bottleneck — an extra server, a 10 % faster cycle, faster repairs, shorter setups, more operators or a bigger buffer — with paired confidence intervals.\n\nMethodology:\n- Each replication records, per station, every active period (uninterrupted time working, in setup, under repair/maintenance or waiting for an operator; starved and blocked times end a period).\n- At every instant the station with the longest current active period is the bottleneck. Where the periods of consecutive bottlenecks overlap, both are shifting bottlenecks; otherwise the station is the sole bottleneck (Roser, Nakano & Tanaka 2001).\n- Stations are ranked by sole + shifting share (averaged over the window of replication 1, votes = how often a station was the top bottleneck across replications); ties are broken by active percentage.\n- What-if options for the top station are simulated with the same seeds as the baseline (common random numbers); the gain interval is a paired Student-t interval of the throughput differences.\n\nImprovement options are illustrative single changes; real fixes have costs and side effects that the model may not capture.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "twinworks_bottleneck_analysis",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwinworksBottleneckAnalysisInput"
              },
              "examples": {
                "example1": {
                  "summary": "Bottleneck demo (5 stations, tiny buffers)",
                  "value": {
                    "template": "bottleneck-buffer-sizing",
                    "replications": 5,
                    "horizonHours": 8
                  }
                },
                "example2": {
                  "summary": "Job shop with setups on the mill",
                  "value": {
                    "template": "job-shop-routings",
                    "replications": 4,
                    "whatIf": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwinworksBottleneckAnalysisResult"
                }
              }
            }
          },
          "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/tools/twinworks-buffer-sweep/calculate": {
      "post": {
        "operationId": "calculateTwinworksBufferSweep",
        "summary": "Sweep a buffer size (or any parameter) and get the throughput curve with confidence intervals.",
        "description": "Runs a Twinworks factory model repeatedly while one parameter changes — typically the capacity of a buffer from 1 to 10 places, but also servers, cycle times, MTTR, batch sizes, conveyor speed or the number of operators. Returns throughput, lead time and WIP per value with confidence intervals, plus the knee point where extra capacity stops paying off.\n\nMethodology:\n- For each parameter value the model is copied, the parameter is set and the model is simulated with the same seeds (common random numbers), so differences between values are not masked by random noise.\n- Throughput, lead time and WIP are reported as Student-t intervals across replications.\n- Knee point = smallest value whose mean throughput is at least 98 % of the best mean throughput in the sweep: beyond it, more buffer mostly adds WIP and lead time (Little’s law).\n\nThe sweep varies one parameter at a time; interactions between buffers are not optimised jointly.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "twinworks_buffer_sweep",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwinworksBufferSweepInput"
              },
              "examples": {
                "example1": {
                  "summary": "Bottleneck demo: buffer B2 from 1 to 10",
                  "value": {
                    "template": "bottleneck-buffer-sizing",
                    "target": "B2",
                    "parameter": "capacity",
                    "from": 1,
                    "to": 10,
                    "step": 1,
                    "replications": 4,
                    "horizonHours": 6
                  }
                },
                "example2": {
                  "summary": "3-station line: arrival interval 45…70 s",
                  "value": {
                    "template": "three-station-line",
                    "target": "SRC1",
                    "parameter": "interval.mean",
                    "from": 45,
                    "to": 70,
                    "step": 5,
                    "replications": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwinworksBufferSweepResult"
                }
              }
            }
          },
          "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/tools/twinworks-simulate/calculate": {
      "post": {
        "operationId": "calculateTwinworksSimulate",
        "summary": "Simulate a production line: throughput, lead time, WIP, OEE and the bottleneck, with CIs.",
        "description": "Runs the Twinworks discrete-event simulation on a factory model (sources, buffers, machines with failures and setups, assembly, conveyors, quality checks, operators and shift calendars). Returns throughput per hour, lead time, WIP with a Little’s-law check, per-station states and OEE, the bottleneck and a cost per good part, with Student-t confidence intervals across seeded replications.\n\nMethodology:\n- Discrete-event simulation with a binary-heap event calendar; ties are processed in (time, priority, insertion order) so every run is reproducible.\n- Parts are pushed downstream with blocking after service: a machine that cannot hand its part on is “blocked”; a machine without parts is “starved/idle”.\n- Each random quantity (arrivals, cycle times, failures, routing choices) has its own seeded stream, so scenario changes do not shift other random numbers (common random numbers).\n- Statistics are reset after the warm-up. Replications use derived seeds; intervals are Student-t intervals of the replication means.\n- Little’s law is checked as L (time-average WIP) versus λ·W (departure rate × mean time in system); differences above 5 % signal a non-stationary system or too short a run.\n- OEE = availability × performance × quality with planned time = time on shift minus planned maintenance; availability losses = breakdowns + setups; performance = ideal cycle time × parts ÷ run time (starving and blocking reduce it); quality = good ÷ processed.\n- Bottleneck: active-period method (Roser et al.) — at each moment the station with the longest uninterrupted active period (working, setup, repair, maintenance, waiting for an operator) is the bottleneck; overlaps between consecutive bottlenecks count as shifting.\n\nA simulation is only as good as its input data. Validate cycle times, failure data and routings against your shop floor before making investment decisions.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "twinworks_simulate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwinworksSimulateInput"
              },
              "examples": {
                "example1": {
                  "summary": "3-station line template, 5 replications",
                  "value": {
                    "template": "three-station-line",
                    "replications": 5
                  }
                },
                "example2": {
                  "summary": "Own model: two machines and a buffer, deterministic",
                  "value": {
                    "model": "{\"name\":\"Two machines\",\"settings\":{\"horizon\":7200,\"warmup\":600},\"nodes\":[{\"id\":\"S\",\"type\":\"source\",\"arrival\":\"saturated\"},{\"id\":\"M1\",\"type\":\"machine\",\"cycle\":{\"type\":\"constant\",\"value\":30}},{\"id\":\"B\",\"type\":\"buffer\",\"capacity\":3},{\"id\":\"M2\",\"type\":\"machine\",\"cycle\":{\"type\":\"constant\",\"value\":40}},{\"id\":\"OUT\",\"type\":\"sink\"}],\"links\":[{\"from\":\"S\",\"to\":\"M1\"},{\"from\":\"M1\",\"to\":\"B\"},{\"from\":\"B\",\"to\":\"M2\"},{\"from\":\"M2\",\"to\":\"OUT\"}]}",
                    "replications": 1
                  }
                },
                "example3": {
                  "summary": "Line with failures over 2 days, 3 replications",
                  "value": {
                    "template": "line-with-failures",
                    "horizonHours": 48,
                    "warmupMinutes": 120,
                    "replications": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwinworksSimulateResult"
                }
              }
            }
          },
          "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/tools/twinworks-line-balance/calculate": {
      "post": {
        "operationId": "calculateTwinworksLineBalance",
        "summary": "Assign assembly tasks to stations for a takt time: efficiency, balance delay and smoothness index.",
        "description": "Solves the simple assembly line balancing problem (type 1) with the Ranked Positional Weight (Helgeson–Birnie) and Largest Candidate rules: tasks with times and precedence relations are assigned to as few stations as possible without exceeding the takt time. Returns the station assignment, line efficiency, balance delay, smoothness index and a ready-to-simulate Twinworks model of the balanced line.\n\nMethodology:\n- Takt time = available production time ÷ demand (or as given). Theoretical minimum stations = ⌈Σ task times ÷ takt⌉.\n- RPW: positional weight = own time + times of all direct and indirect successors; LCR: task time. Stations are filled one by one with the highest-priority task whose predecessors are all assigned and that still fits into the remaining takt time.\n- Efficiency = Σ task times ÷ (stations × takt); balance delay = 1 − efficiency; smoothness index = √Σ(max station time − station time)².\n- The result includes a Twinworks model (one constant-time machine per station, single-place buffers) so the balance can be simulated or opened in the app.\n\nHeuristics give good but not always optimal balances. Zoning constraints, operator skills and task variability are not considered.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "twinworks_line_balance",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwinworksLineBalanceInput"
              },
              "examples": {
                "example1": {
                  "summary": "Wheelbarrow-style example: 8 tasks, 450 min shift, demand 270",
                  "value": {
                    "tasks": [
                      {
                        "id": "A",
                        "name": "Fit frame",
                        "time": 60,
                        "predecessors": ""
                      },
                      {
                        "id": "B",
                        "name": "Mount axle",
                        "time": 40,
                        "predecessors": "A"
                      },
                      {
                        "id": "C",
                        "name": "Fit wheel",
                        "time": 55,
                        "predecessors": "B"
                      },
                      {
                        "id": "D",
                        "name": "Attach tray",
                        "time": 50,
                        "predecessors": "A"
                      },
                      {
                        "id": "E",
                        "name": "Fit legs",
                        "time": 30,
                        "predecessors": "D"
                      },
                      {
                        "id": "F",
                        "name": "Attach handles",
                        "time": 45,
                        "predecessors": "D"
                      },
                      {
                        "id": "G",
                        "name": "Grips",
                        "time": 20,
                        "predecessors": "F"
                      },
                      {
                        "id": "H",
                        "name": "Final check",
                        "time": 35,
                        "predecessors": "C,E,G"
                      }
                    ],
                    "availableMinutes": 450,
                    "demand": 270,
                    "method": "best"
                  }
                },
                "example2": {
                  "summary": "Six tasks with a fixed takt time of 10 s",
                  "value": {
                    "tasks": [
                      {
                        "id": "1",
                        "time": 4,
                        "predecessors": ""
                      },
                      {
                        "id": "2",
                        "time": 3,
                        "predecessors": "1"
                      },
                      {
                        "id": "3",
                        "time": 5,
                        "predecessors": "1"
                      },
                      {
                        "id": "4",
                        "time": 6,
                        "predecessors": "2"
                      },
                      {
                        "id": "5",
                        "time": 2,
                        "predecessors": "3"
                      },
                      {
                        "id": "6",
                        "time": 4,
                        "predecessors": "4,5"
                      }
                    ],
                    "taktTime": 10,
                    "method": "rpw"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwinworksLineBalanceResult"
                }
              }
            }
          },
          "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/tools/twinworks-queue-formulas/calculate": {
      "post": {
        "operationId": "calculateTwinworksQueueFormulas",
        "summary": "M/M/1, M/M/c, M/D/1, M/G/1 and Kingman waiting times — optionally verified by simulation.",
        "description": "Closed-form queueing results for a single workstation: utilization, mean waiting time, queue length and time in system for M/M/1, M/M/c (Erlang C), M/D/1, M/G/1 (Pollaczek–Khinchine) and the Kingman G/G/1 approximation. Optionally runs the Twinworks simulation of the same station and reports whether the theory lies inside the simulated confidence interval.\n\nMethodology:\n- M/M/1: Wq = ρ/(μ−λ). M/M/c: Wq = C(c, a)/(cμ−λ) with the Erlang C probability C computed by a stable recursion. M/G/1: Wq = λE[S²]/(2(1−ρ)) (Pollaczek–Khinchine), M/D/1 is the special case SCV = 0. Kingman: Wq ≈ ((ca²+cs²)/2)·(ρ/(1−ρ))·te.\n- L = λW and Lq = λWq (Little’s law).\n- Verification builds a source → unlimited queue → station → sink model, simulates long replications (≈ 20 000 arrivals each, 5 % warm-up) and checks whether the theoretical Wq lies inside the Student-t interval of the simulated mean wait.\n\nFormulas assume steady state, infinite queue capacity and FIFO service. Kingman is an approximation.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "twinworks_queue_formulas",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwinworksQueueFormulasInput"
              },
              "examples": {
                "example1": {
                  "summary": "M/M/1 at 80 % utilization, verified by simulation",
                  "value": {
                    "queue": "mm1",
                    "arrivalsPerHour": 60,
                    "serviceTime": 48,
                    "verify": true,
                    "replications": 10
                  }
                },
                "example2": {
                  "summary": "Two operators (M/M/2)",
                  "value": {
                    "queue": "mmc",
                    "arrivalsPerHour": 100,
                    "serviceTime": 60,
                    "servers": 2
                  }
                },
                "example3": {
                  "summary": "Kingman: low arrival variability, high process variability",
                  "value": {
                    "queue": "gg1",
                    "arrivalsPerHour": 50,
                    "serviceTime": 60,
                    "arrivalScv": 0.25,
                    "serviceScv": 1.5
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwinworksQueueFormulasResult"
                }
              }
            }
          },
          "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/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "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"
                }
              }
            }
          }
        }
      },
      "KerfwiseCabinetBuilderInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "type": {
            "title": "Cabinet type",
            "type": "string",
            "enum": [
              "base",
              "wall",
              "tall",
              "drawer",
              "corner",
              "open",
              "wardrobe",
              "bookshelf",
              "desk",
              "table",
              "bed"
            ],
            "default": "base"
          },
          "width": {
            "title": "Width",
            "description": "Outer width (table/desk: top length).",
            "type": "number",
            "minimum": 150,
            "maximum": 4000,
            "default": 600,
            "x-unit": "mm"
          },
          "height": {
            "title": "Height",
            "description": "Outer height incl. plinth, without worktop. Empty = type default.",
            "type": "number",
            "minimum": 150,
            "maximum": 3000,
            "x-unit": "mm"
          },
          "depth": {
            "title": "Depth",
            "description": "Outer depth. Empty = type default.",
            "type": "number",
            "minimum": 100,
            "maximum": 2500,
            "x-unit": "mm"
          },
          "materialId": {
            "title": "Carcass material",
            "type": "string",
            "enum": [
              "mel-18",
              "oak-18",
              "birch-15",
              "mdf-19",
              "walnut-19",
              "oakpanel-27",
              "hdf-8",
              "hdf-3"
            ],
            "default": "mel-18"
          },
          "frontMaterialId": {
            "title": "Front material",
            "type": "string",
            "enum": [
              "mel-18",
              "oak-18",
              "birch-15",
              "mdf-19",
              "walnut-19",
              "oakpanel-27",
              "hdf-8",
              "hdf-3"
            ],
            "default": "oak-18"
          },
          "backType": {
            "title": "Back panel",
            "type": "string",
            "enum": [
              "groove",
              "inset",
              "nailed",
              "none"
            ],
            "default": "groove"
          },
          "grooveDepth": {
            "title": "Groove depth",
            "type": "number",
            "minimum": 0,
            "maximum": 20,
            "default": 8,
            "x-unit": "mm"
          },
          "topType": {
            "title": "Top",
            "type": "string",
            "enum": [
              "full",
              "rails"
            ],
            "default": "full"
          },
          "plinthType": {
            "title": "Plinth / toe kick",
            "type": "string",
            "enum": [
              "legs",
              "board",
              "none"
            ],
            "default": "legs"
          },
          "plinthHeight": {
            "title": "Plinth height",
            "type": "number",
            "minimum": 0,
            "maximum": 300,
            "default": 150,
            "x-unit": "mm"
          },
          "doorCount": {
            "title": "Doors",
            "description": "Empty = type default.",
            "type": "integer",
            "minimum": 0,
            "maximum": 4
          },
          "doorStyle": {
            "title": "Door style",
            "type": "string",
            "enum": [
              "overlay",
              "inset"
            ],
            "default": "overlay"
          },
          "drawerCount": {
            "title": "Drawers",
            "description": "Empty = type default. With doors, drawers go on top (150 mm each).",
            "type": "integer",
            "minimum": 0,
            "maximum": 8
          },
          "slideType": {
            "title": "Drawer slides",
            "type": "string",
            "enum": [
              "side",
              "under"
            ],
            "default": "side"
          },
          "shelfCount": {
            "title": "Shelves",
            "description": "Empty = type default.",
            "type": "integer",
            "minimum": 0,
            "maximum": 12
          },
          "adjustableShelves": {
            "title": "Adjustable shelves (32 mm system holes)",
            "type": "boolean",
            "default": true
          },
          "faceFrame": {
            "title": "Face frame",
            "type": "boolean",
            "default": false
          },
          "carcassJoint": {
            "title": "Carcass joinery",
            "type": "string",
            "enum": [
              "butt",
              "dowel",
              "confirmat",
              "pocket",
              "cam",
              "dado",
              "rabbet"
            ],
            "default": "dowel"
          },
          "frameJoint": {
            "title": "Frame / apron joinery",
            "type": "string",
            "enum": [
              "pocket",
              "dowel",
              "mortise-tenon",
              "butt"
            ],
            "default": "pocket"
          },
          "drawerJoint": {
            "title": "Drawer box joinery",
            "type": "string",
            "enum": [
              "butt",
              "dado",
              "dovetail",
              "dowel"
            ],
            "default": "dado"
          },
          "handle": {
            "title": "Handles",
            "type": "string",
            "enum": [
              "bar128",
              "bar160",
              "knob",
              "none"
            ],
            "default": "bar128"
          },
          "bandingDeduct": {
            "title": "Deduct edge-banding thickness from cut sizes",
            "type": "boolean",
            "default": true
          }
        },
        "required": [
          "width"
        ]
      },
      "KerfwiseCabinetBuilderResult": {
        "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",
            "required": [
              "type",
              "size",
              "dimensions",
              "parts",
              "hardware",
              "totals",
              "warnings",
              "project",
              "openInApp"
            ],
            "properties": {
              "type": {
                "type": "string"
              },
              "size": {
                "type": "object",
                "properties": {
                  "w": {
                    "type": "number"
                  },
                  "h": {
                    "type": "number"
                  },
                  "d": {
                    "type": "number"
                  }
                }
              },
              "dimensions": {
                "type": "object",
                "description": "Key derived dimensions (carcass height, inner sizes, door/back sizes, slide length …)."
              },
              "parts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "label",
                    "name",
                    "L",
                    "W",
                    "T",
                    "cutL",
                    "cutW",
                    "material",
                    "grain",
                    "edges",
                    "holes"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "group": {
                      "type": "string"
                    },
                    "L": {
                      "type": "number"
                    },
                    "W": {
                      "type": "number"
                    },
                    "T": {
                      "type": "number"
                    },
                    "cutL": {
                      "type": "number"
                    },
                    "cutW": {
                      "type": "number"
                    },
                    "material": {
                      "type": "string"
                    },
                    "grain": {
                      "type": "boolean"
                    },
                    "edges": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "holes": {
                      "type": "integer"
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "hardware": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "qty": {
                      "type": "number"
                    },
                    "unit": {
                      "type": "string"
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "totals": {
                "type": "object",
                "properties": {
                  "parts": {
                    "type": "integer"
                  },
                  "holes": {
                    "type": "integer"
                  },
                  "areaM2": {
                    "type": "number"
                  },
                  "bandingM": {
                    "type": "number"
                  }
                }
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "project": {
                "type": "object",
                "description": "Kerfwise project JSON containing this cabinet (open it in the app or pass it to kerfwise-cut-list)."
              },
              "openInApp": {
                "type": "string"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KerfwiseCutListInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "project": {
            "title": "Kerfwise project JSON (optional)",
            "description": "Paste a .kerfwise.json file. When given, the cabinet table below is ignored.",
            "type": "string",
            "maxLength": 400000
          },
          "cabinets": {
            "title": "Cabinets",
            "description": "Quick input without a project file. Empty height/depth/doors/drawers/shelves use the type defaults.",
            "type": "array",
            "maxItems": 60,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "base",
                    "wall",
                    "tall",
                    "drawer",
                    "corner",
                    "open",
                    "wardrobe",
                    "bookshelf",
                    "desk",
                    "table",
                    "bed"
                  ]
                },
                "width": {
                  "title": "Width (mm)",
                  "type": "number",
                  "minimum": 150,
                  "maximum": 4000
                },
                "height": {
                  "title": "Height (mm)",
                  "type": "number",
                  "minimum": 150,
                  "maximum": 3000
                },
                "depth": {
                  "title": "Depth (mm)",
                  "type": "number",
                  "minimum": 100,
                  "maximum": 2500
                },
                "doors": {
                  "title": "Doors",
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 4
                },
                "drawers": {
                  "title": "Drawers",
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 8
                },
                "shelves": {
                  "title": "Shelves",
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 12
                },
                "qty": {
                  "title": "Qty",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 50
                }
              },
              "required": [
                "type",
                "width"
              ]
            }
          },
          "materialId": {
            "title": "Carcass material (table input)",
            "type": "string",
            "enum": [
              "mel-18",
              "oak-18",
              "birch-15",
              "mdf-19",
              "walnut-19",
              "oakpanel-27",
              "hdf-8",
              "hdf-3"
            ],
            "default": "mel-18"
          },
          "frontMaterialId": {
            "title": "Front material (table input)",
            "type": "string",
            "enum": [
              "mel-18",
              "oak-18",
              "birch-15",
              "mdf-19",
              "walnut-19",
              "oakpanel-27",
              "hdf-8",
              "hdf-3"
            ],
            "default": "oak-18"
          },
          "currency": {
            "title": "Currency",
            "type": "string",
            "maxLength": 8,
            "default": "EUR"
          },
          "kerf": {
            "title": "Saw kerf",
            "type": "number",
            "minimum": 0,
            "maximum": 10,
            "default": 4,
            "x-unit": "mm"
          },
          "trim": {
            "title": "Sheet trim margin",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 10,
            "x-unit": "mm"
          },
          "labourRate": {
            "title": "Labour rate",
            "description": "Per hour, in the chosen currency.",
            "type": "number",
            "minimum": 0,
            "maximum": 1000,
            "default": 45
          },
          "costMode": {
            "title": "Material cost",
            "type": "string",
            "enum": [
              "full-sheets",
              "used-area"
            ],
            "default": "full-sheets"
          },
          "markupPct": {
            "title": "Markup",
            "type": "number",
            "minimum": 0,
            "maximum": 500,
            "default": 0,
            "x-unit": "%"
          },
          "taxPct": {
            "title": "Tax / VAT",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 0,
            "x-unit": "%"
          }
        },
        "required": []
      },
      "KerfwiseCutListResult": {
        "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",
            "required": [
              "projectName",
              "rows",
              "banding",
              "hardware",
              "materials",
              "cost",
              "totals",
              "warnings"
            ],
            "properties": {
              "projectName": {
                "type": "string"
              },
              "rows": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "no",
                    "name",
                    "qty",
                    "L",
                    "W",
                    "T",
                    "cutL",
                    "cutW",
                    "material"
                  ],
                  "properties": {
                    "no": {
                      "type": "integer"
                    },
                    "labels": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "name": {
                      "type": "string"
                    },
                    "cabinets": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "qty": {
                      "type": "integer"
                    },
                    "L": {
                      "type": "number"
                    },
                    "W": {
                      "type": "number"
                    },
                    "T": {
                      "type": "number"
                    },
                    "cutL": {
                      "type": "number"
                    },
                    "cutW": {
                      "type": "number"
                    },
                    "material": {
                      "type": "string"
                    },
                    "grain": {
                      "type": "boolean"
                    },
                    "edges": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "banding": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "metres": {
                      "type": "number"
                    },
                    "cost": {
                      "type": "number"
                    }
                  }
                }
              },
              "hardware": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "qty": {
                      "type": "number"
                    },
                    "unit": {
                      "type": "string"
                    },
                    "cost": {
                      "type": "number"
                    }
                  }
                }
              },
              "materials": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "material": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "stock": {
                      "type": "integer"
                    },
                    "yieldPct": {
                      "type": "number"
                    },
                    "cost": {
                      "type": "number"
                    }
                  }
                }
              },
              "worktops": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "cost": {
                "type": "object",
                "properties": {
                  "materials": {
                    "type": "number"
                  },
                  "banding": {
                    "type": "number"
                  },
                  "hardware": {
                    "type": "number"
                  },
                  "labour": {
                    "type": "number"
                  },
                  "labourMinutes": {
                    "type": "number"
                  },
                  "extras": {
                    "type": "number"
                  },
                  "subtotal": {
                    "type": "number"
                  },
                  "markup": {
                    "type": "number"
                  },
                  "tax": {
                    "type": "number"
                  },
                  "total": {
                    "type": "number"
                  },
                  "currency": {
                    "type": "string"
                  }
                }
              },
              "totals": {
                "type": "object"
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KerfwiseSheetNestingInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "parts": {
            "title": "Parts",
            "description": "Length runs along the grain. Tick grain to forbid rotation (on a grained material).",
            "type": "array",
            "maxItems": 300,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 60
                },
                "length": {
                  "title": "Length (mm)",
                  "type": "number",
                  "minimum": 1,
                  "maximum": 10000
                },
                "width": {
                  "title": "Width (mm)",
                  "type": "number",
                  "minimum": 1,
                  "maximum": 5000
                },
                "qty": {
                  "title": "Qty",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 500
                },
                "grain": {
                  "title": "Grain",
                  "type": "boolean"
                }
              },
              "required": [
                "name",
                "length",
                "width"
              ]
            }
          },
          "sheetLength": {
            "title": "Sheet length",
            "description": "Common sizes: 2800 × 2070, 2440 × 1220, 3050 × 1220, 2500 × 1250, 2620 × 2070, 2750 × 1830, 2800 × 2100, 2440 × 1830, 1220 × 610.",
            "type": "number",
            "minimum": 100,
            "maximum": 10000,
            "default": 2800,
            "x-unit": "mm"
          },
          "sheetWidth": {
            "title": "Sheet width",
            "type": "number",
            "minimum": 100,
            "maximum": 5000,
            "default": 2070,
            "x-unit": "mm"
          },
          "sheetQty": {
            "title": "Sheets available",
            "description": "0 = unlimited.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000,
            "default": 0
          },
          "sheetPrice": {
            "title": "Price per sheet",
            "type": "number",
            "minimum": 0,
            "maximum": 100000,
            "default": 0
          },
          "kerf": {
            "title": "Saw kerf",
            "type": "number",
            "minimum": 0,
            "maximum": 10,
            "default": 4,
            "x-unit": "mm"
          },
          "trim": {
            "title": "Trim margin per edge",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 10,
            "x-unit": "mm"
          },
          "method": {
            "title": "Method",
            "type": "string",
            "enum": [
              "auto",
              "guillotine",
              "maxrects"
            ],
            "default": "auto"
          },
          "grainedMaterial": {
            "title": "Material has grain",
            "type": "boolean",
            "default": true
          },
          "allowRotation": {
            "title": "Allow rotating parts without grain",
            "type": "boolean",
            "default": true
          },
          "minOffcutLength": {
            "title": "Min. offcut length to keep",
            "type": "number",
            "minimum": 0,
            "maximum": 3000,
            "default": 300,
            "x-unit": "mm"
          },
          "minOffcutWidth": {
            "title": "Min. offcut width to keep",
            "type": "number",
            "minimum": 0,
            "maximum": 3000,
            "default": 100,
            "x-unit": "mm"
          }
        },
        "required": [
          "parts"
        ]
      },
      "KerfwiseSheetNestingResult": {
        "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",
            "required": [
              "method",
              "strategy",
              "sheetCount",
              "yieldPct",
              "sheets",
              "unplaced",
              "offcutAreaM2",
              "cutLengthM",
              "cost"
            ],
            "properties": {
              "method": {
                "type": "string"
              },
              "strategy": {
                "type": "string"
              },
              "sheetCount": {
                "type": "integer"
              },
              "yieldPct": {
                "type": "number"
              },
              "partAreaM2": {
                "type": "number"
              },
              "sheetAreaM2": {
                "type": "number"
              },
              "offcutAreaM2": {
                "type": "number"
              },
              "cutLengthM": {
                "type": "number"
              },
              "cost": {
                "type": "number"
              },
              "sheets": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "index",
                    "yieldPct",
                    "placements",
                    "offcuts"
                  ],
                  "properties": {
                    "index": {
                      "type": "integer"
                    },
                    "yieldPct": {
                      "type": "number"
                    },
                    "cutLength": {
                      "type": "number"
                    },
                    "placements": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "x": {
                            "type": "number"
                          },
                          "y": {
                            "type": "number"
                          },
                          "w": {
                            "type": "number"
                          },
                          "h": {
                            "type": "number"
                          },
                          "rotated": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "offcuts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "x": {
                            "type": "number"
                          },
                          "y": {
                            "type": "number"
                          },
                          "w": {
                            "type": "number"
                          },
                          "h": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "unplaced": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KineticaCollisionCheckInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "joints": {
            "title": "Joint values",
            "description": "Degrees / mm. Empty = home pose.",
            "type": "string",
            "default": ""
          },
          "obstacles": {
            "title": "Obstacles",
            "description": "Box: centre x, y, z and size sx, sy, sz. Sphere: centre and r. Capsule: start x, y, z, end x2, y2, z2 (in the size columns) and r. All in mm, world frame.",
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 40
                },
                "shape": {
                  "title": "Shape",
                  "type": "string",
                  "enum": [
                    "box",
                    "sphere",
                    "capsule"
                  ],
                  "default": "box"
                },
                "x": {
                  "title": "x",
                  "type": "number"
                },
                "y": {
                  "title": "y",
                  "type": "number"
                },
                "z": {
                  "title": "z",
                  "type": "number"
                },
                "sx": {
                  "title": "sx / x2",
                  "type": "number"
                },
                "sy": {
                  "title": "sy / y2",
                  "type": "number"
                },
                "sz": {
                  "title": "sz / z2",
                  "type": "number"
                },
                "r": {
                  "title": "r",
                  "type": "number",
                  "minimum": 0
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ]
            }
          },
          "self": {
            "title": "Check self-collision",
            "type": "boolean",
            "default": true
          },
          "margin": {
            "title": "Safety margin",
            "type": "number",
            "minimum": 0,
            "maximum": 1000,
            "default": 10,
            "x-unit": "mm"
          }
        },
        "required": []
      },
      "KineticaCollisionCheckResult": {
        "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",
            "required": [
              "collides",
              "minClearance",
              "contacts",
              "links",
              "checkedPairs"
            ],
            "properties": {
              "collides": {
                "type": "boolean"
              },
              "minClearance": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "closest": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "contacts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "a": {
                      "type": "string"
                    },
                    "b": {
                      "type": "string"
                    },
                    "distance": {
                      "type": "number"
                    },
                    "kind": {
                      "type": "string"
                    }
                  }
                }
              },
              "links": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "checkedPairs": {
                "type": "integer"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KineticaForwardKinematicsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "joints": {
            "title": "Joint values",
            "description": "Comma-separated, degrees for revolute and mm for prismatic joints. Empty = the robot’s home pose.",
            "type": "string",
            "default": ""
          }
        },
        "required": []
      },
      "KineticaForwardKinematicsResult": {
        "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",
            "required": [
              "robot",
              "dof",
              "joints",
              "tcp",
              "matrix",
              "frames",
              "jacobian",
              "manipulability",
              "withinLimits"
            ],
            "properties": {
              "robot": {
                "type": "string"
              },
              "dof": {
                "type": "integer"
              },
              "joints": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "value": {
                      "type": "number"
                    },
                    "unit": {
                      "type": "string"
                    }
                  }
                }
              },
              "tcp": {
                "type": "object",
                "properties": {
                  "x": {
                    "type": "number"
                  },
                  "y": {
                    "type": "number"
                  },
                  "z": {
                    "type": "number"
                  },
                  "roll": {
                    "type": "number"
                  },
                  "pitch": {
                    "type": "number"
                  },
                  "yaw": {
                    "type": "number"
                  },
                  "quat": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                },
                "required": [
                  "x",
                  "y",
                  "z",
                  "roll",
                  "pitch",
                  "yaw",
                  "quat"
                ]
              },
              "flange": {
                "type": "object",
                "properties": {
                  "x": {
                    "type": "number"
                  },
                  "y": {
                    "type": "number"
                  },
                  "z": {
                    "type": "number"
                  },
                  "roll": {
                    "type": "number"
                  },
                  "pitch": {
                    "type": "number"
                  },
                  "yaw": {
                    "type": "number"
                  },
                  "quat": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                },
                "required": [
                  "x",
                  "y",
                  "z",
                  "roll",
                  "pitch",
                  "yaw",
                  "quat"
                ]
              },
              "matrix": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "frames": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "jacobian": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "manipulability": {
                "type": "object",
                "properties": {
                  "yoshikawa": {
                    "type": "number"
                  },
                  "inverseCondition": {
                    "type": "number"
                  },
                  "status": {
                    "type": "string"
                  }
                }
              },
              "payloadLoads": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "withinLimits": {
                "type": "boolean"
              },
              "violatedJoints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KineticaInverseKinematicsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "x": {
            "title": "Target x",
            "type": "number",
            "default": 700,
            "x-unit": "mm"
          },
          "y": {
            "title": "Target y",
            "type": "number",
            "default": 200,
            "x-unit": "mm"
          },
          "z": {
            "title": "Target z",
            "type": "number",
            "default": 600,
            "x-unit": "mm"
          },
          "roll": {
            "title": "Roll",
            "type": "number",
            "default": 180,
            "x-unit": "deg"
          },
          "pitch": {
            "title": "Pitch",
            "type": "number",
            "default": 0,
            "x-unit": "deg"
          },
          "yaw": {
            "title": "Yaw",
            "type": "number",
            "default": 0,
            "x-unit": "deg"
          },
          "mode": {
            "title": "Task",
            "type": "string",
            "enum": [
              "auto",
              "full",
              "position"
            ],
            "default": "auto"
          },
          "seed": {
            "title": "Preferred configuration",
            "description": "Joint values the solutions are sorted by (closest first). Empty = home pose.",
            "type": "string",
            "default": ""
          },
          "restarts": {
            "title": "Random restarts",
            "type": "integer",
            "minimum": 0,
            "maximum": 64,
            "default": 12
          },
          "rngSeed": {
            "title": "Random seed",
            "description": "Seeds the deterministic restart generator, so the same input always gives the same solutions.",
            "type": "integer",
            "minimum": 0,
            "maximum": 2147483647,
            "default": 7
          }
        },
        "required": [
          "x",
          "y",
          "z"
        ]
      },
      "KineticaInverseKinematicsResult": {
        "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",
            "required": [
              "ok",
              "solutions",
              "reach",
              "message",
              "task"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "message": {
                "type": "string"
              },
              "task": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "best": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "solutions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "joints": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "posError": {
                      "type": "number"
                    },
                    "rotErrorDeg": {
                      "type": "number"
                    },
                    "withinLimits": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string"
                    },
                    "manipulability": {
                      "type": "number"
                    },
                    "source": {
                      "type": "string"
                    }
                  }
                }
              },
              "roundTrip": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "reach": {
                "type": "object",
                "properties": {
                  "distance": {
                    "type": "number"
                  },
                  "maxReach": {
                    "type": "number"
                  },
                  "inReach": {
                    "type": "boolean"
                  }
                }
              },
              "closest": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "attempts": {
                "type": "integer"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "KineticaTrajectoryPlannerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "waypoints": {
            "title": "Waypoints",
            "description": "Row 1 is the start. Target “j: 0, -90, 90, 0, 0, 0” (joints) or “p: x, y, z, roll, pitch, yaw” (TCP pose, mm/deg). PTP speed/accel in % of the joint limits; LIN/CIRC in mm/s and mm/s². CIRC needs a via point “x, y, z”.",
            "type": "array",
            "maxItems": 60,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 40
                },
                "type": {
                  "title": "Move",
                  "type": "string",
                  "enum": [
                    "PTP",
                    "LIN",
                    "CIRC"
                  ],
                  "default": "PTP"
                },
                "target": {
                  "title": "Target",
                  "type": "string",
                  "maxLength": 200
                },
                "via": {
                  "title": "Via (CIRC)",
                  "type": "string",
                  "maxLength": 100
                },
                "vel": {
                  "title": "Speed",
                  "type": "number",
                  "minimum": 0.01
                },
                "acc": {
                  "title": "Accel",
                  "type": "number",
                  "minimum": 0.01
                },
                "blend": {
                  "title": "Blend (mm)",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "dwell": {
                  "title": "Dwell (s)",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                }
              },
              "required": [
                "target"
              ]
            }
          },
          "projectJson": {
            "title": "Kinetica project JSON (optional)",
            "description": "A complete .kinetica.json project; when given, its robot, work objects and program are used instead of the fields above.",
            "type": "string",
            "maxLength": 1000000
          },
          "profile": {
            "title": "Velocity profile",
            "type": "string",
            "enum": [
              "trapezoid",
              "quintic",
              "scurve"
            ],
            "default": "trapezoid"
          },
          "override": {
            "title": "Speed override",
            "type": "number",
            "minimum": 1,
            "maximum": 100,
            "default": 100,
            "x-unit": "%"
          },
          "outputDt": {
            "title": "Output sample period",
            "type": "number",
            "minimum": 0.005,
            "maximum": 1,
            "default": 0.05,
            "x-unit": "s"
          }
        },
        "required": []
      },
      "KineticaTrajectoryPlannerResult": {
        "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",
            "required": [
              "ok",
              "cycleTime",
              "segments",
              "peaks",
              "samples",
              "joints"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "cycleTime": {
                "type": "number"
              },
              "pathLength": {
                "type": "number"
              },
              "joints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "segments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "start": {
                      "type": "number"
                    },
                    "duration": {
                      "type": "number"
                    },
                    "blendOverlap": {
                      "type": "number"
                    },
                    "dwell": {
                      "type": "number"
                    },
                    "speedScale": {
                      "type": "number"
                    }
                  }
                }
              },
              "peaks": {
                "type": "object",
                "properties": {
                  "jointVel": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "jointAcc": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "jointVelPercent": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "tcpSpeed": {
                    "type": "number"
                  }
                }
              },
              "samples": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "t": {
                      "type": "number"
                    },
                    "joints": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "tcp": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    }
                  }
                }
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "OhmforgeAcSweepInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "netlist": {
            "title": "SPICE netlist",
            "description": "Subset: R C L V I D Q M E G K, .model, SIN/PULSE/PWL sources, engineering suffixes (k, m, u, n, p, meg). Node 0 is ground. Leave empty when you pass an Ohmforge project instead.",
            "type": "string",
            "maxLength": 60000
          },
          "project": {
            "title": "Ohmforge project JSON (optional)",
            "description": "Alternative to the netlist: a .ohmforge.json project as saved by the app (format \"ohmforge\", version 1).",
            "type": "string",
            "maxLength": 200000
          },
          "output": {
            "title": "Output node",
            "type": "string",
            "maxLength": 64,
            "default": "out"
          },
          "input": {
            "title": "Input source (gets AC = 1)",
            "description": "Name of the V or I source to excite (e.g. V1). Empty = keep the AC magnitudes from the netlist.",
            "type": "string",
            "maxLength": 64
          },
          "inputNode": {
            "title": "Reference node (optional)",
            "description": "Report V(out)/V(ref) instead of V(out).",
            "type": "string",
            "maxLength": 64
          },
          "fstart": {
            "title": "Start frequency",
            "description": "Empty = .ac line or 1 Hz.",
            "type": "number",
            "minimum": 0.001,
            "maximum": 10000000000,
            "x-unit": "Hz"
          },
          "fstop": {
            "title": "Stop frequency",
            "description": "Empty = .ac line or 10 MHz.",
            "type": "number",
            "minimum": 0.001,
            "maximum": 100000000000,
            "x-unit": "Hz"
          },
          "pointsPerDecade": {
            "title": "Points per decade",
            "description": "Empty = .ac line or 20.",
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "output"
        ]
      },
      "OhmforgeAcSweepResult": {
        "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",
            "required": [
              "output",
              "frequencies",
              "magnitudeDb",
              "phaseDeg",
              "peakDb"
            ],
            "properties": {
              "output": {
                "type": "string"
              },
              "input": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "frequencies": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "magnitudeDb": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "phaseDeg": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "peakDb": {
                "type": "number"
              },
              "peakFrequency": {
                "type": "number"
              },
              "lowGainDb": {
                "type": "number"
              },
              "lower3dB": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "upper3dB": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "unityGainFrequency": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "diagnostics": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "OhmforgeDcOperatingPointInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "netlist": {
            "title": "SPICE netlist",
            "description": "Subset: R C L V I D Q M E G K, .model, SIN/PULSE/PWL sources, engineering suffixes (k, m, u, n, p, meg). Node 0 is ground. Leave empty when you pass an Ohmforge project instead.",
            "type": "string",
            "maxLength": 60000
          },
          "project": {
            "title": "Ohmforge project JSON (optional)",
            "description": "Alternative to the netlist: a .ohmforge.json project as saved by the app (format \"ohmforge\", version 1).",
            "type": "string",
            "maxLength": 200000
          }
        },
        "required": []
      },
      "OhmforgeDcOperatingPointResult": {
        "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",
            "required": [
              "converged",
              "nodes",
              "elements",
              "stress",
              "diagnostics"
            ],
            "properties": {
              "title": {
                "type": "string"
              },
              "converged": {
                "type": "boolean"
              },
              "strategy": {
                "type": "string"
              },
              "iterations": {
                "type": "integer"
              },
              "nodes": {
                "type": "object",
                "additionalProperties": {
                  "type": "number"
                },
                "description": "Node voltages in V (ground = 0 is implicit)."
              },
              "elements": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "current": {
                      "type": "number"
                    },
                    "voltage": {
                      "type": "number"
                    },
                    "power": {
                      "type": "number"
                    },
                    "state": {
                      "type": "string"
                    }
                  }
                }
              },
              "totalSupplyPower": {
                "type": "number"
              },
              "stress": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "element": {
                      "type": "string"
                    },
                    "level": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              },
              "diagnostics": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "OhmforgeLedResistorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "supply": {
            "title": "Supply voltage",
            "type": "number",
            "minimum": 0.5,
            "maximum": 400,
            "default": 9,
            "x-unit": "V"
          },
          "colour": {
            "title": "LED colour",
            "type": "string",
            "enum": [
              "red",
              "orange",
              "yellow",
              "green",
              "blue",
              "white",
              "ir",
              "custom"
            ],
            "default": "red"
          },
          "vf": {
            "title": "Forward voltage (custom)",
            "description": "Only used for \"Custom\".",
            "type": "number",
            "minimum": 0.5,
            "maximum": 50,
            "x-unit": "V"
          },
          "current": {
            "title": "LED current",
            "type": "number",
            "minimum": 0.1,
            "maximum": 1000,
            "default": 20,
            "x-unit": "mA"
          },
          "count": {
            "title": "LEDs in series",
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 1
          },
          "series": {
            "title": "Resistor series",
            "type": "string",
            "enum": [
              "E6",
              "E12",
              "E24"
            ],
            "default": "E12"
          }
        },
        "required": [
          "supply",
          "current"
        ]
      },
      "OhmforgeLedResistorResult": {
        "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",
            "required": [
              "exactOhms",
              "standardOhms",
              "simulatedCurrent",
              "resistorPower",
              "recommendedRating"
            ],
            "properties": {
              "vf": {
                "type": "number"
              },
              "exactOhms": {
                "type": "number"
              },
              "standardOhms": {
                "type": "number"
              },
              "series": {
                "type": "string"
              },
              "simulatedCurrent": {
                "type": "number"
              },
              "simulatedLedVoltage": {
                "type": "number"
              },
              "resistorPower": {
                "type": "number"
              },
              "ledPower": {
                "type": "number"
              },
              "recommendedRating": {
                "type": "number"
              },
              "efficiency": {
                "type": "number"
              },
              "netlist": {
                "type": "string"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "OhmforgeTransientInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "netlist": {
            "title": "SPICE netlist",
            "description": "Subset: R C L V I D Q M E G K, .model, SIN/PULSE/PWL sources, engineering suffixes (k, m, u, n, p, meg). Node 0 is ground. Leave empty when you pass an Ohmforge project instead.",
            "type": "string",
            "maxLength": 60000
          },
          "project": {
            "title": "Ohmforge project JSON (optional)",
            "description": "Alternative to the netlist: a .ohmforge.json project as saved by the app (format \"ohmforge\", version 1).",
            "type": "string",
            "maxLength": 200000
          },
          "tstop": {
            "title": "Stop time",
            "description": "Simulated duration. Empty = use the .tran line of the netlist (or the project's transient settings).",
            "type": "number",
            "minimum": 0,
            "maximum": 1000,
            "x-unit": "s"
          },
          "tstep": {
            "title": "Output step",
            "description": "Spacing of the returned samples (also the largest internal step). Empty = .tran value or stop time / 1000.",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "x-unit": "s"
          },
          "method": {
            "title": "Integration",
            "type": "string",
            "enum": [
              "trap",
              "be"
            ],
            "default": "trap"
          },
          "uic": {
            "title": "Start from initial conditions (skip the operating point)",
            "description": "Capacitors start at their IC (default 0 V). Needed for oscillators.",
            "type": "boolean",
            "default": false
          },
          "probes": {
            "title": "Nodes to return",
            "description": "Node names; empty = all nodes (max 8 in the chart).",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 8
          }
        },
        "required": []
      },
      "OhmforgeTransientResult": {
        "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",
            "required": [
              "ok",
              "tstop",
              "tstep",
              "time",
              "waveforms",
              "measurements"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "tstop": {
                "type": "number"
              },
              "tstep": {
                "type": "number"
              },
              "method": {
                "type": "string"
              },
              "start": {
                "type": "string"
              },
              "steps": {
                "type": "integer"
              },
              "rejectedSteps": {
                "type": "integer"
              },
              "time": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "waveforms": {
                "type": "object",
                "additionalProperties": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "measurements": {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "properties": {
                    "min": {
                      "type": "number"
                    },
                    "max": {
                      "type": "number"
                    },
                    "vpp": {
                      "type": "number"
                    },
                    "mean": {
                      "type": "number"
                    },
                    "rms": {
                      "type": "number"
                    },
                    "frequency": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "duty": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "riseTime": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              },
              "stress": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "diagnostics": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "ThreadsmithDesignStatsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "file": {
            "title": "Embroidery file",
            "description": "Tajima .dst or Melco .exp. Upload as {filename, contentType?, contentBase64}. Max 6144 KiB. Accepts .dst,.exp.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "stitches": {
            "title": "Or: stitch list (JSON)",
            "description": "Same format as threadsmith-stitch-file.",
            "type": "string",
            "maxLength": 8000000
          },
          "colors": {
            "title": "Thread colours in sewing order",
            "description": "Optional #rrggbb per colour block (DST/EXP files store no colours).",
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 60
          },
          "spm": {
            "title": "Machine speed",
            "type": "integer",
            "minimum": 100,
            "maximum": 1500,
            "default": 700,
            "x-unit": "stitches/min"
          },
          "trimSeconds": {
            "title": "Time per trim",
            "type": "number",
            "minimum": 0,
            "maximum": 60,
            "default": 4,
            "x-unit": "s"
          },
          "colorSeconds": {
            "title": "Time per colour change",
            "type": "number",
            "minimum": 0,
            "maximum": 600,
            "default": 20,
            "x-unit": "s"
          },
          "hoop": {
            "title": "Hoop",
            "type": "string",
            "enum": [
              "50x50",
              "100x100",
              "130x180",
              "150x150",
              "160x260",
              "200x200",
              "200x300",
              "240x150",
              "360x200"
            ],
            "default": "130x180"
          },
          "densityThreshold": {
            "title": "Too-dense limit",
            "description": "Thread coverage per 1 mm cell above which the design is flagged (2.6 ≈ underlay + top + some overlap).",
            "type": "number",
            "minimum": 1,
            "maximum": 6,
            "default": 2.6,
            "x-unit": "thread layers"
          }
        },
        "required": []
      },
      "ThreadsmithDesignStatsResult": {
        "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",
            "required": [
              "format",
              "stitches",
              "jumps",
              "trims",
              "colorChanges",
              "widthMm",
              "heightMm",
              "sewingMinutes",
              "sewingTime",
              "topThreadM",
              "bobbinThreadM",
              "longestStitchMm",
              "hoop",
              "colors",
              "density",
              "hotspots",
              "warnings"
            ],
            "properties": {
              "format": {
                "type": "string"
              },
              "label": {
                "type": "string"
              },
              "header": {
                "type": "object"
              },
              "stitches": {
                "type": "integer"
              },
              "jumps": {
                "type": "integer"
              },
              "trims": {
                "type": "integer"
              },
              "colorChanges": {
                "type": "integer"
              },
              "widthMm": {
                "type": "number"
              },
              "heightMm": {
                "type": "number"
              },
              "sewingMinutes": {
                "type": "number"
              },
              "sewingTime": {
                "type": "string"
              },
              "topThreadM": {
                "type": "number"
              },
              "bobbinThreadM": {
                "type": "number"
              },
              "longestStitchMm": {
                "type": "number"
              },
              "hoop": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "fits": {
                    "type": "boolean"
                  },
                  "overflowMm": {
                    "type": "number"
                  }
                },
                "required": [
                  "id",
                  "fits",
                  "overflowMm"
                ]
              },
              "colors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "hex": {
                      "type": "string"
                    },
                    "stitches": {
                      "type": "integer"
                    },
                    "topThreadM": {
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "hex",
                    "stitches",
                    "topThreadM"
                  ]
                }
              },
              "density": {
                "type": "object",
                "properties": {
                  "maxLayers": {
                    "type": "number"
                  },
                  "areaOverMm2": {
                    "type": "number"
                  },
                  "threshold": {
                    "type": "number"
                  }
                },
                "required": [
                  "maxLayers",
                  "areaOverMm2",
                  "threshold"
                ]
              },
              "hotspots": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    },
                    "layers": {
                      "type": "number"
                    }
                  }
                }
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "ThreadsmithDigitizeInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "source": {
            "title": "What to digitize",
            "type": "string",
            "enum": [
              "shape",
              "path",
              "svg",
              "text",
              "project"
            ],
            "default": "shape"
          },
          "shape": {
            "title": "Shape",
            "type": "string",
            "enum": [
              "ellipse",
              "rect",
              "star",
              "hexagon",
              "heart"
            ],
            "default": "ellipse"
          },
          "widthMm": {
            "title": "Shape width",
            "type": "number",
            "minimum": 2,
            "maximum": 400,
            "default": 40,
            "x-unit": "mm"
          },
          "heightMm": {
            "title": "Shape height",
            "type": "number",
            "minimum": 2,
            "maximum": 400,
            "default": 30,
            "x-unit": "mm"
          },
          "pathD": {
            "title": "Path data",
            "description": "SVG path syntax in millimetres (y down, 0,0 = hoop centre). Closed paths (Z) become fills, open paths become lines.",
            "type": "string",
            "maxLength": 200000
          },
          "svg": {
            "title": "SVG markup",
            "description": "paths, rect, circle, ellipse, line, polyline, polygon and transforms are imported; text, images and gradients are skipped with a warning.",
            "type": "string",
            "maxLength": 1000000
          },
          "fitWidth": {
            "title": "Scale SVG to width",
            "description": "Optional. Default: the SVG’s own physical size (px at 96 dpi).",
            "type": "number",
            "minimum": 5,
            "maximum": 400,
            "x-unit": "mm"
          },
          "text": {
            "title": "Text",
            "description": "A–Z, a–z, 0–9 and . , ! ? - _ ' \" : ; ( ) / & + # * =",
            "type": "string",
            "maxLength": 200
          },
          "textSize": {
            "title": "Letter height (capitals)",
            "type": "number",
            "minimum": 3,
            "maximum": 200,
            "default": 12,
            "x-unit": "mm"
          },
          "font": {
            "title": "Font style",
            "type": "string",
            "enum": [
              "single",
              "outline"
            ],
            "default": "single"
          },
          "project": {
            "title": "Project JSON",
            "description": "A .threadsmith.json project (see the app’s project schema).",
            "type": "string",
            "maxLength": 2000000
          },
          "stitchType": {
            "title": "Stitch type",
            "type": "string",
            "enum": [
              "auto",
              "running",
              "satin",
              "tatami",
              "contour",
              "motif"
            ],
            "default": "auto"
          },
          "angle": {
            "title": "Fill angle",
            "type": "number",
            "minimum": -180,
            "maximum": 180,
            "default": 45,
            "x-unit": "°"
          },
          "spacing": {
            "title": "Row spacing / satin density",
            "type": "number",
            "minimum": 0.2,
            "maximum": 3,
            "default": 0.4,
            "x-unit": "mm"
          },
          "stitchLength": {
            "title": "Stitch length",
            "type": "number",
            "minimum": 1,
            "maximum": 7,
            "default": 3.5,
            "x-unit": "mm"
          },
          "satinWidth": {
            "title": "Satin column width (lines)",
            "type": "number",
            "minimum": 0.8,
            "maximum": 10,
            "default": 3,
            "x-unit": "mm"
          },
          "pullComp": {
            "title": "Pull compensation",
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 0.2,
            "x-unit": "mm"
          },
          "underlay": {
            "title": "Underlay",
            "type": "string",
            "enum": [
              "auto",
              "none",
              "center",
              "edge",
              "center-edge",
              "edge-tatami",
              "zigzag",
              "full"
            ],
            "default": "auto"
          },
          "color": {
            "title": "Thread",
            "description": "#rrggbb or a built-in thread name such as ruby, emerald, gold, navy.",
            "type": "string",
            "maxLength": 30,
            "default": "sapphire"
          },
          "hoop": {
            "title": "Hoop",
            "type": "string",
            "enum": [
              "50x50",
              "100x100",
              "130x180",
              "150x150",
              "160x260",
              "200x200",
              "200x300",
              "240x150",
              "360x200"
            ],
            "default": "130x180"
          },
          "spm": {
            "title": "Machine speed",
            "type": "integer",
            "minimum": 100,
            "maximum": 1500,
            "default": 700,
            "x-unit": "stitches/min"
          },
          "includeStitches": {
            "title": "Include the stitch list in the result",
            "description": "Adds result.stitchList ([x, y, type] in mm) for chaining into threadsmith-stitch-file.",
            "type": "boolean",
            "default": false
          }
        },
        "required": []
      },
      "ThreadsmithDigitizeResult": {
        "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",
            "required": [
              "objects",
              "order",
              "stitches",
              "jumps",
              "trims",
              "colorChanges",
              "widthMm",
              "heightMm",
              "sewingMinutes",
              "sewingTime",
              "topThreadM",
              "bobbinThreadM",
              "longestStitchMm",
              "hoop",
              "colors",
              "density",
              "warnings",
              "project",
              "openInApp"
            ],
            "properties": {
              "objects": {
                "type": "integer"
              },
              "order": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "stitches": {
                "type": "integer"
              },
              "jumps": {
                "type": "integer"
              },
              "trims": {
                "type": "integer"
              },
              "colorChanges": {
                "type": "integer"
              },
              "widthMm": {
                "type": "number"
              },
              "heightMm": {
                "type": "number"
              },
              "sewingMinutes": {
                "type": "number"
              },
              "sewingTime": {
                "type": "string"
              },
              "topThreadM": {
                "type": "number"
              },
              "bobbinThreadM": {
                "type": "number"
              },
              "longestStitchMm": {
                "type": "number"
              },
              "hoop": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "fits": {
                    "type": "boolean"
                  },
                  "overflowMm": {
                    "type": "number"
                  }
                },
                "required": [
                  "id",
                  "fits",
                  "overflowMm"
                ]
              },
              "colors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "hex": {
                      "type": "string"
                    },
                    "stitches": {
                      "type": "integer"
                    },
                    "topThreadM": {
                      "type": "number"
                    }
                  },
                  "required": [
                    "name",
                    "hex",
                    "stitches",
                    "topThreadM"
                  ]
                }
              },
              "density": {
                "type": "object",
                "properties": {
                  "maxLayers": {
                    "type": "number"
                  },
                  "areaOverMm2": {
                    "type": "number"
                  },
                  "threshold": {
                    "type": "number"
                  }
                },
                "required": [
                  "maxLayers",
                  "areaOverMm2",
                  "threshold"
                ]
              },
              "warnings": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "project": {
                "type": "object",
                "description": "Normalised Threadsmith project (open it in the app or pass it to threadsmith-stitch-file)."
              },
              "openInApp": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Threadsmith app link with the project in the #project= fragment (null when the project is too large for a URL)."
              },
              "stitchList": {
                "type": "array",
                "items": {
                  "type": "array"
                },
                "description": "[x, y, type] in mm, y down; type = stitch | jump | trim | color | end."
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "ThreadsmithStitchFileInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "format": {
            "title": "File format",
            "type": "string",
            "enum": [
              "dst",
              "exp"
            ],
            "default": "dst"
          },
          "stitches": {
            "title": "Stitch list (JSON)",
            "description": "[[x, y], [x, y, \"jump\"], [x, y, \"trim\"], [x, y, \"color\"], …] in mm (y down), or {\"cmds\": […], \"colors\": [{\"name\", \"hex\"}]} from threadsmith-digitize.",
            "type": "string",
            "maxLength": 8000000
          },
          "project": {
            "title": "Or: Threadsmith project JSON",
            "description": "If given, the project is digitized first.",
            "type": "string",
            "maxLength": 2000000
          },
          "label": {
            "title": "Design label (DST header, 8 characters)",
            "type": "string",
            "maxLength": 16,
            "default": "DESIGN"
          }
        },
        "required": []
      },
      "ThreadsmithStitchFileResult": {
        "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",
            "required": [
              "format",
              "filename",
              "bytes",
              "records",
              "stitchRecords",
              "jumpRecords",
              "colorChanges",
              "splitStitches",
              "verified",
              "maxErrorMm",
              "sha256",
              "artifactUrl",
              "base64",
              "firstRecords"
            ],
            "properties": {
              "format": {
                "type": "string",
                "enum": [
                  "dst",
                  "exp"
                ]
              },
              "filename": {
                "type": "string"
              },
              "bytes": {
                "type": "integer"
              },
              "records": {
                "type": "integer"
              },
              "stitchRecords": {
                "type": "integer"
              },
              "jumpRecords": {
                "type": "integer"
              },
              "colorChanges": {
                "type": "integer"
              },
              "splitStitches": {
                "type": "integer",
                "description": "Stitches longer than the format limit that were split into several records."
              },
              "verified": {
                "type": "boolean",
                "description": "The written file was decoded again and every stitch landed within 0.08 mm of the input."
              },
              "maxErrorMm": {
                "type": "number"
              },
              "sha256": {
                "type": "string"
              },
              "artifactUrl": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "base64": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "File content (only when no artifact store is available or the file is ≤ 64 KiB)."
              },
              "header": {
                "type": "object"
              },
              "firstRecords": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TwinworksBottleneckAnalysisInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "model": {
            "title": "Model or project JSON",
            "description": "A Twinworks project (.twinworks.json, format \"twinworks-project\") or a bare model with \"nodes\" and \"links\". Times in seconds, lengths in metres. Leave empty and pick a template instead.",
            "type": "string",
            "maxLength": 400000
          },
          "template": {
            "title": "Or start from a template",
            "type": "string",
            "enum": [
              "",
              "three-station-line",
              "line-with-failures",
              "assembly-two-feeders",
              "job-shop-routings",
              "bottleneck-buffer-sizing",
              "conveyor-packaging",
              "mm1-validation"
            ],
            "default": ""
          },
          "replications": {
            "title": "Replications",
            "type": "integer",
            "minimum": 2,
            "maximum": 20,
            "default": 5
          },
          "horizonHours": {
            "title": "Run length per replication",
            "description": "Overrides the model setting.",
            "type": "number",
            "minimum": 0.1,
            "maximum": 2400,
            "x-unit": "h"
          },
          "whatIf": {
            "title": "Simulate improvement options for the top bottleneck",
            "type": "boolean",
            "default": true
          }
        },
        "required": []
      },
      "TwinworksBottleneckAnalysisResult": {
        "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",
            "required": [
              "primary",
              "ranking",
              "recommendations",
              "baselineThroughput",
              "whatIf"
            ],
            "properties": {
              "primary": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "primaryName": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "ranking": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "rank",
                    "id",
                    "name",
                    "sole",
                    "shifting",
                    "total",
                    "activePct",
                    "utilization",
                    "dominantState",
                    "votes"
                  ],
                  "properties": {
                    "rank": {
                      "type": "integer"
                    },
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "sole": {
                      "type": "number"
                    },
                    "shifting": {
                      "type": "number"
                    },
                    "total": {
                      "type": "number"
                    },
                    "activePct": {
                      "type": "number"
                    },
                    "utilization": {
                      "type": "number"
                    },
                    "dominantState": {
                      "type": "string"
                    },
                    "votes": {
                      "type": "integer"
                    }
                  }
                }
              },
              "recommendations": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "baselineThroughput": {
                "type": "object",
                "required": [
                  "mean",
                  "lo",
                  "hi",
                  "halfWidth",
                  "n"
                ],
                "properties": {
                  "mean": {
                    "type": "number"
                  },
                  "lo": {
                    "type": "number"
                  },
                  "hi": {
                    "type": "number"
                  },
                  "halfWidth": {
                    "type": "number"
                  },
                  "n": {
                    "type": "integer"
                  }
                }
              },
              "whatIf": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "label",
                    "throughput",
                    "gain",
                    "gainPct"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "throughput": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "gain": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "gainPct": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TwinworksBufferSweepInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "model": {
            "title": "Model or project JSON",
            "description": "A Twinworks project (.twinworks.json, format \"twinworks-project\") or a bare model with \"nodes\" and \"links\". Times in seconds, lengths in metres. Leave empty and pick a template instead.",
            "type": "string",
            "maxLength": 400000
          },
          "template": {
            "title": "Or start from a template",
            "type": "string",
            "enum": [
              "",
              "three-station-line",
              "line-with-failures",
              "assembly-two-feeders",
              "job-shop-routings",
              "bottleneck-buffer-sizing",
              "conveyor-packaging",
              "mm1-validation"
            ],
            "default": ""
          },
          "target": {
            "title": "Object id",
            "description": "Id of the buffer/machine/conveyor/source to change, or pool:<id> for an operator pool. Default for the bottleneck template: B2.",
            "type": "string",
            "maxLength": 60
          },
          "parameter": {
            "title": "Parameter",
            "type": "string",
            "enum": [
              "capacity",
              "servers",
              "cycle.value",
              "cycle.mean",
              "batchSize",
              "interval.mean",
              "interval.value",
              "speed",
              "length",
              "failure.mttr.mean",
              "failure.mtbf.mean",
              "setup.value",
              "scrapPct",
              "count"
            ],
            "default": "capacity"
          },
          "from": {
            "title": "From",
            "type": "number",
            "minimum": 0,
            "maximum": 10000000,
            "default": 1
          },
          "to": {
            "title": "To",
            "type": "number",
            "minimum": 0,
            "maximum": 10000000,
            "default": 10
          },
          "step": {
            "title": "Step",
            "type": "number",
            "minimum": 0.0001,
            "maximum": 10000000,
            "default": 1
          },
          "replications": {
            "title": "Replications per value",
            "type": "integer",
            "minimum": 1,
            "maximum": 20,
            "default": 4
          },
          "horizonHours": {
            "title": "Run length per replication",
            "description": "Overrides the model setting.",
            "type": "number",
            "minimum": 0.1,
            "maximum": 2400,
            "x-unit": "h"
          }
        },
        "required": []
      },
      "TwinworksBufferSweepResult": {
        "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",
            "required": [
              "target",
              "parameter",
              "points",
              "knee",
              "bestThroughput"
            ],
            "properties": {
              "target": {
                "type": "string"
              },
              "parameter": {
                "type": "string"
              },
              "points": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "value",
                    "throughput",
                    "leadTime",
                    "wip"
                  ],
                  "properties": {
                    "value": {
                      "type": "number"
                    },
                    "throughput": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "leadTime": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "wip": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "costPerGoodPart": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "bottleneck": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "knee": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Smallest value reaching 98 % of the best mean throughput."
              },
              "bestThroughput": {
                "type": "number"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TwinworksSimulateInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "model": {
            "title": "Model or project JSON",
            "description": "A Twinworks project (.twinworks.json, format \"twinworks-project\") or a bare model with \"nodes\" and \"links\". Times in seconds, lengths in metres. Leave empty and pick a template instead.",
            "type": "string",
            "maxLength": 400000
          },
          "template": {
            "title": "Or start from a template",
            "type": "string",
            "enum": [
              "",
              "three-station-line",
              "line-with-failures",
              "assembly-two-feeders",
              "job-shop-routings",
              "bottleneck-buffer-sizing",
              "conveyor-packaging",
              "mm1-validation"
            ],
            "default": ""
          },
          "horizonHours": {
            "title": "Run length per replication",
            "description": "Overrides the model setting (includes the warm-up).",
            "type": "number",
            "minimum": 0.01,
            "maximum": 2400,
            "x-unit": "h"
          },
          "warmupMinutes": {
            "title": "Warm-up",
            "description": "Statistics are reset after the warm-up. Overrides the model setting.",
            "type": "number",
            "minimum": 0,
            "maximum": 144000,
            "x-unit": "min"
          },
          "seed": {
            "title": "Random seed",
            "description": "Same seed → same result. Replication r uses a seed derived from it.",
            "type": "integer",
            "minimum": 0,
            "maximum": 4294967295
          },
          "replications": {
            "title": "Replications",
            "description": "Independent runs with different seeds; used for the confidence intervals.",
            "type": "integer",
            "minimum": 1,
            "maximum": 30
          },
          "confidence": {
            "title": "Confidence level",
            "type": "string",
            "enum": [
              "",
              "0.9",
              "0.95",
              "0.99"
            ],
            "default": ""
          }
        },
        "required": []
      },
      "TwinworksSimulateResult": {
        "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",
            "required": [
              "modelName",
              "replications",
              "confidence",
              "horizonSeconds",
              "warmupSeconds",
              "throughputPerHour",
              "leadTime",
              "wip",
              "little",
              "good",
              "scrap",
              "stations",
              "bottleneck",
              "cost"
            ],
            "properties": {
              "modelName": {
                "type": "string"
              },
              "replications": {
                "type": "integer"
              },
              "confidence": {
                "type": "number"
              },
              "horizonSeconds": {
                "type": "number"
              },
              "warmupSeconds": {
                "type": "number"
              },
              "seeds": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "throughputPerHour": {
                "type": "object",
                "required": [
                  "mean",
                  "lo",
                  "hi",
                  "halfWidth",
                  "n"
                ],
                "properties": {
                  "mean": {
                    "type": "number"
                  },
                  "lo": {
                    "type": "number"
                  },
                  "hi": {
                    "type": "number"
                  },
                  "halfWidth": {
                    "type": "number"
                  },
                  "n": {
                    "type": "integer"
                  }
                }
              },
              "leadTime": {
                "type": "object",
                "required": [
                  "mean",
                  "p50",
                  "p90",
                  "p95",
                  "max",
                  "meanCi"
                ],
                "properties": {
                  "mean": {
                    "type": "number"
                  },
                  "p50": {
                    "type": "number"
                  },
                  "p90": {
                    "type": "number"
                  },
                  "p95": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  },
                  "meanCi": {
                    "type": "object",
                    "required": [
                      "mean",
                      "lo",
                      "hi",
                      "halfWidth",
                      "n"
                    ],
                    "properties": {
                      "mean": {
                        "type": "number"
                      },
                      "lo": {
                        "type": "number"
                      },
                      "hi": {
                        "type": "number"
                      },
                      "halfWidth": {
                        "type": "number"
                      },
                      "n": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "wip": {
                "type": "object",
                "required": [
                  "avg",
                  "max",
                  "avgCi"
                ],
                "properties": {
                  "avg": {
                    "type": "number"
                  },
                  "max": {
                    "type": "number"
                  },
                  "avgCi": {
                    "type": "object",
                    "required": [
                      "mean",
                      "lo",
                      "hi",
                      "halfWidth",
                      "n"
                    ],
                    "properties": {
                      "mean": {
                        "type": "number"
                      },
                      "lo": {
                        "type": "number"
                      },
                      "hi": {
                        "type": "number"
                      },
                      "halfWidth": {
                        "type": "number"
                      },
                      "n": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "little": {
                "type": "object",
                "required": [
                  "L",
                  "lambdaPerHour",
                  "W",
                  "lambdaW",
                  "relError",
                  "ok"
                ],
                "properties": {
                  "L": {
                    "type": "number"
                  },
                  "lambdaPerHour": {
                    "type": "number"
                  },
                  "W": {
                    "type": "number"
                  },
                  "lambdaW": {
                    "type": "number"
                  },
                  "relError": {
                    "type": "number"
                  },
                  "ok": {
                    "type": "boolean"
                  }
                }
              },
              "good": {
                "type": "integer"
              },
              "scrap": {
                "type": "integer"
              },
              "scrapPct": {
                "type": "number"
              },
              "stations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "id",
                    "name",
                    "type",
                    "servers",
                    "processed",
                    "throughputPerHour",
                    "utilization",
                    "states",
                    "availability",
                    "performance",
                    "quality",
                    "oee"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "servers": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "throughputPerHour": {
                      "type": "number"
                    },
                    "utilization": {
                      "type": "number"
                    },
                    "utilizationCi": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "states": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "availability": {
                      "type": "number"
                    },
                    "performance": {
                      "type": "number"
                    },
                    "quality": {
                      "type": "number"
                    },
                    "oee": {
                      "type": "number"
                    },
                    "oeeCi": {
                      "type": "object",
                      "required": [
                        "mean",
                        "lo",
                        "hi",
                        "halfWidth",
                        "n"
                      ],
                      "properties": {
                        "mean": {
                          "type": "number"
                        },
                        "lo": {
                          "type": "number"
                        },
                        "hi": {
                          "type": "number"
                        },
                        "halfWidth": {
                          "type": "number"
                        },
                        "n": {
                          "type": "integer"
                        }
                      }
                    },
                    "failures": {
                      "type": "integer"
                    },
                    "setups": {
                      "type": "integer"
                    }
                  }
                }
              },
              "buffers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "capacity": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "avgContents": {
                      "type": "number"
                    },
                    "maxContents": {
                      "type": "number"
                    },
                    "avgWait": {
                      "type": "number"
                    }
                  }
                }
              },
              "bottleneck": {
                "type": "object",
                "required": [
                  "primary",
                  "ranking",
                  "recommendations"
                ],
                "properties": {
                  "primary": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "ranking": {
                    "type": "array"
                  },
                  "recommendations": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "votes": {
                    "type": "object"
                  }
                }
              },
              "cost": {
                "type": "object",
                "required": [
                  "currency",
                  "total",
                  "costPerGoodPart"
                ],
                "properties": {
                  "currency": {
                    "type": "string"
                  },
                  "total": {
                    "type": "number"
                  },
                  "costPerGoodPart": {
                    "type": "number"
                  },
                  "costPerGoodPartCi": {
                    "type": "object",
                    "required": [
                      "mean",
                      "lo",
                      "hi",
                      "halfWidth",
                      "n"
                    ],
                    "properties": {
                      "mean": {
                        "type": "number"
                      },
                      "lo": {
                        "type": "number"
                      },
                      "hi": {
                        "type": "number"
                      },
                      "halfWidth": {
                        "type": "number"
                      },
                      "n": {
                        "type": "integer"
                      }
                    }
                  },
                  "scrapCost": {
                    "type": "number"
                  },
                  "labour": {
                    "type": "number"
                  },
                  "machineTime": {
                    "type": "number"
                  },
                  "material": {
                    "type": "number"
                  },
                  "variable": {
                    "type": "number"
                  },
                  "overhead": {
                    "type": "number"
                  },
                  "revenue": {
                    "type": "number"
                  },
                  "profit": {
                    "type": "number"
                  }
                }
              },
              "openInAppUrl": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TwinworksLineBalanceInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "tasks": {
            "title": "Tasks",
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "id": {
                  "title": "Task id",
                  "type": "string",
                  "maxLength": 20
                },
                "name": {
                  "title": "Description",
                  "type": "string",
                  "maxLength": 80
                },
                "time": {
                  "title": "Time (s)",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100000
                },
                "predecessors": {
                  "title": "Predecessors (comma-separated ids)",
                  "type": "string",
                  "maxLength": 400
                }
              },
              "required": [
                "id",
                "time"
              ]
            }
          },
          "taktTime": {
            "title": "Takt time",
            "description": "Leave empty to compute it from available time ÷ demand.",
            "type": "number",
            "minimum": 0.001,
            "maximum": 10000000,
            "x-unit": "s"
          },
          "availableMinutes": {
            "title": "Available production time",
            "description": "Per period, e.g. 450 min per shift.",
            "type": "number",
            "minimum": 1,
            "maximum": 1000000,
            "x-unit": "min"
          },
          "demand": {
            "title": "Demand in that period",
            "type": "number",
            "minimum": 1,
            "maximum": 1000000000,
            "x-unit": "units"
          },
          "method": {
            "title": "Heuristic",
            "type": "string",
            "enum": [
              "best",
              "rpw",
              "lcr"
            ],
            "default": "best"
          }
        },
        "required": [
          "tasks"
        ]
      },
      "TwinworksLineBalanceResult": {
        "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",
            "required": [
              "method",
              "taktTime",
              "totalWork",
              "theoreticalMin",
              "stationCount",
              "stations",
              "efficiency",
              "balanceDelay",
              "smoothnessIndex",
              "cycleTime",
              "maxThroughputPerHour",
              "model"
            ],
            "properties": {
              "method": {
                "type": "string"
              },
              "taktTime": {
                "type": "number"
              },
              "totalWork": {
                "type": "number"
              },
              "theoreticalMin": {
                "type": "integer"
              },
              "stationCount": {
                "type": "integer"
              },
              "stations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "station",
                    "tasks",
                    "time",
                    "idle",
                    "utilization"
                  ],
                  "properties": {
                    "station": {
                      "type": "integer"
                    },
                    "tasks": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "time": {
                      "type": "number"
                    },
                    "idle": {
                      "type": "number"
                    },
                    "utilization": {
                      "type": "number"
                    }
                  }
                }
              },
              "efficiency": {
                "type": "number"
              },
              "balanceDelay": {
                "type": "number"
              },
              "smoothnessIndex": {
                "type": "number"
              },
              "cycleTime": {
                "type": "number"
              },
              "maxThroughputPerHour": {
                "type": "number"
              },
              "positionalWeights": {
                "type": "object",
                "additionalProperties": {
                  "type": "number"
                }
              },
              "alternative": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "model": {
                "type": "object"
              }
            }
          },
          "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"
              }
            }
          }
        }
      },
      "TwinworksQueueFormulasInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "queue": {
            "title": "Queue model",
            "type": "string",
            "enum": [
              "mm1",
              "mmc",
              "md1",
              "mg1",
              "gg1"
            ],
            "default": "mm1"
          },
          "arrivalsPerHour": {
            "title": "Arrival rate",
            "type": "number",
            "minimum": 0.0001,
            "maximum": 10000000,
            "default": 60,
            "x-unit": "parts/h"
          },
          "serviceTime": {
            "title": "Mean service (cycle) time",
            "type": "number",
            "minimum": 0.0001,
            "maximum": 10000000,
            "default": 48,
            "x-unit": "s"
          },
          "servers": {
            "title": "Servers (M/M/c)",
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 2
          },
          "serviceScv": {
            "title": "Service SCV (variance ÷ mean²)",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 1
          },
          "arrivalScv": {
            "title": "Inter-arrival SCV (G/G/1)",
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "default": 1
          },
          "verify": {
            "title": "Verify by simulation",
            "description": "Runs the same station in Twinworks (M/M/1, M/M/c, M/D/1 only).",
            "type": "boolean",
            "default": false
          },
          "replications": {
            "title": "Replications for the check",
            "type": "integer",
            "minimum": 3,
            "maximum": 20,
            "default": 10
          }
        },
        "required": [
          "arrivalsPerHour",
          "serviceTime"
        ]
      },
      "TwinworksQueueFormulasResult": {
        "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",
            "required": [
              "model",
              "rho",
              "stable",
              "Wq",
              "W",
              "Lq",
              "L",
              "exact",
              "verification"
            ],
            "properties": {
              "model": {
                "type": "string"
              },
              "rho": {
                "type": "number"
              },
              "stable": {
                "type": "boolean"
              },
              "Wq": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "W": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "Lq": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "L": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "pWait": {
                "type": "number"
              },
              "exact": {
                "type": "boolean"
              },
              "verification": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "WqSim": {
                    "type": "object",
                    "required": [
                      "mean",
                      "lo",
                      "hi",
                      "halfWidth",
                      "n"
                    ],
                    "properties": {
                      "mean": {
                        "type": "number"
                      },
                      "lo": {
                        "type": "number"
                      },
                      "hi": {
                        "type": "number"
                      },
                      "halfWidth": {
                        "type": "number"
                      },
                      "n": {
                        "type": "integer"
                      }
                    }
                  },
                  "utilizationSim": {
                    "type": "object",
                    "required": [
                      "mean",
                      "lo",
                      "hi",
                      "halfWidth",
                      "n"
                    ],
                    "properties": {
                      "mean": {
                        "type": "number"
                      },
                      "lo": {
                        "type": "number"
                      },
                      "hi": {
                        "type": "number"
                      },
                      "halfWidth": {
                        "type": "number"
                      },
                      "n": {
                        "type": "integer"
                      }
                    }
                  },
                  "insideCi": {
                    "type": "boolean"
                  },
                  "replications": {
                    "type": "integer"
                  },
                  "horizonSeconds": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "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"
              }
            }
          }
        }
      }
    }
  }
}