xwkya
**Is your feature request related to a problem? Please describe.** I recently started using it to showcase a network, and certain buttons trigger an animation. If we need to perform actions on Animation end, it's unreliable to start timeout with durationMs delay as the `cameraPosition()` call can get overridden by another call (user pressing another button). Hence we would be performing the promise resolution of the first `cameraPosition()` call without it being resolved in the end. **Describe the solution you'd like** I have fixed this locally by wrapping camera position inside a Promise based framework with a token generated for each call. - When call occurs to `cameraMovementWrapper`, a token is generated and stored in a state and a `cameraPosition` call occurs. We create a promise, store its reference in the component and return it. - A recursive resolution is called with a loop on animation frames inside the Promise body. If the camera is close to its final position , transition period expired or the associated token does not match the stored token inside the component, the Promise is resolved. We resolve with success if the token matches at Resolution time and reject if token does not match. - From the user perspective, we get a promise resolution and can call subsequent actions or the promise chain is broken and error can be caught. **Note** Let me know if you're interested and accepting contributions. I can submit a PR with the solution you prefer. **Describe alternatives you've considered** Modifying this library, we can use a resolution on the Tween completion, and maybe use a token based approach to camera movement requests and break the promise if another request is performed. **Additional context** Sample code (I work with force-graph-3d) ``` function moveCameraWithPromise(graph, pos, lookAt, transitionMs, token, tolerance = 2) { graph.cameraPosition(pos, lookAt, transitionMs); const startTime = performance.now(); return new Promise((resolve, reject) => { const check = () => { // Invalidate if a new camera action has been requested. if (token !== cameraAnimationTokenRef.current) { reject(new Error('Cancelled')); return; } const elapsed = performance.now() - startTime; const camPos = graph.camera().position; const dx = camPos.x - pos.x; const dy = camPos.y - pos.y; const dz = camPos.z - pos.z; const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); if (distance < tolerance || elapsed >= transitionMs) { resolve(); } else { requestAnimationFrame(check); } }; requestAnimationFrame(check); }); } ```