@wandelbots/wandelbots-js-react-components 2.27.1 → 2.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/Setup.d.ts +1 -1
  3. package/dist/Setup.d.ts.map +1 -1
  4. package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts +2 -2
  5. package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts.map +1 -1
  6. package/dist/components/3d-viewport/TrajectoryRenderer.d.ts +1 -1
  7. package/dist/components/3d-viewport/TrajectoryRenderer.d.ts.map +1 -1
  8. package/dist/components/robots/DHRobot.d.ts.map +1 -1
  9. package/dist/components/robots/GenericRobot.d.ts +2 -2
  10. package/dist/components/robots/GenericRobot.d.ts.map +1 -1
  11. package/dist/components/robots/Robot.d.ts +2 -2
  12. package/dist/components/robots/Robot.d.ts.map +1 -1
  13. package/dist/components/robots/RobotAnimator.d.ts.map +1 -1
  14. package/dist/components/robots/RobotAnimator.test.d.ts +2 -0
  15. package/dist/components/robots/RobotAnimator.test.d.ts.map +1 -0
  16. package/dist/components/robots/SupportedRobot.d.ts +3 -3
  17. package/dist/components/robots/SupportedRobot.d.ts.map +1 -1
  18. package/dist/components/utils/interpolation.d.ts +159 -0
  19. package/dist/components/utils/interpolation.d.ts.map +1 -0
  20. package/dist/components/utils/interpolation.test.d.ts +2 -0
  21. package/dist/components/utils/interpolation.test.d.ts.map +1 -0
  22. package/dist/externalizeComponent.d.ts +1 -1
  23. package/dist/externalizeComponent.d.ts.map +1 -1
  24. package/dist/index.cjs +39 -47
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +8251 -9820
  29. package/dist/index.js.map +1 -1
  30. package/dist/test/setup.d.ts +2 -0
  31. package/dist/test/setup.d.ts.map +1 -0
  32. package/package.json +33 -32
  33. package/src/Setup.tsx +1 -1
  34. package/src/components/3d-viewport/SafetyZonesRenderer.tsx +2 -2
  35. package/src/components/3d-viewport/TrajectoryRenderer.tsx +1 -1
  36. package/src/components/jogging/JoggingOptions.tsx +1 -1
  37. package/src/components/robots/DHRobot.tsx +37 -10
  38. package/src/components/robots/GenericRobot.tsx +4 -5
  39. package/src/components/robots/Robot.tsx +2 -2
  40. package/src/components/robots/RobotAnimator.test.tsx +113 -0
  41. package/src/components/robots/RobotAnimator.tsx +38 -23
  42. package/src/components/robots/SupportedRobot.tsx +3 -3
  43. package/src/components/utils/converters.ts +1 -1
  44. package/src/components/utils/interpolation.test.ts +1123 -0
  45. package/src/components/utils/interpolation.ts +379 -0
  46. package/src/externalizeComponent.tsx +1 -1
  47. package/src/index.ts +1 -0
  48. package/src/test/setup.ts +111 -0
@@ -0,0 +1,2 @@
1
+ import "@testing-library/jest-dom";
2
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wandelbots/wandelbots-js-react-components",
3
- "version": "2.27.1",
3
+ "version": "2.28.0",
4
4
  "description": "React UI toolkit for building applications on top of the Wandelbots platform",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -25,6 +25,8 @@
25
25
  "dev:wbjs": "nodemon --watch $WBJS_PATH -e tgz --exec 'npm install file:$WBJS_PATH && storybook dev -p 6006 --no-open'",
26
26
  "tsc": "tsc --pretty --noEmit -p stories/tsconfig.json",
27
27
  "test": "test-storybook --url http://127.0.0.1:6006 --index-json --browsers chromium",
28
+ "test:unit": "vitest --workspace vitest.workspace.ts --project unit",
29
+ "test:unit:run": "vitest run --workspace vitest.workspace.ts --project unit",
28
30
  "ci:test": "run-s ci:test:build ci:test:built",
