What's wrong with this script? import os
import time
import numpy as np
from PIL import Image, ImageDraw
import cv2
from moviepy.editor import VideoClip
from moviepy.video.fx.all import fadein, fadeout
from tqdm import tqdm
from functools import partial

# Paths
image_one_path = '/home/daddy/morph/one.jpeg'  # Update with your first image path
image_two_path = '/home/daddy/morph/two.jpeg'  # Update with your second image path
output_path = '/home/daddy/morph/output'       # Update with your desired output directory
output_filename = f'tornado_morph_{int(time.time())}.mp4'

# Ensure output directory exists
os.makedirs(output_path, exist_ok=True)

# Input parameters with default values
duration1 = 3        # Duration of first image display (in seconds)
duration2 = 7        # Duration of tornado formation and movement (in seconds)
duration3 = 5        # Duration of second image display (in seconds)
particle_size = 8    # Size of each particle in pixels
fps = 30             # Frames per second

# Load images and resize to the same dimensions
img1 = Image.open(image_one_path).convert('RGBA').resize((1024, 1024))
img2 = Image.open(image_two_path).convert('RGBA').resize((1024, 1024))

# Convert images to NumPy arrays
img1_array = np.array(img1)
img2_array = np.array(img2)

# Get image dimensions
width, height = img1.size

# Generate particle positions and colors
particles = []

for y in range(0, height, particle_size):
   for x in range(0, width, particle_size):
       # Extract the average color of the particle area
       particle_color = img1_array[y:y+particle_size, x:x+particle_size].mean(axis=(0, 1))
       particles.append({
           'x': x,
           'y': y,
           'color': particle_color,
           'active': True  # Whether the particle is still visible
       })

# Tornado parameters
tornado_height = height * 0.5       # Half the image height
tornado_width_top = width * 0.2     # Width at the top of the tornado
tornado_width_bottom = width * 0.05 # Width at the bottom of the tornado
tornado_start_x = width * 0.2       # Starting X position of the tornado
tornado_start_y = height * 0.25     # Starting Y position (vertically centered)

# Tornado path from left to right
tornado_path = {
   'start_x': tornado_start_x,
   'end_x': width - tornado_start_x,
   'y': tornado_start_y
}

def move_particles_to_tornado(particles, t, total_duration):
   """
   Move particles into a spiral towards the tornado center.
   """
   progress = t / total_duration  # Normalize time to [0, 1]
   for particle in particles:
       if not particle['active']:
           continue

       # Calculate the distance to the tornado center
       dx = tornado_start_x - particle['x']
       dy = tornado_start_y - particle['y']
       distance = np.hypot(dx, dy)

       # Spiral motion parameters
       angle = np.arctan2(dy, dx) + progress * 20  # Adjust the multiplier for spiral speed
       radius = distance * (1 - progress)          # Radius decreases over time

       # New position in the spiral path
       new_x = tornado_start_x + radius * np.cos(angle)
       new_y = tornado_start_y + radius * np.sin(angle)

       # Update particle position
       particle['x'] = new_x
       particle['y'] = new_y

       # Mark particle as inactive if it reaches the center
       if radius < 5:
           particle['active'] = False

def move_tornado_across_screen(t, total_duration):
   """
   Calculate tornado position moving from left to right.
   """
   progress = t / total_duration  # Normalize time to [0, 1]
   tornado_x = tornado_path['start_x'] + progress * (tornado_path['end_x'] - tornado_path['start_x'])
   return tornado_x

def make_frame(t):
   """
   Create each frame of the video at time t.
   """
   # Use the global particles list
   global particles
   frame = Image.new('RGBA', (width, height))
   draw = ImageDraw.Draw(frame)

   # First phase: Display the first image
   if t < duration1:
       frame.paste(img1, (0, 0))

   # Second phase: Particles move into the tornado
   elif t < duration1 + duration2:
       progress = (t - duration1) / duration2
       # Move particles towards the tornado
       move_particles_to_tornado(particles, t - duration1, duration2)
       # Draw particles
       for particle in particles:
           if particle['active']:
               x = int(particle['x'])
               y = int(particle['y'])
               color = tuple(particle['color'].astype(int))
               # Ensure particles are within image bounds
               if 0 <= x < width and 0 <= y < height:
                   draw.rectangle([x, y, x + particle_size, y + particle_size], fill=color)

   # Third phase: Tornado reveals the second image
   else:
       progress = (t - duration1 - duration2) / duration3
       tornado_x = move_tornado_across_screen(t - duration1 - duration2, duration3)

       # Create a mask for the tornado path
       mask = Image.new('L', (width, height), 0)
       mask_draw = ImageDraw.Draw(mask)
       # Define tornado shape (a cone) at the current position
       top_width = tornado_width_top
       bottom_width = tornado_width_bottom
       tornado_height_pixels = int(tornado_height)
       polygon = [
           (tornado_x - top_width / 2, tornado_start_y),
           (tornado_x + top_width / 2, tornado_start_y),
           (tornado_x + bottom_width / 2, tornado_start_y + tornado_height_pixels),
           (tornado_x - bottom_width / 2, tornado_start_y + tornado_height_pixels)
       ]
       mask_draw.polygon(polygon, fill=255)

       # Composite images using the mask
       frame = Image.composite(img2, img1, mask)

       # Optional: Draw the tornado outline (for visualization)
       # draw.polygon(polygon, outline='white')

   # Convert the frame to a NumPy array
   frame_array = np.array(frame.convert('RGB'))
   return frame_array

# Total duration of the video
total_duration = duration1 + duration2 + duration3

# Create the video clip
video_clip = VideoClip(make_frame, duration=total_duration)

# Apply fade-in and fade-out effects
video_clip = fadein(video_clip, 1.5).fx(fadeout, 1.5)

# Full output video path
output_video_path = os.path.join(output_path, output_filename)

# Write the video file
video_clip.write_videofile(output_video_path, fps=fps, codec='libx264')