{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "mud-tank",
  "type": "registry:component",
  "title": "Active mud tank",
  "description": "Skid-mounted active mud pit: open-top steel tank on runners with external stiffeners, compartment bulkheads with top-operated equalising valves, translucent mud surface at `level`, grating top with ISO 14122 perimeter handrail and caged ladder. One top-entry agitator per compartment (right-angle helical-bevel gearbox and motor on bridge beams, shaft and canted-blade impellers turning when `running`, second impeller in tall tanks) seen through a guarded hatch opening. Mud-gun header with valved drop pipes and swivel nozzles, suction nozzle with suction bell, return and equalising nozzles, clean-out doors.",
  "dependencies": [
    "three",
    "@react-three/fiber",
    "@react-three/drei"
  ],
  "registryDependencies": [
    "https://deck-twin-library.demoareeb.workers.dev/r/core.json"
  ],
  "files": [
    {
      "path": "drilling/mud-tank.tsx",
      "type": "registry:file",
      "target": "components/deck-twin/drilling/mud-tank.tsx",
      "content": "// Active mud pit: skid-mounted open-top steel tank with compartments, top-entry agitators, mud guns, grating, handrails and ladder (ISO 14122, API RP 13C practice).\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 { flange, grating, handrail, ladder, liftingLug, member, motor, motorSize, tagPlate } from '../lib/parts'\nimport { port, type Port } from '../lib/ports'\nimport { Rotors, type RotorSpec } from '../lib/rotors'\nimport { pipeOD, pipeWall } from '../lib/standards'\n\nexport interface MudTankProps {\n  length?: number\n  width?: number\n  /** wall height, m */\n  height?: number\n  compartments?: number\n  /** agitator motor, kW */\n  agitatorKw?: number\n  /** mud level, fraction of wall height */\n  level?: number\n  suctionNps?: number\n  returnNps?: number\n  color?: string\n  tag?: string\n  /** turn the agitators */\n  running?: boolean\n}\n\nexport const defaults = {\n  length: 9,\n  width: 3,\n  height: 2.4,\n  compartments: 2,\n  agitatorKw: 15,\n  level: 0.62,\n  suctionNps: 10,\n  returnNps: 8,\n  color: '#a8402e',\n  tag: 'T-3201',\n  running: true,\n}\n\ntype P = typeof defaults\n\nfunction layout(p: Omit<P, 'tag' | 'running' | 'color' | 'level' | 'agitatorKw'>) {\n  const L = Math.max(4, p.length)\n  const W = Math.max(2, p.width)\n  const H = Math.max(1.5, p.height)\n  const n = Math.max(1, Math.min(4, Math.round(p.compartments)))\n  const yF = 0.3\n  const yT = yF + H\n  const ns = 0.2\n  return {\n    L, W, H, n, yF, yT,\n    suction: [-L / 2 - ns, yF + 0.4, -W / 2 + 0.7] as V3,\n    ret: [L / 2 + ns, yT - 0.4, W / 2 - 0.7] as V3,\n    equal: [L / 2 + ns, yF + 0.4, -W / 2 + 0.7] as V3,\n    gun: [L / 2 + 0.35, yT + 0.3, W / 2 - 0.3] as V3,\n    xs: Array.from({ length: n }, (_, i) => -L / 2 + (L * (i + 0.5)) / n),\n  }\n}\n\nexport function ports(props: MudTankProps = {}): Port[] {\n  const p = { ...defaults, ...props }\n  const l = layout(p)\n  return [\n    port('suction', 'Pump suction', l.suction, [-1, 0, 0], p.suctionNps, 150),\n    port('return', 'Mud return', l.ret, [1, 0, 0], p.returnNps, 150),\n    port('equalise', 'Equalising line', l.equal, [1, 0, 0], p.suctionNps, 150, 'utility'),\n    port('mud-gun', 'Mud gun supply', l.gun, [1, 0, 0], 3, 150, 'utility'),\n  ]\n}\n\nexport function MudTank({ tag = defaults.tag, ...rest }: MudTankProps & GroupProps) {\n  const { length, width, height, compartments, agitatorKw, level, suctionNps, returnNps, color, running, ...group } = { ...defaults, ...rest }\n  const out = useMemo(\n    () => build({ length, width, height, compartments, agitatorKw, level, suctionNps, returnNps, color, tag, running }),\n    [length, width, height, compartments, agitatorKw, level, suctionNps, returnNps, color, tag],\n  )\n  useEffect(() => () => [out.built, ...out.rotors.map((r) => r.built)].forEach((b) => b.geometry.dispose()), [out])\n  return (\n    <group {...group}>\n      <KitMesh data={out.built} />\n      <Rotors rotors={out.rotors} running={running} />\n    </group>\n  )\n}\n\nexport default MudTank\n\nfunction build(p: P) {\n  const k = new Kit()\n  const l = layout(p)\n  const { L, W, H, n, yF, yT, xs } = l\n  const C: MatKey = paint(p.color)\n  const t = 0.008\n  const rotors: RotorSpec[] = []\n\n  // skid runners and cross members, floor\n  for (const s of [-1, 1]) {\n    member(k, [-L / 2, 0.15, s * (W / 2 - 0.15)], [L / 2, 0.15, s * (W / 2 - 0.15)], 'HEB 300', 'structSteelDark')\n    k.box('structSteelDark', [0.3, 0.3, 0.02], [s * (L / 2 + 0.01), 0.15, 0])\n  }\n  for (let i = 0; i <= Math.round(L / 1.2); i++) member(k, [-L / 2 + 0.15 + ((L - 0.3) * i) / Math.round(L / 1.2), 0.15, -W / 2 + 0.3], [-L / 2 + 0.15 + ((L - 0.3) * i) / Math.round(L / 1.2), 0.15, W / 2 - 0.3], 'IPE 300', 'structSteelDark')\n  k.box(C, [L, t, W], [0, yF + t / 2, 0])\n\n  // walls with external stiffeners and a top rim angle\n  for (const s of [-1, 1]) {\n    k.box(C, [L, H, t], [0, yF + H / 2, s * (W / 2 - t / 2)])\n    k.box(C, [t, H, W], [s * (L / 2 - t / 2), yF + H / 2, 0])\n    const nx = Math.round(L / 0.8)\n    for (let i = 1; i < nx; i++) member(k, [-L / 2 + (L * i) / nx, yF, s * (W / 2 + 0.04)], [-L / 2 + (L * i) / nx, yT - 0.06, s * (W / 2 + 0.04)], 'UPN 80', C, [0, 0, s])\n    for (const y of [yF + H * 0.45]) k.box(C, [L, 0.08, 0.05], [0, y, s * (W / 2 + 0.03)])\n    k.box(C, [L + 0.1, 0.06, 0.06], [0, yT - 0.03, s * (W / 2 + 0.03)])\n    k.box(C, [0.06, 0.06, W + 0.1], [s * (L / 2 + 0.03), yT - 0.03, 0])\n  }\n  for (const sx of [-1, 1]) for (const sz of [-1, 1]) liftingLug(k, [sx * (L / 2 - 0.3), yT, sz * (W / 2 - 0.05)], 'x', 1.6, C)\n\n  // compartment bulkheads, each with an equalising valve worked from the top by an extension stem\n  for (let i = 1; i < n; i++) {\n    const x = -L / 2 + (L * i) / n\n    k.box(C, [t, H, W - 2 * t], [x, yF + H / 2, 0])\n    k.cyl('valveBody', 0.18, 0.2, [x, yF + 0.4, -W / 2 + 0.7], 'x', 24)\n    k.rod('stainless', [x + 0.05, yF + 0.55, -W / 2 + 0.7], [x + 0.05, yT + 0.9, -W / 2 + 0.7], 0.02, 10)\n    k.handwheel('actuatorRed', 0.4, [x + 0.05, yT + 0.9, -W / 2 + 0.7], 'y', 4)\n    k.box('structSteelDark', [0.12, 0.6, 0.12], [x + 0.05, yT + 0.3, -W / 2 + 0.7])\n  }\n\n  // mud surface (translucent so the agitator impellers read through the open hatches)\n  const yl = yF + H * Math.max(0.1, Math.min(0.95, p.level))\n  k.box(paint('#6a4f33', { metalness: 0, roughness: 0.18, transparent: true, opacity: 0.72, weather: 0 }), [L - 2 * t - 0.01, 0.004, W - 2 * t - 0.01], [0, yl, 0])\n\n  // top-entry agitators: bridge beams, right-angle helical-bevel gearbox, motor, shaft, canted 4-blade impeller\n  const m = motorSize(p.agitatorKw, 4)\n  const D = Math.min(1.2, W * 0.38)\n  const hatch = Math.max(0.4, Math.min(0.75, L / n / 2 - 0.15))\n  const top = yT\n  for (const x of xs) {\n    for (const s of [-1, 1]) member(k, [x + s * 0.28, top + 0.08, -W / 2], [x + s * 0.28, top + 0.08, W / 2], 'UPN 160', 'structSteelDark')\n    const yg = top + 0.18\n    // gearbox: housing, output flange, input bevel housing on +z, breather, oil gauge\n    k.rbox('machineryGreen', [0.42, 0.42, 0.42], 0.04, [x, yg + 0.21, 0])\n    k.cyl('machineryGreen', 0.16, 0.06, [x, yg + 0.45, 0], 'y', 28)\n    k.cyl('machineryGreen', 0.13, 0.12, [x, yg + 0.22, 0.27], 'z', 28)\n    k.cyl('brass', 0.015, 0.06, [x - 0.12, yg + 0.5, -0.1], 'y', 8)\n    k.cyl('glass', 0.025, 0.01, [x + 0.212, yg + 0.12, 0], 'x', 16)\n    const H0 = yg + 0.22 - (top + 0.1825)\n    const zp1 = 0.33 + m.L + 0.06\n    k.box('structSteelDark', [0.7, 0.025, zp1 + 0.3], [x, top + 0.17, (zp1 - 0.3) / 2])\n    k.with(new THREE.Matrix4().compose(new THREE.Vector3(x, yg + 0.22, 0.33), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2), new THREE.Vector3(1, 1, 1)), () =>\n      motor(k, { R: Math.min(m.R, H0 - 0.02), L: m.L, H: H0, tbox: 'top', cable: false }),\n    )\n    // hatch opening in the grating around the shaft: frame, open leaves, guard rail\n    const hx0 = x - hatch\n    const hx1 = x + hatch\n    handrail(k, [[hx0, top, -W / 2 + 0.15], [hx0, top, -0.35], [hx1, top, -0.35], [hx1, top, -W / 2 + 0.15]], 'safetyYellow')\n    // turning shaft + impeller (rotor about y at the shaft axis)\n    const rk = new Kit()\n    const yi = yF + Math.max(0.3, D * 0.35)\n    rk.cyl('stainless', 0.04, yg - yi, [0, (yg + yi) / 2, 0], 'y', 16)\n    rk.cyl('flangeSteel', 0.09, 0.03, [0, yg - 0.03, 0], 'y', 20)\n    rk.cyl('flangeSteel', 0.08, 0.1, [0, yi, 0], 'y', 20)\n    for (let i = 0; i < 4; i++) {\n      const a = (i / 4) * Math.PI * 2\n      const q = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), -a).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 4))\n      rk.box('flangeSteel', [D / 2 - 0.06, 0.012, 0.16], [Math.cos(a) * (D / 4 + 0.03), yi, Math.sin(a) * (D / 4 + 0.03)], q)\n    }\n    if (H > 2.2) {\n      const y2 = yi + H * 0.42\n      rk.cyl('flangeSteel', 0.07, 0.08, [0, y2, 0], 'y', 20)\n      for (let i = 0; i < 4; i++) {\n        const a = (i / 4) * Math.PI * 2 + Math.PI / 4\n        const q = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), -a).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 4))\n        rk.box('flangeSteel', [D * 0.4 - 0.06, 0.01, 0.13], [Math.cos(a) * (D * 0.2 + 0.03), y2, Math.sin(a) * (D * 0.2 + 0.03)], q)\n      }\n    }\n    // shaft stabiliser on the floor\n    k.cyl('structSteelDark', 0.08, 0.12, [x, yF + 0.07, 0], 'y', 16, undefined, true)\n    rotors.push({ built: rk.build(), axis: 'y', pos: [x, 0, 0], rpm: 58 })\n  }\n\n  // grating deck with the hatch openings left clear\n  const cells: [number, number, number, number][] = []\n  const edges = [-L / 2, ...xs.flatMap((x) => [x - hatch, x + hatch]), L / 2]\n  for (let i = 0; i < edges.length - 1; i += 2) cells.push([edges[i], edges[i + 1], -W / 2, W / 2])\n  for (const x of xs) {\n    cells.push([x - hatch, x + hatch, -0.35, W / 2])\n    cells.push([x - hatch, x + hatch, -W / 2, -W / 2 + 0.15])\n  }\n  for (const [x0, x1, z0, z1] of cells) {\n    const nx = Math.max(1, Math.round((x1 - x0) / 1.0))\n    for (let i = 0; i < nx; i++) grating(k, [x0 + ((x1 - x0) * (i + 0.5)) / nx, top, (z0 + z1) / 2], (x1 - x0) / nx - 0.01, z1 - z0 - 0.01)\n  }\n  for (let i = 0; i <= Math.round(L / 1.0); i++) k.box('structSteelDark', [0.05, 0.08, W - 0.02], [-L / 2 + 0.03 + ((L - 0.06) * i) / Math.round(L / 1.0), top - 0.07, 0])\n\n  // perimeter handrail (gap at the ladder) and caged ladder on the -X end\n  const g = 0.35\n  handrail(k, [[-L / 2 + 0.05, top, -g], [-L / 2 + 0.05, top, -W / 2 + 0.05], [L / 2 - 0.05, top, -W / 2 + 0.05], [L / 2 - 0.05, top, W / 2 - 0.05], [-L / 2 + 0.05, top, W / 2 - 0.05], [-L / 2 + 0.05, top, g]])\n  ladder(k, [-L / 2 - 0.2, 0, 0], top, [-1, 0, 0])\n  for (const s of [-1, 1]) k.box('safetyYellow', [0.25, 0.04, 0.04], [-L / 2 - 0.1, top - 0.1, s * 0.25])\n  k.rod('safetyYellow', [-L / 2 - 0.08, top + 1.1, -g], [-L / 2 - 0.08, top + 1.1, g], 0.02, 8)\n\n  // mud guns: header on stand-offs along the +Z rail, isolation valve and drop pipe with a swivel nozzle per compartment\n  const gun = l.gun\n  const zg = gun[2]\n  const yh = gun[1]\n  const gfl = flange(k, 3, 150, gun, 'x', true)\n  k.pipe('pipePaint', [-L / 2 + 0.6, yh, zg], [gun[0] - gfl, yh, zg], pipeOD(3), pipeWall(3))\n  k.dome('pipePaint', pipeOD(3) / 2, [-L / 2 + 0.6, yh, zg], '-x', Math.PI / 2, 0.5, 16)\n  for (let i = 0; i <= Math.round(L / 1.5); i++) {\n    const x = -L / 2 + 0.7 + ((L - 0.9) * i) / Math.round(L / 1.5)\n    k.box('structSteelDark', [0.05, yh - top, 0.05], [x, (yh + top) / 2, zg])\n  }\n  for (const x of xs) {\n    const xg = x + hatch + 0.45\n    k.rbox('valveBody', [0.12, 0.14, 0.14], 0.01, [xg, yh - 0.12, zg])\n    k.rod('stainless', [xg, yh - 0.12, zg - 0.07], [xg, yh - 0.12, zg - 0.25], 0.01, 8)\n    k.rod('actuatorRed', [xg, yh - 0.12, zg - 0.25], [xg + 0.2, yh - 0.12, zg - 0.25], 0.012, 8)\n    k.pipe('pipePaint', [xg, yh, zg], [xg, yh - 0.05, zg], pipeOD(2))\n    k.pipe('pipePaint', [xg, yh - 0.19, zg], [xg, yF + 0.75, zg], pipeOD(2), pipeWall(2))\n    k.cyl('flangeSteel', 0.05, 0.08, [xg, yF + 0.71, zg], 'y', 16)\n    k.rod('pipePaint', [xg, yF + 0.67, zg], [xg - 0.18, yF + 0.5, zg - 0.18], pipeOD(2) / 2, 12)\n    k.cyl('stainless', 0.03, 0.06, [xg - 0.2, yF + 0.48, zg - 0.2], [-1, -1, -1], 12, 0.018)\n  }\n\n  // nozzles: suction (bottom, -X end), return (top, +X end), equalising (bottom, +X end)\n  const nz = (face: V3, dir: 1 | -1, nps: number, mat: MatKey = C) => {\n    const fl = flange(k, nps, 150, face, dir > 0 ? 'x' : '-x', true)\n    k.pipe(mat, [dir * (L / 2 - 0.05), face[1], face[2]], [face[0] - dir * fl, face[1], face[2]], pipeOD(nps), pipeWall(nps))\n    k.cyl(mat, pipeOD(nps) * 0.85, 0.012, [dir * (L / 2 + 0.006), face[1], face[2]], 'x', 32)\n  }\n  nz(l.suction, -1, p.suctionNps)\n  nz(l.ret, 1, p.returnNps)\n  nz(l.equal, 1, p.suctionNps)\n  // suction bell inside the tank\n  k.lathe(C, [[pipeOD(p.suctionNps) * 0.9, -0.1], [pipeOD(p.suctionNps) * 0.55, 0.05], [pipeOD(p.suctionNps) * 0.5, 0.3]], [-L / 2 + 0.35, l.suction[1], l.suction[2]], 'x', 32)\n\n  // clean-out doors at the floor on the -Z side, one per compartment\n  for (const x of xs) {\n    k.box(C, [0.6, 0.45, 0.03], [x - 0.6, yF + 0.3, -W / 2 - 0.015])\n    for (const dx of [-0.25, 0, 0.25]) for (const dy of [-0.17, 0.17]) k.hex('nut', 0.03, 0.02, [x - 0.6 + dx, yF + 0.3 + dy, -W / 2 - 0.035], 'z')\n    k.rod('safetyYellow', [x - 0.85, yF + 0.3, -W / 2 - 0.05], [x - 0.35, yF + 0.3, -W / 2 - 0.05], 0.015, 8)\n  }\n\n  tagPlate(k, p.tag, [L / 2 - 1.2, yF + H * 0.75, W / 2 + 0.07], 'z', 0.4)\n  tagPlate(k, p.tag, [-L / 2 + 1.2, yF + H * 0.75, -W / 2 - 0.07], '-z', 0.4)\n  k.cyl('brass', 0.015, 0.03, [L / 2 - 0.3, 0.2, W / 2 + 0.005], 'z', 10)\n\n  return { built: k.build(), rotors }\n}\n"
    }
  ],
  "categories": [
    "drilling"
  ],
  "meta": {
    "export": "MudTank",
    "anchor": "base",
    "standards": [
      "API RP 13C",
      "ISO 14122-2/3/4",
      "ASME B16.5"
    ]
  }
}