29
31
  "ci:test:build": "storybook build --quiet --test",
30
32
  "ci:test:built": "run-p --race ci:test:server ci:test:runner",
@@ -48,45 +50,44 @@
48
50
  "devDependencies": {
49
51
  "@emotion/react": "^11.14.0",
50
52
  "@emotion/styled": "^11.14.0",
51
- "@mui/icons-material": "^6.4.1",
52
- "@mui/material": "^6.4.0",
53
- "@react-spring/three": "^9.7.5",
54
- "@react-three/drei": "^9.122.0",
55
- "@react-three/fiber": "^8.18.0",
53
+ "@mui/icons-material": "^7.1.1",
54
+ "@mui/material": "^7.1.1",
55
+ "@react-three/drei": "^10.2.0",
56
+ "@react-three/fiber": "^9.1.2",
56
57
  "@rollup/plugin-commonjs": "^28.0.2",
57
58
  "@rollup/plugin-json": "^6.1.0",
58
59
  "@rollup/plugin-node-resolve": "^16.0.0",
59
60
  "@rollup/plugin-terser": "^0.4.4",
60
61
  "@rollup/plugin-typescript": "^12.1.2",
61
- "@storybook/addon-docs": "^8.6.4",
62
- "@storybook/addon-essentials": "^8.6.4",
63
- "@storybook/addon-interactions": "^8.6.4",
64
- "@storybook/blocks": "^8.6.4",
65
- "@storybook/csf-tools": "^8.6.4",
66
- "@storybook/react": "^8.6.4",
67
- "@storybook/react-vite": "^8.6.4",
68
- "@storybook/test": "^8.6.4",
69
- "@storybook/test-runner": "^0.21.3",
70
- "@storybook/types": "^8.6.4",
62
+ "@storybook/addon-docs": "^9.0.8",
63
+ "@storybook/react-vite": "^9.0.8",
64
+ "@storybook/test-runner": "^0.23.0",
71
65
  "@svgr/rollup": "^8.1.0",
66
+ "@testing-library/jest-dom": "^6.6.3",
67
+ "@testing-library/react": "^16.3.0",
68
+ "@testing-library/user-event": "^14.6.1",
72
69
  "@types/lodash-es": "^4.17.12",
73
- "@types/react": "^18.3.12",
70
+ "@types/react": "^19.1.8",
74
71
  "@types/three": "^0.174.0",
75
72
  "@vitejs/plugin-react": "^4.3.4",
76
- "@wandelbots/nova-js": "^2.0.1",
73
+ "@wandelbots/nova-js": "^2.1.0",
77
74
  "add": "^2.0.6",
75
+ "eslint-plugin-storybook": "^9.0.8",
78
76
  "glob": "^11.0.1",
79
77
  "http-server": "^14.1.1",
80
78
  "husky": "^9.1.7",
79
+ "i18next": "^25.2.1",
81
80
  "jest-simple-dot-reporter": "^1.0.5",
82
81
  "jest-summary-reporter": "^0.0.2",
82
+ "jsdom": "^26.1.0",
83
+ "monaco-editor": "^0.52.2",
83
84
  "nodemon": "^3.1.9",
84
85
  "npm-run-all": "^4.1.5",
85
86
  "postcss": "^8.5.3",
86
87
  "prettier-eslint": "^16.3.0",
87
88
  "prop-types": "^15.8.1",
88
- "react": "^18.3.1",
89
- "react-dom": "^18.3.1",
89
+ "react": "^19.1.0",
90
+ "react-dom": "^19.1.0",
90
91
  "rimraf": "^6.0.1",
91
92
  "rollup": "^4.34.9",
92
93
  "rollup-plugin-dts": "^6.1.1",
@@ -94,8 +95,7 @@
94
95
  "rollup-plugin-peer-deps-external": "^2.2.4",
95
96
  "rollup-plugin-postcss": "^4.0.2",
96
97
  "semantic-release": "^24.2.3",
97
- "storybook": "^8.6.4",
98
- "storybook-dark-mode": "^4.0.2",
98
+ "storybook": "^9.0.8",
99
99
  "storybook-preset-inline-svg": "^1.0.1",
100
100
  "three": "^0.174.0",
101
101
  "three-stdlib": "^2.35.14",
@@ -110,11 +110,12 @@
110
110
  "peerDependencies": {
111
111
  "@emotion/react": "^11.11.1",
112
112
  "@emotion/styled": "^11.11.0",
113
- "@mui/icons-material": "^6",
114
- "@mui/material": "^6",
115
- "@react-spring/three": "^9",
116
- "@react-three/drei": "^9.122.0",
117
- "@react-three/fiber": "^8.18.0",
113
+ "@mui/icons-material": "^6 || ^7",
114
+ "@mui/material": "^6 || ^7",
115
+ "@react-three/drei": "^9.122.0 || ^10",
116
+ "@react-three/fiber": "^8 || ^9",
117
+ "react": "^18.0.0 || ^19.0.0",
118
+ "react-dom": "^18.0.0 || ^19.0.0",
118
119
  "three": ">=0.174",
119
120
  "three-stdlib": ">=2"
120
121
  },
@@ -122,9 +123,6 @@
122
123
  "react-dom": {
123
124
  "optional": true
124
125
  },
125
- "@react-spring/three": {
126
- "optional": true
127
- },
128
126
  "@react-three/drei": {
129
127
  "optional": true
130
128
  },
@@ -145,8 +143,11 @@
145
143
  "lodash-es": "^4.17.21",
146
144
  "mobx": "^6.13.6",
147
145
  "mobx-react-lite": "^4.1.0",
148
- "react-error-boundary": "^5.0.0",
149
- "react-i18next": "^15.4.1",
146
+ "react-error-boundary": "^6.0.0",
147
+ "react-i18next": "^15.5.2",
150
148
  "shiki": "^3.1.0"
149
+ },
150
+ "overrides": {
151
+ "storybook": "$storybook"
151
152
  }
