From 844c8c3366d52029f0aff845052975523fb2b7a6 Mon Sep 17 00:00:00 2001
From: SreeNath14 <153710861+SreeNath14@users.noreply.github.com>
Date: Wed, 2 Apr 2025 11:10:44 +0530
Subject: [PATCH] updated new animation

---
 .../simulation/process/animationWorker.js     |   4 +
 .../simulation/process/processAnimator.tsx    | 149 ++---
 .../simulation/process/processCreator.tsx     | 542 +++++++++++++++---
 3 files changed, 514 insertions(+), 181 deletions(-)
 create mode 100644 app/src/modules/simulation/process/animationWorker.js

diff --git a/app/src/modules/simulation/process/animationWorker.js b/app/src/modules/simulation/process/animationWorker.js
new file mode 100644
index 0000000..e9dddd1
--- /dev/null
+++ b/app/src/modules/simulation/process/animationWorker.js
@@ -0,0 +1,4 @@
+
+const animationWorker = () => {
+  return;
+};
diff --git a/app/src/modules/simulation/process/processAnimator.tsx b/app/src/modules/simulation/process/processAnimator.tsx
index 123ec80..d8e35e6 100644
--- a/app/src/modules/simulation/process/processAnimator.tsx
+++ b/app/src/modules/simulation/process/processAnimator.tsx
@@ -5,11 +5,13 @@ import { useLoader, useFrame } from "@react-three/fiber";
 import * as THREE from "three";
 import { GLTF } from "three-stdlib";
 import boxGltb from "../../../assets/gltf-glb/crate_box.glb";
