{
  "schemaVersion": 1,
  "id": "tutorial-reach",
  "name": "Reach · Bench Arm Tutorial",
  "template": "custom",
  "presetId": "arm-desktop",
  "parts": [
    {
      "id": "body",
      "defId": "preset-body",
      "name": "Anchored arm base",
      "position": [
        0,
        0.013500000000000002,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {
        "anchored": 1
      },
      "customDef": {
        "id": "preset-body",
        "name": "Anchored arm base",
        "category": "Structure",
        "subCategory": "Preset structure",
        "tags": [
          "preset"
        ],
        "visual": "chassis",
        "description": "Generic rigid support geometry with specified dimensions and mass; no structural flex or stress solution.",
        "size": [
          0.16,
          0.025,
          0.16
        ],
        "mass": 0.45,
        "color": "#597b8b",
        "shape": "box",
        "pins": [],
        "params": {},
        "price": 0,
        "fidelity": "geometry-only",
        "source": "BotSims generic preset geometry, not manufacturer CAD.",
        "version": 1
      }
    },
    {
      "id": "pedestal",
      "defId": "preset-pedestal",
      "name": "Arm pedestal",
      "position": [
        0,
        0.066,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "body",
      "customDef": {
        "id": "preset-pedestal",
        "name": "Arm pedestal",
        "category": "Structure",
        "subCategory": "Preset structure",
        "tags": [
          "preset"
        ],
        "visual": "chassis",
        "description": "Generic rigid support geometry with specified dimensions and mass; no structural flex or stress solution.",
        "size": [
          0.055,
          0.08,
          0.055
        ],
        "mass": 0.12,
        "color": "#597b8b",
        "shape": "box",
        "pins": [],
        "params": {},
        "price": 0,
        "fidelity": "geometry-only",
        "source": "BotSims generic preset geometry, not manufacturer CAD.",
        "version": 1
      }
    },
    {
      "id": "shoulder",
      "defId": "servo",
      "name": "Shoulder servo",
      "position": [
        0,
        0.116,
        0
      ],
      "rotation": [
        1.5707963267948966,
        0,
        0
      ],
      "joint": "fixed",
      "params": {
        "loadAxisZ": 1,
        "ratedTorque": 1,
        "kinematicJoint": 1,
        "motionAxisX": 0,
        "motionAxisY": 0,
        "motionAxisZ": 1
      },
      "parentId": "body"
    },
    {
      "id": "upper-arm",
      "defId": "arm-link",
      "name": "Robot arm link · 150 mm",
      "position": [
        0.085,
        0.116,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "shoulder"
    },
    {
      "id": "elbow",
      "defId": "servo",
      "name": "Elbow servo",
      "position": [
        0.17,
        0.116,
        0
      ],
      "rotation": [
        1.5707963267948966,
        0,
        0
      ],
      "joint": "fixed",
      "params": {
        "loadAxisZ": 1,
        "ratedTorque": 0.35,
        "kinematicJoint": 1,
        "motionAxisX": 0,
        "motionAxisY": 0,
        "motionAxisZ": 1
      },
      "parentId": "upper-arm"
    },
    {
      "id": "forearm",
      "defId": "arm-link",
      "name": "Robot arm link · 150 mm",
      "position": [
        0.255,
        0.116,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "elbow"
    },
    {
      "id": "tool",
      "defId": "gripper",
      "name": "Two-finger gripper",
      "position": [
        0.365,
        0.116,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "forearm"
    },
    {
      "id": "battery",
      "defId": "battery",
      "name": "2S battery · 2.2 Ah",
      "position": [
        -0.04,
        0.046,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "body"
    },
    {
      "id": "regulator",
      "defId": "regulator",
      "name": "5 V buck regulator",
      "position": [
        -0.035,
        0.07100000000000001,
        0.04
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "body"
    },
    {
      "id": "controller",
      "defId": "esp32-devkit",
      "name": "ESP32 DevKit · virtual controller",
      "position": [
        0.025,
        0.07100000000000001,
        0
      ],
      "rotation": [
        0,
        0,
        0
      ],
      "joint": "fixed",
      "params": {},
      "parentId": "body"
    }
  ],
  "wires": [
    {
      "id": "preset-wire-1",
      "from": {
        "part": "battery",
        "pin": "POS"
      },
      "to": {
        "part": "regulator",
        "pin": "VIN"
      }
    },
    {
      "id": "preset-wire-2",
      "from": {
        "part": "battery",
        "pin": "GND"
      },
      "to": {
        "part": "regulator",
        "pin": "GND"
      }
    },
    {
      "id": "preset-wire-3",
      "from": {
        "part": "regulator",
        "pin": "VOUT"
      },
      "to": {
        "part": "shoulder",
        "pin": "VCC"
      }
    },
    {
      "id": "preset-wire-4",
      "from": {
        "part": "battery",
        "pin": "GND"
      },
      "to": {
        "part": "shoulder",
        "pin": "GND"
      }
    },
    {
      "id": "preset-wire-5",
      "from": {
        "part": "controller",
        "pin": "SERVO_1"
      },
      "to": {
        "part": "shoulder",
        "pin": "PWM"
      }
    },
    {
      "id": "preset-wire-6",
      "from": {
        "part": "regulator",
        "pin": "VOUT"
      },
      "to": {
        "part": "elbow",
        "pin": "VCC"
      }
    },
    {
      "id": "preset-wire-7",
      "from": {
        "part": "battery",
        "pin": "GND"
      },
      "to": {
        "part": "elbow",
        "pin": "GND"
      }
    },
    {
      "id": "preset-wire-8",
      "from": {
        "part": "controller",
        "pin": "SERVO_2"
      },
      "to": {
        "part": "elbow",
        "pin": "PWM"
      }
    },
    {
      "id": "preset-wire-9",
      "from": {
        "part": "regulator",
        "pin": "VOUT"
      },
      "to": {
        "part": "controller",
        "pin": "VIN"
      }
    },
    {
      "id": "preset-wire-10",
      "from": {
        "part": "battery",
        "pin": "GND"
      },
      "to": {
        "part": "controller",
        "pin": "GND"
      }
    }
  ],
  "groups": [
    {
      "id": "power",
      "name": "Power & controller",
      "partIds": [
        "battery",
        "regulator",
        "controller"
      ]
    },
    {
      "id": "mechanism",
      "name": "Mechanical layout",
      "partIds": [
        "body",
        "pedestal",
        "shoulder",
        "upper-arm",
        "elbow",
        "forearm",
        "tool"
      ]
    }
  ],
  "code": "// Reach: two-joint bench-arm teaching project.\n// Kinematic motion preview; no IK, grasping, joint torque or moving-link collisions.\nlet lastStage = -1;\nfunction step(robot) {\n  robot.drive(0, 0);\n  if (robot.brownout || robot.battery.voltage < 6.25) return;\n  const phase = robot.time * 0.8;\n  robot.servo('shoulder', 0.28 + 0.16 * Math.sin(phase));\n  robot.servo('elbow', -0.22 + 0.14 * Math.sin(phase + 0.8));\n  const stage = Math.floor(robot.time / 3) % 3;\n  if (stage !== lastStage) { robot.log(['Approach preview', 'Reach preview', 'Return preview'][stage]); lastStage = stage; }\n}\n",
  "environment": {
    "scenario": "workbench",
    "slope": 0,
    "friction": 0.8,
    "payload": 0,
    "seed": 42,
    "initialSoc": 1,
    "obstacles": []
  },
  "ai": {
    "provider": "replay",
    "endpoint": "",
    "model": "recorded-rover-guide",
    "timeoutMs": 15000,
    "prompt": "You control a simulated robot. Use bounded wheel commands. Stop when sensors are unavailable or battery is low. Describe your intended action briefly.",
    "vision": false
  },
  "createdAt": "2026-10-29T00:00:00.000Z",
  "updatedAt": "2026-10-29T00:00:00.000Z"
}