152
153
  }
package/src/Setup.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OrbitControls } from "@react-three/drei"
2
- import { Canvas, type Props as CanvasProps } from "@react-three/fiber"
2
+ import { Canvas, type CanvasProps } from "@react-three/fiber"
3
3
  import * as React from "react"
4
4
  import { Vector3 } from "three"
5
5
  import { PresetEnvironment } from "./components/3d-viewport/PresetEnvironment"
@@ -1,4 +1,4 @@
1
- import { type GroupProps } from "@react-three/fiber"
1
+ import { type ThreeElements } from "@react-three/fiber"
2
2
  import type { Geometry } from "@wandelbots/nova-api/v1"
3
3
  import type { SafetySetupSafetyZone } from "@wandelbots/nova-js/v1"
4
4
  import * as THREE from "three"
@@ -6,7 +6,7 @@ import { ConvexGeometry } from "three-stdlib"
6
6
 
7
7
  export type SafetyZonesRendererProps = {
8
8
  safetyZones: SafetySetupSafetyZone[]
9
- } & GroupProps
9
+ } & ThreeElements["group"]
10
10
 
11
11
  interface CoplanarityResult {
12
12
  isCoplanar: boolean
@@ -4,7 +4,7 @@ import * as THREE from "three"
4
4
 
5
5
  export type TrajectoryRendererProps = {
6
6
  trajectory: GetTrajectoryResponse
7
- } & JSX.IntrinsicElements["group"]
7
+ } & React.JSX.IntrinsicElements["group"]
8
8
 