+import camera from "../../../assets/gltf-glb/camera face 2.gltf";
 
 interface PointAction {
   uuid: string;
   name: string;
   type: "Inherit" | "Spawn" | "Despawn" | "Delay" | "Swap";
+  objectType: string;
   material: string;
   delay: string | number;
   spawnInterval: string | number;
@@ -54,18 +56,8 @@ interface AnimationState {
   currentDelayDuration: number;
   delayComplete: boolean;
   currentPathIndex: number;
-  spawnPoints: Record<
-    string,
-    {
-      position: THREE.Vector3;
-      interval: number;
-      lastSpawnTime: number;
-    }
-  >;
 }
 
-const MAX_SPAWNED_OBJECTS = 20;
-
 const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
   processes,
 }) => {
@@ -76,7 +68,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
   const groupRef = useRef<THREE.Group>(null);
   const meshRef = useRef<THREE.Mesh>(null);
   const [visible, setVisible] = useState(false);
-  const spawnedObjectsRef = useRef<THREE.Object3D[]>([]);
+  const [currentPathIndex, setCurrentPathIndex] = useState(0);
 
   const materials = useMemo(
     () => ({
@@ -125,18 +117,26 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
     currentDelayDuration: 0,
     delayComplete: false,
     currentPathIndex: 0,
-    spawnPoints: {},
   });
 
   const getPointDataForAnimationIndex = (index: number) => {
     if (!processes[0]?.paths) return null;
 
-    if (index < 3) {
-      return processes[0].paths[0]?.points[index];
-    } else {
-      const path2Index = index - 3;
-      return processes[0].paths[1]?.points[path2Index];
+    let cumulativePoints = 0;
+    console.log("cumulativePoints: ", cumulativePoints);
+
+    for (const path of processes[0].paths) {
+      const pointCount = path.points?.length || 0;
+
+      if (index < cumulativePoints + pointCount) {
+        const pointIndex = index - cumulativePoints;
+        return path.points?.[pointIndex] || null;
+      }
+
+      cumulativePoints += pointCount;
     }
+
+    return null;
   };
 
   useEffect(() => {
@@ -152,22 +152,8 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
         currentDelayDuration: 0,
         delayComplete: false,
         currentPathIndex: 0,
-        spawnPoints: {},
       };
 
-      // Clear spawned objects
-      if (groupRef.current) {
-        spawnedObjectsRef.current.forEach((obj) => {
-          if (groupRef.current?.children.includes(obj)) {
-            groupRef.current.remove(obj);
-          }
-          if (obj instanceof THREE.Mesh) {
-            obj.material.dispose();
-          }
-        });
-        spawnedObjectsRef.current = [];
-      }
-
       const currentRef = gltf?.scene ? groupRef.current : meshRef.current;
       if (currentRef && animationPath.length > 0) {
         currentRef.position.copy(animationPath[0]);
@@ -178,15 +164,9 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
   }, [isPlaying, currentProcess, animationPath]);
 
   const handleMaterialSwap = (materialType: string) => {
-    const newMaterial =
-      materials[materialType as keyof typeof materials] || materials.Default;
-    setCurrentMaterial(newMaterial);
-
-    spawnedObjectsRef.current.forEach((obj) => {
-      if (obj instanceof THREE.Mesh) {
-        obj.material = newMaterial.clone();
-      }
-    });
+    setCurrentMaterial(
+      materials[materialType as keyof typeof materials] || materials.Default
+    );
   };
 
   const hasNonInheritActions = (actions: PointAction[] = []) => {
@@ -195,8 +175,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
 
   const handlePointActions = (
     actions: PointAction[] = [],
-    currentTime: number,
-    currentPosition: THREE.Vector3
+    currentTime: number
   ) => {
     let shouldStopAnimation = false;
 
@@ -231,18 +210,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
           break;
 
         case "Spawn":
-          const spawnInterval =
-            typeof action.spawnInterval === "number"
-              ? action.spawnInterval
-              : parseFloat(action.spawnInterval as string) || 1;
-
-          const positionKey = currentPosition.toArray().join(",");
-
-          animationStateRef.current.spawnPoints[positionKey] = {
-            position: currentPosition.clone(),
-            interval: spawnInterval,
-            lastSpawnTime: currentTime - spawnInterval, // Force immediate spawn
-          };
+          setVisible(true);
           break;
 
         case "Swap":
@@ -252,6 +220,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
           break;
 
         case "Inherit":
+          // Handle inherit logic if needed
           break;
       }
     });
@@ -273,24 +242,38 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
     const path = animationPath;
     const stateRef = animationStateRef.current;
 
+    // Check if we need to switch paths (specific to your structure)
     if (stateRef.currentIndex === 3 && stateRef.currentPathIndex === 0) {
+      setCurrentPathIndex(1);
       stateRef.currentPathIndex = 1;
     }
 
+    // Get the current point data
     const currentPointData = getPointDataForAnimationIndex(
       stateRef.currentIndex
     );
 
+    // Execute actions when we first arrive at a point
+
     if (stateRef.progress === 0 && currentPointData?.actions) {
+      console.log(
+        `Processing actions at point ${stateRef.currentIndex}`,
+        currentPointData.actions
+      );
       const shouldStop = handlePointActions(
         currentPointData.actions,
-        currentTime,
-        currentRef.position
+        currentTime
       );
       if (shouldStop) return;
     }
 
+    // Handle delays
     if (stateRef.isDelaying) {
+      console.log(
+        `Delaying... ${currentTime - stateRef.delayStartTime}/${
+          stateRef.currentDelayDuration
+        }`
+      );
       if (
         currentTime - stateRef.delayStartTime >=
         stateRef.currentDelayDuration
@@ -298,46 +281,10 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
         stateRef.isDelaying = false;
         stateRef.delayComplete = true;
       } else {
-        return;
+        return; // Keep waiting
       }
     }
 
-    // Handle spawning - this is the key updated part
-    Object.entries(stateRef.spawnPoints).forEach(([key, spawnPoint]) => {
-      if (currentTime - spawnPoint.lastSpawnTime >= spawnPoint.interval) {
-        spawnPoint.lastSpawnTime = currentTime;
-
-        if (gltf?.scene && groupRef?.current) {
-          const newObject = gltf.scene.clone();
-          newObject.position.copy(spawnPoint.position);
-
-          newObject.traverse((child) => {
-            if (child instanceof THREE.Mesh) {
-              child.material = currentMaterial.clone();
-            }
-          });
-
-          groupRef.current.add(newObject);
-          spawnedObjectsRef.current.push(newObject);
-
-          // Clean up old objects if needed
-          console.log(
-            "spawnedObjectsRef.current.length: ",
-            spawnedObjectsRef.current.length
-          );
-          if (spawnedObjectsRef.current.length > MAX_SPAWNED_OBJECTS) {
-            const oldest = spawnedObjectsRef.current.shift();
-            if (oldest && groupRef.current.children.includes(oldest)) {
-              groupRef.current.remove(oldest);
-              if (oldest instanceof THREE.Mesh) {
-                oldest.material.dispose();
-              }
-            }
-          }
-        }
-      }
-    });
-
     const nextPointIdx = stateRef.currentIndex + 1;
     const isLastPoint = nextPointIdx >= path.length;
 
@@ -374,22 +321,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
     }
   });
 
