import { makeCameraPresets, makeThumbnailStrategy } from './factory'; import type { MachineDossier } from './types'; export const PUMP_AND_FLUID_DOSSIERS = [ { machineId: 'centrifugal-pump', slugAliases: ['volute-centrifugal-pump', 'radial-flow-pump'], title: 'Centrifugal Pump', category: 'Pumps & Fluid Systems', difficulty: 'Beginner', complexityScore: 4, registryKeywords: ['centrifugal pump', 'impeller', 'volute', 'cavitation', 'flow', 'pressure'], oneParagraphDescription: 'A centrifugal pump converts shaft power into fluid pressure by spinning an impeller inside a volute casing. The procedural cutaway shows axial inlet flow, radial acceleration through impeller vanes, pressure recovery in the volute, and a cavitation indicator at the low-pressure eye.', learningObjectives: [ 'Identify the impeller, eye, vanes, volute, shaft, seal, and flanges.', 'Trace flow from suction inlet to discharge outlet.', 'Explain how velocity added by the impeller becomes pressure in the volute.', 'Recognize cavitation risk at the impeller eye.', ], facts: [ { label: 'Pump type', value: 'Dynamic radial-flow pump', details: 'Energy is added continuously by rotating vanes rather than trapping fixed volumes.', }, { label: 'Typical speed', value: '1450–3600 rpm', details: 'Industrial pumps often run near common motor synchronous speeds.', }, { label: 'Key curve', value: 'Head vs. flow', details: 'Operating point is where the pump curve intersects the system resistance curve.', }, { label: 'Cavitation risk', value: 'Low inlet pressure', details: 'Vapor bubbles can form near the eye and collapse on higher-pressure surfaces.', }, { label: 'Applications', value: 'Water supply, HVAC, chemical transfer', details: 'Widely used for clean or moderately contaminated liquids.', }, ], componentTree: [ { id: 'centrifugal-hydraulic-end', name: 'Hydraulic end', kind: 'assembly', description: 'Impeller, eye, vanes, and volute form the pressure-generating flow path.', engineeringRole: 'Adds angular momentum to liquid and recovers pressure in the casing.', materialHint: 'cutaway blue volute, polished impeller', labelAnchor: [0, 0.1, 0], explodedOffset: [0, 0, 0.22], replacementNode: 'CentrifugalHydraulicEnd', animationChannels: ['impeller-rotation', 'fluid-flow', 'pressure-gradient'], children: [ { id: 'pump-impeller', name: 'Impeller', kind: 'part', description: 'Rotating vaned wheel that accelerates liquid outward.', engineeringRole: 'Transfers shaft work to fluid kinetic energy.', materialHint: 'polished stainless impeller with blue rim highlights', labelAnchor: [0, 0.14, 0.08], explodedOffset: [0, 0, 0.42], replacementNode: 'PumpImpeller', animationChannels: ['impeller-rotation'], }, { id: 'impeller-eye', name: 'Impeller eye', kind: 'part', description: 'Low-pressure inlet region at the center of the impeller.', engineeringRole: 'Draws liquid axially into the rotating vane passages.', materialHint: 'deep blue inlet throat', labelAnchor: [-0.28, 0.08, 0.18], explodedOffset: [-0.1, 0, 0.48], replacementNode: 'ImpellerEye', animationChannels: ['fluid-flow', 'cavitation-indicator'], }, { id: 'impeller-vanes', name: 'Impeller vanes', kind: 'assembly', description: 'Curved passages imparting tangential velocity to the liquid.', engineeringRole: 'Set pump head, flow direction, and hydraulic efficiency.', materialHint: 'bright vane surfaces', labelAnchor: [0.42, 0.2, 0.1], explodedOffset: [0.22, 0.1, 0.52], replacementNode: 'ImpellerVanes', animationChannels: ['impeller-rotation', 'fluid-flow'], }, { id: 'volute-casing', name: 'Volute casing', kind: 'part', description: 'Spiral casing with increasing area around the impeller.', engineeringRole: 'Collects high-velocity liquid and converts velocity into static pressure.', materialHint: 'transparent blue-grey cast casing', labelAnchor: [0.55, 0.32, 0], explodedOffset: [0.32, 0.18, 0], replacementNode: 'VoluteCasing', animationChannels: ['pressure-gradient'], }, ], }, { id: 'centrifugal-mechanical-end', name: 'Mechanical end', kind: 'assembly', description: 'Shaft, seal, bearings, suction flange, and discharge flange connect pump to the system.', engineeringRole: 'Supports the rotating impeller and contains pressurized liquid.', materialHint: 'dark housing, polished shaft, gasket accents', labelAnchor: [0, -0.65, 0], explodedOffset: [0, -0.28, 0], replacementNode: 'CentrifugalMechanicalEnd', animationChannels: ['shaft-rotation'], children: [ { id: 'pump-shaft', name: 'Pump shaft', kind: 'part', description: 'Motor-driven shaft carrying the impeller.', engineeringRole: 'Transmits torque through the seal into the wet end.', materialHint: 'polished steel', labelAnchor: [0, -0.18, 0.35], explodedOffset: [0, -0.18, 0.52], replacementNode: 'PumpShaft', animationChannels: ['shaft-rotation', 'impeller-rotation'], }, { id: 'mechanical-seal', name: 'Mechanical seal', kind: 'part', description: 'Precision sealing faces around the rotating shaft.', engineeringRole: 'Prevents leakage while allowing shaft rotation.', materialHint: 'dark carbon ring and bright ceramic face', labelAnchor: [-0.55, -0.2, 0], explodedOffset: [-0.32, -0.15, 0], replacementNode: 'MechanicalSeal', animationChannels: [], }, { id: 'suction-flange', name: 'Suction flange', kind: 'part', description: 'Inlet connection feeding liquid to the impeller eye.', engineeringRole: 'Provides low-loss inlet path and bolted piping interface.', materialHint: 'blue flange with gasket', labelAnchor: [-0.95, 0, 0], explodedOffset: [-0.58, 0, 0], replacementNode: 'SuctionFlange', animationChannels: ['fluid-flow'], }, { id: 'discharge-flange', name: 'Discharge flange', kind: 'part', description: 'Outlet connection at the volute tongue.', engineeringRole: 'Delivers higher-pressure flow to the system.', materialHint: 'amber-blue discharge flange', labelAnchor: [0.52, 0.88, 0], explodedOffset: [0.28, 0.55, 0], replacementNode: 'DischargeFlange', animationChannels: ['fluid-flow', 'pressure-gradient'], }, { id: 'cavitation-indicator', name: 'Cavitation indicator', kind: 'sensor', description: 'Bubble and warning overlay near the impeller eye when inlet pressure is low.', engineeringRole: 'Shows vapor formation caused by insufficient net positive suction head.', materialHint: 'white-blue bubbles with amber warning glyph', labelAnchor: [-0.35, 0.32, 0.24], explodedOffset: [-0.18, 0.16, 0.48], replacementNode: 'CavitationIndicator', animationChannels: ['cavitation-indicator'], }, ], }, ], labels: [ { partId: 'pump-impeller', text: 'Impeller adds velocity to liquid', position: [0.05, 0.28, 0.42], priority: 'primary' }, { partId: 'volute-casing', text: 'Volute recovers pressure', position: [0.72, 0.44, 0.26], priority: 'primary' }, { partId: 'impeller-eye', text: 'Low pressure eye can cavitate', position: [-0.38, 0.22, 0.42], priority: 'secondary' }, { partId: 'mechanical-seal', text: 'Seal keeps liquid inside around shaft', position: [-0.72, -0.22, 0.22], priority: 'detail' }, ], cameraPresets: makeCameraPresets(4.4, [0, 0.12, 0], { id: 'impeller-eye-close', label: 'Impeller Eye', position: [1.1, 1.12, 2.2], target: [-0.12, 0.14, 0.05], description: 'Cutaway close-up on inlet eye, vanes, and cavitation overlay.', }), guidedTour: [ { id: 'flow-path', title: 'From suction to discharge', body: 'Liquid enters axially through the suction flange, turns through the impeller, and exits the volute.', cameraPresetId: 'isometric', highlightedPartIds: ['suction-flange', 'impeller-eye', 'pump-impeller', 'discharge-flange'], durationSeconds: 7, animationTimeScale: 0.5, setExplode: 0.08, }, { id: 'impeller-work', title: 'Impeller adds energy', body: 'Rotating vanes accelerate liquid outward, raising velocity and pressure.', cameraPresetId: 'impeller-eye-close', highlightedPartIds: ['pump-impeller', 'impeller-vanes', 'pump-shaft'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.14, crossSection: { axis: 'z', offset: 0 }, }, { id: 'volute-pressure', title: 'Volute pressure recovery', body: 'The spiral volute area grows around the impeller, converting velocity into static pressure.', cameraPresetId: 'front', highlightedPartIds: ['volute-casing', 'discharge-flange'], durationSeconds: 6, animationTimeScale: 0.45, setExplode: 0.12, }, { id: 'cavitation', title: 'Cavitation warning', body: 'If inlet pressure drops too low, vapor bubbles form near the eye and collapse downstream.', cameraPresetId: 'impeller-eye-close', highlightedPartIds: ['cavitation-indicator', 'impeller-eye', 'impeller-vanes'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.18, }, ], animationModel: { nominalRpm: 1750, cycleSecondsAtNominal: 0.034, loopMode: 'continuous', stepCount: 4, primaryDriver: 'impeller-angle-and-flow-rate', engineeringNotes: 'Pump animation is continuous-flow. Flow ribbons should curve from axial inlet to radial impeller exit and then spiral into the discharge volute.', channels: [ { id: 'shaft-rotation', label: 'Shaft rotation', targetPartIds: ['pump-shaft'], transform: 'rotation', driver: 'motor speed', expression: 'rotate shaft at selected RPM about pump axis', phaseDeg: 0, notes: 'Shaft and impeller rotate together.', }, { id: 'impeller-rotation', label: 'Impeller rotation', targetPartIds: ['pump-impeller', 'impeller-vanes'], transform: 'rotation', driver: 'shaft angle θ', expression: 'rotate impeller continuously; vane blur scales with RPM', phaseDeg: 0, notes: 'Keep vane geometry visible at low RPM for instruction.', }, { id: 'fluid-flow', label: 'Fluid flow path', targetPartIds: ['suction-flange', 'impeller-eye', 'impeller-vanes', 'discharge-flange'], transform: 'flow', driver: 'flow rate', expression: 'blue particles enter eye, accelerate outward, and follow volute to discharge', phaseDeg: 0, notes: 'Particle velocity increases through impeller and slows slightly in volute.', }, { id: 'pressure-gradient', label: 'Pressure gradient', targetPartIds: ['volute-casing', 'discharge-flange'], transform: 'material', driver: 'head rise', expression: 'color shifts from deep blue at eye to lighter blue/amber near discharge', phaseDeg: 0, notes: 'Gradient reinforces pressure recovery.', }, { id: 'cavitation-indicator', label: 'Cavitation indicator', targetPartIds: ['cavitation-indicator', 'impeller-eye'], transform: 'material', driver: 'NPSH margin slider or cavitation tour step', expression: 'bubble opacity and warning icon increase when inlet pressure margin is low', phaseDeg: 0, notes: 'Use as an educational overlay, not a default alarm state.', }, ], }, explodedView: { defaultDistance: 0.3, maxDistance: 1.08, groups: [ { id: 'wet-end-forward', label: 'Impeller and volute', partIds: ['pump-impeller', 'impeller-eye', 'impeller-vanes', 'volute-casing'], axis: 'z', direction: 1, order: 1, reason: 'Pulls the hydraulic end open for flow visualization.', }, { id: 'flanges-out', label: 'Suction and discharge flanges', partIds: ['suction-flange', 'discharge-flange'], axis: 'x', direction: 1, order: 2, reason: 'Separates inlet and outlet piping interfaces.', }, { id: 'mechanical-down', label: 'Mechanical end', partIds: ['pump-shaft', 'mechanical-seal', 'cavitation-indicator'], axis: 'y', direction: -1, order: 3, reason: 'Reveals shaft seal and cavitation teaching overlay.', }, ], }, crossSection: { defaultAxis: 'z', recommendedPlanes: [ { id: 'hydraulic-cutaway', label: 'Hydraulic cutaway', axis: 'z', offset: 0, description: 'Opens the impeller and volute flow path.', }, { id: 'shaft-seal', label: 'Shaft seal section', axis: 'x', offset: -0.45, description: 'Shows the mechanical seal around the shaft.', }, ], }, thumbnail: makeThumbnailStrategy( ['volute-casing', 'pump-impeller', 'suction-flange', 'discharge-flange'], ['cavitation-indicator', 'pressure-gradient'], 'Render the spiral volute in cutaway with a bright impeller and blue-to-amber discharge flow.', ), assetReplacement: { proceduralBlueprintId: 'centrifugal-pump', preferredGlbPath: 'src/assets/machines/centrifugal-pump/centrifugal-pump.glb', rootNodeName: 'CentrifugalPump', requiredNamedNodes: ['PumpImpeller', 'ImpellerEye', 'ImpellerVanes', 'VoluteCasing', 'PumpShaft', 'SuctionFlange', 'DischargeFlange'], optionalNamedNodes: ['MechanicalSeal', 'CavitationIndicator', 'BearingFrame', 'PressureGradientOverlay', 'Baseplate'], materialSlots: ['cast-metal', 'stainless-steel', 'flow-blue', 'pressure-amber', 'seal-dark', 'warning-emissive'], coordinateSystem: 'Y up, pump shaft along Z, suction entering along negative X, discharge exiting positive Y.', replacementInstructions: 'Keep impeller and shaft separate rotating nodes. Volute should be a selectable cutaway mesh with flow ribbons independent from physical casing geometry.', }, relatedMachines: ['gear-pump', 'piston-pump', 'turbojet-engine'], }, { machineId: 'gear-pump', slugAliases: ['external-gear-pump', 'positive-displacement-gear-pump'], title: 'Gear Pump', category: 'Pumps & Fluid Systems', difficulty: 'Intermediate', complexityScore: 4, registryKeywords: ['gear pump', 'positive displacement', 'meshing gears', 'fluid pockets', 'relief valve'], oneParagraphDescription: 'A gear pump is a positive-displacement pump that traps liquid between gear teeth and housing walls, carrying it from inlet to outlet as the gears rotate. The procedural cutaway highlights displacement pockets, the meshing seal line, pressure build-up, and a relief valve for over-pressure protection.', learningObjectives: [ 'Identify drive gear, idler gear, housing, inlet, outlet, trapped pockets, and relief valve.', 'Explain why fluid travels around the outside of the gears rather than through the mesh.', 'Relate displacement per revolution to gear size and tooth spaces.', 'Understand why a relief valve is needed on positive-displacement pumps.', ], facts: [ { label: 'Pump type', value: 'Positive displacement', details: 'Each revolution moves a nearly fixed volume of liquid independent of discharge pressure until slip increases.', }, { label: 'Flow path', value: 'Around gear outside', details: 'The gear mesh blocks flow through the centre and forces pockets around the housing.', }, { label: 'Typical fluids', value: 'Oils, fuels, hydraulic fluids', details: 'Best suited to lubricating fluids with moderate viscosity.', }, { label: 'Pressure protection', value: 'Relief valve required', details: 'Blocking the outlet can rapidly raise pressure because displacement continues.', }, { label: 'Flow ripple', value: 'Tooth-passing pulsation', details: 'Flow has small periodic ripple as pockets open and close.', }, ], componentTree: [ { id: 'gear-pump-rotor-set', name: 'Meshing gear set', kind: 'assembly', description: 'Drive and idler gears rotate in opposite directions inside a close-fitting housing.', engineeringRole: 'Traps and transports displacement pockets from inlet to outlet.', materialHint: 'machined steel gears with oil-blue pocket highlights', labelAnchor: [0, 0.1, 0], explodedOffset: [0, 0, 0.22], replacementNode: 'GearPumpRotorSet', animationChannels: ['drive-gear-rotation', 'idler-gear-rotation', 'fluid-pocket-motion'], children: [ { id: 'drive-gear', name: 'Drive gear', kind: 'part', description: 'Powered gear connected to the input shaft.', engineeringRole: 'Drives the idler gear and creates tooth-space pockets.', materialHint: 'polished steel with blue input marker', labelAnchor: [-0.35, 0.18, 0], explodedOffset: [-0.28, 0.12, 0.38], replacementNode: 'DriveGear', animationChannels: ['drive-gear-rotation'], }, { id: 'idler-gear', name: 'Idler gear', kind: 'part', description: 'Meshing gear driven by the drive gear.', engineeringRole: 'Completes the pumping pair and carries pockets on the opposite side.', materialHint: 'polished steel with amber output side highlight', labelAnchor: [0.35, 0.18, 0], explodedOffset: [0.28, 0.12, 0.38], replacementNode: 'IdlerGear', animationChannels: ['idler-gear-rotation'], }, { id: 'meshing-seal-line', name: 'Meshing seal line', kind: 'sensor', description: 'Highlighted contact region where gear teeth prevent direct inlet-to-outlet leakage.', engineeringRole: 'Shows why fluid is carried around the outside, not through the center mesh.', materialHint: 'thin amber emissive line', labelAnchor: [0, 0.22, 0.14], explodedOffset: [0, 0.18, 0.48], replacementNode: 'MeshingSealLine', animationChannels: ['mesh-contact-highlight'], }, ], }, { id: 'gear-pump-housing-flow', name: 'Housing and flow passages', kind: 'assembly', description: 'Close-clearance housing, inlet, outlet, and animated fluid pockets define the pumping path.', engineeringRole: 'Seals tooth pockets and converts gear rotation into positive displacement.', materialHint: 'dark cutaway body with blue fluid pockets', labelAnchor: [0, -0.55, 0], explodedOffset: [0, -0.28, 0], replacementNode: 'GearPumpHousingFlow', animationChannels: ['fluid-pocket-motion', 'pressure-rise-overlay'], children: [ { id: 'gear-pump-housing', name: 'Close-clearance housing', kind: 'part', description: 'Body with tight radial clearances around both gears.', engineeringRole: 'Prevents pockets from leaking back to the inlet.', materialHint: 'dark cast body with cutaway top', labelAnchor: [0, -0.62, 0], explodedOffset: [0, -0.46, 0], replacementNode: 'GearPumpHousing', animationChannels: [], }, { id: 'gear-pump-inlet', name: 'Inlet port', kind: 'part', description: 'Low-pressure port where expanding tooth spaces fill with liquid.', engineeringRole: 'Supplies fluid to pockets as gears unmesh.', materialHint: 'blue inlet port', labelAnchor: [-0.85, 0, 0], explodedOffset: [-0.58, 0, 0], replacementNode: 'GearPumpInlet', animationChannels: ['fluid-pocket-motion'], }, { id: 'gear-pump-outlet', name: 'Outlet port', kind: 'part', description: 'High-pressure port where tooth spaces collapse and discharge liquid.', engineeringRole: 'Receives fixed displacement and sends it into the system.', materialHint: 'amber-blue outlet port', labelAnchor: [0.85, 0, 0], explodedOffset: [0.58, 0, 0], replacementNode: 'GearPumpOutlet', animationChannels: ['fluid-pocket-motion', 'pressure-rise-overlay'], }, { id: 'fluid-pockets', name: 'Displacement pockets', kind: 'effect', description: 'Animated liquid volumes trapped between gear teeth and housing.', engineeringRole: 'Represents the volume moved each revolution.', materialHint: 'transparent blue pocket segments', labelAnchor: [0, 0.52, 0.16], explodedOffset: [0, 0.42, 0.48], replacementNode: 'FluidPockets', animationChannels: ['fluid-pocket-motion'], }, { id: 'relief-valve', name: 'Relief valve', kind: 'control', description: 'Spring-loaded bypass that opens when discharge pressure is excessive.', engineeringRole: 'Protects pump, motor, and piping from blocked-outlet pressure spikes.', materialHint: 'orange spring and valve poppet', labelAnchor: [0.62, -0.52, 0], explodedOffset: [0.45, -0.4, 0], replacementNode: 'ReliefValve', animationChannels: ['relief-valve-opening'], }, ], }, ], labels: [ { partId: 'fluid-pockets', text: 'Fluid pockets move around the outside', position: [0, 0.68, 0.34], priority: 'primary' }, { partId: 'meshing-seal-line', text: 'Gear mesh blocks centre leakage', position: [0, 0.36, 0.32], priority: 'primary' }, { partId: 'relief-valve', text: 'Relief valve protects against over-pressure', position: [0.78, -0.62, 0.24], priority: 'secondary' }, { partId: 'gear-pump-outlet', text: 'Discharge pressure rises here', position: [1.02, 0.08, 0.24], priority: 'secondary' }, ], cameraPresets: makeCameraPresets(4.1, [0, 0.02, 0], { id: 'pocket-path', label: 'Pocket Path', position: [1.1, 1.1, 2.15], target: [0, 0.18, 0], description: 'Close-up of tooth spaces carrying fluid around the housing wall.', }), guidedTour: [ { id: 'positive-displacement', title: 'Fixed volume per revolution', body: 'The gear teeth create pockets that carry a nearly fixed volume of liquid each turn.', cameraPresetId: 'isometric', highlightedPartIds: ['drive-gear', 'idler-gear', 'fluid-pockets'], durationSeconds: 7, animationTimeScale: 0.4, setExplode: 0.08, }, { id: 'around-not-through', title: 'Fluid goes around, not through', body: 'The meshing teeth seal the center, forcing liquid to travel around the outer housing clearances.', cameraPresetId: 'pocket-path', highlightedPartIds: ['meshing-seal-line', 'fluid-pockets', 'gear-pump-housing'], durationSeconds: 7, animationTimeScale: 0.28, setExplode: 0.15, crossSection: { axis: 'z', offset: 0 }, }, { id: 'inlet-outlet', title: 'Unmesh to fill, mesh to discharge', body: 'Tooth spaces expand at the inlet and collapse at the outlet, producing pressure rise.', cameraPresetId: 'front', highlightedPartIds: ['gear-pump-inlet', 'gear-pump-outlet', 'drive-gear', 'idler-gear'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.12, }, { id: 'relief-protection', title: 'Relief valve protection', body: 'If outlet pressure rises too far, the relief valve opens a bypass path to protect the system.', cameraPresetId: 'right', highlightedPartIds: ['relief-valve', 'gear-pump-outlet'], durationSeconds: 6, animationTimeScale: 0.45, setExplode: 0.2, }, ], animationModel: { nominalRpm: 600, cycleSecondsAtNominal: 0.1, loopMode: 'continuous', stepCount: 4, primaryDriver: 'drive-gear-angle', engineeringNotes: 'Use paired counter-rotation with discrete pocket markers moving around outer arcs. Pocket flow should stop at the mesh center and reappear at the outlet path, not pass through the gear mesh.', channels: [ { id: 'drive-gear-rotation', label: 'Drive gear rotation', targetPartIds: ['drive-gear'], transform: 'rotation', driver: 'input shaft angle θ', expression: 'rotate drive gear clockwise in default view', phaseDeg: 0, notes: 'Input arrow uses blue accent color.', }, { id: 'idler-gear-rotation', label: 'Idler gear rotation', targetPartIds: ['idler-gear'], transform: 'rotation', driver: 'gear mesh constraint', expression: 'rotate idler gear counter-clockwise at equal speed', phaseDeg: 0, notes: 'Equal tooth count in teaching model gives equal speed.', }, { id: 'fluid-pocket-motion', label: 'Fluid pocket motion', targetPartIds: ['fluid-pockets', 'gear-pump-inlet', 'gear-pump-outlet'], transform: 'flow', driver: 'gear tooth phase', expression: 'pocket markers appear where gears unmesh, travel around housing, and discharge where teeth mesh', phaseDeg: 0, notes: 'Use tooth-count frequency for ripple effect.', }, { id: 'mesh-contact-highlight', label: 'Mesh seal highlight', targetPartIds: ['meshing-seal-line'], transform: 'material', driver: 'tooth mesh phase', expression: 'thin highlight pulses where opposing teeth contact', phaseDeg: 0, notes: 'Clarifies the no-flow-through-center rule.', }, { id: 'pressure-rise-overlay', label: 'Outlet pressure overlay', targetPartIds: ['gear-pump-outlet'], transform: 'material', driver: 'outlet restriction', expression: 'amber intensity rises with restriction and discharge pressure', phaseDeg: 0, notes: 'Pairs with relief valve opening.', }, { id: 'relief-valve-opening', label: 'Relief valve opening', targetPartIds: ['relief-valve'], transform: 'translation', driver: 'discharge pressure threshold', expression: 'poppet lifts against spring and bypass flow appears when pressure exceeds set point', phaseDeg: 0, notes: 'Triggered in guided tour and high-load demo mode.', }, ], }, explodedView: { defaultDistance: 0.3, maxDistance: 1.05, groups: [ { id: 'gears-forward', label: 'Gear rotor set', partIds: ['drive-gear', 'idler-gear', 'meshing-seal-line'], axis: 'z', direction: 1, order: 1, reason: 'Pulls gears out of the housing to show tooth pockets.', }, { id: 'ports-out', label: 'Ports and flow', partIds: ['gear-pump-inlet', 'gear-pump-outlet', 'fluid-pockets'], axis: 'x', direction: 1, order: 2, reason: 'Separates inlet and outlet paths for flow direction.', }, { id: 'relief-down', label: 'Relief valve', partIds: ['relief-valve', 'gear-pump-housing'], axis: 'y', direction: -1, order: 3, reason: 'Opens pressure-protection hardware below the main pumping cavity.', }, ], }, crossSection: { defaultAxis: 'z', recommendedPlanes: [ { id: 'gear-cavity', label: 'Gear cavity', axis: 'z', offset: 0, description: 'Cuts through both gears and displacement pockets.', }, { id: 'relief-path', label: 'Relief valve path', axis: 'y', offset: -0.45, description: 'Shows spring-loaded bypass between outlet and inlet side.', }, ], }, thumbnail: makeThumbnailStrategy( ['gear-pump-housing', 'drive-gear', 'idler-gear'], ['fluid-pockets', 'relief-valve'], 'Render top cutaway with blue pocket markers around both gears and an orange relief valve.', ), assetReplacement: { proceduralBlueprintId: 'gear-pump', preferredGlbPath: 'src/assets/machines/gear-pump/gear-pump.glb', rootNodeName: 'GearPump', requiredNamedNodes: ['DriveGear', 'IdlerGear', 'GearPumpHousing', 'GearPumpInlet', 'GearPumpOutlet', 'FluidPockets'], optionalNamedNodes: ['MeshingSealLine', 'ReliefValve', 'InputShaft', 'BearingBushings', 'PressureGauge'], materialSlots: ['machined-steel', 'housing-dark', 'flow-blue', 'pressure-amber', 'relief-orange', 'seal-line-emissive'], coordinateSystem: 'Y up, gear axes along Z, inlet on negative X and outlet on positive X in front view.', replacementInstructions: 'Drive and idler gears must have separate pivots with equal center distance. Keep fluid pockets as independent animated effects so they can be hidden in solid display mode.', }, relatedMachines: ['centrifugal-pump', 'piston-pump', 'hydraulic-cylinder'], }, { machineId: 'piston-pump', slugAliases: ['reciprocating-piston-pump', 'plunger-pump', 'single-cylinder-piston-pump'], title: 'Piston Pump', category: 'Pumps & Fluid Systems', difficulty: 'Intermediate', complexityScore: 5, registryKeywords: ['piston pump', 'reciprocating pump', 'check valves', 'crank', 'plunger', 'positive displacement'], oneParagraphDescription: 'A piston pump uses a reciprocating piston or plunger and one-way check valves to draw fluid into a chamber and then force it out under pressure. The procedural assembly shows the crank-slider drive, changing chamber volume, inlet and outlet valve motion, and pulsating pressure flow.', learningObjectives: [ 'Identify piston/plunger, cylinder, crank, connecting rod, inlet valve, outlet valve, and manifolds.', 'Explain suction and discharge strokes.', 'Understand how check valves enforce one-way flow.', 'Relate stroke length and bore to displacement per cycle.', ], facts: [ { label: 'Pump type', value: 'Positive displacement reciprocating', details: 'Flow volume is set by bore area, stroke length, and cycle rate.', }, { label: 'Valve type', value: 'Check valves', details: 'Pressure difference opens the inlet or outlet valve at the correct part of the stroke.', }, { label: 'Pressure capability', value: 'High', details: 'Plunger pumps can produce high pressures because displacement chambers are small and sealed.', }, { label: 'Flow character', value: 'Pulsating', details: 'Single-cylinder pumps produce flow pulses unless damped by accumulators or multiple cylinders.', }, { label: 'Applications', value: 'Pressure washers, dosing pumps, hydraulic systems', details: 'Used when accurate displacement or high pressure is needed.', }, ], componentTree: [ { id: 'piston-pump-drive', name: 'Crank drive', kind: 'assembly', description: 'Crank, rod, flywheel, and guide convert rotary input into piston reciprocation.', engineeringRole: 'Sets stroke length and cycle timing for the displacement chamber.', materialHint: 'polished steel crank with dark flywheel', labelAnchor: [-0.55, 0, 0], explodedOffset: [-0.25, 0, 0], replacementNode: 'PistonPumpDrive', animationChannels: ['pump-crank-rotation', 'pump-rod-swing', 'piston-reciprocation'], children: [ { id: 'pump-crank', name: 'Crank and flywheel', kind: 'part', description: 'Rotating crank throw driven by motor or handwheel.', engineeringRole: 'Converts rotary motion into reciprocating piston stroke.', materialHint: 'dark flywheel with polished crank pin', labelAnchor: [-0.92, 0.05, 0], explodedOffset: [-0.55, 0.08, 0], replacementNode: 'PumpCrank', animationChannels: ['pump-crank-rotation'], }, { id: 'pump-connecting-rod', name: 'Connecting rod', kind: 'part', description: 'Link from crank pin to piston or crosshead.', engineeringRole: 'Transmits alternating loads and creates the sinusoidal stroke.', materialHint: 'polished steel rod', labelAnchor: [-0.45, 0.05, 0], explodedOffset: [-0.28, 0.08, 0], replacementNode: 'PumpConnectingRod', animationChannels: ['pump-rod-swing'], }, { id: 'piston-pump-piston', name: 'Piston / plunger', kind: 'part', description: 'Sliding displacement member inside the pump cylinder.', engineeringRole: 'Changes chamber volume to create suction and discharge pressure.', materialHint: 'bright stainless plunger with dark seal rings', labelAnchor: [0.05, 0.05, 0], explodedOffset: [0.08, 0.08, 0], replacementNode: 'PistonPumpPiston', animationChannels: ['piston-reciprocation'], }, ], }, { id: 'piston-pump-fluid-end', name: 'Fluid end and check valves', kind: 'assembly', description: 'Cylinder, inlet valve, outlet valve, and manifolds route flow by pressure difference.', engineeringRole: 'Turns changing chamber volume into one-way pumped flow.', materialHint: 'cutaway stainless body, blue inlet and amber outlet flow', labelAnchor: [0.45, 0.12, 0], explodedOffset: [0.26, 0, 0], replacementNode: 'PistonPumpFluidEnd', animationChannels: ['chamber-volume', 'inlet-valve-motion', 'outlet-valve-motion', 'pulsating-flow'], children: [ { id: 'pump-cylinder', name: 'Pump cylinder', kind: 'part', description: 'Pressure chamber around the reciprocating piston.', engineeringRole: 'Contains fluid pressure and defines displacement with piston area.', materialHint: 'cutaway stainless cylinder', labelAnchor: [0.35, 0.12, 0], explodedOffset: [0.25, 0.06, 0], replacementNode: 'PumpCylinder', animationChannels: ['chamber-volume'], }, { id: 'inlet-check-valve', name: 'Inlet check valve', kind: 'part', description: 'One-way valve opening when chamber pressure falls below inlet pressure.', engineeringRole: 'Allows fluid into the cylinder during suction stroke and blocks reverse flow.', materialHint: 'blue poppet and spring', labelAnchor: [0.48, -0.35, 0], explodedOffset: [0.36, -0.28, 0], replacementNode: 'InletCheckValve', animationChannels: ['inlet-valve-motion'], }, { id: 'outlet-check-valve', name: 'Outlet check valve', kind: 'part', description: 'One-way valve opening when chamber pressure exceeds outlet pressure.', engineeringRole: 'Discharges fluid during compression stroke and prevents backflow.', materialHint: 'amber poppet and spring', labelAnchor: [0.78, 0.35, 0], explodedOffset: [0.52, 0.28, 0], replacementNode: 'OutletCheckValve', animationChannels: ['outlet-valve-motion'], }, { id: 'inlet-manifold-piston-pump', name: 'Inlet manifold', kind: 'part', description: 'Low-pressure passage feeding the inlet check valve.', engineeringRole: 'Supplies fluid during suction with minimal restriction.', materialHint: 'transparent blue passage', labelAnchor: [0.2, -0.62, 0], explodedOffset: [0.15, -0.46, 0], replacementNode: 'PistonPumpInletManifold', animationChannels: ['pulsating-flow'], }, { id: 'outlet-manifold-piston-pump', name: 'Outlet manifold', kind: 'part', description: 'High-pressure passage receiving discharge pulses.', engineeringRole: 'Carries pressurized fluid to the load or accumulator.', materialHint: 'transparent amber-blue passage', labelAnchor: [0.95, 0.62, 0], explodedOffset: [0.68, 0.45, 0], replacementNode: 'PistonPumpOutletManifold', animationChannels: ['pulsating-flow'], }, { id: 'pressure-pulse-overlay', name: 'Pressure pulse overlay', kind: 'sensor', description: 'Animated gauge trace showing pulsating discharge pressure.', engineeringRole: 'Connects reciprocating displacement to pressure ripple.', materialHint: 'emissive graph line with tabular values', labelAnchor: [0.95, -0.45, 0], explodedOffset: [0.7, -0.34, 0], replacementNode: 'PressurePulseOverlay', animationChannels: ['pressure-pulse-overlay'], }, ], }, ], labels: [ { partId: 'piston-pump-piston', text: 'Piston changes chamber volume', position: [0.08, 0.2, 0.28], priority: 'primary' }, { partId: 'inlet-check-valve', text: 'Inlet opens on suction stroke', position: [0.52, -0.5, 0.25], priority: 'primary' }, { partId: 'outlet-check-valve', text: 'Outlet opens on discharge stroke', position: [0.88, 0.48, 0.25], priority: 'primary' }, { partId: 'pressure-pulse-overlay', text: 'Single-cylinder flow is pulsating', position: [1.08, -0.55, 0.22], priority: 'secondary' }, ], cameraPresets: makeCameraPresets(4.6, [0.15, 0, 0], { id: 'check-valves', label: 'Check Valves', position: [1.35, 1.1, 2.2], target: [0.58, 0.05, 0], description: 'Close-up of inlet and outlet valve timing against piston stroke.', }), guidedTour: [ { id: 'stroke-drive', title: 'Crank creates stroke', body: 'The crank and rod convert rotation into a reciprocating piston motion.', cameraPresetId: 'front', highlightedPartIds: ['pump-crank', 'pump-connecting-rod', 'piston-pump-piston'], durationSeconds: 7, animationTimeScale: 0.4, setExplode: 0.08, }, { id: 'suction-stroke', title: 'Suction stroke', body: 'As chamber volume increases, pressure drops and the inlet check valve opens.', cameraPresetId: 'check-valves', highlightedPartIds: ['piston-pump-piston', 'inlet-check-valve', 'inlet-manifold-piston-pump'], durationSeconds: 6, animationTimeScale: 0.28, setExplode: 0.14, crossSection: { axis: 'z', offset: 0 }, }, { id: 'discharge-stroke', title: 'Discharge stroke', body: 'As the piston advances, the inlet closes, outlet opens, and fluid exits under pressure.', cameraPresetId: 'check-valves', highlightedPartIds: ['outlet-check-valve', 'outlet-manifold-piston-pump', 'pressure-pulse-overlay'], durationSeconds: 6, animationTimeScale: 0.28, setExplode: 0.14, }, { id: 'displacement', title: 'Displacement per cycle', body: 'Bore area and stroke length set how much fluid is moved each cycle before leakage and compressibility effects.', cameraPresetId: 'isometric', highlightedPartIds: ['pump-cylinder', 'piston-pump-piston', 'pressure-pulse-overlay'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.18, }, ], animationModel: { nominalRpm: 180, cycleSecondsAtNominal: 0.333, loopMode: 'reciprocating', stepCount: 4, primaryDriver: 'crank-angle', engineeringNotes: 'One crank revolution gives one suction and one discharge stroke for this single-acting teaching pump. Valve motion is pressure-derived and should lag piston velocity slightly for believable behavior.', channels: [ { id: 'pump-crank-rotation', label: 'Crank rotation', targetPartIds: ['pump-crank'], transform: 'rotation', driver: 'crank angle θ', expression: 'rotate crank and flywheel continuously about input axis', phaseDeg: 0, notes: 'Master channel for piston displacement.', }, { id: 'pump-rod-swing', label: 'Connecting rod swing', targetPartIds: ['pump-connecting-rod'], transform: 'oscillation', driver: 'crank pin to piston pin constraint', expression: 'orient rod between rotating crank pin and translating piston pin', phaseDeg: 0, notes: 'Preserve rod length across the cycle.', }, { id: 'piston-reciprocation', label: 'Piston reciprocation', targetPartIds: ['piston-pump-piston'], transform: 'translation', driver: 'crank-slider relation', expression: 'horizontal displacement between suction and discharge stroke endpoints', phaseDeg: 0, notes: 'Increasing chamber volume corresponds to suction stroke.', }, { id: 'chamber-volume', label: 'Chamber volume shading', targetPartIds: ['pump-cylinder'], transform: 'material', driver: 'piston position', expression: 'blue chamber volume expands on suction and compresses on discharge', phaseDeg: 0, notes: 'Transparency helps show the active fluid volume.', }, { id: 'inlet-valve-motion', label: 'Inlet check valve', targetPartIds: ['inlet-check-valve'], transform: 'translation', driver: 'chamber pressure less than inlet pressure', expression: 'poppet lifts during suction stroke and closes near bottom dead centre', phaseDeg: 180, notes: 'Open only when piston retracts and pressure is low.', }, { id: 'outlet-valve-motion', label: 'Outlet check valve', targetPartIds: ['outlet-check-valve'], transform: 'translation', driver: 'chamber pressure greater than outlet pressure', expression: 'poppet lifts during discharge stroke and closes near top dead centre', phaseDeg: 0, notes: 'Open only when piston advances.', }, { id: 'pulsating-flow', label: 'Pulsating flow', targetPartIds: ['inlet-manifold-piston-pump', 'outlet-manifold-piston-pump'], transform: 'flow', driver: 'valve state', expression: 'blue inlet flow during suction; amber outlet flow during discharge', phaseDeg: 0, notes: 'Outlet pulses should be visibly intermittent.', }, { id: 'pressure-pulse-overlay', label: 'Pressure pulse overlay', targetPartIds: ['pressure-pulse-overlay'], transform: 'material', driver: 'discharge stroke and outlet restriction', expression: 'graph line rises during discharge and decays between pulses', phaseDeg: 0, notes: 'Useful for explaining accumulators in future expansion.', }, ], }, explodedView: { defaultDistance: 0.32, maxDistance: 1.1, groups: [ { id: 'drive-left', label: 'Crank drive', partIds: ['pump-crank', 'pump-connecting-rod', 'piston-pump-piston'], axis: 'x', direction: -1, order: 1, reason: 'Separates motion conversion from the fluid end.', }, { id: 'valves-right', label: 'Check valves', partIds: ['inlet-check-valve', 'outlet-check-valve', 'inlet-manifold-piston-pump', 'outlet-manifold-piston-pump'], axis: 'x', direction: 1, order: 2, reason: 'Opens one-way flow components for suction/discharge explanation.', }, { id: 'overlays-up', label: 'Pressure overlays', partIds: ['pressure-pulse-overlay', 'pump-cylinder'], axis: 'y', direction: 1, order: 3, reason: 'Lifts pressure and volume teaching elements into view.', }, ], }, crossSection: { defaultAxis: 'z', recommendedPlanes: [ { id: 'cylinder-centreline', label: 'Cylinder centreline', axis: 'z', offset: 0, description: 'Cuts through piston, chamber, and check valve seats.', }, { id: 'valve-manifold', label: 'Valve manifold', axis: 'x', offset: 0.62, description: 'Shows inlet and outlet valve passages.', }, ], }, thumbnail: makeThumbnailStrategy( ['pump-crank', 'piston-pump-piston', 'pump-cylinder'], ['inlet-check-valve', 'outlet-check-valve', 'pressure-pulse-overlay'], 'Render the crank-slider on the left and highlighted check valves on the right.', ), assetReplacement: { proceduralBlueprintId: 'piston-pump', preferredGlbPath: 'src/assets/machines/piston-pump/piston-pump.glb', rootNodeName: 'PistonPump', requiredNamedNodes: [ 'PumpCrank', 'PumpConnectingRod', 'PistonPumpPiston', 'PumpCylinder', 'InletCheckValve', 'OutletCheckValve', 'PistonPumpInletManifold', 'PistonPumpOutletManifold', ], optionalNamedNodes: ['PressurePulseOverlay', 'CrossheadGuide', 'AccumulatorStub', 'Baseplate', 'ValveSprings'], materialSlots: ['machined-steel', 'housing-stainless', 'flow-blue', 'pressure-amber', 'seal-dark', 'overlay-emissive'], coordinateSystem: 'Y up, piston stroke along X, crank axis along Z, fluid outlet upward in positive Y.', replacementInstructions: 'Piston must translate along cylinder axis; check-valve poppets should be separate short-stroke nodes. Keep inlet and outlet flow effects independent from solid manifolds.', }, relatedMachines: ['gear-pump', 'centrifugal-pump', 'hydraulic-cylinder'], }, { machineId: 'hydraulic-cylinder', slugAliases: ['double-acting-hydraulic-cylinder', 'linear-actuator-hydraulic-cylinder'], title: 'Hydraulic Cylinder', category: 'Pumps & Fluid Systems', difficulty: 'Beginner', complexityScore: 3, registryKeywords: ['hydraulic cylinder', 'linear actuator', 'piston rod', 'seals', 'pressure', 'extend retract'], oneParagraphDescription: 'A hydraulic cylinder converts pressurized fluid into controlled linear force through a piston sealed inside a barrel. The procedural cutaway shows extend and retract ports, piston area difference, rod seals, pressure indicators, and clevis mounts so users can understand force generation and leakage control.', learningObjectives: [ 'Identify barrel, piston, rod, seals, end caps, ports, and mounts.', 'Explain extension and retraction by pressurizing opposite chambers.', 'Relate pressure and piston area to output force.', 'Understand why retract force is lower when rod area reduces effective area.', ], facts: [ { label: 'Actuator type', value: 'Linear fluid-power actuator', details: 'Hydraulic pressure acts on piston area to create linear force.', }, { label: 'Force equation', value: 'F = P × A', details: 'Available force equals pressure multiplied by effective piston area.', }, { label: 'Double acting', value: 'Two pressure ports', details: 'Fluid can extend or retract the rod by pressurizing either side.', }, { label: 'Typical pressure', value: '70–350 bar', details: 'Mobile and industrial systems commonly operate in this range.', }, { label: 'Applications', value: 'Excavators, presses, steering, lifts', details: 'Used where high linear force and controllability are required.', }, ], componentTree: [ { id: 'cylinder-pressure-vessel', name: 'Pressure vessel assembly', kind: 'assembly', description: 'Barrel, end caps, ports, and cutaway chambers contain hydraulic pressure.', engineeringRole: 'Provides sealed volumes where pressure can act on the piston.', materialHint: 'dark honed barrel with transparent blue oil chambers', labelAnchor: [0, 0.08, 0], explodedOffset: [0, 0, 0.15], replacementNode: 'CylinderPressureVessel', animationChannels: ['pressure-chamber-fill'], children: [ { id: 'hydraulic-barrel', name: 'Cylinder barrel', kind: 'part', description: 'Honed tube that guides the piston and contains pressure.', engineeringRole: 'Maintains roundness and surface finish for sealing and low friction.', materialHint: 'dark steel tube with cutaway window', labelAnchor: [0, 0.22, 0], explodedOffset: [0, 0.18, 0], replacementNode: 'HydraulicBarrel', animationChannels: [], }, { id: 'cap-end-port', name: 'Cap-end port', kind: 'part', description: 'Hydraulic connection feeding the full-area side of the piston.', engineeringRole: 'Pressurizes the cap chamber to extend the rod.', materialHint: 'blue port boss', labelAnchor: [-0.8, 0.34, 0], explodedOffset: [-0.45, 0.22, 0], replacementNode: 'CapEndPort', animationChannels: ['pressure-chamber-fill'], }, { id: 'rod-end-port', name: 'Rod-end port', kind: 'part', description: 'Hydraulic connection feeding the annular rod-side chamber.', engineeringRole: 'Pressurizes the rod side to retract the cylinder.', materialHint: 'amber-blue port boss', labelAnchor: [0.7, 0.34, 0], explodedOffset: [0.38, 0.22, 0], replacementNode: 'RodEndPort', animationChannels: ['pressure-chamber-fill'], }, { id: 'end-caps', name: 'End caps and gland', kind: 'assembly', description: 'Closures at both ends including the rod gland and cap end.', engineeringRole: 'Seal pressure and support rod exit hardware.', materialHint: 'machined steel caps', labelAnchor: [0, -0.28, 0], explodedOffset: [0, -0.28, 0], replacementNode: 'EndCaps', animationChannels: [], }, ], }, { id: 'cylinder-moving-seal-group', name: 'Piston, rod, and seals', kind: 'assembly', description: 'Moving piston and rod slide inside the barrel while seals separate pressure chambers.', engineeringRole: 'Converts pressure force into external linear motion and prevents leakage.', materialHint: 'polished chrome rod, dark seals, aluminium piston', labelAnchor: [0.25, 0, 0.12], explodedOffset: [0, 0, 0.42], replacementNode: 'CylinderMovingSealGroup', animationChannels: ['rod-extension', 'seal-highlight'], children: [ { id: 'hydraulic-piston', name: 'Piston', kind: 'part', description: 'Disc attached to the rod and sealed against the barrel bore.', engineeringRole: 'Separates cap and rod chambers and receives pressure force.', materialHint: 'machined aluminium piston with dark seal bands', labelAnchor: [0.18, 0.05, 0.22], explodedOffset: [0.05, 0.08, 0.55], replacementNode: 'HydraulicPiston', animationChannels: ['rod-extension'], }, { id: 'piston-rod', name: 'Piston rod', kind: 'part', description: 'Chrome-plated rod delivering linear force outside the cylinder.', engineeringRole: 'Transmits piston force to the load while resisting buckling and corrosion.', materialHint: 'polished chrome', labelAnchor: [0.95, 0.05, 0], explodedOffset: [0.45, 0.05, 0.35], replacementNode: 'PistonRod', animationChannels: ['rod-extension'], }, { id: 'piston-seals', name: 'Piston seals', kind: 'part', description: 'Sealing rings preventing bypass leakage between chambers.', engineeringRole: 'Maintains pressure differential across the piston.', materialHint: 'dark elastomer bands', labelAnchor: [0.1, 0.22, 0.28], explodedOffset: [0.08, 0.2, 0.62], replacementNode: 'PistonSeals', animationChannels: ['rod-extension', 'seal-highlight'], }, { id: 'rod-seal-wiper', name: 'Rod seal and wiper', kind: 'part', description: 'Gland seals and wiper around the rod exit.', engineeringRole: 'Retains oil, excludes dirt, and supports long seal life.', materialHint: 'dark elastomer rings in gland', labelAnchor: [0.62, -0.16, 0.18], explodedOffset: [0.28, -0.14, 0.45], replacementNode: 'RodSealWiper', animationChannels: ['seal-highlight'], }, ], }, { id: 'cylinder-mounts-indicators', name: 'Mounts and indicators', kind: 'assembly', description: 'Clevis mounts, pressure gauges, and force arrows contextualize the actuator in a mechanism.', engineeringRole: 'Shows how hydraulic pressure becomes useful external load force.', materialHint: 'dark clevis forks, emissive pressure gauges', labelAnchor: [0, -0.62, 0], explodedOffset: [0, -0.32, 0], replacementNode: 'CylinderMountsIndicators', animationChannels: ['force-arrow', 'pressure-chamber-fill'], children: [ { id: 'cap-clevis', name: 'Cap-end clevis', kind: 'part', description: 'Rear mounting fork attached to the cylinder body.', engineeringRole: 'Anchors reaction load to a machine frame.', materialHint: 'dark forged steel fork', labelAnchor: [-1.18, -0.08, 0], explodedOffset: [-0.72, -0.08, 0], replacementNode: 'CapClevis', animationChannels: [], }, { id: 'rod-clevis', name: 'Rod-end clevis', kind: 'part', description: 'Front mounting fork attached to the rod end.', engineeringRole: 'Applies actuator force to the moving linkage.', materialHint: 'dark forged steel fork with amber force arrow', labelAnchor: [1.55, -0.08, 0], explodedOffset: [0.82, -0.08, 0], replacementNode: 'RodClevis', animationChannels: ['rod-extension', 'force-arrow'], }, { id: 'pressure-indicators', name: 'Pressure indicators', kind: 'sensor', description: 'Twin gauges and chamber color overlays for extend and retract pressure.', engineeringRole: 'Connects pressure routing to rod motion and output force.', materialHint: 'glass gauges with tabular numerals', labelAnchor: [0, -0.86, 0], explodedOffset: [0, -0.55, 0], replacementNode: 'PressureIndicators', animationChannels: ['pressure-chamber-fill'], }, { id: 'force-arrow', name: 'Output force arrow', kind: 'sensor', description: 'Arrow showing direction and magnitude of linear force at the rod clevis.', engineeringRole: 'Visualizes F = P × A for the active chamber.', materialHint: 'amber emissive arrow', labelAnchor: [1.28, 0.18, 0], explodedOffset: [0.72, 0.18, 0], replacementNode: 'ForceArrow', animationChannels: ['force-arrow'], }, ], }, ], labels: [ { partId: 'hydraulic-piston', text: 'Pressure acts on piston area', position: [0.2, 0.18, 0.44], priority: 'primary' }, { partId: 'piston-rod', text: 'Rod delivers linear force', position: [1.05, 0.2, 0.28], priority: 'primary' }, { partId: 'rod-end-port', text: 'Rod-side pressure retracts the cylinder', position: [0.82, 0.48, 0.22], priority: 'secondary' }, { partId: 'rod-seal-wiper', text: 'Rod seal keeps oil in and dirt out', position: [0.72, -0.28, 0.3], priority: 'detail' }, ], cameraPresets: makeCameraPresets(4.8, [0.2, 0, 0], { id: 'seal-cutaway', label: 'Seal Cutaway', position: [1.35, 1.0, 2.35], target: [0.35, 0.02, 0], description: 'Close-up on piston seals, rod gland, and pressure chambers.', }), guidedTour: [ { id: 'pressure-to-force', title: 'Pressure becomes force', body: 'Hydraulic pressure acts on piston area, producing a large linear force at the rod.', cameraPresetId: 'isometric', highlightedPartIds: ['hydraulic-piston', 'piston-rod', 'force-arrow'], durationSeconds: 7, animationTimeScale: 0.45, setExplode: 0.06, }, { id: 'extend', title: 'Extension stroke', body: 'Pressurizing the cap-end chamber pushes the piston and rod outward.', cameraPresetId: 'front', highlightedPartIds: ['cap-end-port', 'hydraulic-piston', 'piston-rod', 'pressure-indicators'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.1, crossSection: { axis: 'z', offset: 0 }, }, { id: 'retract', title: 'Retraction stroke', body: 'Pressurizing the rod-end chamber retracts the rod, but effective area is smaller because the rod occupies space.', cameraPresetId: 'seal-cutaway', highlightedPartIds: ['rod-end-port', 'piston-rod', 'hydraulic-piston'], durationSeconds: 6, animationTimeScale: 0.35, setExplode: 0.14, }, { id: 'sealing', title: 'Seals control leakage', body: 'Piston seals separate the two chambers while rod seals and wipers protect the external rod interface.', cameraPresetId: 'right', highlightedPartIds: ['piston-seals', 'rod-seal-wiper'], durationSeconds: 6, animationTimeScale: 0.45, setExplode: 0.2, }, ], animationModel: { nominalRpm: 30, cycleSecondsAtNominal: 2, loopMode: 'reciprocating', stepCount: 4, primaryDriver: 'extension-parameter-0-to-1', engineeringNotes: 'Hydraulic-cylinder animation is an extend/retract sweep rather than rotary RPM. The RPM slider can map to cycles per minute for consistency with the shared player.', channels: [ { id: 'rod-extension', label: 'Rod extension', targetPartIds: ['hydraulic-piston', 'piston-rod', 'rod-clevis', 'piston-seals'], transform: 'translation', driver: 'extension parameter e', expression: 'translate piston/rod from fully retracted to fully extended along cylinder axis', phaseDeg: 0, notes: 'Use eased direction changes to avoid visual snapping at stroke ends.', }, { id: 'pressure-chamber-fill', label: 'Pressure chamber fill', targetPartIds: ['cap-end-port', 'rod-end-port', 'pressure-indicators'], transform: 'material', driver: 'active direction', expression: 'cap chamber glows blue during extension; rod chamber glows amber during retraction', phaseDeg: 0, notes: 'Indicators show different effective areas for extend vs retract.', }, { id: 'seal-highlight', label: 'Seal highlight', targetPartIds: ['piston-seals', 'rod-seal-wiper'], transform: 'material', driver: 'tour step or leakage demo', expression: 'dark seals receive thin blue edge highlight when selected or during sealing tour', phaseDeg: 0, notes: 'Highlight remains subtle in normal play mode.', }, { id: 'force-arrow', label: 'Output force arrow', targetPartIds: ['force-arrow', 'rod-clevis'], transform: 'translation', driver: 'pressure times effective area', expression: 'arrow points along rod direction and scales with selected chamber pressure and area', phaseDeg: 0, notes: 'Retract arrow should be shorter at equal pressure due to rod area subtraction.', }, ], }, explodedView: { defaultDistance: 0.28, maxDistance: 1, groups: [ { id: 'barrel-up', label: 'Barrel and ports', partIds: ['hydraulic-barrel', 'cap-end-port', 'rod-end-port', 'end-caps'], axis: 'y', direction: 1, order: 1, reason: 'Opens the pressure vessel around the moving piston.', }, { id: 'moving-group-forward', label: 'Moving rod group', partIds: ['hydraulic-piston', 'piston-rod', 'piston-seals', 'rod-seal-wiper'], axis: 'z', direction: 1, order: 2, reason: 'Separates moving and sealing components from the barrel.', }, { id: 'mounts-out', label: 'Mounts and indicators', partIds: ['cap-clevis', 'rod-clevis', 'pressure-indicators', 'force-arrow'], axis: 'x', direction: 1, order: 3, reason: 'Shows reaction and output load paths.', }, ], }, crossSection: { defaultAxis: 'z', recommendedPlanes: [ { id: 'longitudinal-cylinder', label: 'Longitudinal cylinder cut', axis: 'z', offset: 0, description: 'Cuts through barrel, piston, rod, and both chambers.', }, { id: 'rod-gland', label: 'Rod gland', axis: 'x', offset: 0.65, description: 'Shows rod seal and wiper stack at the gland.', }, ], }, thumbnail: makeThumbnailStrategy( ['hydraulic-barrel', 'piston-rod', 'cap-clevis', 'rod-clevis'], ['pressure-indicators', 'force-arrow'], 'Render an extended cutaway cylinder with blue pressure chamber and amber force arrow.', ), assetReplacement: { proceduralBlueprintId: 'hydraulic-cylinder', preferredGlbPath: 'src/assets/machines/hydraulic-cylinder/hydraulic-cylinder.glb', rootNodeName: 'HydraulicCylinder', requiredNamedNodes: ['HydraulicBarrel', 'HydraulicPiston', 'PistonRod', 'CapEndPort', 'RodEndPort', 'PistonSeals', 'RodSealWiper'], optionalNamedNodes: ['EndCaps', 'CapClevis', 'RodClevis', 'PressureIndicators', 'ForceArrow', 'OilChamberMeshes'], materialSlots: ['dark-steel', 'chrome', 'seal-rubber', 'oil-blue', 'pressure-amber', 'overlay-emissive'], coordinateSystem: 'Y up, cylinder stroke axis along X, cap end at negative X and rod end at positive X.', replacementInstructions: 'Parent piston, rod, rod clevis, and piston seals under a translating rod group. Keep pressure chamber meshes separate so extend/retract fill colors can be animated.', }, relatedMachines: ['piston-pump', 'gear-pump', 'toggle-clamp'], }, ] as const satisfies readonly MachineDossier[];