9
9
  export function TrajectoryRenderer({
10
10
  trajectory,
@@ -11,7 +11,7 @@ import {
11
11
 
12
12
  export const JoggingOptions = observer(({ store }: { store: JoggingStore }) => {
13
13
  const { t } = useTranslation()
14
- const joggingOptions = []
14
+ const joggingOptions: React.ReactElement[] = []
15
15
 
16
16
  function translateOrientation(orientation: OrientationId): string {
17
17
  switch (orientation) {
@@ -1,5 +1,6 @@
1
1
  import { Line } from "@react-three/drei"
2
2
  import type { DHParameter } from "@wandelbots/nova-api/v1"
3
+ import React, { useRef } from "react"
3
4
  import type * as THREE from "three"
4
5
  import { Matrix4, Quaternion, Vector3 } from "three"
5
6
  import type { LineGeometry } from "three/examples/jsm/lines/LineGeometry.js"
@@ -17,6 +18,16 @@ export function DHRobot({
17
18
  // reused in every update
18
19
  const accumulatedMatrix = new Matrix4()
19
20
 
21
+ // Store direct references to avoid searching by name
22
+ const lineRefs = useRef<any[]>([])
23
+ const meshRefs = useRef<(THREE.Mesh | null)[]>([])
24
+
25
+ // Initialize refs array when dhParameters change
26
+ React.useEffect(() => {
27
+ lineRefs.current = new Array(dhParameters.length).fill(null)
28
+ meshRefs.current = new Array(dhParameters.length).fill(null)
29
+ }, [dhParameters.length])
30
+
20
31
  // Updates accumulatedMatrix with every execution
21
32
  // Reset the matrix to identity if you start a new position update
22
33
  function getLinePoints(
@@ -49,7 +60,7 @@ export function DHRobot({
49
60
 
50
61
  function setJointLineRotation(
51
62
  jointIndex: number,
52
- line: THREE.Line,
63
+ line: any, // Use any for drei Line component
53
64
  mesh: THREE.Mesh,
54
65
  jointValue: number,
55
66
  ) {
@@ -71,14 +82,20 @@ export function DHRobot({
71
82
 
72
83
  function setRotation(joints: THREE.Object3D[], jointValues: number[]) {
73
84
  accumulatedMatrix.identity()
74
- joints.forEach((joint, jointIndex) => {
75
- setJointLineRotation(
76
- jointIndex,
77
- joint.getObjectByName(CHILD_LINE) as THREE.Line,
78
- joint.getObjectByName(CHILD_MESH) as THREE.Mesh,
79
- jointValues[jointIndex]!,
80
- )
81
- })
85
+
86
+ // Use direct refs instead of searching by name
87
+ for (
88
+ let jointIndex = 0;
89
+ jointIndex < Math.min(joints.length, jointValues.length);
90
+ jointIndex++
91
+ ) {
92
+ const line = lineRefs.current[jointIndex]
93
+ const mesh = meshRefs.current[jointIndex]
94
+
95
+ if (line && mesh) {
96
+ setJointLineRotation(jointIndex, line, mesh, jointValues[jointIndex]!)
97
+ }
98
+ }
82
99
  }
83
100
 
84
101
  return (
@@ -103,12 +120,22 @@ export function DHRobot({
103
120
  return (
104
121
  <group name={jointName} key={jointName}>
105
122
  <Line
123
+ ref={(ref) => {
124
+ lineRefs.current[index] = ref
125
+ }}
106
126
  name={CHILD_LINE}
107
127
  points={[a, b]}
108
128
  color={"white"}
109
129
  lineWidth={5}
110
130
  />
111
- <mesh name={CHILD_MESH} key={"mesh_" + index} position={b}>
131
+ <mesh
132
+ ref={(ref) => {
133
+ meshRefs.current[index] = ref
134
+ }}
135
+ name={CHILD_MESH}
136
+ key={"mesh_" + index}
137
+ position={b}
138
+ >
112
139
  <sphereGeometry args={[0.01, 32, 32]} />
113
140
  <meshStandardMaterial color={"black"} depthTest={true} />
114
141
  </mesh>
@@ -1,6 +1,5 @@
1
- import { animated } from "@react-spring/three"
2
1
  import { useGLTF } from "@react-three/drei"
3
- import type { GroupProps } from "@react-three/fiber"
2
+ import type { ThreeElements } from "@react-three/fiber"
4
3
  import React, { useCallback } from "react"
5
4
  import type { Group, Mesh } from "three"
6
5
  import { type Object3D } from "three"
@@ -14,7 +13,7 @@ export type RobotModelProps = {
14
13
  */
15
14
  postModelRender?: () => void
16
15
  flangeRef?: React.Ref<Group>
17
- } & GroupProps
16
+ } & ThreeElements["group"]
18
17
 
19
18
  function isMesh(node: Object3D): node is Mesh {
20
19
  return node.type === "Mesh"
@@ -54,7 +53,7 @@ export function GenericRobot({
54
53
  )
55
54
  } else {
56
55
  return (
57
- <animated.group
56
+ <group
58
57
  name={node.name}
59
58
  key={node.uuid}
60
59
  position={node.position}
@@ -62,7 +61,7 @@ export function GenericRobot({
62
61
  ref={isFlange(node) ? flangeRef : undefined}
63
62
  >
64
63
  {node.children.map(renderNode)}
65
- </animated.group>
64
+ </group>
66
65
  )
67
66
  }
68
67
  }
@@ -1,4 +1,4 @@
1
- import { type GroupProps } from "@react-three/fiber"
1
+ import { type ThreeElements } from "@react-three/fiber"
2
2
 
3
3
  import type { ConnectedMotionGroup } from "@wandelbots/nova-js/v1"
4
4
  import type { Group } from "three"
@@ -10,7 +10,7 @@ export type RobotProps = {
10
10
  getModel?: (modelFromController: string) => string
11
11
  flangeRef?: React.Ref<Group>
12
12
  transparentColor?: string
13
- } & GroupProps
13
+ } & ThreeElements["group"]
14
14
 
15
15
  /**
16
16
  * The Robot component is a wrapper around the SupportedRobot component
@@ -0,0 +1,113 @@
1
+ import type {
2
+ DHParameter,
3
+ MotionGroupStateResponse,
4
+ } from "@wandelbots/nova-api/v1"
5
+ import { describe, expect, it, vi } from "vitest"
6
+ import RobotAnimator from "./RobotAnimator"
7
+
8
+ // Mock the dependencies
9
+ vi.mock("./robotModelLogic", () => ({
10
+ collectJoints: vi.fn(),
11
+ }))
12
+
13
+ vi.mock("../utils/interpolation", () => ({
14
+ ValueInterpolator: vi.fn().mockImplementation(() => ({
15
+ setTarget: vi.fn(),
16
+ getCurrentValues: vi.fn(() => []),
17
+ destroy: vi.fn(),
18
+ })),
19
+ }))
20
+
21
+ describe("RobotAnimator", () => {
22
+ it("should export the component correctly", () => {
23
+ expect(RobotAnimator).toBeDefined()
24
+ expect(typeof RobotAnimator).toBe("function")
25
+ })
26
+
27
+ it("should handle props with different numbers of joints", () => {
28
+ // Test that the component accepts different numbers of DH parameters
29
+ const mockMotionState4Joints: MotionGroupStateResponse = {
30
+ state: {
31
+ joint_position: {
32
+ joints: [0.1, 0.2, 0.3, 0.4],
33
+ },
34
+ },
35
+ } as any
36
+
37
+ const mockDHParameters4Joints: DHParameter[] = [
38
+ { theta: 0, reverse_rotation_direction: false },
39
+ { theta: 0, reverse_rotation_direction: false },
40
+ { theta: 0, reverse_rotation_direction: false },
41
+ { theta: 0, reverse_rotation_direction: false },
42
+ ]
43
+
44
+ const mockMotionState7Joints: MotionGroupStateResponse = {
45
+ state: {
46
+ joint_position: {
47
+ joints: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7],
48
+ },
49
+ },
50
+ } as any
51
+
52
+ const mockDHParameters7Joints: DHParameter[] = Array(7).fill({
53
+ theta: 0,
54
+ reverse_rotation_direction: false,
55
+ })
56
+
57
+ // These should not throw TypeScript errors
58
+ expect(() => {
59
+ const props4 = {
60
+ rapidlyChangingMotionState: mockMotionState4Joints,
61
+ dhParameters: mockDHParameters4Joints,
62
+ children: null,
63
+ }
64
+ // Verify props are correctly typed
65
+ expect(props4.dhParameters).toHaveLength(4)
66
+ expect(
67
+ props4.rapidlyChangingMotionState.state.joint_position.joints,
68
+ ).toHaveLength(4)
69
+ }).not.toThrow()
70
+
71
+ expect(() => {
72
+ const props7 = {
73
+ rapidlyChangingMotionState: mockMotionState7Joints,
74
+ dhParameters: mockDHParameters7Joints,
75
+ children: null,
76
+ }
77
+ expect(props7.dhParameters).toHaveLength(7)
78
+ expect(
79
+ props7.rapidlyChangingMotionState.state.joint_position.joints,
80
+ ).toHaveLength(7)
81
+ }).not.toThrow()
82
+ })
83
+
84
+ it("should use custom interpolation for smooth value transitions", () => {
85
+ // Test the rotation calculation logic
86
+ const dhParam1 = { theta: 0.1, reverse_rotation_direction: false }
87
+ const dhParam2 = { theta: -0.2, reverse_rotation_direction: true }
88
+ const jointValue1 = 0.5
89
+ const jointValue2 = 1.0
90
+
91
+ // Calculate expected rotations
92
+ const expectedRotation1 = 1 * jointValue1 + 0.1 // 0.6
93
+ const expectedRotation2 = -1 * jointValue2 + -0.2 // -1.2
94
+
95
+ expect(expectedRotation1).toBe(0.6)
96
+ expect(expectedRotation2).toBe(-1.2)
97
+
98
+ // Test edge cases
99
+ const dhParamReverse = { theta: 0, reverse_rotation_direction: true }
100
+ const jointValueZero = 0
101
+ const expectedRotationReverse = -1 * jointValueZero + 0 // 0
102
+
103
+ expect(expectedRotationReverse).toBe(0)
104
+
105
+ // Test rotation direction logic
106
+ const testValue = 1.5
107
+ const normalParam = { theta: 0, reverse_rotation_direction: false }
108
+ const reversedParam = { theta: 0, reverse_rotation_direction: true }
109
+
110
+ expect(1 * testValue + 0).toBe(1.5) // Normal direction
111
+ expect(-1 * testValue + 0).toBe(-1.5) // Reversed direction
112
+ })
113
+ })
@@ -1,12 +1,12 @@
1
- import { Globals, useSpring } from "@react-spring/three"
2
- import { useThree } from "@react-three/fiber"
1
+ import { useFrame, useThree } from "@react-three/fiber"
3
2
  import type {
4
3
  DHParameter,
5
4
  MotionGroupStateResponse,
6
5
  } from "@wandelbots/nova-api/v1"
7
- import React, { useRef } from "react"
6
+ import React, { useEffect, useRef } from "react"
8
7
  import type { Group, Object3D } from "three"
9
8
  import { useAutorun } from "../utils/hooks"
9
+ import { ValueInterpolator } from "../utils/interpolation"
10
10
  import { collectJoints } from "./robotModelLogic"
11
11
 
12
12
  type RobotAnimatorProps = {
@@ -22,11 +22,42 @@ export default function RobotAnimator({
22
22
  onRotationChanged,
23
23
  children,
24
24
  }: RobotAnimatorProps) {
25
- Globals.assign({ frameLoop: "always" })
26
25
  const jointValues = useRef<number[]>([])
27
26
  const jointObjects = useRef<Object3D[]>([])
27
+ const interpolatorRef = useRef<ValueInterpolator | null>(null)
28
28
  const { invalidate } = useThree()
29
29
 
30
+ // Initialize interpolator
31
+ useEffect(() => {
32
+ const initialJointValues =
33
+ rapidlyChangingMotionState.state.joint_position.joints.filter(
34
+ (item) => item !== undefined,
35
+ )
36
+
37
+ interpolatorRef.current = new ValueInterpolator(initialJointValues, {
38
+ tension: 120, // Controls spring stiffness - higher values create faster, more responsive motion
39
+ friction: 20, // Controls damping - higher values reduce oscillation and create smoother settling
40
+ threshold: 0.001,
41
+ })
42
+
43
+ return () => {
44
+ interpolatorRef.current?.destroy()
45
+ }
46
+ }, [])
47
+
48
+ // Animation loop that runs at the display's refresh rate
49
+ useFrame((state, delta) => {
50
+ if (interpolatorRef.current) {
51
+ const isComplete = interpolatorRef.current.update(delta)
52
+ setRotation()
53
+
54
+ // Trigger a re-render only if the animation is still running
55
+ if (!isComplete) {
56
+ invalidate()
57
+ }
58
+ }
59
+ })
60
+
30
61
  function setGroupRef(group: Group | null) {
31
62
  if (!group) return
32
63
 
@@ -39,13 +70,11 @@ export default function RobotAnimator({
39
70
 
40
71
  function updateJoints(newJointValues: number[]) {
41
72
  jointValues.current = newJointValues
42
- setSpring.start(Object.assign({}, jointValues.current) as any)
73
+ interpolatorRef.current?.setTarget(newJointValues)
43
74
  }
44
75
 
45
76
  function setRotation() {
46
- const updatedJointValues = jointObjects.current.map((_, objectIndex) =>
47
- (axisValues as any)[objectIndex].get(),
48
- )
77
+ const updatedJointValues = interpolatorRef.current?.getCurrentValues() || []
49
78
 
50
79
  if (onRotationChanged) {
51
80
  onRotationChanged(jointObjects.current, updatedJointValues)
@@ -56,7 +85,7 @@ export default function RobotAnimator({
56
85
  const rotationSign = dhParam.reverse_rotation_direction ? -1 : 1
57
86
 
58
87
  object.rotation.y =
59
- rotationSign * updatedJointValues[index]! + rotationOffset
88
+ rotationSign * (updatedJointValues[index] || 0) + rotationOffset
60
89
  }
61
90
  }
62
91
  }
@@ -70,19 +99,5 @@ export default function RobotAnimator({
70
99
  requestAnimationFrame(() => updateJoints(newJointValues))
71
100
  })
72
101
 
73
- const [axisValues, setSpring] = useSpring(() => ({
74
- ...Object.assign(
75
- {},
76
- rapidlyChangingMotionState.state.joint_position.joints,
77
- ),
78
- onChange: () => {
79
- setRotation()
80
- invalidate()
81
- },
82
- onResolve: () => {
83
- setRotation()
84
- },
85
- }))
86
-
87
102
  return <group ref={setGroupRef}>{children}</group>
88
103
  }
@@ -1,4 +1,4 @@
1
- import type { GroupProps } from "@react-three/fiber"
1
+ import type { ThreeElements } from "@react-three/fiber"
2
2
  import type {
3
3
  DHParameter,
4
4
  MotionGroupStateResponse,
@@ -18,7 +18,7 @@ import { defaultGetModel } from "./robotModelLogic"
18
18
  export type DHRobotProps = {
19
19
  rapidlyChangingMotionState: MotionGroupStateResponse
20
20
  dhParameters: Array<DHParameter>
21
- } & GroupProps
21
+ } & ThreeElements["group"]
22
22
 
23
23
  export type SupportedRobotProps = {
24
24
  rapidlyChangingMotionState: MotionGroupStateResponse
@@ -28,7 +28,7 @@ export type SupportedRobotProps = {
28
28
  getModel?: (modelFromController: string) => string
29
29
  postModelRender?: () => void
30
30
  transparentColor?: string
31
- } & GroupProps
31
+ } & ThreeElements["group"]
32
32
 
33
33
  export const SupportedRobot = externalizeComponent(
34
34
  ({
@@ -20,4 +20,4 @@ export function tryStringifyJson(json: unknown): string | undefined {
20
20
  } catch {
21
21
  return undefined
22
22
  }
23
- }
23
+ }