{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pipe-handling-catwalk",
  "type": "registry:component",
  "title": "Pipe-handling catwalk & V-door ramp",
  "description": "Pipe-handling catwalk machine: fabricated body on base runners, checker-plate deck, lined V-trough with a chain-driven skate, three pipe-rack bays each side with stands, end stops and indexer fingers, and hydraulic kicker arms that lift with `kick`. Range-2 drill-pipe joints with tool-joint upsets, hardbanding and thread protectors lie on the racks (`joints` per side) and one waits in the trough. A 36° V-door ramp (slide) with wear plate and side guides climbs to a drill-floor landing at `floorHeight`; control console with hydraulic hoses at the far end. No process ports.",
  "dependencies": [
    "three",
    "@react-three/fiber",
    "@react-three/drei"
  ],
  "registryDependencies": [
    "https://deck-twin-library.demoareeb.workers.dev/r/core.json"
  ],
  "files": [
    {
      "path": "drilling/pipe-handling-catwalk.tsx",
      "type": "registry:file",
      "target": "components/deck-twin/drilling/pipe-handling-catwalk.tsx",
      "content": "// Pipe-handling catwalk machine with V-door ramp: trough and skate, pipe-rack bays with indexers, hydraulic kicker arms, drill pipe joints (API 5DP / API 7K).\nimport * as THREE from 'three'\nimport { useEffect, useMemo } from 'react'\nimport { Kit, type MatKey, type V3 } from '../lib/kit'\nimport { paint } from '../lib/materials'\nimport { KitMesh, type GroupProps } from '../lib/mesh'\nimport { checkerPlate, junctionBox, member, tagPlate } from '../lib/parts'\nimport { inch } from '../lib/standards'\n\nexport interface PipeHandlingCatwalkProps {\n  /** catwalk length, m */\n  length?: number\n  /** drill floor height above the catwalk deck level, m */\n  floorHeight?: number\n  /** joints on each pipe rack */\n  joints?: number\n  /** drill pipe OD, inches */\n  pipeOd?: number\n  /** kicker arm stroke, 0 parked … 1 fully raised */\n  kick?: number\n  color?: string\n  tag?: string\n}\n\nexport const defaults = { length: 13.5, floorHeight: 6, joints: 4, pipeOd: 5, kick: 0.35, color: '#d9a21b', tag: 'CW-01' }\n\ntype P = typeof defaults\n\nexport function PipeHandlingCatwalk({ length = defaults.length, floorHeight = defaults.floorHeight, joints = defaults.joints, pipeOd = defaults.pipeOd, kick = defaults.kick, color = defaults.color, tag = defaults.tag, ...group }: PipeHandlingCatwalkProps & GroupProps) {\n  const out = useMemo(() => build({ length, floorHeight, joints, pipeOd, kick, color, tag }), [length, floorHeight, joints, pipeOd, color, tag, kick])\n  useEffect(() => () => [out.built, out.arm].forEach((b) => b.geometry.dispose()), [out])\n  const a = Math.max(0, Math.min(1, kick)) * 0.55\n  return (\n    <group {...group}>\n      <KitMesh data={out.built} />\n      {out.arms.map((p, i) => (\n        <group key={i} position={p.pos} rotation={[p.side * a, 0, 0]} scale={[1, 1, p.side]}>\n          <KitMesh data={out.arm} />\n        </group>\n      ))}\n    </group>\n  )\n}\n\nexport default PipeHandlingCatwalk\n\n/** Drill pipe joint along +X from x0: tube with pin and box tool-joint upsets and hardbanding. */\nfunction joint(k: Kit, x0: number, len: number, c: [number, number], od: number, mat: MatKey) {\n  const r = od / 2\n  const tj = Math.max(r * 1.32, r + 0.02)\n  const [y, z] = c\n  k.lathe(mat, [[r * 0.82, 0], [tj * 0.85, 0], [tj, 0.03], [tj, 0.24], [r * 1.05, 0.32], [r, 0.36], [r, len - 0.5], [r * 1.05, len - 0.46], [tj, len - 0.38], [tj, len - 0.03], [tj * 0.75, len], [r * 0.6, len + 0.1], [r * 0.45, len + 0.12]], [x0, y, z], 'x', 24)\n  k.lathe('pipeBore', [[r * 0.8, 0.001], [0, 0.001]], [x0, y, z], '-x', 16)\n  for (const xx of [0.06, len - 0.2]) k.cyl('machined', tj + 0.001, 0.08, [x0 + xx + 0.04, y, z], 'x', 24)\n  // thread protectors\n  k.cyl('actuatorBlue', tj * 1.02, 0.12, [x0 - 0.05, y, z], 'x', 20)\n  k.cyl('actuatorBlue', r * 0.7, 0.14, [x0 + len + 0.12, y, z], 'x', 16)\n}\n\nfunction build(p: P) {\n  const k = new Kit()\n  const C: MatKey = paint(p.color)\n  const PIPE: MatKey = paint('#3d4e5c', { metalness: 0.5, roughness: 0.45 })\n  const L = Math.max(10, p.length)\n  const W = 1.5\n  const yD = 1.05 // catwalk deck height, typical\n  const od = inch(Math.max(2.375, Math.min(6.625, p.pipeOd)))\n  const jl = Math.min(L - 1.2, 9.45) // range 2 joint\n  const nj = Math.max(0, Math.min(8, Math.round(p.joints)))\n\n  // catwalk body: side beams, cross members, legs on base runners, checker-plate deck either side of the trough\n  for (const s of [-1, 1]) {\n    member(k, [-L / 2, yD - 0.2, s * (W / 2 - 0.1)], [L / 2, yD - 0.2, s * (W / 2 - 0.1)], 'HEB 400', C)\n    member(k, [-L / 2, 0.1, s * (W / 2 - 0.1)], [L / 2, 0.1, s * (W / 2 - 0.1)], 'HEB 200', C)\n  }\n  const nl = Math.round(L / 2.2)\n  for (let i = 0; i <= nl; i++) {\n    const x = -L / 2 + 0.2 + ((L - 0.4) * i) / nl\n    for (const s of [-1, 1]) member(k, [x, 0.2, s * (W / 2 - 0.1)], [x, yD - 0.4, s * (W / 2 - 0.1)], 'HEB 200', C)\n    member(k, [x, yD - 0.25, -W / 2 + 0.2], [x, yD - 0.25, W / 2 - 0.2], 'IPE 200', C)\n    member(k, [x, 0.1, -W / 2 + 0.2], [x, 0.1, W / 2 - 0.2], 'IPE 200', C)\n  }\n  for (const s of [-1, 1]) checkerPlate(k, [0, yD, s * (W / 2 - 0.25)], L, 0.5)\n  // V trough with wear strips, and the skate (pipe pusher) on its rails\n  const yT = yD - 0.12\n  for (const s of [-1, 1]) {\n    k.box(C, [L, 0.012, 0.32], [0, yT + 0.06, s * 0.13], new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), -s * 0.45))\n    k.box('rubberBlack', [L, 0.01, 0.04], [0, yT + 0.035, s * 0.07], new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), -s * 0.45))\n  }\n  const xs = -L / 2 + 0.9\n  k.rbox('actuatorYellow', [0.6, 0.3, 0.4], 0.03, [xs, yT + 0.2, 0])\n  k.box('nut', [0.04, 0.35, 0.3], [xs + 0.32, yT + 0.25, 0])\n  for (const s of [-1, 1]) k.cyl('rubberBlack', 0.07, 0.06, [xs, yT + 0.08, s * 0.24], 'z', 16)\n  // drive chain run in the trough bottom\n  k.box('nut', [L - 1, 0.02, 0.03], [0, yT + 0.01, 0])\n\n  // pipe-rack bays either side: rack beams on stands, stops, indexer fingers, joints of drill pipe\n  const rackX = [-jl / 2 + 0.9, 0, jl / 2 - 0.9]\n  const rw = 2.6\n  const yR = yD - 0.05\n  for (const s of [-1, 1]) {\n    for (const x of rackX) {\n      const z0 = s * (W / 2)\n      const z1 = s * (W / 2 + rw)\n      member(k, [x, yR - 0.15, z0], [x, yR - 0.15 + 0.04, z1], 'HEB 300', 'structSteelDark')\n      for (const z of [z1 - s * 0.2, z0 + s * 1.2]) {\n        k.box('structSteelDark', [0.2, yR - 0.33, 0.2], [x, (yR - 0.3 + 0.03) / 2, z])\n        k.box('structSteelDark', [0.4, 0.03, 0.4], [x, 0.015, z])\n      }\n      k.box('safetyYellow', [0.3, 0.25, 0.03], [x, yR + 0.12, z1])\n      // indexer finger at the inner end\n      k.box('actuatorYellow', [0.08, 0.12, 0.18], [x, yR + 0.06, z0 + s * 0.25])\n      k.cyl('stainless', 0.025, 0.25, [x - 0.1, yR - 0.1, z0 + s * 0.25], 'y', 10)\n    }\n    for (let j = 0; j < nj; j++) {\n      const z = s * (W / 2 + rw - 0.22 - j * (od * 1.4 + 0.03))\n      const tj = Math.max((od / 2) * 1.32, od / 2 + 0.02)\n      joint(k, -jl / 2, jl, [yR + tj, z], od, PIPE)\n    }\n  }\n  // joint waiting in the trough\n  joint(k, xs + 0.36, jl * 0.98, [yT + 0.13, 0], od, PIPE)\n\n  // V-door ramp (pipe slide) from the catwalk end up to the drill floor, with wear plate, side guides and a mid support\n  const H = Math.max(2.5, p.floorHeight)\n  const ang = (36 * Math.PI) / 180\n  const run = (H - yD) / Math.tan(ang)\n  const x0 = L / 2\n  const x1 = x0 + run\n  const len = Math.hypot(run, H - yD)\n  const qr = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), ang)\n  const mid: V3 = [(x0 + x1) / 2, (yD + H) / 2, 0]\n  k.with(new THREE.Matrix4().compose(new THREE.Vector3(...mid), qr, new THREE.Vector3(1, 1, 1)), () => {\n    k.box(C, [len, 0.02, 0.9], [0, -0.01, 0])\n    k.box('stainless', [len, 0.006, 0.5], [0, 0.003, 0])\n    for (const s of [-1, 1]) {\n      k.box(C, [len, 0.3, 0.02], [0, 0.13, s * 0.46])\n      member(k, [-len / 2, -0.14, s * 0.4], [len / 2, -0.14, s * 0.4], 'UPN 200', C)\n    }\n    for (let i = 0; i <= Math.round(len / 1.5); i++) k.box(C, [0.08, 0.2, 0.8], [-len / 2 + 0.1 + ((len - 0.2) * i) / Math.round(len / 1.5), -0.12, 0])\n  })\n  for (const s of [-1, 1]) {\n    const xm = x0 + run * 0.45\n    member(k, [xm, 0, s * 0.4], [xm, yD + (H - yD) * 0.45 - 0.3, s * 0.4], 'HEB 200', C)\n    k.box(C, [0.4, 0.03, 0.4], [xm, 0.015, s * 0.4])\n  }\n  // drill floor edge at the V-door: landing beam on a column, hook plates, toe board and V-door posts\n  member(k, [x1 + 0.05, H - 0.2, -1.4], [x1 + 0.05, H - 0.2, 1.4], 'HEB 400', 'structSteelDark')\n  member(k, [x1 + 0.05, 0, 0], [x1 + 0.05, H - 0.4, 0], 'HEB 400', 'structSteelDark')\n  k.box('structSteelDark', [0.6, 0.03, 0.6], [x1 + 0.05, 0.015, 0])\n  checkerPlate(k, [x1 + 0.8, H, 0], 1.5, 3)\n  k.box('structSteelDark', [1.5, 0.3, 3], [x1 + 0.8, H - 0.15, 0])\n  for (const s of [-1, 1]) {\n    k.box(C, [0.12, 0.12, 0.1], [x1 - 0.02, H + 0.02, s * 0.35])\n    k.box('safetyYellow', [0.25, 2.2, 0.25], [x1 + 0.2, H + 1.1, s * 0.85])\n  }\n\n  // control console at the -X end, hydraulic power hoses\n  const xc = -L / 2 - 0.5\n  k.box('structSteelDark', [0.6, 0.03, 0.8], [xc, 0.015, 0])\n  k.rbox('stainless', [0.5, 1.0, 0.6], 0.03, [xc, 0.55, 0])\n  k.box('stainless', [0.5, 0.06, 0.65], [xc, 1.1, 0], new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), 0.3))\n  for (let i = 0; i < 4; i++) k.rod('actuatorRed', [xc + 0.05, 1.15, -0.2 + i * 0.13], [xc + 0.08, 1.3, -0.2 + i * 0.13], 0.01, 6)\n  junctionBox(k, [xc - 0.25, 0.7, 0], '-x', [0.25, 0.25, 0.12])\n  for (const s of [-1, 1]) k.spline('rubberBlack', [[xc + 0.25, 0.3, s * 0.15], [xc + 0.6, 0.15, s * 0.3], [-L / 2 + 0.5, 0.25, s * 0.5]], 0.018, 8, 20)\n  tagPlate(k, p.tag, [0, yD - 0.25, W / 2 + 0.002], 'z', 0.3)\n\n  // kicker arm (built about its pivot on the catwalk edge, lifting towards -Z; mirrored for the other side)\n  const a = new Kit()\n  a.rbox('actuatorYellow', [0.14, 0.08, 0.95], 0.02, [0, 0.0, -0.45], undefined)\n  a.box('actuatorYellow', [0.14, 0.14, 0.08], [0, 0.06, -0.92])\n  a.cyl('stainless', 0.045, 0.2, [0, 0, 0], 'x', 16)\n  a.cyl('actuatorYellow', 0.06, 0.4, [0, -0.25, -0.3], [0, 1, -0.6], 16)\n  const arms = rackX.flatMap((x) => [-1, 1].map((side) => ({ pos: [x + 0.2, yD + 0.02, side * (W / 2 - 0.1)] as V3, side })))\n  // the arm's local -Z points out to the rack; mirror for the +Z side\n  return { built: k.build(), arm: a.build(), arms: arms.map((r) => ({ ...r, side: -r.side })) }\n}\n"
    }
  ],
  "categories": [
    "drilling"
  ],
  "meta": {
    "export": "PipeHandlingCatwalk",
    "anchor": "base",
    "standards": [
      "API 7K",
      "API 5DP",
      "ISO 14122"
    ]
  }
}