UNPKG

@wandelbots/wandelbots-js-react-components

Version:

React UI toolkit for building applications on top of the Wandelbots platform

1 lines 628 kB
{"version":3,"file":"index-CqMZL0FV.cjs","sources":["../src/components/ProgramControl.tsx","../src/components/ProgramStateIndicator.tsx","../src/components/utils/hooks.tsx","../src/components/utils/interpolation.ts","../node_modules/@wandelbots/nova-api/dist/defineProperty-CQ_RnIQg.js","../node_modules/@wandelbots/nova-api/dist/v2/index.js"],"sourcesContent":["import { Pause, PlayArrow, Stop } from \"@mui/icons-material\"\nimport { Box, Button, Typography, useTheme } from \"@mui/material\"\nimport { observer } from \"mobx-react-lite\"\nimport { useTranslation } from \"react-i18next\"\nimport { externalizeComponent } from \"../externalizeComponent\"\n\nexport enum ProgramState {\n IDLE = \"idle\",\n PREPARING = \"preparing\",\n STARTING = \"starting\",\n RUNNING = \"running\",\n PAUSING = \"pausing\",\n PAUSED = \"paused\",\n STOPPING = \"stopping\",\n COMPLETED = \"completed\",\n FAILED = \"failed\",\n STOPPED = \"stopped\",\n ERROR = \"error\",\n}\n\nexport interface ProgramControlProps {\n /** The current state of the program control */\n state: ProgramState\n /** Callback fired when the run/resume button is clicked */\n onRun: () => void\n /** Callback fired when the pause button is clicked (only available in 'with_pause' variant) */\n onPause?: () => void\n /** Callback fired when the stop button is clicked */\n onStop: () => void\n /**\n * Function to reset the component from 'stopping' state back to 'idle'.\n * This must be called manually by the user when requiresManualReset is true.\n */\n onReset?: () => void\n /**\n * When true, the component will stay in 'stopping' state until onReset is called manually.\n * When false (default), auto-resets to 'idle' after 2 seconds.\n */\n requiresManualReset?: boolean\n /**\n * Variant of the component:\n * - 'with_pause': Shows run/pause/stop buttons (default)\n * - 'without_pause': Shows only run/stop buttons\n */\n variant?: \"with_pause\" | \"without_pause\"\n /** Additional CSS class name */\n className?: string\n}\n\ninterface ButtonConfig {\n enabled: boolean\n label: string\n color: string\n onClick: () => void\n}\n\n/**\n * A control component for program execution with run, pause, and stop functionality.\n *\n * Features:\n * - State machine with idle, preparing, starting, running, pausing, paused, stopping, completed, failed, stopped, and error states\n * - Two variants: with_pause (3 buttons) and without_pause (2 buttons)\n * - Optional manual reset functionality\n * - Responsive design with 110px circular buttons\n * - Material-UI theming integration\n */\nexport const ProgramControl = externalizeComponent(\n observer(\n ({\n state,\n onRun,\n onPause,\n onStop,\n onReset,\n requiresManualReset = false,\n variant = \"with_pause\",\n className,\n }: ProgramControlProps) => {\n const theme = useTheme()\n const { t } = useTranslation()\n\n const getButtonConfigs = (): ButtonConfig[] => {\n const baseConfigs: Record<string, ButtonConfig> = {\n run: {\n enabled:\n state === ProgramState.IDLE ||\n state === ProgramState.STOPPED ||\n state === ProgramState.PAUSED ||\n state === ProgramState.COMPLETED ||\n state === ProgramState.FAILED ||\n state === ProgramState.ERROR,\n label:\n state === ProgramState.PAUSED\n ? t(\"ProgramControl.Resume.bt\")\n : state === ProgramState.ERROR || state === ProgramState.FAILED\n ? t(\"ProgramControl.Retry.bt\")\n : t(\"ProgramControl.Start.bt\"),\n color: theme.palette.success.main,\n onClick: onRun,\n },\n pause: {\n enabled: state === ProgramState.RUNNING,\n label: t(\"ProgramControl.Pause.bt\"),\n color: \"#FFFFFF33\",\n onClick: onPause || (() => {}),\n },\n stop: {\n enabled:\n state === ProgramState.PREPARING ||\n state === ProgramState.STARTING ||\n state === ProgramState.RUNNING ||\n state === ProgramState.PAUSING ||\n state === ProgramState.PAUSED,\n label: t(\"ProgramControl.Stop.bt\"),\n color: theme.palette.error.main,\n onClick: onStop,\n },\n }\n\n if (variant === \"without_pause\") {\n return [baseConfigs.run, baseConfigs.stop]\n }\n\n return [baseConfigs.run, baseConfigs.pause, baseConfigs.stop]\n }\n\n const getButtonIcon = (index: number) => {\n const iconProps = { sx: { fontSize: \"55px\" } }\n\n if (variant === \"without_pause\") {\n return index === 0 ? (\n <PlayArrow {...iconProps} />\n ) : (\n <Stop {...iconProps} />\n )\n }\n\n switch (index) {\n case 0:\n return <PlayArrow {...iconProps} />\n case 1:\n return <Pause {...iconProps} />\n case 2:\n return <Stop {...iconProps} />\n default:\n return null\n }\n }\n\n const buttonConfigs = getButtonConfigs()\n\n return (\n <Box\n className={className}\n sx={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 2,\n }}\n >\n <Box\n sx={{\n display: \"flex\",\n gap: \"40px\",\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n {buttonConfigs.map((config, index) => (\n <Box\n key={config.label}\n sx={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 1,\n }}\n >\n <Button\n variant=\"contained\"\n disabled={\n !config.enabled ||\n state === ProgramState.PREPARING ||\n state === ProgramState.STARTING ||\n state === ProgramState.PAUSING ||\n (state === ProgramState.STOPPING && !requiresManualReset)\n }\n onClick={config.onClick}\n sx={{\n width: \"88px\",\n height: \"88px\",\n borderRadius: \"88px\",\n backgroundColor: config.color,\n opacity:\n config.enabled &&\n state !== ProgramState.PREPARING &&\n state !== ProgramState.STARTING &&\n state !== ProgramState.PAUSING &&\n !(state === ProgramState.STOPPING && !requiresManualReset)\n ? 1\n : 0.3,\n \"&:hover\": {\n backgroundColor: config.color,\n opacity:\n config.enabled &&\n state !== ProgramState.PREPARING &&\n state !== ProgramState.STARTING &&\n state !== ProgramState.PAUSING &&\n !(\n state === ProgramState.STOPPING &&\n !requiresManualReset\n )\n ? 0.8\n : 0.3,\n },\n \"&:disabled\": {\n backgroundColor: config.color,\n opacity: 0.3,\n },\n minWidth: \"88px\",\n flexShrink: 0,\n }}\n >\n {getButtonIcon(index)}\n </Button>\n\n <Typography\n variant=\"body1\"\n sx={{\n color:\n config.enabled &&\n state !== ProgramState.PREPARING &&\n state !== ProgramState.STARTING &&\n state !== ProgramState.PAUSING &&\n !(state === ProgramState.STOPPING && !requiresManualReset)\n ? config.color\n : theme.palette.text.disabled,\n textAlign: \"center\",\n opacity:\n config.enabled &&\n state !== ProgramState.PREPARING &&\n state !== ProgramState.STARTING &&\n state !== ProgramState.PAUSING &&\n !(state === ProgramState.STOPPING && !requiresManualReset)\n ? 1\n : 0.3,\n }}\n >\n {config.label}\n </Typography>\n </Box>\n ))}\n </Box>\n </Box>\n )\n },\n ),\n)\n","import { Chip, Typography, useTheme } from \"@mui/material\"\nimport type { OperationMode, SafetyStateType } from \"@wandelbots/nova-js/v2\"\nimport { observer } from \"mobx-react-lite\"\nimport { useTranslation } from \"react-i18next\"\nimport { externalizeComponent } from \"../externalizeComponent\"\nimport { ProgramState } from \"./ProgramControl\"\n\nexport interface ProgramStateIndicatorProps {\n /** The current state of the program */\n programState: ProgramState\n /** The current safety state of the robot controller */\n safetyState: SafetyStateType\n /** The current operation mode of the robot controller */\n operationMode: OperationMode\n /** Additional CSS class name */\n className?: string\n}\n\n/**\n * A state indicator component that displays the current program execution state\n * combined with robot controller safety and operation mode states.\n *\n * Features:\n * - Combines program state with safety and operation mode states\n * - Color-coded based on state severity (success, warning, error)\n * - Rendered as Material-UI filled chip\n * - Localization support via react-i18next\n */\nexport const ProgramStateIndicator = externalizeComponent(\n observer(\n ({\n programState,\n safetyState,\n operationMode,\n className,\n }: ProgramStateIndicatorProps) => {\n const theme = useTheme()\n const { t } = useTranslation()\n\n const getStateInfo = () => {\n // First check for emergency stop or critical safety states\n if (\n safetyState === \"SAFETY_STATE_DEVICE_EMERGENCY_STOP\" ||\n safetyState === \"SAFETY_STATE_ROBOT_EMERGENCY_STOP\" ||\n safetyState === \"SAFETY_STATE_STOP_0\" ||\n safetyState === \"SAFETY_STATE_STOP_1\" ||\n safetyState === \"SAFETY_STATE_STOP_2\" ||\n safetyState === \"SAFETY_STATE_PROTECTIVE_STOP\" ||\n safetyState === \"SAFETY_STATE_STOP\" ||\n safetyState === \"SAFETY_STATE_REDUCED\" ||\n safetyState === \"SAFETY_STATE_MASTERING\" ||\n safetyState === \"SAFETY_STATE_CONFIRM_SAFETY\" ||\n safetyState === \"SAFETY_STATE_OPERATOR_SAFETY\" ||\n safetyState === \"SAFETY_STATE_RECOVERY\" ||\n safetyState === \"SAFETY_STATE_VIOLATION\"\n ) {\n return {\n label: t(\"ProgramStateIndicator.EStop.lb\"),\n color: theme.palette.error.main,\n }\n }\n\n // Check for error states\n if (\n safetyState === \"SAFETY_STATE_UNKNOWN\" ||\n safetyState === \"SAFETY_STATE_FAULT\"\n ) {\n return {\n label: t(\"ProgramStateIndicator.Error.lb\"),\n color: theme.palette.error.main,\n }\n }\n\n // For normal safety states, check program state\n if (safetyState === \"SAFETY_STATE_NORMAL\") {\n switch (programState) {\n case ProgramState.PREPARING:\n return {\n label: t(\"ProgramStateIndicator.Preparing.lb\"),\n color: theme.palette.warning.main,\n }\n case ProgramState.STARTING:\n return {\n label: t(\"ProgramStateIndicator.Starting.lb\"),\n color: theme.palette.warning.main,\n }\n case ProgramState.RUNNING:\n return {\n label: t(\"ProgramStateIndicator.Running.lb\"),\n color: theme.palette.success.main,\n }\n case ProgramState.PAUSING:\n return {\n label: t(\"ProgramStateIndicator.Pausing.lb\"),\n color: theme.palette.warning.main,\n }\n case ProgramState.PAUSED:\n return {\n label: t(\"ProgramStateIndicator.Paused.lb\"),\n color: theme.palette.grey[600],\n }\n case ProgramState.STOPPING:\n return {\n label: t(\"ProgramStateIndicator.Stopping.lb\"),\n color: theme.palette.warning.main,\n }\n case ProgramState.COMPLETED:\n return {\n label: t(\"ProgramStateIndicator.Completed.lb\"),\n color: theme.palette.success.main,\n }\n case ProgramState.FAILED:\n return {\n label: t(\"ProgramStateIndicator.Failed.lb\"),\n color: theme.palette.error.main,\n }\n case ProgramState.STOPPED:\n return {\n label: t(\"ProgramStateIndicator.Stopped.lb\"),\n color: theme.palette.warning.main,\n }\n case ProgramState.ERROR:\n return {\n label: t(\"ProgramStateIndicator.Error.lb\"),\n color: theme.palette.error.main,\n }\n case ProgramState.IDLE:\n default:\n return {\n label: t(\"ProgramStateIndicator.Ready.lb\"),\n color: theme.palette.success.main,\n }\n }\n }\n\n // Default fallback\n return {\n label: t(\"ProgramStateIndicator.Idle.lb\"),\n color: theme.palette.grey[600],\n }\n }\n\n const { label, color } = getStateInfo()\n\n // Add operation mode suffix if not automatic\n const getOperationModeText = () => {\n switch (operationMode) {\n case \"OPERATION_MODE_AUTO\":\n return t(\"ProgramStateIndicator.Auto.lb\")\n case \"OPERATION_MODE_MANUAL\":\n return t(\"ProgramStateIndicator.Manual.lb\")\n case \"OPERATION_MODE_MANUAL_T1\":\n return t(\"ProgramStateIndicator.ManualT1.lb\")\n case \"OPERATION_MODE_MANUAL_T2\":\n return t(\"ProgramStateIndicator.ManualT2.lb\")\n default:\n return t(\"ProgramStateIndicator.Auto.lb\") // Default to Auto for unknown modes\n }\n }\n\n const fullLabel = `${label} / ${getOperationModeText()}`\n\n return (\n <Chip\n className={className}\n label={\n <Typography\n variant=\"body2\"\n sx={{\n fontSize: \"0.75rem\", // Smaller than body2\n lineHeight: 1.2,\n }}\n >\n {fullLabel}\n </Typography>\n }\n variant=\"filled\"\n sx={{\n backgroundColor: color,\n color: theme.palette.getContrastText(color),\n fontWeight: 500,\n height: \"auto\",\n \"& .MuiChip-label\": {\n paddingX: 1.5,\n paddingY: 0.5,\n },\n }}\n />\n )\n },\n ),\n)\n","import { autorun, reaction } from \"mobx\"\nimport { useEffect, type EffectCallback } from \"react\"\n\n/**\n * Run code once on component mount. Shorthand for useEffect(effect, []).\n */\nexport function useMounted(effect: EffectCallback) {\n useEffect(effect, [])\n}\n\n/**\n * Initialize a mobx autorun watcher on component mount, and\n * clean it up when the component unmounts.\n */\nexport function useAutorun(view: Parameters<typeof autorun>[0]) {\n useMounted(() => {\n return autorun(view)\n })\n}\n\n/**\n * Initialize a mobx reaction watcher on component mount, and\n * clean it up when the component unmounts.\n */\nexport function useReaction<T>(\n expression: Parameters<typeof reaction<T>>[0],\n effect: Parameters<typeof reaction<T>>[1],\n opts?: Parameters<typeof reaction<T>>[2],\n) {\n useMounted(() => {\n return reaction(expression, effect, opts)\n })\n}\n\n/**\n * Run a callback on every animation frame. Cleans up\n * after component unmount.\n */\nexport function useAnimationFrame(callback: () => void) {\n return useMounted(() => {\n let frameId: number\n\n function frame() {\n callback()\n frameId = requestAnimationFrame(frame)\n }\n\n frameId = requestAnimationFrame(frame)\n\n return () => {\n cancelAnimationFrame(frameId)\n }\n })\n}\n","import React from \"react\"\n\n/**\n * Smooth value interpolation utility using spring physics with tension and friction.\n * Designed for React Three Fiber applications with smooth, natural animations.\n *\n * Features:\n * - Spring physics with configurable tension and friction\n * - Frame-rate independent using delta timing\n * - Handles irregular frame timing and rapid target updates\n * - Manual update() calls for useFrame integration (no automatic RAF loop)\n * - Direct mutation for performance\n *\n * @example\n * ```tsx\n * // Basic spring animation\n * const interpolator = new ValueInterpolator([0, 0, 0], {\n * tension: 120, // Higher = faster, stiffer spring (default: 120)\n * friction: 20, // Higher = more damping, less oscillation (default: 20)\n * onChange: (values) => {\n * robot.joints.forEach((joint, i) => {\n * joint.rotation.y = values[i]\n * })\n * }\n * })\n *\n * interpolator.setTarget([1.5, -0.8, 2.1])\n *\n * // React Three Fiber usage\n * function MyComponent() {\n * const [interpolator] = useInterpolation([0, 0, 0])\n *\n * useFrame((state, delta) => {\n * interpolator.update(delta)\n * })\n *\n * useEffect(() => {\n * interpolator.setTarget([1, 2, 3])\n * }, [])\n *\n * return <mesh position={interpolator.getCurrentValues()} />\n * }\n * ```\n */\n\nexport interface InterpolationOptions {\n /** Spring tension (higher = faster, stiffer spring) - default: 120 */\n tension?: number\n /** Spring friction (higher = more damping, less oscillation) - default: 20 */\n friction?: number\n /** Minimum threshold to consider interpolation complete - default: 0.001 */\n threshold?: number\n /** Callback when values change during interpolation */\n onChange?: (values: number[]) => void\n /** Callback when interpolation reaches target values */\n onComplete?: (values: number[]) => void\n}\n\nexport class ValueInterpolator {\n private currentValues: number[] = []\n private targetValues: number[] = []\n private previousTargetValues: number[] = []\n private targetUpdateTime: number = 0\n private animationId: number | null = null\n private options: Required<InterpolationOptions>\n private updateCount: number = 0 // Track how many updates have occurred\n\n // Spring physics state\n private velocities: number[] = []\n\n constructor(\n initialValues: number[] = [],\n options: InterpolationOptions = {},\n ) {\n this.options = {\n tension: 120,\n friction: 20,\n threshold: 0.001,\n onChange: () => {},\n onComplete: () => {},\n ...options,\n }\n\n this.currentValues = [...initialValues]\n this.targetValues = [...initialValues]\n this.previousTargetValues = [...initialValues]\n this.velocities = new Array(initialValues.length).fill(0)\n this.targetUpdateTime = performance.now()\n this.updateCount = 0\n }\n\n /**\n * Update interpolation using spring physics\n *\n * Call this method every frame for smooth animation. In React Three Fiber,\n * call from within useFrame callback with the provided delta time.\n *\n * @param delta - Time elapsed since last update in seconds (e.g., 1/60 ≈ 0.0167 for 60fps)\n * @returns true when interpolation is complete (all values reached their targets)\n */\n update(delta: number = 1 / 60): boolean {\n let hasChanges = false\n let isComplete = true\n\n // Increment update counter for initialization smoothing\n this.updateCount++\n\n // Limit delta to prevent physics instability during large frame drops\n const clampedDelta = Math.min(delta, 1 / 15) // Maximum 66ms frame time allowed\n\n // Apply gentle ramp-up for the first few frames to prevent initial jumpiness\n // Only apply reduced force for the very first frame to prevent jarring starts\n const initializationFactor =\n this.updateCount === 1\n ? 0.7 // Slightly reduced force only on the very first frame\n : 1\n\n for (let i = 0; i < this.currentValues.length; i++) {\n const current = this.currentValues[i]\n const target = this.targetValues[i]\n const velocity = this.velocities[i]\n\n // Calculate spring physics forces\n const displacement = target - current\n const springForce =\n displacement * this.options.tension * initializationFactor\n const dampingForce = velocity * this.options.friction\n\n // Calculate acceleration from net force (F = ma, assuming mass = 1)\n const acceleration = springForce - dampingForce\n\n // Integrate physics using Verlet method for numerical stability\n const newVelocity = velocity + acceleration * clampedDelta\n const newValue = current + newVelocity * clampedDelta\n\n // Determine if this value has settled (close to target with low velocity)\n const isValueComplete =\n Math.abs(displacement) < this.options.threshold &&\n Math.abs(newVelocity) < this.options.threshold * 10\n\n if (!isValueComplete) {\n isComplete = false\n // Continue spring animation\n this.currentValues[i] = newValue\n this.velocities[i] = newVelocity\n hasChanges = true\n } else {\n // Snap exactly to target when close enough (prevents endless micro-movements)\n if (this.currentValues[i] !== target) {\n this.currentValues[i] = target\n this.velocities[i] = 0\n hasChanges = true\n }\n }\n }\n\n if (hasChanges) {\n this.options.onChange(this.currentValues)\n }\n\n if (isComplete) {\n this.options.onComplete(this.currentValues)\n }\n\n return isComplete\n }\n\n /**\n * Set new target values for the interpolation to move towards\n *\n * Includes smart blending for very rapid target updates (faster than 120fps)\n * to prevent jarring movements when targets change frequently.\n */\n setTarget(newValues: number[]): void {\n const now = performance.now()\n const timeSinceLastUpdate = now - this.targetUpdateTime\n\n // Store previous target for smooth transitions\n this.previousTargetValues = [...this.targetValues]\n this.targetValues = [...newValues]\n this.targetUpdateTime = now\n\n // Reset update counter for smooth initialization when target changes\n this.updateCount = 0\n\n // Apply target blending for extremely rapid updates to prevent jarring jumps\n // Only activates when targets change faster than 120fps (< 8ms between updates)\n // AND this is not the first target being set (avoid blending initial target with initial values)\n const isInitialTargetSet = this.previousTargetValues.every(\n (val, i) => val === this.currentValues[i],\n )\n\n if (\n timeSinceLastUpdate < 8 &&\n timeSinceLastUpdate > 0 &&\n this.previousTargetValues.length > 0 &&\n !isInitialTargetSet // Don't blend if this is the first meaningful target change\n ) {\n // Blend between previous and new target based on time elapsed\n const blendFactor = Math.min(timeSinceLastUpdate / 8, 1) // 0 to 1 over 8ms\n\n for (let i = 0; i < this.targetValues.length; i++) {\n const prev = this.previousTargetValues[i] || 0\n const next = newValues[i] || 0\n\n // Only blend significant changes to avoid unnecessary smoothing\n const change = Math.abs(next - prev)\n if (change > 0.1) {\n this.targetValues[i] = prev + (next - prev) * blendFactor\n }\n }\n }\n\n // Ensure value and velocity arrays have matching lengths\n while (this.currentValues.length < newValues.length) {\n this.currentValues.push(newValues[this.currentValues.length])\n this.velocities.push(0) // New values start with zero velocity\n }\n if (this.currentValues.length > newValues.length) {\n this.currentValues = this.currentValues.slice(0, newValues.length)\n this.velocities = this.velocities.slice(0, newValues.length)\n }\n\n // Does not start automatic interpolation - requires manual update() calls\n // This design prevents conflicts when using with React Three Fiber's useFrame\n }\n\n /**\n * Get a copy of all current interpolated values\n */\n getCurrentValues(): number[] {\n return [...this.currentValues]\n }\n\n /**\n * Get a single interpolated value by its array index\n */\n getValue(index: number): number {\n return this.currentValues[index] ?? 0\n }\n\n /**\n * Check if automatic interpolation is currently running\n *\n * This only tracks auto-interpolation started with startAutoInterpolation().\n * Manual update() calls are not tracked by this method.\n */\n isInterpolating(): boolean {\n return this.animationId !== null\n }\n\n /**\n * Stop automatic interpolation if it's running\n *\n * This cancels the internal animation frame loop but does not affect\n * manual update() calls.\n */\n stop(): void {\n if (this.animationId !== null) {\n cancelAnimationFrame(this.animationId)\n this.animationId = null\n }\n }\n\n /**\n * Instantly set values without interpolation\n */\n setImmediate(values: number[]): void {\n this.stop()\n this.currentValues = [...values]\n this.targetValues = [...values]\n this.previousTargetValues = [...values]\n this.velocities = new Array(values.length).fill(0) // Reset velocities\n this.targetUpdateTime = performance.now()\n this.updateCount = 0 // Reset update counter\n this.options.onChange(this.currentValues)\n }\n\n /**\n * Update interpolation options\n */\n updateOptions(newOptions: Partial<InterpolationOptions>): void {\n this.options = { ...this.options, ...newOptions }\n }\n\n /**\n * Start automatic interpolation with an animation loop\n *\n * This begins a requestAnimationFrame loop that calls update() automatically.\n * For React Three Fiber components, prefer using manual update() calls\n * within useFrame hooks instead.\n */\n startAutoInterpolation(): void {\n this.startInterpolation()\n }\n\n /**\n * Clean up all resources and stop any running animations\n *\n * This cancels any active animation frames and resets internal state.\n * Call this when the component unmounts or is no longer needed.\n */\n destroy(): void {\n this.stop()\n }\n\n private startInterpolation(): void {\n if (this.animationId !== null) {\n return // Already interpolating\n }\n\n this.animate()\n }\n\n private animate = (): void => {\n // Use delta timing with a fallback for consistent automatic animations\n const isComplete = this.update(1 / 60) // Simulate 60fps for auto-interpolation\n\n if (!isComplete) {\n this.animationId = requestAnimationFrame(this.animate)\n } else {\n this.animationId = null\n }\n }\n}\n\n/**\n * React hook for using the ValueInterpolator with useFrame\n *\n * This hook creates a ValueInterpolator that uses spring physics for smooth,\n * natural animations. Call interpolator.update(delta) in your useFrame callback.\n *\n * @example\n * ```tsx\n * function AnimatedMesh() {\n * const [interpolator] = useInterpolation([0, 0, 0], {\n * tension: 120, // Higher = faster spring\n * friction: 20 // Higher = more damping\n * })\n * const meshRef = useRef()\n *\n * useFrame((state, delta) => {\n * if (interpolator.update(delta)) {\n * // Animation complete\n * }\n * // Apply current values directly to mesh\n * const [x, y, z] = interpolator.getCurrentValues()\n * meshRef.current.position.set(x, y, z)\n * })\n *\n * return <mesh ref={meshRef} />\n * }\n * ```\n */\nexport function useInterpolation(\n initialValues: number[] = [],\n options: InterpolationOptions = {},\n): [ValueInterpolator] {\n const interpolatorRef = React.useRef<ValueInterpolator | null>(null)\n\n // Initialize interpolator\n if (!interpolatorRef.current) {\n interpolatorRef.current = new ValueInterpolator(initialValues, options)\n }\n\n // Update options when they change\n React.useEffect(() => {\n interpolatorRef.current?.updateOptions(options)\n }, [options])\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n interpolatorRef.current?.destroy()\n }\n }, [])\n\n return [interpolatorRef.current!]\n}\n","//#region node_modules/.pnpm/@oxc-project+runtime@0.87.0/node_modules/@oxc-project/runtime/src/helpers/esm/typeof.js\nfunction _typeof(o) {\n\t\"@babel/helpers - typeof\";\n\treturn _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function(o$1) {\n\t\treturn typeof o$1;\n\t} : function(o$1) {\n\t\treturn o$1 && \"function\" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? \"symbol\" : typeof o$1;\n\t}, _typeof(o);\n}\n\n//#endregion\n//#region node_modules/.pnpm/@oxc-project+runtime@0.87.0/node_modules/@oxc-project/runtime/src/helpers/esm/toPrimitive.js\nfunction toPrimitive(t, r) {\n\tif (\"object\" != _typeof(t) || !t) return t;\n\tvar e = t[Symbol.toPrimitive];\n\tif (void 0 !== e) {\n\t\tvar i = e.call(t, r || \"default\");\n\t\tif (\"object\" != _typeof(i)) return i;\n\t\tthrow new TypeError(\"@@toPrimitive must return a primitive value.\");\n\t}\n\treturn (\"string\" === r ? String : Number)(t);\n}\n\n//#endregion\n//#region node_modules/.pnpm/@oxc-project+runtime@0.87.0/node_modules/@oxc-project/runtime/src/helpers/esm/toPropertyKey.js\nfunction toPropertyKey(t) {\n\tvar i = toPrimitive(t, \"string\");\n\treturn \"symbol\" == _typeof(i) ? i : i + \"\";\n}\n\n//#endregion\n//#region node_modules/.pnpm/@oxc-project+runtime@0.87.0/node_modules/@oxc-project/runtime/src/helpers/esm/defineProperty.js\nfunction _defineProperty(e, r, t) {\n\treturn (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n\t\tvalue: t,\n\t\tenumerable: !0,\n\t\tconfigurable: !0,\n\t\twritable: !0\n\t}) : e[r] = t, e;\n}\n\n//#endregion\nexport { _defineProperty };","import { _defineProperty } from \"../defineProperty-CQ_RnIQg.js\";\nimport globalAxios from \"axios\";\n\n//#region v2/base.ts\nconst BASE_PATH = \"/api/v2\".replace(/\\/+$/, \"\");\nconst COLLECTION_FORMATS = {\n\tcsv: \",\",\n\tssv: \" \",\n\ttsv: \"\t\",\n\tpipes: \"|\"\n};\nvar BaseAPI = class {\n\tconstructor(configuration, basePath = BASE_PATH, axios = globalAxios) {\n\t\tthis.basePath = basePath;\n\t\tthis.axios = axios;\n\t\t_defineProperty(this, \"configuration\", void 0);\n\t\tif (configuration) {\n\t\t\tthis.configuration = configuration;\n\t\t\tthis.basePath = configuration.basePath ?? basePath;\n\t\t}\n\t}\n};\nvar RequiredError = class extends Error {\n\tconstructor(field, msg) {\n\t\tsuper(msg);\n\t\tthis.field = field;\n\t\tthis.name = \"RequiredError\";\n\t}\n};\nconst operationServerMap = {};\n\n//#endregion\n//#region v2/common.ts\nconst DUMMY_BASE_URL = \"https://example.com\";\n/**\n*\n* @throws {RequiredError}\n*/\nconst assertParamExists = function(functionName, paramName, paramValue) {\n\tif (paramValue === null || paramValue === void 0) throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`);\n};\nconst setBasicAuthToObject = function(object, configuration) {\n\tif (configuration && (configuration.username || configuration.password)) object[\"auth\"] = {\n\t\tusername: configuration.username,\n\t\tpassword: configuration.password\n\t};\n};\nconst setBearerAuthToObject = async function(object, configuration) {\n\tif (configuration && configuration.accessToken) object[\"Authorization\"] = \"Bearer \" + (typeof configuration.accessToken === \"function\" ? await configuration.accessToken() : await configuration.accessToken);\n};\nfunction setFlattenedQueryParams(urlSearchParams, parameter, key = \"\") {\n\tif (parameter == null) return;\n\tif (typeof parameter === \"object\") if (Array.isArray(parameter)) parameter.forEach((item) => setFlattenedQueryParams(urlSearchParams, item, key));\n\telse Object.keys(parameter).forEach((currentKey) => setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== \"\" ? \".\" : \"\"}${currentKey}`));\n\telse if (urlSearchParams.has(key)) urlSearchParams.append(key, parameter);\n\telse urlSearchParams.set(key, parameter);\n}\nconst setSearchParams = function(url, ...objects) {\n\tconst searchParams = new URLSearchParams(url.search);\n\tsetFlattenedQueryParams(searchParams, objects);\n\turl.search = searchParams.toString();\n};\nconst serializeDataIfNeeded = function(value, requestOptions, configuration) {\n\tconst nonString = typeof value !== \"string\";\n\treturn (nonString && configuration && configuration.isJsonMime ? configuration.isJsonMime(requestOptions.headers[\"Content-Type\"]) : nonString) ? JSON.stringify(value !== void 0 ? value : {}) : value || \"\";\n};\nconst toPathString = function(url) {\n\treturn url.pathname + url.search + url.hash;\n};\nconst createRequestFunction = function(axiosArgs, globalAxios$1, BASE_PATH$1, configuration) {\n\treturn (axios = globalAxios$1, basePath = BASE_PATH$1) => {\n\t\tconst axiosRequestArgs = {\n\t\t\t...axiosArgs.options,\n\t\t\turl: (axios.defaults.baseURL ? \"\" : configuration?.basePath ?? basePath) + axiosArgs.url\n\t\t};\n\t\treturn axios.request(axiosRequestArgs);\n\t};\n};\n\n//#endregion\n//#region v2/api.ts\nconst AbbControllerKindEnum = { AbbController: \"AbbController\" };\n/**\n* ## BEHAVIOR_AUTOMATIC This is the default behavior. The motion groups of the controller take commanded joint configuration as actual joint state. Configures the compliance of the virtual robot with the normal ControllerState cycle time. If set, the virtual robot will act like a physical one, e.g., with a cycle time of 8ms to respond to a new joint state command. ## BEHAVIOR_AUTOMATIC_NOT_COMPLY_WITH_CYCLETIME Configures the compliance of the virtual robot with the normal ControllerState cycle time. If set, the robot will respond as fast as possible, limited only by software execution speed. Because of that the execution of a movement requires less time than with BEHAVIOR_AUTOMATIC. ## BEHAVIOR_EXTERNAL_SOURCE The external client is the only source of actual joint state changes. This mode is used to enable third party software indicating the current joint state via [externalJointsStream](externalJointsStream). \n*/\nconst Behavior = {\n\tBehaviorAutomatic: \"BEHAVIOR_AUTOMATIC\",\n\tBehaviorAutomaticNotComplyWithCycletime: \"BEHAVIOR_AUTOMATIC_NOT_COMPLY_WITH_CYCLETIME\",\n\tBehaviorExternalSource: \"BEHAVIOR_EXTERNAL_SOURCE\"\n};\nconst BlendingAutoBlendingNameEnum = { BlendingAuto: \"BlendingAuto\" };\nconst BlendingPositionBlendingNameEnum = { BlendingPosition: \"BlendingPosition\" };\nconst BooleanValueValueTypeEnum = { Boolean: \"boolean\" };\nconst BoxShapeTypeEnum = { Box: \"box\" };\nconst BoxBoxTypeEnum = {\n\tHollow: \"HOLLOW\",\n\tFull: \"FULL\"\n};\nconst BusIOModbusClientBusTypeEnum = { ModbusClient: \"modbus_client\" };\nconst BusIOModbusServerBusTypeEnum = { ModbusServer: \"modbus_server\" };\nconst BusIOModbusTCPClientNetworkTypeEnum = { Tcp: \"tcp\" };\nconst BusIOModbusTCPServerNetworkTypeEnum = { Tcp: \"tcp\" };\nconst BusIOModbusVirtualBusTypeEnum = { ModbusVirtual: \"modbus_virtual\" };\nconst BusIOProfinetBusTypeEnum = { Profinet: \"profinet\" };\nconst BusIOProfinetVirtualBusTypeEnum = { ProfinetVirtual: \"profinet_virtual\" };\n/**\n* Current state of the BUS input/output service. \n*/\nconst BusIOsStateEnum = {\n\tBusIosStateUnknown: \"BUS_IOS_STATE_UNKNOWN\",\n\tBusIosStateInitializing: \"BUS_IOS_STATE_INITIALIZING\",\n\tBusIosStateConnected: \"BUS_IOS_STATE_CONNECTED\",\n\tBusIosStateDisconnected: \"BUS_IOS_STATE_DISCONNECTED\"\n};\nconst CapsuleShapeTypeEnum = { Capsule: \"capsule\" };\n/**\n* Comparator for the comparison of two values. The comparator is used to compare two values and return a boolean result. The default comparator is unknown. \n*/\nconst Comparator = {\n\tComparatorEquals: \"COMPARATOR_EQUALS\",\n\tComparatorNotEquals: \"COMPARATOR_NOT_EQUALS\",\n\tComparatorGreater: \"COMPARATOR_GREATER\",\n\tComparatorGreaterEqual: \"COMPARATOR_GREATER_EQUAL\",\n\tComparatorLess: \"COMPARATOR_LESS\",\n\tComparatorLessEqual: \"COMPARATOR_LESS_EQUAL\"\n};\nconst ConfigurationArchiveStatusCreatingStatusEnum = { Creating: \"creating\" };\nconst ConfigurationArchiveStatusErrorStatusEnum = { Error: \"error\" };\nconst ConfigurationArchiveStatusSuccessStatusEnum = { Success: \"success\" };\nconst ConvexHullShapeTypeEnum = { ConvexHull: \"convex_hull\" };\nconst CylinderShapeTypeEnum = { Cylinder: \"cylinder\" };\n/**\n* The direction in which the trajectory is executed. Default: Forward. \n*/\nconst Direction = {\n\tDirectionForward: \"DIRECTION_FORWARD\",\n\tDirectionBackward: \"DIRECTION_BACKWARD\"\n};\nconst ErrorInvalidJointCountErrorFeedbackNameEnum = { ErrorInvalidJointCount: \"ErrorInvalidJointCount\" };\nconst ErrorJointLimitExceededErrorFeedbackNameEnum = { ErrorJointLimitExceeded: \"ErrorJointLimitExceeded\" };\nconst ErrorJointPositionCollisionErrorFeedbackNameEnum = { ErrorJointPositionCollision: \"ErrorJointPositionCollision\" };\nconst ErrorMaxIterationsExceededErrorFeedbackNameEnum = { ErrorMaxIterationsExceeded: \"ErrorMaxIterationsExceeded\" };\nconst FanucControllerKindEnum = { FanucController: \"FanucController\" };\nconst FeedbackCollisionErrorFeedbackNameEnum = { FeedbackCollision: \"FeedbackCollision\" };\nconst FeedbackJointLimitExceededErrorFeedbackNameEnum = { FeedbackJointLimitExceeded: \"FeedbackJointLimitExceeded\" };\nconst FeedbackOutOfWorkspaceErrorFeedbackNameEnum = { FeedbackOutOfWorkspace: \"FeedbackOutOfWorkspace\" };\nconst FeedbackSingularityErrorFeedbackNameEnum = { FeedbackSingularity: \"FeedbackSingularity\" };\nconst FloatValueValueTypeEnum = { Float: \"float\" };\nconst IOBooleanValueValueTypeEnum = { Boolean: \"boolean\" };\n/**\n* Identifies the input/output type.\n*/\nconst IODirection = {\n\tIoTypeInput: \"IO_TYPE_INPUT\",\n\tIoTypeOutput: \"IO_TYPE_OUTPUT\"\n};\nconst IOFloatValueValueTypeEnum = { Float: \"float\" };\nconst IOIntegerValueValueTypeEnum = { Integer: \"integer\" };\n/**\n* States the source of the input/output signal. \n*/\nconst IOOrigin = {\n\tController: \"CONTROLLER\",\n\tBusIo: \"BUS_IO\"\n};\n/**\n* Data type of the input/output.\n*/\nconst IOValueType = {\n\tIoValueBoolean: \"IO_VALUE_BOOLEAN\",\n\tIoValueAnalogFloat: \"IO_VALUE_ANALOG_FLOAT\",\n\tIoValueAnalogInteger: \"IO_VALUE_ANALOG_INTEGER\"\n};\nconst InitializeJoggingRequestMessageTypeEnum = { InitializeJoggingRequest: \"InitializeJoggingRequest\" };\nconst InitializeJoggingResponseKindEnum = { InitializeReceived: \"INITIALIZE_RECEIVED\" };\nconst InitializeMovementRequestMessageTypeEnum = { InitializeMovementRequest: \"InitializeMovementRequest\" };\nconst InitializeMovementResponseKindEnum = { InitializeReceived: \"INITIALIZE_RECEIVED\" };\nconst IntegerValueValueTypeEnum = { Integer: \"integer\" };\nconst JoggingDetailsKindEnum = { Jogging: \"JOGGING\" };\nconst JoggingPausedByUserKindEnum = { PausedByUser: \"PAUSED_BY_USER\" };\nconst JoggingPausedNearCollisionKindEnum = { PausedNearCollision: \"PAUSED_NEAR_COLLISION\" };\nconst JoggingPausedNearJointLimitKindEnum = { PausedNearJointLimit: \"PAUSED_NEAR_JOINT_LIMIT\" };\nconst JoggingPausedOnIOKindEnum = { PausedOnIo: \"PAUSED_ON_IO\" };\nconst JoggingRunningKindEnum = { Running: \"RUNNING\" };\nconst JointVelocityRequestMessageTypeEnum = { JointVelocityRequest: \"JointVelocityRequest\" };\nconst JointVelocityResponseKindEnum = { JointVelocityReceived: \"JOINT_VELOCITY_RECEIVED\" };\nconst KukaControllerKindEnum = { KukaController: \"KukaController\" };\nconst LicenseStatusEnum = {\n\tOk: \"OK\",\n\tExpired: \"EXPIRED\",\n\tSuspended: \"SUSPENDED\",\n\tGracePeriodOver: \"GRACE_PERIOD_OVER\",\n\tNotFound: \"NOT_FOUND\"\n};\nconst Manufacturer = {\n\tAbb: \"abb\",\n\tFanuc: \"fanuc\",\n\tKuka: \"kuka\",\n\tUniversalrobots: \"universalrobots\",\n\tYaskawa: \"yaskawa\"\n};\nconst MidpointInsertionAlgorithmAlgorithmNameEnum = { MidpointInsertionAlgorithm: \"MidpointInsertionAlgorithm\" };\n/**\n* Area of the MODBUS input/output variable. Is used to interpret the corresponding bits correctly. \n*/\nconst ModbusIOArea = {\n\tModbusIoAreaUnknown: \"MODBUS_IO_AREA_UNKNOWN\",\n\tModbusIoAreaCoils: \"MODBUS_IO_AREA_COILS\",\n\tModbusIoAreaDiscreteInputs: \"MODBUS_IO_AREA_DISCRETE_INPUTS\",\n\tModbusIoAreaHoldingRegisters: \"MODBUS_IO_AREA_HOLDING_REGISTERS\",\n\tModbusIoAreaInputRegisters: \"MODBUS_IO_AREA_INPUT_REGISTERS\"\n};\n/**\n* Byte order of the MODBUS input/output variable. Used to interpret the corresponding bits correctly. \n*/\nconst ModbusIOByteOrder = {\n\tModbusIoByteOrderUnknown: \"MODBUS_IO_BYTE_ORDER_UNKNOWN\",\n\tModbusIoByteOrderAbcd: \"MODBUS_IO_BYTE_ORDER_ABCD\",\n\tModbusIoByteOrderBadc: \"MODBUS_IO_BYTE_ORDER_BADC\",\n\tModbusIoByteOrderCdab: \"MODBUS_IO_BYTE_ORDER_CDAB\",\n\tModbusIoByteOrderDcba: \"MODBUS_IO_BYTE_ORDER_DCBA\"\n};\n/**\n* Value type of the MODBUS input/output variable. Used to interpret the corresponding bits correctly. \n*/\nconst ModbusIOTypeEnum = {\n\tModbusIoTypeUnknown: \"MODBUS_IO_TYPE_UNKNOWN\",\n\tModbusIoTypeBool: \"MODBUS_IO_TYPE_BOOL\",\n\tModbusIoTypeUint16: \"MODBUS_IO_TYPE_UINT16\",\n\tModbusIoTypeFloat32: \"MODBUS_IO_TYPE_FLOAT32\"\n};\nconst MovementErrorResponseKindEnum = { MotionError: \"MOTION_ERROR\" };\n/**\n* The operating state.\n*/\nconst OperatingState = {\n\tActive: \"ACTIVE\",\n\tInactive: \"INACTIVE\"\n};\n/**\n* Current operation mode of the configured robot controller. Operation modes in which the attached motion groups can be moved are: - OPERATION_MODE_MANUAL (if enabling switch is pressed) - OPERATION_MODE_MANUAL_T1 (if enabling switch is pressed) - OPERATION_MODE_MANUAL_T2 (if enabling switch is pressed) - OPERATION_MODE_AUTO (without needing to press enabling switch) All other modes are considered as non-operational. \n*/\nconst OperationMode = {\n\tOperationModeUnknown: \"OPERATION_MODE_UNKNOWN\",\n\tOperationModeNoController: \"OPERATION_MODE_NO_CONTROLLER\",\n\tOperationModeDisconnected: \"OPERATION_MODE_DISCONNECTED\",\n\tOperationModePowerOn: \"OPERATION_MODE_POWER_ON\",\n\tOperationModePending: \"OPERATION_MODE_PENDING\",\n\tOperationModeManual: \"OPERATION_MODE_MANUAL\",\n\tOperationModeManualT1: \"OPERATION_MODE_MANUAL_T1\",\n\tOperationModeManualT2: \"OPERATION_MODE_MANUAL_T2\",\n\tOperationModeAuto: \"OPERATION_MODE_AUTO\",\n\tOperationModeRecovery: \"OPERATION_MODE_RECOVERY\"\n};\n/**\n* The type of rotation description that is used to specify the orientation. **Rotation Vector notation** * The rotation is represented using an axis-angle representation: > axis = Vector[0:2] > angle = |axis| in [rad] > axis.normalized * angle **Quaternion notation** * The rotation is represented using a unit quaternion: [x, y, z, w]. * The vector part [x, y, z] is the imaginary part of the quaternion, and the scalar part [w] is the real part. **Euler notation** * *extrinsic* fixed external reference system * *intrinsic* reference system fixed to rotation body > angles = Vector[0:2] in [rad]. * ZYX, ZXZ,... - mapping of the given angles values to the (either intrinsic or extrinsic) axes in the stated order. > Example ZYX: Z = Vector[0], Y = Vector[1], X = Vector[2]. \n*/\nconst OrientationType = {\n\tRotationVector: \"ROTATION_VECTOR\",\n\tQuaternion: \"QUATERNION\",\n\tEulerAnglesIntrinsicZxz: \"EULER_ANGLES_INTRINSIC_ZXZ\",\n\tEulerAnglesIntrinsicXyx: \"EULER_ANGLES_INTRINSIC_XYX\",\n\tEulerAnglesIntrinsicYzy: \"EULER_ANGLES_INTRINSIC_YZY\",\n\tEulerAnglesIntrinsicZyz: \"EULER_ANGLES_INTRINSIC_ZYZ\",\n\tEulerAnglesIntrinsicXzx: \"EULER_ANGLES_INTRINSIC_XZX\",\n\tEulerAnglesIntrinsicYxy: \"EULER_ANGLES_INTRINSIC_YXY\",\n\tEulerAnglesIntrinsicXyz: \"EULER_ANGLES_INTRINSIC_XYZ\",\n\tEulerAnglesIntrinsicYzx: \"EULER_ANGLES_INTRINSIC_YZX\",\n\tEulerAnglesIntrinsicZxy: \"EULER_ANGLES_INTRINSIC_ZXY\",\n\tEulerAnglesIntrinsicXzy: \"EULER_ANGLES_INTRINSIC_XZY\",\n\tEulerAnglesIntrinsicZyx: \"EULER_ANGLES_INTRINSIC_ZYX\",\n\tEulerAnglesIntrinsicYxz: \"EULER_ANGLES_INTRINSIC_YXZ\",\n\tEulerAnglesExtrinsicZxz: \"EULER_ANGLES_EXTRINSIC_ZXZ\",\n\tEulerAnglesExtrinsicXyx: \"EULER_ANGLES_EXTRINSIC_XYX\",\n\tEulerAnglesExtrinsicYzy: \"EULER_ANGLES_EXTRINSIC_YZY\",\n\tEulerAnglesExtrinsicZyz: \"EULER_ANGLES_EXTRINSIC_ZYZ\",\n\tEulerAnglesExtrinsicXzx: \"EULER_ANGLES_EXTRINSIC_XZX\",\n\tEulerAnglesExtrinsicYxy: \"EULER_ANGLES_EXTRINSIC_YXY\",\n\tEulerAnglesExtrinsicZyx: \"EULER_ANGLES_EXTRINSIC_ZYX\",\n\tEulerAnglesExtrinsicXzy: \"EULER_ANGLES_EXTRINSIC_XZY\",\n\tEulerAnglesExtrinsicYxz: \"EULER_ANGLES_EXTRINSIC_YXZ\",\n\tEulerAnglesExtrinsicYzx: \"EULER_ANGLES_EXTRINSIC_YZX\",\n\tEulerAnglesExtrinsicXyz: \"EULER_ANGLES_EXTRINSIC_XYZ\",\n\tEulerAnglesExtrinsicZxy: \"EULER_ANGLES_EXTRINSIC_ZXY\"\n};\nconst PathCartesianPTPPathDefinitionNameEnum = { PathCartesianPtp: \"PathCartesianPTP\" };\nconst PathCirclePathDefinitionNameEnum = { PathCircle: \"PathCircle\" };\nconst PathCubicSplinePathDefinitionNameEnum = { PathCubicSpline: \"PathCubicSpline\" };\nconst PathJointPTPPathDefinitionNameEnum = { PathJointPtp: \"PathJointPTP\" };\nconst PathLinePathDefinitionNameEnum = { PathLine: \"PathLine\" };\nconst PauseJoggingRequestMessageTypeEnum = { PauseJoggingRequest: \"PauseJoggingRequest\" };\nconst PauseJoggingResponseKindEnum = { PauseReceived: \"PAUSE_RECEIVED\" };\nconst PauseMovementRequestMessageTypeEnum = { PauseMovementRequest: \"PauseMovementRequest\" };\nconst PauseMovementResponseKindEnum = { PauseReceived: \"PAUSE_RECEIVED\" };\nconst PlaneShapeTypeEnum = { Plane: \"plane\" };\nconst PlaybackSpeedRequestMessageTypeEnum = { PlaybackSpeedRequest: \"PlaybackSpeedRequest\" };\nconst PlaybackSpeedResponseKindEnum = { PlaybackSpeedReceived: \"PLAYBACK_SPEED_RECEIVED\" };\n/**\n* The direction of the input/output variable, indicating whether it is an input or output for the PROFINET device, e.g., NOVA\\'s PROFINET service.\n*/\nconst ProfinetIODirection = {\n\tProfinetIoDirectionInput: \"PROFINET_IO_DIRECTION_INPUT\",\n\tProfinetIoDirectionOutput: \"PROFINET_IO_DIRECTION_OUTPUT\",\n\tProfinetIoDirectionInout: \"PROFINET_IO_DIRECTION_INOUT\"\n};\n/**\n* Value type of the PROFINET input/output variable. Is used to interpret the corresponding bits correctly. \n*/\nconst ProfinetIOTypeEnum = {\n\tProfinetIoTypeUnknown: \"PROFINET_IO_TYPE_UNKNOWN\",\n\tProfinetIoTypeBool: \"PROFINET_IO_TYPE_BOOL\",\n\tProfinetIoTypeUsint: \"PROFINET_IO_TYPE_USINT\",\n\tProfinetIoTypeSint: \"PROFINET_IO_TYPE_SINT\",\n\tProfinetIoTypeUint: \"PROFINET_IO_TYPE_UINT\",\n\tProfinetIoTypeInt: \"PROFINET_IO_TYPE_INT\",\n\tProfinetIoTypeUdint: \"PROFINET_IO_TYPE_UDINT\",\n\tProfinetIoTypeDint: \"PROFINET_IO_TYPE_DINT\",\n\tProfinetIoTypeReal: \"PROFINET_IO_TYPE_REAL\",\n\tProfinetIoTypeLreal: \"PROFINET_IO_TYPE_LREAL\"\n};\n/**\n* The state of a program run.\n*/\nconst ProgramRunState = {\n\tPreparing: \"PREPARING\",\n\tRunning: \"RUNNING\",\n\tCompleted: \"COMPLETED\",\n\tFailed: \"FAILED\",\n\tStopped: \"STOPPED\"\n};\nconst RRTConnectAlgorithmAlgorithmNameEnum = { RrtConnectAlgorithm: \"RRTConnectAlgorithm\" };\nconst RectangleShapeTypeEnum = { Rectangle: \"rectangle\" };\nconst RectangularCapsuleShapeTypeEnum = { RectangularCapsule: \"rectangular_capsule\" };\n/**\n* The channel that defines what a new Wandelbots NOVA version is. * `next` the over all latest version * `stable` newes patch of the current version \n*/\nconst ReleaseChannel = {\n\tStable: \"stable\",\n\tNext: \"next\"\n};\n/**\n* Defines the current system mode of the robot system, including NOVA communicating with the robot controller. ### MODE_CONTROLLER_NOT_CONFIGURED No controller with the specified identifier is configured. Call [addRobotController](addRobotController) to register a controller. ### MODE_INITIALIZING Indicates that a connection to the robot controller is established or reestablished in case of a disconnect. On success, the controller is set to MODE_MONITOR. On failure, the initialization process is retried until successful or cancelled by the user. ### MODE_MONITOR Read-only mode with an active controller connection. - Receives robot state and I/O signals - Move requests are rejected - No commands are sent to the controller ### MODE_CONTROL Active control mode. **Movement is possible in this mode** The robot is cyclically commanded to hold its current position. The robot state is received in sync with the controller cycle. Motion and jogging requests are accepted and executed. Input/Output interaction is en