-  useEffect(() => {
-    return () => {
-      if (groupRef.current) {
-        spawnedObjectsRef.current.forEach((obj) => {
-          if (groupRef.current?.children.includes(obj)) {
-            groupRef.current.remove(obj);
-          }
-          if (obj instanceof THREE.Mesh) {
-            obj.material.dispose();
-          }
-        });
-        spawnedObjectsRef.current = [];
-      }
-    };
-  }, []);
-
   if (!processes || processes.length === 0) {
     return null;
   }
diff --git a/app/src/modules/simulation/process/processCreator.tsx b/app/src/modules/simulation/process/processCreator.tsx
index 8e1ed1d..e70408b 100644
--- a/app/src/modules/simulation/process/processCreator.tsx
+++ b/app/src/modules/simulation/process/processCreator.tsx
@@ -1,3 +1,402 @@
+// import React, {
+//   useEffect,
+//   useMemo,
+//   useState,
+//   useCallback,
+//   useRef,
+// } from "react";
+// import { useSimulationPaths } from "../../../store/store";
+// import * as THREE from "three";
+// import { useThree } from "@react-three/fiber";
+// import {
+//   ConveyorEventsSchema,
+//   VehicleEventsSchema,
+// } from "../../../types/world/worldTypes";
+
+// // Type definitions
+// export interface PointAction {
+//   uuid: string;
+//   name: string;
+//   type: string;
+//   material: string;
+//   delay: number | string;
+//   spawnInterval: string | number;
+//   isUsed: boolean;
+// }
+
+// export interface PathPoint {
+//   uuid: string;
+//   position: [number, number, number];
+//   actions: PointAction[];
+//   connections: {
+//     targets: Array<{ pathUUID: string }>;
+//   };
+// }
+
+// export interface SimulationPath {
+//   modeluuid: string;
+//   points: PathPoint[];
+//   pathPosition: [number, number, number];
+//   speed?: number;
+// }
+
+// export interface Process {
+//   id: string;
+//   paths: SimulationPath[];
+//   animationPath: THREE.Vector3[];
+//   pointActions: PointAction[][];
+//   speed: number;
+// }
+
+// interface ProcessCreatorProps {
+//   onProcessesCreated: (processes: Process[]) => void;
+// }
+
+// // Convert event schemas to SimulationPath
+// function convertToSimulationPath(
+//   path: ConveyorEventsSchema | VehicleEventsSchema
+// ): SimulationPath {
+//   const { modeluuid } = path;
+
+//   // Simplified normalizeAction function that preserves exact original properties
+//   const normalizeAction = (action: any): PointAction => {
+//     return { ...action }; // Return exact copy with no modifications
+//   };
+
+//   if (path.type === "Conveyor") {
+//     return {
+//       modeluuid,
+//       points: path.points.map((point) => ({
+//         uuid: point.uuid,
+//         position: point.position,
+//         actions: point.actions.map(normalizeAction), // Preserve exact actions
+//         connections: {
+//           targets: point.connections.targets.map((target) => ({
+//             pathUUID: target.pathUUID,
+//           })),
+//         },
+//       })),
+//       pathPosition: path.position,
+//       speed:
+//         typeof path.speed === "string"
+//           ? parseFloat(path.speed) || 1
+//           : path.speed || 1,
+//     };
+//   } else {
+//     return {
+//       modeluuid,
+//       points: [
+//         {
+//           uuid: path.point.uuid,
+//           position: path.point.position,
+//           actions: Array.isArray(path.point.actions)
+//             ? path.point.actions.map(normalizeAction)
+//             : [normalizeAction(path.point.actions)],
+//           connections: {
+//             targets: path.point.connections.targets.map((target) => ({
+//               pathUUID: target.pathUUID,
+//             })),
+//           },
+//         },
+//       ],
+//       pathPosition: path.position,
+//       speed: path.point.speed || 1,
+//     };
+//   }
+// }
+
+// // Custom shallow comparison for arrays
+// const areArraysEqual = (a: any[], b: any[]) => {
+//   if (a.length !== b.length) return false;
+//   for (let i = 0; i < a.length; i++) {
+//     if (a[i] !== b[i]) return false;
+//   }
+//   return true;
+// };
+
+// // Helper function to create an empty process
+// const createEmptyProcess = (): Process => ({
+//   id: `process-${Math.random().toString(36).substring(2, 11)}`,
+//   paths: [],
+//   animationPath: [],
+//   pointActions: [],
+//   speed: 1,
+// });
+
+// // Enhanced connection checking function
+// function shouldReverseNextPath(
+//   currentPath: SimulationPath,
+//   nextPath: SimulationPath
+// ): boolean {
+//   if (nextPath.points.length !== 3) return false;
+
+//   const currentLastPoint = currentPath.points[currentPath.points.length - 1];
+//   const nextFirstPoint = nextPath.points[0];
+//   const nextLastPoint = nextPath.points[nextPath.points.length - 1];
+
+//   // Check if current last connects to next last (requires reversal)
+//   const connectsToLast = currentLastPoint.connections.targets.some(
+//     (target) =>
+//       target.pathUUID === nextPath.modeluuid &&
+//       nextLastPoint.connections.targets.some(
+//         (t) => t.pathUUID === currentPath.modeluuid
+//       )
+//   );
+
+//   // Check if current last connects to next first (no reversal needed)
+//   const connectsToFirst = currentLastPoint.connections.targets.some(
+//     (target) =>
+//       target.pathUUID === nextPath.modeluuid &&
+//       nextFirstPoint.connections.targets.some(
+//         (t) => t.pathUUID === currentPath.modeluuid
+//       )
+//   );
+
+//   // Only reverse if connected to last point and not to first point
+//   return connectsToLast && !connectsToFirst;
+// }
+
+// // Updated path adjustment function
+// function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
+//   if (paths.length < 2) return paths;
+
+//   const adjustedPaths = [...paths];
+
+//   for (let i = 0; i < adjustedPaths.length - 1; i++) {
+//     const currentPath = adjustedPaths[i];
+//     const nextPath = adjustedPaths[i + 1];
+
+//     if (shouldReverseNextPath(currentPath, nextPath)) {
+//       const reversedPoints = [
+//         nextPath.points[2],
+//         nextPath.points[1],
+//         nextPath.points[0],
+//       ];
+
+//       adjustedPaths[i + 1] = {
+//         ...nextPath,
+//         points: reversedPoints,
+//       };
+//     }
+//   }
+
+//   return adjustedPaths;
+// }
+
+// // Main hook for process creation
+// export function useProcessCreation() {
+//   const { scene } = useThree();
+//   const [processes, setProcesses] = useState<Process[]>([]);
+
+//   const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
+//     return path.points.some((point) =>
+//       point.actions.some((action) => action.type.toLowerCase() === "spawn")
+//     );
+//   }, []);
+
+//   const createProcess = useCallback(
+//     (paths: SimulationPath[]): Process => {
+//       if (!paths || paths.length === 0) {
+//         return createEmptyProcess();
+//       }
+
+//       const animationPath: THREE.Vector3[] = [];
+//       const pointActions: PointAction[][] = [];
+//       const processSpeed = paths[0]?.speed || 1;
+
+//       for (const path of paths) {
+//         for (const point of path.points) {
+//           const obj = scene.getObjectByProperty("uuid", point.uuid);
+//           if (!obj) {
+//             console.warn(`Object with UUID ${point.uuid} not found in scene`);
+//             continue;
+//           }
+
+//           const position = obj.getWorldPosition(new THREE.Vector3());
+//           animationPath.push(position.clone());
+//           pointActions.push(point.actions);
+//         }
+//       }
+
+//       return {
+//         id: `process-${Math.random().toString(36).substring(2, 11)}`,
+//         paths,
+//         animationPath,
+//         pointActions,
+//         speed: processSpeed,
+//       };
+//     },
+//     [scene]
+//   );
+
+//   const getAllConnectedPaths = useCallback(
+//     (
+//       initialPath: SimulationPath,
+//       allPaths: SimulationPath[],
+//       visited: Set<string> = new Set()
+//     ): SimulationPath[] => {
+//       const connectedPaths: SimulationPath[] = [];
+//       const queue: SimulationPath[] = [initialPath];
+//       visited.add(initialPath.modeluuid);
+
+//       const pathMap = new Map<string, SimulationPath>();
+//       allPaths.forEach((path) => pathMap.set(path.modeluuid, path));
+
+//       while (queue.length > 0) {
+//         const currentPath = queue.shift()!;
+//         connectedPaths.push(currentPath);
+
+//         // Process outgoing connections
+//         for (const point of currentPath.points) {
+//           for (const target of point.connections.targets) {
+//             if (!visited.has(target.pathUUID)) {
+//               const targetPath = pathMap.get(target.pathUUID);
+//               if (targetPath) {
+//                 visited.add(target.pathUUID);
+//                 queue.push(targetPath);
+//               }
+//             }
+//           }
+//         }
+
+//         // Process incoming connections
+//         for (const [uuid, path] of pathMap) {
+//           if (!visited.has(uuid)) {
+//             const hasConnectionToCurrent = path.points.some((point) =>
+//               point.connections.targets.some(
+//                 (t) => t.pathUUID === currentPath.modeluuid
+//               )
+//             );
+//             if (hasConnectionToCurrent) {
+//               visited.add(uuid);
+//               queue.push(path);
+//             }
+//           }
+//         }
+//       }
+
+//       return connectedPaths;
+//     },
+//     []
+//   );
+
+//   const createProcessesFromPaths = useCallback(
+//     (paths: SimulationPath[]): Process[] => {
+//       if (!paths || paths.length === 0) return [];
+
+//       const visited = new Set<string>();
+//       const processes: Process[] = [];
+//       const pathMap = new Map<string, SimulationPath>();
+//       paths.forEach((path) => pathMap.set(path.modeluuid, path));
+
+//       for (const path of paths) {
+//         if (!visited.has(path.modeluuid) && hasSpawnAction(path)) {
+//           const connectedPaths = getAllConnectedPaths(path, paths, visited);
+//           const adjustedPaths = adjustPathPointsOrder(connectedPaths);
+//           const process = createProcess(adjustedPaths);
+//           processes.push(process);
+//         }
+//       }
+
+//       return processes;
+//     },
+//     [createProcess, getAllConnectedPaths, hasSpawnAction]
+//   );
+
+//   return {
+//     processes,
+//     createProcessesFromPaths,
+//     setProcesses,
+//   };
+// }
+
+// const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
+//   ({ onProcessesCreated }) => {
+//     const { simulationPaths } = useSimulationPaths();
+//     const { createProcessesFromPaths } = useProcessCreation();
+//     const prevPathsRef = useRef<SimulationPath[]>([]);
+//     const prevProcessesRef = useRef<Process[]>([]);
+
+//     const convertedPaths = useMemo((): SimulationPath[] => {
+//       if (!simulationPaths) return [];
+//       return simulationPaths.map((path) =>
+//         convertToSimulationPath(
+//           path as ConveyorEventsSchema | VehicleEventsSchema
+//         )
+//       );
+//     }, [simulationPaths]);
+
+//     const pathsDependency = useMemo(() => {
+//       if (!convertedPaths) return null;
+//       return convertedPaths.map((path) => ({
+//         id: path.modeluuid,
+//         hasSpawn: path.points.some((p: PathPoint) =>
+//           p.actions.some((a: PointAction) => a.type.toLowerCase() === "spawn")
+//         ),
+//         connections: path.points
+//           .flatMap((p: PathPoint) =>
+//             p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
+//           )
+//           .join(","),
+//       }));
+//     }, [convertedPaths]);
+
+//     useEffect(() => {
+//       if (!convertedPaths || convertedPaths.length === 0) {
+//         if (prevProcessesRef.current.length > 0) {
+//           onProcessesCreated([]);
+//           prevProcessesRef.current = [];
+//         }
+//         return;
+//       }
+
+//       if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
+//         return;
+//       }
+
+//       prevPathsRef.current = convertedPaths;
+//       const newProcesses = createProcessesFromPaths(convertedPaths);
+
+//       // console.log("--- Action Types in Paths ---");
+//       // convertedPaths.forEach((path) => {
+//       //   path.points.forEach((point) => {
+//       //     point.actions.forEach((action) => {
+//       //       console.log(
+//       //         `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
+//       //       );
+//       //     });
+//       //   });
+//       // });
+//       // console.log("New processes:", newProcesses);
+
+//       if (
+//         newProcesses.length !== prevProcessesRef.current.length ||
+//         !newProcesses.every(
+//           (proc, i) =>
+//             proc.paths.length === prevProcessesRef.current[i]?.paths.length &&
+//             proc.paths.every(
+//               (path, j) =>
+//                 path.modeluuid ===
+//                 prevProcessesRef.current[i]?.paths[j]?.modeluuid
+//             )
+//         )
+//       ) {
+//         onProcessesCreated(newProcesses);
+//         // prevProcessesRef.current = newProcesses;
+//       }
+//     }, [
+//       pathsDependency,
+//       onProcessesCreated,
+//       convertedPaths,
+//       createProcessesFromPaths,
+//     ]);
+
+//     return null;
+//   }
+// );
+
+// export default ProcessCreator;
+
 import React, {
   useEffect,
   useMemo,
@@ -23,7 +422,6 @@ export interface PointAction {
   spawnInterval: string | number;
   isUsed: boolean;
 }
-
 export interface PathPoint {
   uuid: string;
   position: [number, number, number];
@@ -32,14 +430,12 @@ export interface PathPoint {
     targets: Array<{ pathUUID: string }>;
   };
 }
-
 export interface SimulationPath {
   modeluuid: string;
   points: PathPoint[];
   pathPosition: [number, number, number];
   speed?: number;
 }
-
 export interface Process {
   id: string;
   paths: SimulationPath[];
@@ -47,7 +443,6 @@ export interface Process {
   pointActions: PointAction[][];
   speed: number;
 }
-
 interface ProcessCreatorProps {
   onProcessesCreated: (processes: Process[]) => void;
 }
@@ -58,51 +453,83 @@ function convertToSimulationPath(
 ): SimulationPath {
   const { modeluuid } = path;
 
-  // Simplified normalizeAction function that preserves exact original properties
+  // Helper function to normalize actions
   const normalizeAction = (action: any): PointAction => {
     return { ...action }; // Return exact copy with no modifications
   };
 
+  // Extract points from the path
+  let points: PathPoint[];
   if (path.type === "Conveyor") {
-    return {
-      modeluuid,
-      points: path.points.map((point) => ({
-        uuid: point.uuid,
-        position: point.position,
-        actions: point.actions.map(normalizeAction), // Preserve exact actions
+    points = path.points.map((point) => ({
+      uuid: point.uuid,
+      position: point.position,
+      actions: point.actions.map(normalizeAction), // Preserve exact actions
+      connections: {
+        targets: point.connections.targets.map((target) => ({
+          pathUUID: target.pathUUID,
+        })),
+      },
+    }));
+  } else {
+    points = [
+      {
+        uuid: path.point.uuid,
+        position: path.point.position,
+        actions: Array.isArray(path.point.actions)
+          ? path.point.actions.map(normalizeAction)
+          : [normalizeAction(path.point.actions)],
         connections: {
-          targets: point.connections.targets.map((target) => ({
+          targets: path.point.connections.targets.map((target) => ({
             pathUUID: target.pathUUID,
           })),
         },
-      })),
-      pathPosition: path.position,
-      speed:
-        typeof path.speed === "string"
-          ? parseFloat(path.speed) || 1
-          : path.speed || 1,
-    };
-  } else {
-    return {
-      modeluuid,
-      points: [
-        {
-          uuid: path.point.uuid,
-          position: path.point.position,
-          actions: Array.isArray(path.point.actions)
-            ? path.point.actions.map(normalizeAction)
-            : [normalizeAction(path.point.actions)],
-          connections: {
-            targets: path.point.connections.targets.map((target) => ({
-              pathUUID: target.pathUUID,
-            })),
-          },
-        },
-      ],
-      pathPosition: path.position,
-      speed: path.point.speed || 1,
-    };
+      },
+    ];
   }
+
+  // Check if point 1 or point 2 has a spawn action
+  const hasSpawnInFirstTwoPoints =
+    points.length >= 2 &&
+    (points[0].actions.some(
+      (action) => action.type.toLowerCase() === "spawn"
+    ) ||
+      points[1].actions.some(
+        (action) => action.type.toLowerCase() === "spawn"
+      ));
+
+  // Swap points 1 and 3 only if:
+  // 1. There are at least three points,
+  // 2. The third point contains a spawn action, and
+  // 3. Neither point 1 nor point 2 has a spawn action
+  if (
+    !hasSpawnInFirstTwoPoints &&
+    points.length >= 3 &&
+    points[2].actions.some((action) => action.type.toLowerCase() === "spawn")
+  ) {
+    const temp = points[0];
+    points[0] = points[2];
+    points[2] = temp;
+  }
+
+  // Determine the speed based on the type of path
+  let speed: number;
+  if (path.type === "Conveyor") {
+    speed =
+      typeof path.speed === "string"
+        ? parseFloat(path.speed) || 1
+        : path.speed || 1;
+  } else {
+    // For VehicleEventsSchema, use a default speed of 1
+    speed = 1;
+  }
+
+  return {
+    modeluuid,
+    points,
+    pathPosition: path.position,
+    speed,
+  };
 }
 
 // Custom shallow comparison for arrays
@@ -129,7 +556,6 @@ function shouldReverseNextPath(
   nextPath: SimulationPath
 ): boolean {
   if (nextPath.points.length !== 3) return false;
-
   const currentLastPoint = currentPath.points[currentPath.points.length - 1];
   const nextFirstPoint = nextPath.points[0];
   const nextLastPoint = nextPath.points[nextPath.points.length - 1];
@@ -159,27 +585,22 @@ function shouldReverseNextPath(
 // Updated path adjustment function
 function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
   if (paths.length < 2) return paths;
-
   const adjustedPaths = [...paths];
-
   for (let i = 0; i < adjustedPaths.length - 1; i++) {
     const currentPath = adjustedPaths[i];
     const nextPath = adjustedPaths[i + 1];
-
     if (shouldReverseNextPath(currentPath, nextPath)) {
       const reversedPoints = [
         nextPath.points[2],
         nextPath.points[1],
         nextPath.points[0],
       ];
-
       adjustedPaths[i + 1] = {
         ...nextPath,
         points: reversedPoints,
       };
     }
   }
-
   return adjustedPaths;
 }
 
@@ -187,7 +608,6 @@ function adjustPathPointsOrder(paths: SimulationPath[]): SimulationPath[] {
 export function useProcessCreation() {
   const { scene } = useThree();
   const [processes, setProcesses] = useState<Process[]>([]);
-
   const hasSpawnAction = useCallback((path: SimulationPath): boolean => {
     return path.points.some((point) =>
       point.actions.some((action) => action.type.toLowerCase() === "spawn")
@@ -199,11 +619,9 @@ export function useProcessCreation() {
       if (!paths || paths.length === 0) {
         return createEmptyProcess();
       }
-
       const animationPath: THREE.Vector3[] = [];
       const pointActions: PointAction[][] = [];
       const processSpeed = paths[0]?.speed || 1;
-
       for (const path of paths) {
         for (const point of path.points) {
           const obj = scene.getObjectByProperty("uuid", point.uuid);
@@ -211,13 +629,11 @@ export function useProcessCreation() {
             console.warn(`Object with UUID ${point.uuid} not found in scene`);
             continue;
           }
-
           const position = obj.getWorldPosition(new THREE.Vector3());
           animationPath.push(position.clone());
           pointActions.push(point.actions);
         }
       }
-
       return {
         id: `process-${Math.random().toString(36).substring(2, 11)}`,
         paths,
@@ -238,10 +654,8 @@ export function useProcessCreation() {
       const connectedPaths: SimulationPath[] = [];
       const queue: SimulationPath[] = [initialPath];
       visited.add(initialPath.modeluuid);
-
       const pathMap = new Map<string, SimulationPath>();
       allPaths.forEach((path) => pathMap.set(path.modeluuid, path));
-
       while (queue.length > 0) {
         const currentPath = queue.shift()!;
         connectedPaths.push(currentPath);
@@ -274,7 +688,6 @@ export function useProcessCreation() {
           }
         }
       }
-
       return connectedPaths;
     },
     []
@@ -283,12 +696,10 @@ export function useProcessCreation() {
   const createProcessesFromPaths = useCallback(
     (paths: SimulationPath[]): Process[] => {
       if (!paths || paths.length === 0) return [];
-
       const visited = new Set<string>();
       const processes: Process[] = [];
       const pathMap = new Map<string, SimulationPath>();
       paths.forEach((path) => pathMap.set(path.modeluuid, path));
-
       for (const path of paths) {
         if (!visited.has(path.modeluuid) && hasSpawnAction(path)) {
           const connectedPaths = getAllConnectedPaths(path, paths, visited);
@@ -297,7 +708,6 @@ export function useProcessCreation() {
           processes.push(process);
         }
       }
-
       return processes;
     },
     [createProcess, getAllConnectedPaths, hasSpawnAction]
@@ -338,6 +748,9 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
             p.connections.targets.map((t: { pathUUID: string }) => t.pathUUID)
           )
           .join(","),
+        actions: JSON.stringify(
+          path.points.flatMap((p: PathPoint) => p.actions)
+        ), // Serialize all actions
       }));
     }, [convertedPaths]);
 
@@ -349,26 +762,11 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
         }
         return;
       }
-
       if (areArraysEqual(prevPathsRef.current, convertedPaths)) {
         return;
       }
-
       prevPathsRef.current = convertedPaths;
       const newProcesses = createProcessesFromPaths(convertedPaths);
-
-      // console.log("--- Action Types in Paths ---");
-      // convertedPaths.forEach((path) => {
-      //   path.points.forEach((point) => {
-      //     point.actions.forEach((action) => {
-      //       console.log(
-      //         `Path ${path.modeluuid}, Point ${point.uuid}: ${action.type}`
-      //       );
-      //     });
-      //   });
-      // });
-      // console.log("New processes:", newProcesses);
-
       if (
         newProcesses.length !== prevProcessesRef.current.length ||
         !newProcesses.every(
@@ -382,7 +780,7 @@ const ProcessCreator: React.FC<ProcessCreatorProps> = React.memo(
         )
       ) {
         onProcessesCreated(newProcesses);
-        // prevProcessesRef.current = newProcesses;
+        prevProcessesRef.current = newProcesses;
       }
     }, [
       pathsDependency,