# Motor-operated valve (MOV)

Flanged wedge-gate valve with bolted bonnet and yoke carrying a multi-turn electric actuator: gearcase, motor housing, display window and local selector / control knobs, terminal box with cable glands, side handwheel with hand/auto lever, stem cover tube with sight slot. `open` raises the stem through the gate stroke.

**Standards:** API 600, ISO 5210, IEC 60034, ASME B16.34, ASME B16.10, ASME B16.5

## Installation

```bash
npx -y https://decktwin.com/cli/deck-twin-0.2.2.tgz add motor-operated-valve
```

Copies `valves/motor-operated-valve.tsx`, any helper files it imports and the shared `lib/` into `src/components/deck-twin/`. Needs `three`, `@react-three/fiber` and `@react-three/drei`.

## Usage

```tsx
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { Stage } from './components/deck-twin/lib/stage'
import { MotorOperatedValve } from './components/deck-twin/valves/motor-operated-valve'

export default function Scene() {
  return (
    <Canvas shadows camera={{ position: [8, 5, 9], fov: 35 }}>
      <Stage>
        <MotorOperatedValve tag="MOV-6401" />
      </Stage>
      <OrbitControls makeDefault />
    </Canvas>
  )
}
```

## Props

| Prop | Type | Default | Range |
| --- | --- | --- | --- |
| `nps` | `number (NPS, in)` | `8` |  |
| `rating` | `150 \| 300 \| 600 \| 900 \| 1500 \| 2500` | `300` |  |
| `open` | `number` | `1` | 0 – 1 |
| `tag` | `string` | `""` |  |
| `...group` | position, rotation, scale… |  |  |

## Ports

Flange faces in the component's local frame, metres. Origin: pipe centreline, flow along X.

| Id | Label | Position | Direction | Size | Class |
| --- | --- | --- | --- | --- | --- |
| `A` | End A | -0.209, 0.000, 0.000 | -1, 0, 0 | 8" | 300 |
| `B` | End B | 0.210, 0.000, 0.000 | 1, 0, 0 | 8" | 300 |

## P&ID

Valve bow-tie with a stem to a circle containing M: the electric motor actuator. The tag bubble is usually MOV, XV or HV, and the valve fails in place (FL / FAI).

tag MOV · tag XV · ISA MOV · ISA XV · ISA HV · ISA ZSO · ISA ZSC · ISA 5.1 (electric motor actuator) on an ISO 10628-2 gate body

Circle with M = motor actuator; dome = diaphragm (control valve); rectangle = piston or spring-return (ESDV / BDV). A square with "M" is used by some legends for the same thing.

Valve datasheet (API 600) + electric actuator datasheet (ISO 5210 / IEC 60034) fields and the props they set:

| Field | Prop |
| --- | --- |
| Size | `nps` |
| Pressure class | `rating` |
| Tag number | `tag` |

## Typical suppliers

Rotork · Velan. The geometry is generic and sized from public standards. It is not vendor CAD.

## Source

`valves/motor-operated-valve.tsx`. This is the component file only: it imports shared code, so install it with the command above rather than pasting it alone. https://decktwin.com/r/motor-operated-valve.json has every file.

```tsx
// Motor-operated gate valve (MOV): wedge-gate body, bolted bonnet, yoke, multi-turn electric actuator with handwheel, local controls and stem cover. API 600, ISO 5210, ASME B16.10.
import type { Kit, MatKey } from '../lib/kit'
import { KitMesh, type GroupProps } from '../lib/mesh'
import { port, type Port } from '../lib/ports'
import { faceToFace, flange, pipeOD, type Rating } from '../lib/standards'
import { clamp, gateBody, gateWedge, osyYoke, plateText, useKit2 } from './_body'
import { electricActuator } from './_operators'

export interface MotorOperatedValveProps {
  /** nominal pipe size, inches */
  nps?: number
  rating?: Rating
  /** stem travel, 0 closed … 1 open */
  open?: number
  body?: MatKey
  actuator?: MatKey
  tag?: string
}

export const defaults = { nps: 8, rating: 300 as Rating, open: 1, body: 'valveBody' as MatKey, actuator: 'actuatorRed' as MatKey, tag: '' }

/** typical: gate stroke equals the bore */
const stroke = (nps: number) => Math.max(0.03, pipeOD(nps) * 0.95)
/** typical: actuator scale from valve size and class (thrust grows with bore area and pressure) */
const actScale = (nps: number, rating: Rating) => clamp(0.85 + pipeOD(nps) * 1.5 + (rating >= 600 ? 0.15 : 0), 0.85, 2)

export function ports(p: MotorOperatedValveProps = {}): Port[] {
  const { nps, rating } = { ...defaults, ...p }
  const L = faceToFace('gate', nps, rating)
  return [port('A', 'End A', [-L / 2, 0, 0], [-1, 0, 0], nps, rating), port('B', 'End B', [L / 2, 0, 0], [1, 0, 0], nps, rating)]
}

export function MotorOperatedValve(props: MotorOperatedValveProps & GroupProps) {
  const { nps, rating, open, body, actuator, tag, ...group } = { ...defaults, ...props }
  const [fixed, moving] = useKit2((k, mv) => build(k, mv, nps, rating, body, actuator, tag), [nps, rating, body, actuator, tag])
  return (
    <group {...group}>
      <KitMesh data={fixed} />
      <KitMesh data={moving} position-y={-(1 - clamp(open, 0, 1)) * stroke(nps)} />
    </group>
  )
}

export default MotorOperatedValve

function build(k: Kit, mv: Kit, nps: number, rating: Rating, M: MatKey, A: MatKey, tag: string) {
  const L = faceToFace('gate', nps, rating)
  const g = gateBody(k, nps, rating, L, M, plateText(nps, rating))
  const { yB, stemR, D } = g
  const y = osyYoke(k, M, yB, D, stemR, Math.max(0.12, 0.08 + D * 1.4)).top
  const s = actScale(nps, rating)
  const f = flange(nps, rating)
  const act = electricActuator(k, y, s, A, tag || 'MOV')
  // stem cover tube with sight slot and vent cap
  const T = stroke(nps)
  const rc = Math.max(stemR * 2, 0.025)
  const y0 = act.top + 0.01
  const top = y0 + T + 0.06
  k.cyl(A, rc * 1.5, 0.02, [0, y0, 0], 'y', 20)
  k.cyl('stainless', rc, top - y0, [0, (top + y0) / 2, 0], 'y', 20)
  k.box('nut', [0.003, (top - y0) * 0.7, rc * 0.6], [rc * 0.98, (top + y0) / 2, 0])
  k.cyl('stainless', rc * 1.15, 0.015, [0, top + 0.0075, 0], 'y', 20)
  k.hex('brass', rc * 0.6, 0.012, [0, top + 0.02, 0])
  // rising stem: in the yoke window and up into the cover tube (drawn open)
  gateWedge(mv, D, g.ri, T)
  const ys = T + g.ri
  mv.cyl('stainless', stemR, top - 0.02 - ys, [0, (top - 0.02 + ys) / 2, 0], 'y', 12)
  mv.hex('nut', stemR * 3, stemR * 1.2, [0, y - Math.max(0.03, D * 0.2), 0])
  // earth boss on the body
  k.cyl('brass', 0.008, 0.02, [0, -f.od / 2 * 0.55, g.rz * 0.95], 'z', 8)
}
```
