Regènère mon script en inclinant les walls vers l'intérieur, ajoute la son bounce.wav à chaque collision et note la couleur du gagnant à la fin et fait fonctionner les émojis car actuellement ils s'affichent en carré => □

```python
import pygame
import random
import math
import cv2
import numpy as np
import os
from datetime import datetime

class MazeBallRaceGenerator:
    def __init__(self):
        # Configuration vidéo
        self.WIDTH = 1080
        self.HEIGHT = 1920  # Format TikTok (9:16)
        self.FPS = 60
        self.DURATION = 20  # Plus d'1 minute pour inclure le ralenti
        self.TOTAL_FRAMES = self.FPS * self.DURATION
        
        # Couleurs personnalisables des balles (facile à modifier)
        self.BALL_COLORS = {
            "Rouge": (255, 87, 87),
            "Vert": (87, 255, 87),
            "Bleu": (87, 87, 255),
            "Jaune": (255, 255, 87),
            "Rose": (255, 87, 255),
            "Cyan": (87, 255, 255),
            "Orange": (255, 165, 0),
            "Violet": (147, 112, 219),
            "Blanc": (255, 255, 255),
            "Or": (255, 215, 0)
        }
        
        # Textes d'engagement
        self.intro_text = "Quelle sera la balle qui arrivera en premier ?"
        self.intro_text2 = "Note ta couleur en commentaire ! 👇"
        self.outro_text = "Abonne-toi pour demander des couleurs personnalisées ! ❤️"
        
        # Variables de course
        self.balls = []
        self.maze_walls = []
        self.obstacles = []
        self.particles = []
        self.finish_line_y = 1750
        self.race_started = False
        self.race_finished = False
        self.winner = None
        self.slowmo_start = None
        self.fireworks = []
        
        # État du jeu
        self.current_text = ""
        self.text_timer = 0
        self.background_color = (15, 15, 25)
        
        # Audio (simulation - dans une vraie implémentation, utilisez pygame.mixer)
        self.collision_sounds = []
        
    def create_ball(self, x, y, color_name, color):
        """Crée une balle de course"""
        return {
            'x': x,
            'y': y,
            'vx': 0,
            'vy': 0,
            'radius': 25,
            'color': color,
            'color_name': color_name,
            'trail': [],
            'speed': random.uniform(2.5, 4.0),  # Vitesse de base aléatoire
            'boost': 1.0,
            'stuck_timer': 0,
            'distance_traveled': 0,
            'finished': False,
            'finish_time': None
        }
    
    def create_maze(self):
        """Crée un labyrinthe en entonnoir avec murs inclinés vers l'intérieur à 30°"""
        walls = []
        
        # Murs extérieurs
        walls.append({'x': 0, 'y': 0, 'width': self.WIDTH, 'height': 20})  # Haut
        walls.append({'x': 0, 'y': 0, 'width': 20, 'height': self.HEIGHT})  # Gauche
        walls.append({'x': self.WIDTH-20, 'y': 0, 'width': 20, 'height': self.HEIGHT})  # Droite
        
        # Système d'entonnoir progressif avec murs inclinés vers l'intérieur
        wall_thickness = 25
        angle_offset = 30  # Décalage pour simuler l'inclinaison de 30°
        
        # Niveau 1 - Larges ouvertures (5 chemins) - inclinés vers l'intérieur
        y = 350
        wall_width = 150
        for i in range(4):
            base_x = 50 + i * 250
            if base_x + wall_width < self.WIDTH - 50:
                # Mur incliné : plus large en haut, plus étroit en bas
                walls.append({
                    'x': base_x + angle_offset, 
                    'y': y, 
                    'width': wall_width - (angle_offset * 2), 
                    'height': wall_thickness, 
                    'type': 'angled_funnel'
                })
        
        # Niveau 2 - Se resserre légèrement (4 chemins) - plus inclinés
        y = 550
        wall_width = 170
        angle_offset = 35
        for i in range(3):
            base_x = 100 + i * 280
            if base_x + wall_width < self.WIDTH - 100:
                walls.append({
                    'x': base_x + angle_offset, 
                    'y': y, 
                    'width': wall_width - (angle_offset * 2), 
                    'height': wall_thickness, 
                    'type': 'angled_funnel'
                })
        
        # Niveau 3 - Plus étroit (3 chemins larges) - encore plus inclinés
        y = 750
        wall_width = 200
        angle_offset = 40
        positions = [50, 400, 750]
        for base_x in positions:
            walls.append({
                'x': base_x + angle_offset, 
                'y': y, 
                'width': wall_width - (angle_offset * 2), 
                'height': wall_thickness, 
                'type': 'angled_funnel'
            })
        
        # Niveau 4 - Entonnoir modéré (2 passages) - très inclinés
        y = 950
        wall_width = 250
        angle_offset = 50
        positions = [100, 650]
        for base_x in positions:
            walls.append({
                'x': base_x + angle_offset, 
                'y': y, 
                'width': wall_width - (angle_offset * 2), 
                'height': wall_thickness, 
                'type': 'angled_funnel'
            })
        
        # Niveau 5 - Se concentre vers le centre - maximum d'inclinaison
        y = 1150
        wall_width = 200
        angle_offset = 60
        positions = [150, 650]
        for base_x in positions:
            walls.append({
                'x': base_x + angle_offset, 
                'y': y, 
                'width': wall_width - (angle_offset * 2), 
                'height': wall_thickness, 
                'type': 'angled_funnel'
            })
        
        # Niveau 6 - Avant-dernier rétrécissement
        y = 1350
        wall_width = 180
        angle_offset = 65
        positions = [200, 600]
        for base_x in positions:
            walls.append({
                'x': base_x + angle_offset, 
                'y': y, 
                'width': wall_width - (angle_offset * 2), 
                'height': wall_thickness, 
                'type': 'angled_funnel'
            })
        
        # Niveau 7 - Dernier obstacle avant l'arrivée (passage central large)
        y = 1550
        wall_width = 300
        angle_offset = 70
        positions = [50, 650]
        for base_x in positions:
            walls.append({
                'x': base_x + angle_offset, 
                'y': y, 
                'width': wall_width - (angle_offset * 2), 
                'height': wall_thickness, 
                'type': 'angled_funnel'
            })
        
        # Obstacles mobiles moins bloquants (gardés tels quels)
        self.obstacles = [
            {'x': 300, 'y': 450, 'width': 40, 'height': 40, 'vx': 1, 'type': 'moving'},
            {'x': 700, 'y': 650, 'width': 50, 'height': 30, 'vx': -1.2, 'type': 'moving'},
            {'x': 400, 'y': 850, 'width': 35, 'height': 35, 'vy': 0.8, 'type': 'moving'},
        ]
        
        return walls
    
    def create_firework(self, x, y):
        """Crée un feu d'artifice"""
        colors = list(self.BALL_COLORS.values())
        for _ in range(50):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(5, 15)
            self.fireworks.append({
                'x': x,
                'y': y,
                'vx': math.cos(angle) * speed,
                'vy': math.sin(angle) * speed,
                'color': random.choice(colors),
                'life': 60,
                'size': random.randint(3, 8),
                'gravity': random.uniform(0.1, 0.3)
            })
    
    def initialize_race(self):
        """Initialise la course avec les balles"""
        start_y = 200
        colors = list(self.BALL_COLORS.items())
        
        # Crée les balles de course
        for i, (name, color) in enumerate(colors):
            x = 100 + (i * 90)  # Espacement horizontal
            if x > self.WIDTH - 100:  # Deuxième ligne si nécessaire
                x = 100 + ((i - 10) * 90)
                start_y = 250
            
            ball = self.create_ball(x, start_y, name, color)
            self.balls.append(ball)
        
        # Crée le labyrinthe
        self.maze_walls = self.create_maze()
    
    def update_balls_physics(self):
        """Met à jour la physique des balles avec IA améliorée pour éviter les blocages"""
        if not self.race_started:
            return
        
        gravity = 1.2  # Gravité plus forte pour pousser vers le bas
        friction = 0.90
        center_screen = self.WIDTH // 2  # DÉPLACER CETTE LIGNE ICI
        
        for ball in self.balls:
            if ball['finished']:
                continue
                
            # Force principale vers le bas (gravité + biais)
            base_downward_force = ball['speed'] * 1.5
            
            # Détection intelligente des obstacles
            future_x = ball['x']
            future_y = ball['y'] + base_downward_force
            
            blocked_down = False
            blocked_left = False
            blocked_right = False
            
            # Vérifie les collisions avec tous les murs
            for wall in self.maze_walls:
                # Test collision vers le bas
                if (future_x + ball['radius'] > wall['x'] and 
                    future_x - ball['radius'] < wall['x'] + wall['width'] and
                    future_y + ball['radius'] > wall['y'] and 
                    future_y - ball['radius'] < wall['y'] + wall['height']):
                    blocked_down = True
                
                # Test collision vers la gauche
                test_x_left = ball['x'] - ball['speed']
                if (test_x_left + ball['radius'] > wall['x'] and 
                    test_x_left - ball['radius'] < wall['x'] + wall['width'] and
                    ball['y'] + ball['radius'] > wall['y'] and 
                    ball['y'] - ball['radius'] < wall['y'] + wall['height']):
                    blocked_left = True
                
                # Test collision vers la droite
                test_x_right = ball['x'] + ball['speed']
                if (test_x_right + ball['radius'] > wall['x'] and 
                    test_x_right - ball['radius'] < wall['x'] + wall['width'] and
                    ball['y'] + ball['radius'] > wall['y'] and 
                    ball['y'] - ball['radius'] < wall['y'] + wall['height']):
                    blocked_right = True
            
            # Logique de mouvement intelligente
            if not blocked_down:
                # Chemin libre vers le bas - PRIORITÉ ABSOLUE
                ball['vy'] = base_downward_force
                ball['vx'] *= 0.7  # Réduit le mouvement horizontal
                ball['stuck_timer'] = 0
            else:
                # Bloqué vers le bas - cherche un passage latéral
                ball['vy'] = 0.5  # Garde une petite poussée vers le bas
                
                # Trouve le meilleur passage latéral (center_screen est maintenant défini)
                if ball['x'] < center_screen:
                    # Côté gauche - essaie d'aller vers la droite
                    if not blocked_right:
                        ball['vx'] = ball['speed'] * 1.2
                    elif not blocked_left:
                        ball['vx'] = -ball['speed'] * 0.8
                    else:
                        # Complètement bloqué - force le mouvement
                        ball['vx'] = ball['speed'] * random.choice([-1.5, 1.5])
                else:
                    # Côté droit - essaie d'aller vers la gauche
                    if not blocked_left:
                        ball['vx'] = -ball['speed'] * 1.2
                    elif not blocked_right:
                        ball['vx'] = ball['speed'] * 0.8
                    else:
                        # Complètement bloqué - force le mouvement
                        ball['vx'] = ball['speed'] * random.choice([-1.5, 1.5])
                
                ball['stuck_timer'] += 1
            
            # Anti-blocage agressif
            if ball['stuck_timer'] > 60:  # 1 seconde bloqué
                # Téléporte légèrement la balle
                ball['x'] += random.uniform(-50, 50)
                ball['y'] += random.uniform(10, 30)  # Pousse vers le bas
                ball['vx'] = random.uniform(-ball['speed'], ball['speed'])
                ball['vy'] = ball['speed'] * 2
                ball['stuck_timer'] = 0
                print(f"Anti-blocage activé pour balle {ball['color_name']}")
            
            # Suppression de la force centripète - laisse les balles choisir leur chemin naturellement
            
            # Applique le mouvement
            ball['x'] += ball['vx']
            ball['y'] += ball['vy']
            
            # Variabilité pour plus de réalisme
            ball['vx'] += random.uniform(-0.3, 0.3)
            ball['vy'] += random.uniform(-0.2, 0.2)
            
            # Friction
            ball['vx'] *= friction
            ball['vy'] *= 0.95  # Moins de friction verticale
            
            # Collision avec les bords
            if ball['x'] - ball['radius'] <= 20:
                ball['x'] = 20 + ball['radius']
                ball['vx'] = abs(ball['vx']) * 0.8
                self.play_collision_sound()
            
            if ball['x'] + ball['radius'] >= self.WIDTH - 20:
                ball['x'] = self.WIDTH - 20 - ball['radius']
                ball['vx'] = -abs(ball['vx']) * 0.8
                self.play_collision_sound()
            
            # Empêche de remonter trop haut
            if ball['y'] < 100:
                ball['y'] = 100
                ball['vy'] = abs(ball['vy'])
            
            # Collision avec les murs du labyrinthe
            for wall in self.maze_walls:
                if (ball['x'] + ball['radius'] > wall['x'] and 
                    ball['x'] - ball['radius'] < wall['x'] + wall['width'] and
                    ball['y'] + ball['radius'] > wall['y'] and 
                    ball['y'] - ball['radius'] < wall['y'] + wall['height']):
                    
                    # Repousse la balle avec effet d'entonnoir
                    center_x = wall['x'] + wall['width'] / 2
                    center_y = wall['y'] + wall['height'] / 2
                    
                    dx = ball['x'] - center_x
                    dy = ball['y'] - center_y
                    
                    if abs(dx) > abs(dy):
                        # Collision horizontale - pousse vers les côtés ET vers le bas
                        direction = 1 if dx > 0 else -1
                        ball['vx'] = ball['speed'] * direction * 1.5
                        ball['vy'] = ball['speed'] * 0.5  # Ajoute une poussée vers le bas
                        ball['x'] = wall['x'] + (wall['width'] + ball['radius'] + 5 if dx > 0 else -ball['radius'] - 5)
                    else:
                        # Collision verticale
                        if dy > 0:  # Balle en dessous du mur
                            ball['vy'] = ball['speed'] * 1.2  # Pousse vers le bas
                            ball['y'] = wall['y'] + wall['height'] + ball['radius'] + 5
                        else:  # Balle au-dessus du mur
                            ball['vy'] = -ball['speed'] * 0.3  # Léger rebond vers le haut
                            ball['y'] = wall['y'] - ball['radius'] - 5
                    
                    self.play_collision_sound()
                    self.create_particle_explosion(ball['x'], ball['y'], ball['color'])
            
            # Traînée
            ball['trail'].append((int(ball['x']), int(ball['y'])))
            if len(ball['trail']) > 10:
                ball['trail'].pop(0)
            
            # Vérifie la ligne d'arrivée
            if ball['y'] >= self.finish_line_y and not ball['finished']:
                ball['finished'] = True
                ball['finish_time'] = pygame.time.get_ticks()
                
                if not self.race_finished:
                    self.winner = ball
                    self.race_finished = True
                    self.slowmo_start = pygame.time.get_ticks()
                    
                    # Crée des feux d'artifice
                    for _ in range(5):
                        self.create_firework(
                            random.randint(100, self.WIDTH-100),
                            random.randint(self.finish_line_y-200, self.finish_line_y-50)
                        )
    
    def update_obstacles(self):
        """Met à jour les obstacles mobiles"""
        for obstacle in self.obstacles:
            if obstacle['type'] == 'moving':
                if 'vx' in obstacle:
                    obstacle['x'] += obstacle['vx']
                    if obstacle['x'] <= 20 or obstacle['x'] + obstacle['width'] >= self.WIDTH - 20:
                        obstacle['vx'] *= -1
                
                if 'vy' in obstacle:
                    obstacle['y'] += obstacle['vy']
                    if obstacle['y'] <= 20 or obstacle['y'] + obstacle['height'] >= self.HEIGHT - 20:
                        obstacle['vy'] *= -1
    
    def create_particle_explosion(self, x, y, color):
        """Crée une explosion de particules"""
        for _ in range(15):
            angle = random.uniform(0, 2 * math.pi)
            speed = random.uniform(2, 6)
            self.particles.append({
                'x': x,
                'y': y,
                'vx': math.cos(angle) * speed,
                'vy': math.sin(angle) * speed,
                'color': color,
                'life': 20,
                'size': random.randint(2, 5)
            })
    
    def update_particles(self):
        """Met à jour les particules"""
        for particle in self.particles[:]:
            particle['x'] += particle['vx']
            particle['y'] += particle['vy']
            particle['vy'] += 0.2
            particle['life'] -= 1
            particle['size'] = max(1, particle['size'] - 0.1)
            
            if particle['life'] <= 0:
                self.particles.remove(particle)
    
    def update_fireworks(self):
        """Met à jour les feux d'artifice"""
        for firework in self.fireworks[:]:
            firework['x'] += firework['vx']
            firework['y'] += firework['vy']
            firework['vy'] += firework['gravity']
            firework['life'] -= 1
            firework['size'] = max(1, firework['size'] - 0.1)
            
            if firework['life'] <= 0:
                self.fireworks.remove(firework)
    
    def play_collision_sound(self):
        """Simule un son de collision (dans une vraie implémentation, jouer un son)"""
        # Dans une vraie implémentation :
        # pygame.mixer.Sound("collision.wav").play()
        pass
    
    def generate_scenario(self, frame):
        """Génère le scénario selon le moment"""
        # Texte d'introduction (5 premières secondes)
        if frame == 30:
            self.current_text = self.intro_text
            self.text_timer = 180
        
        if frame == 180:
            self.current_text = self.intro_text2
            self.text_timer = 120
        
        # Début de la course
        if frame == 180:  # 6 secondes
            self.race_started = True
            self.current_text = "C'est parti ! 🏁"
            self.text_timer = 60
        
        # Messages d'encouragement
        if frame == 900:  # 15 secondes
            self.current_text = "Qui va gagner ? 🤔"
            self.text_timer = 90
        
        if frame == 1800:  # 30 secondes
            self.current_text = "Ça se resserre ! 🔥"
            self.text_timer = 90
        
        if frame == 2400:  # 40 secondes
            self.current_text = "Presque arrivé ! 🏃♂️💨"
            self.text_timer = 90
        
        # Force la fin si trop long (sécurité)
        if frame > 3000 and not self.race_finished:  # Après 50 secondes
            # Force toutes les balles à terminer
            for ball in self.balls:
                if not ball['finished']:
                    ball['y'] = self.finish_line_y + 10
                    ball['finished'] = True
                    ball['finish_time'] = pygame.time.get_ticks()
                    
                    if not self.race_finished:
                        self.winner = ball
                        self.race_finished = True
                        self.slowmo_start = pygame.time.get_ticks()
                        
                        # Crée des feux d'artifice
                        for _ in range(5):
                            self.create_firework(
                                random.randint(100, self.WIDTH-100),
                                random.randint(self.finish_line_y-200, self.finish_line_y-50)
                            )
        
        # Texte de fin
        if self.race_finished and frame > self.slowmo_start + 300:
            if self.winner:
                self.current_text = f"🏆 {self.winner['color_name']} GAGNE ! 🏆"
                self.text_timer = 180
        
        # Message d'abonnement
        if frame > self.TOTAL_FRAMES - 300:
            self.current_text = self.outro_text
            self.text_timer = 300
    
    def draw_frame(self, surface):
        """Dessine un frame"""
        # Fond dégradé
        for y in range(self.HEIGHT):
            color_factor = y / self.HEIGHT
            r = int(self.background_color[0] + color_factor * 30)
            g = int(self.background_color[1] + color_factor * 30)
            b = int(self.background_color[2] + color_factor * 60)
            pygame.draw.line(surface, (r, g, b), (0, y), (self.WIDTH, y))
        
        # Dessine le labyrinthe
        for wall in self.maze_walls:
            # Mur principal
            pygame.draw.rect(surface, (100, 100, 120), 
                           (wall['x'], wall['y'], wall['width'], wall['height']))
            # Bordure brillante
            pygame.draw.rect(surface, (150, 150, 180), 
                           (wall['x'], wall['y'], wall['width'], wall['height']), 3)
        
        # Dessine les obstacles mobiles
        for obstacle in self.obstacles:
            pygame.draw.rect(surface, (200, 100, 100), 
                           (obstacle['x'], obstacle['y'], obstacle['width'], obstacle['height']))
            pygame.draw.rect(surface, (255, 150, 150), 
                           (obstacle['x'], obstacle['y'], obstacle['width'], obstacle['height']), 2)
        
        # Ligne d'arrivée
        for i in range(0, self.WIDTH, 40):
            color = (255, 255, 255) if (i // 40) % 2 == 0 else (0, 0, 0)
            pygame.draw.rect(surface, color, (i, self.finish_line_y-10, 40, 20))
        
        # Dessine les particules
        for particle in self.particles:
            if particle['life'] > 0:
                alpha = particle['life'] / 20.0
                color = [int(c * alpha) for c in particle['color']]
                pygame.draw.circle(surface, color, 
                                 (int(particle['x']), int(particle['y'])), 
                                 int(particle['size']))
        
        # Dessine les feux d'artifice
        for firework in self.fireworks:
            if firework['life'] > 0:
                alpha = firework['life'] / 60.0
                color = [int(c * alpha) for c in firework['color']]
                pygame.draw.circle(surface, color,
                                 (int(firework['x']), int(firework['y'])),
                                 int(firework['size']))
        
        # Dessine les traînées des balles
        for ball in self.balls:
            for i, pos in enumerate(ball['trail']):
                if i > 0:
                    alpha = i / len(ball['trail'])
                    color = tuple(int(c * alpha) for c in ball['color'])
                    pygame.draw.line(surface, color, 
                                   ball['trail'][i-1], pos, 3)
        
        # Dessine les balles
        for ball in self.balls:
            # Aura pour le gagnant
            if ball == self.winner:
                glow_radius = ball['radius'] + 15 + int(8 * math.sin(pygame.time.get_ticks() / 100))
                glow_color = tuple(c // 2 for c in ball['color'])
                pygame.draw.circle(surface, glow_color, 
                                 (int(ball['x']), int(ball['y'])), glow_radius)
            
            # Balle principale
            pygame.draw.circle(surface, ball['color'], 
                             (int(ball['x']), int(ball['y'])), ball['radius'])
            
            # Reflet
            highlight_color = tuple(min(255, c + 80) for c in ball['color'])
            pygame.draw.circle(surface, highlight_color, 
                             (int(ball['x'] - ball['radius']//3), 
                              int(ball['y'] - ball['radius']//3)), 
                             ball['radius']//4)
            
            # Nom de la couleur sur la balle
            font = pygame.font.Font(None, 24)
            text = font.render(ball['color_name'][:3], True, (0, 0, 0))
            text_rect = text.get_rect(center=(int(ball['x']), int(ball['y'])))
            surface.blit(text, text_rect)
    
    def draw_text(self, surface):
        """Dessine le texte d'engagement"""
        if self.text_timer > 0:
            font_size = 64 if len(self.current_text) < 30 else 48
            font = pygame.font.Font(None, font_size)
            
            # Divise le texte en lignes si nécessaire
            lines = []
            if len(self.current_text) > 40:
                words = self.current_text.split()
                line = ""
                for word in words:
                    if len(line + word) < 40:
                        line += word + " "
                    else:
                        lines.append(line.strip())
                        line = word + " "
                lines.append(line.strip())
            else:
                lines = [self.current_text]
            
            # Dessine chaque ligne
            for i, line in enumerate(lines):
                text_surface = font.render(line, True, (255, 255, 255))
                
                # Ombre
                shadow_surface = font.render(line, True, (0, 0, 0))
                y_pos = 100 + (i * 70)
                surface.blit(shadow_surface, (self.WIDTH//2 - text_surface.get_width()//2 + 3, y_pos + 3))
                
                # Texte principal
                surface.blit(text_surface, (self.WIDTH//2 - text_surface.get_width()//2, y_pos))
            
            self.text_timer -= 1
    
    def generate_video(self, output_path="maze_ball_race.mp4"):
        """Génère la vidéo complète"""
        # Initialise Pygame sans audio pour éviter les erreurs
        os.environ['SDL_AUDIODRIVER'] = 'dummy'
        pygame.init()
        pygame.font.init()
        
        # Initialise la course
        self.initialize_race()
        
        # Crée une surface pour le rendu
        surface = pygame.Surface((self.WIDTH, self.HEIGHT))
        
        # Configuration de l'enregistrement vidéo
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        out = cv2.VideoWriter(output_path, fourcc, self.FPS, (self.WIDTH, self.HEIGHT))
        
        print(f"Génération de la vidéo de course: {self.DURATION}s à {self.FPS}fps...")
        print("Cela peut prendre quelques minutes...")
        
        for frame in range(self.TOTAL_FRAMES):
            # Génère le scénario
            self.generate_scenario(frame)
            
            # Met à jour la physique
            self.update_balls_physics()
            self.update_obstacles()
            self.update_particles()
            self.update_fireworks()
            
            # Dessine le frame
            self.draw_frame(surface)
            self.draw_text(surface)
            
            # Convertit en format OpenCV
            frame_array = pygame.surfarray.array3d(surface)
            frame_array = np.rot90(frame_array)
            frame_array = np.flipud(frame_array)
            frame_array = cv2.cvtColor(frame_array, cv2.COLOR_RGB2BGR)
            
            # Écrit le frame
            out.write(frame_array)
            
            # Affiche le progrès
            if frame % (self.FPS * 5) == 0:
                progress = (frame / self.TOTAL_FRAMES) * 100
                print(f"Progrès: {progress:.1f}%")
        
        # Finalise la vidéo
        out.release()
        pygame.quit()
        
        print(f"Vidéo de course générée avec succès: {output_path}")
        return output_path

def create_custom_maze_race(custom_colors=None):
    """Crée une vidéo de course avec des couleurs personnalisées"""
    generator = MazeBallRaceGenerator()
    
    # Applique les couleurs personnalisées si fournies
    if custom_colors:
        generator.BALL_COLORS.update(custom_colors)
    
    # Génère un nom de fichier unique
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    output_path = f"maze_ball_race_{timestamp}.mp4"
    
    return generator.generate_video(output_path)

# Script principal
if __name__ == "__main__":
    print("🏁 GÉNÉRATEUR DE COURSE DE BALLES DANS UN LABYRINTHE 🏁")
    print("=" * 60)
    
    # Exemple avec couleurs personnalisées
    custom_colors = {
        "Turquoise": (64, 224, 208),
        "Corail": (255, 127, 80),
        "Lavande": (230, 230, 250)
    }
    
    try:
        print("🎬 Génération en cours...")
        # video_path = create_custom_maze_race(custom_colors)  # Avec couleurs custom
        video_path = create_custom_maze_race()  # Couleurs par défaut
        
        print(f"\n✅ Succès! Votre vidéo de course est prête: {video_path}")
        print("\n🚀 Conseils pour maximiser l'engagement:")
        print("- Titre: 'Quelle couleur va gagner? 🏁'")
        print("- Hashtags: #ballrace #satisfying #maze #fyp #challenge")
        print("- Description: 'Note ta couleur préférée en commentaire!'")
        print("- Répondez aux commentaires avec des encouragements")
        print("- Proposez des couleurs personnalisées pour les abonnés")
        
        print(f"\n🎨 Couleurs disponibles: {', '.join(MazeBallRaceGenerator().BALL_COLORS.keys())}")
        
    except Exception as e:
        print(f"❌ Erreur lors de la génération: {e}")
        print("Vérifiez que les dépendances sont installées:")
        print("pip install pygame opencv-python numpy")
```