{
  "what": "Three-armed Tender docking carousel. Meshes are in each part's own frame; assemble them by this table.",
  "axes": "Blender metres here are (bx, by, bz); Unreal = (bx, -by, bz) * 100 cm. Root frame = ArmsRoot of UCarrierCarouselComponent (hub axis, carrier z 0).",
  "from_unreal_blockout": {
    "cradle_radius_m": 6.0,
    "stowed_z_m": -1.0,
    "board_z_m": -6.3,
    "ceiling_z_m": 1.2,
    "arm_yaw_deg_unreal": "90 + AngleDeg + 120 * Arm (ArmYawDeg)"
  },
  "boom_aim": {
    "note": "each boom is turned 0.8594 deg from its nominal yaw so its tip is over the hatch collar centre (Tender x +0.09), not the Tender origin",
    "unreal_yaw_deg": [
      89.1406,
      209.1406,
      329.1406
    ],
    "tip_radius_cm": 600.067
  },
  "parts": [
    {
      "mesh": "SM_DockArm_Mount",
      "parent": "carrier (does not turn)",
      "location_cm": [
        0,
        0,
        0
      ],
      "moves": "never"
    },
    {
      "mesh": "SM_DockArm_Turret",
      "parent": "ArmsRoot",
      "location_cm": [
        0,
        0,
        0
      ],
      "moves": "yaw = hub AngleDeg (the drum and the three root stubs with the boom joints' clevises are this mesh)"
    },
    {
      "mesh": "SM_DockArm_Boom",
      "count": 3,
      "parent": "Turret, in the boom frame (yaw from boom_aim)",
      "location_cm": [
        150.0,
        0,
        85.0
      ],
      "moves": "Unreal pitch = -theta (the boom joint, added 2026-10-16: 0 down to BOARD, then it pitches the arm down into the moon pool: see 'hoist')"
    },
    {
      "mesh": "SM_DockArm_UpperLink",
      "count": 3,
      "parent": "Boom",
      "location_cm": [
        450.067,
        0,
        9.0
      ],
      "moves": "Unreal pitch = +shoulder (phi on the plain hoist)"
    },
    {
      "mesh": "SM_DockArm_LowerLink",
      "count": 3,
      "parent": "UpperLink",
      "location_cm": [
        -300.0,
        0,
        0
      ],
      "moves": "Unreal pitch = -elbow (2 phi on the plain hoist)"
    },
    {
      "mesh": "SM_DockArm_Head",
      "count": 3,
      "parent": "LowerLink",
      "location_cm": [
        300.0,
        0,
        0
      ],
      "moves": "Unreal pitch = +wrist = elbow - shoulder + theta (the head stays level)"
    },
    {
      "mesh": "SM_DockArm_Claw",
      "count": 12,
      "parent": "Head",
      "moves": "Unreal pitch = +open * 25 deg",
      "instances": [
        {
          "location_cm": [
            46.315,
            -46.315,
            -43.0
          ],
          "unreal_yaw_deg": -45.0
        },
        {
          "location_cm": [
            -46.316,
            -46.315,
            -43.0
          ],
          "unreal_yaw_deg": -135.0
        },
        {
          "location_cm": [
            -46.316,
            46.315,
            -43.0
          ],
          "unreal_yaw_deg": -225.0
        },
        {
          "location_cm": [
            46.315,
            46.316,
            -43.0
          ],
          "unreal_yaw_deg": -315.0
        }
      ]
    }
  ],
  "hoist": {
    "what": "y = StowedZ - TenderOriginZ (metres let down, 0 .. 9.3); r = reach_in (0 .. 2.5 m; the vessel interior uses 2.34 on the launch arm). Angles in radians, the boom frame has x radial out, z up",
    "to_BOARD": "y <= 5.3, the boom level (theta 0): x = r (y/5.3)^2, D = sqrt(x^2 + y^2); shoulder = atan2(y, x) - acos(D/6), elbow = pi - 2 acos(D/6), wrist = elbow - shoulder. r = 0 gives phi = asin(y/6): shoulder phi, elbow 2 phi, wrist phi; 62.047 deg at BOARD",
    "on_down_to_POOL": "y > 5.3 (POOL at 9.3): the wrist W = (R_TIP - r, ZS - y) goes straight on down; the knee keeps its BOARD bend D = sqrt(r^2 + 5.3^2); the shoulder S is the upper intersection of the circle of radius LJ = 4.5016 about the joint J = (1.50, 0.85) with the circle of radius D about W: L = |W - J|, a = (LJ^2 - D^2 + L^2)/(2 L), h = sqrt(LJ^2 - a^2), c = (W - J)/L, S = J + a c + h (-c.z, c.x); theta = 1.1456 deg - atan2(S.z - J.z, S.x - J.x) (the boom's pitch down). In the boom frame turned down by theta: x_in = -((W - S) . (cos theta, -sin theta)), y_dn = -((W - S) . (sin theta, cos theta)); shoulder = atan2(y_dn, x_in) - acos(D/6), elbow = pi - 2 acos(D/6), wrist = elbow - shoulder + theta. If the circles do not meet (r near 0, deep) the knee opens: D = L - LJ + 0.05 (at most 5.94)",
    "at_POOL_on_the_launch_arm_deg": {
      "boom": 51.4,
      "shoulder": 119.21,
      "elbow": 149.85,
      "wrist": 82.04
    },
    "joint_ranges_deg": {
      "boom": [
        0,
        75.0
      ],
      "shoulder": [
        0,
        172.0
      ],
      "elbow": [
        0,
        180
      ],
      "wrist": [
        -105.0,
        105.0
      ]
    },
    "link_length_cm": 300.0,
    "wrist_axis_above_tender_origin_cm": 194.0,
    "in_the_ship": "hub 7.5 m over the sub bay's deck; at POOL the Tender's top is 1.3 m below the deck and its keel 3.2 m above the hull's aperture. The rig's drivers are these formulas in staged form (build/kinematics.py)"
  },
  "tender_origin_in_head_frame_cm": [
    -0.135,
    8.999,
    -194.0
  ],
  "tender_yaw_relative_to_head_deg_unreal": -89.1406,
  "ore_hose": {
    "what": "SM_DockArm_OreHose: a film duct of 11 cm radius per arm, built in the boom frame (rest = stowed), every ring skinned to ONE bone with weight 1",
    "route": "hub pod port (22 deg off the arm) -> under the root stub -> through the boom joint's axis line, outside its clevis -> top of the boom -> flat U-turn round the tip -> lane beside the arm -> over the shoulder -> down the upper link -> U-turn round the elbow -> down the lower link -> through the wrist -> coupling on the head",
    "lane": "the hose runs beside the arm at Unreal y = +86 cm of the boom frame (Blender y -0.86 m); the middle of the arm is taken by the boom when the arm is folded",
    "bones": {
      "Hub": "rigid with the turret, in the boom frame (the port to the boom joint)",
      "Boom / Upper / Lower / Head": "follow the arm's boom, upper link, lower link and head (pivots in 'parts' above)",
      "R1..R6": "at the boom joint: i/7 of the boom's pitch",
      "S1..S8": "at the shoulder pivot: i/9 of the upper link's rotation",
      "E1..E9": "at the elbow pivot, carried by the upper link: plus i/10 of the lower link's rotation relative to it",
      "W1..W4": "at the wrist pivot, carried by the lower link: plus i/5 of the head's rotation relative to it"
    },
    "material": "M_DockArm_OreHose: clear ducting with a spiral rib (T_DockArm_Duct_BaseColor with the opacity in its alpha: film about 0.2 to 0.3, rib 1; T_DockArm_Duct_Roughness; T_DockArm_Duct_Normal is OpenGL, flip green for Unreal). Two-sided, translucent, reflections by Fresnel. One texture repeat = one circumference (0.69 m) of hose, 14 rib turns in it. Clamp bands are M_DockArm_HoseBand",
    "needs_headroom": "top of the hose is at z 1.37 m in the root frame when stowed: above the old blockout bay's ceiling (1.20), fine under the vessel interior's roof"
  },
  "surfaces": {
    "uv0": "UVMap: a unique unwrap in the shared 4096 px atlas (the two baked maps). Turret and mount unwrap one sector; their other sectors lie whole tiles further along U, so these samplers must wrap. Decal quads carry decal-sheet coordinates here",
    "uv1": "UV_Tile: metres. Tiling sets are sampled at uv1 / repeat_m",
    "masks": "T_DockArm_Masks (linear): R ambient occlusion, G edge (1 on a hard edge, 0 from 20 mm away), B crevice (1 open, lower in a gap)",
    "bevel_normal": "T_DockArm_BevelNormal: tangent space on UV0, OpenGL (flip green for Unreal); rounds every hard edge by 12 mm",
    "sets_from": "ModSci_Engineer/Textures (Modular SciFi Season 2, already in the Unreal project); smudge mask Base/Glass/T_Glass_DirtRough.png",
    "materials": [
      {
        "material": "M_DockArm_Paint",
        "diffuse": "Base/ScratchedMetal/T_ScratchedMetal_Diff.png",
        "roughness": "Base/ScratchedMetal/T_ScratchedMetal_Rough.png",
        "normal": "Base/ScratchedMetal/T_ScratchedMetal_Normal.png",
        "repeat_m": 0.9,
        "tint_linear": [
          0.64,
          0.65,
          0.65
        ],
        "metallic": 0.0,
        "shade_range": [
          0.88,
          1.05
        ],
        "roughness_range": [
          0.6,
          0.34
        ],
        "normal_strength": 0.35,
        "smudge_added_to_roughness": 0.05,
        "smudge_repeat_m": 2.6,
        "crevice_shade": 0.22,
        "edge_chips": 0.45
      },
      {
        "material": "M_DockArm_Graphite",
        "diffuse": "Base/StainedSteel/T_StainSteeled_Diff.png",
        "roughness": "Base/ScratchedMetal/T_ScratchedMetal_Rough.png",
        "normal": "Base/ScratchedMetal/T_ScratchedMetal_Normal.png",
        "repeat_m": 0.7,
        "tint_linear": [
          0.04,
          0.043,
          0.048
        ],
        "metallic": 0.0,
        "shade_range": [
          0.87,
          1.13
        ],
        "roughness_range": [
          0.66,
          0.42
        ],
        "normal_strength": 0.3,
        "smudge_added_to_roughness": 0.06,
        "smudge_repeat_m": 1.9,
        "crevice_shade": 0.15,
        "edge_chips": 0.5
      },
      {
        "material": "M_DockArm_Steel",
        "diffuse": "Base/StainedSteel/T_StainSteeled_Diff.png",
        "roughness": "Base/StainedSteel/T_StainSteeled_Rough.png",
        "normal": "Base/Glass/T_Scratch_Norm.png",
        "repeat_m": 0.5,
        "tint_linear": [
          0.6,
          0.61,
          0.63
        ],
        "metallic": 1.0,
        "shade_range": [
          0.8,
          1.15
        ],
        "roughness_range": [
          0.22,
          0.36
        ],
        "normal_strength": 0.5,
        "smudge_added_to_roughness": 0.05,
        "smudge_repeat_m": 0.9,
        "crevice_shade": 0.2,
        "edge_chips": 0.0
      },
      {
        "material": "M_DockArm_Rubber",
        "diffuse": null,
        "roughness": "Base/ScratchedMetal/T_ScratchedMetal_Rough.png",
        "normal": null,
        "repeat_m": 0.4,
        "tint_linear": [
          0.017,
          0.017,
          0.018
        ],
        "metallic": 0.0,
        "shade_range": [
          1.0,
          1.0
        ],
        "roughness_range": [
          0.86,
          0.62
        ],
        "normal_strength": 0.0,
        "smudge_added_to_roughness": 0.08,
        "smudge_repeat_m": 1.2,
        "crevice_shade": 0.1,
        "edge_chips": 0.0
      },
      {
        "material": "M_DockArm_SafetyOrange",
        "diffuse": "Base/ScratchedMetal/T_ScratchedMetal_Diff.png",
        "roughness": "Base/ScratchedMetal/T_ScratchedMetal_Rough.png",
        "normal": "Base/ScratchedMetal/T_ScratchedMetal_Normal.png",
        "repeat_m": 0.6,
        "tint_linear": [
          0.78,
          0.19,
          0.02
        ],
        "metallic": 0.0,
        "shade_range": [
          0.84,
          1.06
        ],
        "roughness_range": [
          0.62,
          0.36
        ],
        "normal_strength": 0.4,
        "smudge_added_to_roughness": 0.06,
        "smudge_repeat_m": 1.4,
        "crevice_shade": 0.25,
        "edge_chips": 0.7
      },
      {
        "material": "M_DockArm_HoseBand",
        "diffuse": "Base/StainedSteel/T_StainSteeled_Diff.png",
        "roughness": "Base/StainedSteel/T_StainSteeled_Rough.png",
        "normal": "Base/Glass/T_Scratch_Norm.png",
        "repeat_m": 0.35,
        "tint_linear": [
          0.6,
          0.61,
          0.63
        ],
        "metallic": 1.0,
        "shade_range": [
          0.8,
          1.15
        ],
        "roughness_range": [
          0.22,
          0.36
        ],
        "normal_strength": 0.5,
        "smudge_added_to_roughness": 0.05,
        "smudge_repeat_m": 0.6,
        "crevice_shade": 0.0,
        "edge_chips": 0.0
      }
    ],
    "glow": {
      "M_DockArm_GlowCyan": {
        "color": [
          0.1,
          0.85,
          1.0
        ],
        "strength": 1.2
      },
      "M_DockArm_GlowAmber": {
        "color": [
          1.0,
          0.55,
          0.08
        ],
        "strength": 1.2
      }
    },
    "lens": "M_DockArm_LensGlass: near-black smoked glass, roughness 0.16 to 0.24 by the smudge mask",
    "value_range_of_each_map": {
      "T_StainSteeled_Diff.png": [
        0.1735,
        0.2741
      ],
      "T_StainSteeled_Rough.png": [
        0.3608,
        0.8784
      ],
      "T_ScratchedMetal_Diff.png": [
        0.6172,
        0.6724
      ],
      "T_ScratchedMetal_Rough.png": [
        0.6314,
        0.8196
      ]
    },
    "recipe": "base colour = tint * lerp(shade_range, luminance of the diffuse map over its value range); roughness = lerp(roughness_range, roughness map over its value range) + smudge * amount; crevice shade = (1 - B)^1.4 * amount toward near-black, + 0.35 of it on the roughness; edge chips = smoothstep(0.38, 0.72, G * lerp(1.25, 0.55, roughness map) * smoothstep(0.72, 0.93, R) * amount) toward the bare-metal colour with metallic 1"
  }
}