Skip to content

Instantly share code, notes, and snippets.

@SoMaCoSF
Created May 24, 2025 17:31
Show Gist options
  • Save SoMaCoSF/5854bb2f800b23c7d4ba9a68d889c3b8 to your computer and use it in GitHub Desktop.
Save SoMaCoSF/5854bb2f800b23c7d4ba9a68d889c3b8 to your computer and use it in GitHub Desktop.
🎬 ManimGL MCP Integration - Complete Setup for Cursor AI - Features: Auto directory setup | History tracking | Replay system | MCP integration | Preview window

🎬 ManimGL MCP Integration - Complete Setup Guide

A comprehensive solution for integrating ManimGL (Mathematical Animation Engine) with Cursor's Model Context Protocol (MCP), featuring automatic directory management, animation history tracking, and replay functionality.

✨ Features

  • 🚀 Automatic Directory Management - Creates and manages scripts/manim/ and visualizations/manim/ folders
  • 📜 Animation History Tracking - Logs every animation with timestamp, script, scene, and arguments
  • 🔄 Replay System - Re-run any previous animation by ID
  • 🎯 Organized Output - Clean separation of scripts and rendered content
  • 🎨 Preview Window - Maintains ManimGL's interactive preview functionality
  • 🔧 MCP Integration - Seamless integration with Cursor's AI coding assistant

📋 Prerequisites

  • Python 3.8+ with ManimGL installed (pip install manimgl)
  • Cursor IDE with MCP support
  • Windows PowerShell (for installer script)

🚀 Quick Setup

Option 1: Automatic Installation (Recommended)

  1. Download and run the PowerShell installer:
# Download installer (replace with your gist URL)
Invoke-WebRequest -Uri "https://gist.githubusercontent.com/[USERNAME]/[GIST_ID]/raw/setup_manimgl_mcp.ps1" -OutFile "setup_manimgl_mcp.ps1"

# Run installer
.\setup_manimgl_mcp.ps1

Option 2: Manual Setup

  1. Create Directory Structure:
mkdir -p scripts/manim
mkdir -p visualizations/manim
  1. Create Wrapper Script (save as manimgl_wrapper.py):
#!/usr/bin/env python3
"""
ManimGL Wrapper Script for MCP
Ensures proper directory structure exists before running ManimGL
Includes history tracking and replay functionality
"""

import os
import sys
import subprocess
import json
import datetime
from pathlib import Path

class ManimHistory:
    def __init__(self, scripts_dir):
        self.scripts_dir = Path(scripts_dir)
        self.history_file = self.scripts_dir / ".manim_history.json"
        self.history = self.load_history()
    
    def load_history(self):
        """Load animation history from file"""
        if self.history_file.exists():
            try:
                with open(self.history_file, 'r') as f:
                    return json.load(f)
            except:
                return []
        return []
    
    def save_history(self):
        """Save animation history to file"""
        with open(self.history_file, 'w') as f:
            json.dump(self.history, f, indent=2)
    
    def add_entry(self, script_file, scene_name, args, working_dir):
        """Add a new entry to history"""
        entry = {
            "timestamp": datetime.datetime.now().isoformat(),
            "script_file": str(script_file),
            "scene_name": scene_name,
            "args": args,
            "working_dir": str(working_dir),
            "id": len(self.history) + 1
        }
        self.history.append(entry)
        self.save_history()
        return entry["id"]
    
    def list_history(self, limit=10):
        """List recent animation history"""
        print("📜 Recent ManimGL Animation History:")
        print("=" * 60)
        
        if not self.history:
            print("No previous animations found.")
            return
        
        recent = self.history[-limit:] if len(self.history) > limit else self.history
        
        for entry in reversed(recent):
            timestamp = datetime.datetime.fromisoformat(entry["timestamp"])
            print(f"[{entry['id']:2d}] {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
            print(f"     📄 {entry['script_file']}")
            print(f"     🎬 {entry['scene_name']}")
            if entry.get('args'):
                args_str = " ".join(entry['args'])
                if len(args_str) > 50:
                    args_str = args_str[:47] + "..."
                print(f"     ⚙️  {args_str}")
            print()
    
    def get_entry(self, entry_id):
        """Get a specific history entry by ID"""
        for entry in self.history:
            if entry["id"] == entry_id:
                return entry
        return None
    
    def replay_entry(self, entry_id):
        """Replay a specific animation by ID"""
        entry = self.get_entry(entry_id)
        if not entry:
            print(f"❌ Animation with ID {entry_id} not found.")
            return False
        
        print(f"🔄 Replaying animation #{entry_id}:")
        print(f"   📄 {entry['script_file']}")
        print(f"   🎬 {entry['scene_name']}")
        
        # Change to the working directory
        os.chdir(entry["working_dir"])
        
        # Build the command
        cmd = [sys.executable, "-m", "manimlib"] + entry["args"]
        
        print(f"✓ Running: {' '.join(cmd)}")
        result = subprocess.run(cmd)
        return result.returncode == 0

def ensure_directories():
    """Create the required directory structure if it doesn't exist"""
    # Get the project root (where this script is located)
    project_root = Path.cwd()
    
    # Define the required directories
    scripts_dir = project_root / "scripts" / "manim"
    visualizations_dir = project_root / "visualizations" / "manim"
    
    # Create directories if they don't exist
    scripts_dir.mkdir(parents=True, exist_ok=True)
    visualizations_dir.mkdir(parents=True, exist_ok=True)
    
    print(f"✓ Scripts directory: {scripts_dir}")
    print(f"✓ Visualizations directory: {visualizations_dir}")
    
    return scripts_dir, visualizations_dir

def show_help():
    """Show custom help for the wrapper"""
    print("ManimGL Wrapper - Enhanced with History")
    print("=" * 40)
    print()
    print("Usage:")
    print("  python manimgl_wrapper.py [script.py] [SceneName] [options]")
    print("  python manimgl_wrapper.py --history [--limit N]")
    print("  python manimgl_wrapper.py --replay ID")
    print()
    print("History Commands:")
    print("  --history         Show recent animation history")
    print("  --history --limit N   Show last N animations (default: 10)")
    print("  --replay ID       Replay animation with given ID")
    print()
    print("Examples:")
    print("  manimgl_wrapper.py fibonacci_spiral.py FibonacciSpiral")
    print("  manimgl_wrapper.py --history")
    print("  manimgl_wrapper.py --replay 5")
    print()
    print("All other ManimGL options are passed through:")

def main():
    """Main wrapper function"""
    try:
        # Ensure directories exist first
        scripts_dir, visualizations_dir = ensure_directories()
        
        # Initialize history with scripts directory
        history = ManimHistory(scripts_dir)
        
        # Handle history commands
        if "--history" in sys.argv:
            limit = 10
            if "--limit" in sys.argv:
                try:
                    limit_idx = sys.argv.index("--limit") + 1
                    limit = int(sys.argv[limit_idx])
                except (IndexError, ValueError):
                    limit = 10
            history.list_history(limit)
            return
        
        if "--replay" in sys.argv:
            try:
                replay_idx = sys.argv.index("--replay") + 1
                entry_id = int(sys.argv[replay_idx])
                success = history.replay_entry(entry_id)
                sys.exit(0 if success else 1)
            except (IndexError, ValueError):
                print("❌ Please provide a valid animation ID to replay.")
                print("Use --history to see available animations.")
                sys.exit(1)
        
        if "--help" in sys.argv or "-h" in sys.argv:
            show_help()
            print()
            print("ManimGL Help:")
            print("-" * 40)
            # Also show ManimGL help
            subprocess.run([sys.executable, "-m", "manimlib", "--help"])
            return
        
        # Normal ManimGL execution
        # Change to scripts directory
        os.chdir(scripts_dir)
        print(f"✓ Working directory: {scripts_dir}")
        
        # Build the ManimGL command
        manimgl_args = [
            sys.executable, "-m", "manimlib"
        ]
        
        # Add the video_dir argument
        manimgl_args.extend(["--video_dir", str(visualizations_dir)])
        
        # Add any additional arguments passed to this wrapper
        user_args = []
        if len(sys.argv) > 1:
            user_args = sys.argv[1:]
            manimgl_args.extend(user_args)
        
        print(f"✓ Running: {' '.join(manimgl_args)}")
        
        # Extract script file and scene name for history
        script_file = ""
        scene_name = ""
        if len(user_args) >= 1:
            script_file = user_args[0]
        if len(user_args) >= 2:
            scene_name = user_args[1]
        
        # Add to history if we have both script and scene
        if script_file and scene_name and not any(arg.startswith('-') for arg in [script_file, scene_name]):
            entry_id = history.add_entry(script_file, scene_name, user_args, scripts_dir)
            print(f"📝 Added to history as #{entry_id}")
        
        # Execute ManimGL
        result = subprocess.run(manimgl_args)
        sys.exit(result.returncode)
        
    except Exception as e:
        print(f"❌ Error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()
  1. Update MCP Configuration - Add to your ~/.cursor/mcp.json:
{
  "mcpServers": {
    "manimgl": {
      "command": "python",
      "args": ["path/to/your/project/manimgl_wrapper.py"],
      "cwd": "path/to/your/project",
      "env": {
        "MANIMGL_LOG_LEVEL": "INFO"
      }
    }
  }
}

📂 Directory Structure

After setup, your project will have:

PROJECT_ROOT/
├── scripts/
│   └── manim/                      # 📁 All ManimGL Python scripts
│       ├── .manim_history.json     # 📝 Animation execution history
│       └── [your_scripts.py]       # 🎨 Your animation scripts
├── visualizations/
│   └── manim/                      # 📁 All ManimGL outputs
│       ├── [output_videos.mp4]     # 🎥 Rendered videos
│       └── [output_images.png]     # 🖼️ Rendered images
└── manimgl_wrapper.py              # 🔧 Enhanced wrapper with history

🎮 Usage

Through MCP (AI Assistant)

Simply ask your AI assistant to create ManimGL animations, and everything is handled automatically!

Manual Commands

View Animation History:

python manimgl_wrapper.py --history
python manimgl_wrapper.py --history --limit 20  # Show last 20

Replay Previous Animation:

python manimgl_wrapper.py --replay 5  # Replay animation #5

Run New Animation:

python manimgl_wrapper.py my_script.py MyScene
python manimgl_wrapper.py my_script.py MyScene --skip_animations

Get Help:

python manimgl_wrapper.py --help

📊 History Format

Each animation run creates a history entry with:

  • ID: Unique identifier for replay
  • Timestamp: When the animation was executed
  • Script File: Which Python file was run
  • Scene Name: Which scene class was rendered
  • Arguments: Complete command line arguments used

🔧 Customization

Environment Variables

  • MANIMGL_LOG_LEVEL: Controls logging verbosity (DEBUG, INFO, WARNING, ERROR)

Wrapper Modifications

The manimgl_wrapper.py script can be customized to:

  • Change default directories
  • Modify history tracking behavior
  • Add custom preprocessing steps
  • Integrate with other tools

🐛 Troubleshooting

Common Issues

"ModuleNotFoundError: No module named 'manimlib'"

pip install manimgl

"Permission denied" on Windows

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

MCP not recognizing the server

  • Restart Cursor after updating mcp.json
  • Check that the wrapper script path is absolute
  • Verify Python path is correct

Animations not showing preview window

  • ManimGL preview window should open automatically
  • Use interactive keys: d, f, z to control playback
  • Press ESC or Cmd+Q to quit

Debug Mode

Run with verbose output:

python manimgl_wrapper.py --help  # Shows all available options
python manimgl_wrapper.py my_script.py MyScene --log-level DEBUG

🤝 Contributing

This setup is designed to be:

  • Extensible: Easy to add new features
  • Maintainable: Clear separation of concerns
  • Portable: Works across different projects
  • Documented: Comprehensive usage examples

Feel free to customize the wrapper script for your specific needs!

📜 License

This setup guide and associated scripts are provided as-is for educational and development purposes. ManimGL itself is governed by its own license terms.


🎬 Happy Animating! Create beautiful mathematical animations with the power of AI assistance and organized project management.

#!/usr/bin/env python3
"""
ManimGL Wrapper Script for MCP
Ensures proper directory structure exists before running ManimGL
Includes history tracking and replay functionality
"""
import os
import sys
import subprocess
import json
import datetime
from pathlib import Path
class ManimHistory:
def __init__(self, scripts_dir):
self.scripts_dir = Path(scripts_dir)
self.history_file = self.scripts_dir / ".manim_history.json"
self.history = self.load_history()
def load_history(self):
"""Load animation history from file"""
if self.history_file.exists():
try:
with open(self.history_file, 'r') as f:
return json.load(f)
except:
return []
return []
def save_history(self):
"""Save animation history to file"""
with open(self.history_file, 'w') as f:
json.dump(self.history, f, indent=2)
def add_entry(self, script_file, scene_name, args, working_dir):
"""Add a new entry to history"""
entry = {
"timestamp": datetime.datetime.now().isoformat(),
"script_file": str(script_file),
"scene_name": scene_name,
"args": args,
"working_dir": str(working_dir),
"id": len(self.history) + 1
}
self.history.append(entry)
self.save_history()
return entry["id"]
def list_history(self, limit=10):
"""List recent animation history"""
print("📜 Recent ManimGL Animation History:")
print("=" * 60)
if not self.history:
print("No previous animations found.")
return
recent = self.history[-limit:] if len(self.history) > limit else self.history
for entry in reversed(recent):
timestamp = datetime.datetime.fromisoformat(entry["timestamp"])
print(f"[{entry['id']:2d}] {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
print(f" 📄 {entry['script_file']}")
print(f" 🎬 {entry['scene_name']}")
if entry.get('args'):
args_str = " ".join(entry['args'])
if len(args_str) > 50:
args_str = args_str[:47] + "..."
print(f" ⚙️ {args_str}")
print()
def get_entry(self, entry_id):
"""Get a specific history entry by ID"""
for entry in self.history:
if entry["id"] == entry_id:
return entry
return None
def replay_entry(self, entry_id):
"""Replay a specific animation by ID"""
entry = self.get_entry(entry_id)
if not entry:
print(f"❌ Animation with ID {entry_id} not found.")
return False
print(f"🔄 Replaying animation #{entry_id}:")
print(f" 📄 {entry['script_file']}")
print(f" 🎬 {entry['scene_name']}")
# Change to the working directory
os.chdir(entry["working_dir"])
# Build the command
cmd = [sys.executable, "-m", "manimlib"] + entry["args"]
print(f"✓ Running: {' '.join(cmd)}")
result = subprocess.run(cmd)
return result.returncode == 0
def ensure_directories():
"""Create the required directory structure if it doesn't exist"""
# Get the project root (where this script is located)
project_root = Path.cwd()
# Define the required directories
scripts_dir = project_root / "scripts" / "manim"
visualizations_dir = project_root / "visualizations" / "manim"
# Create directories if they don't exist
scripts_dir.mkdir(parents=True, exist_ok=True)
visualizations_dir.mkdir(parents=True, exist_ok=True)
print(f"✓ Scripts directory: {scripts_dir}")
print(f"✓ Visualizations directory: {visualizations_dir}")
return scripts_dir, visualizations_dir
def show_help():
"""Show custom help for the wrapper"""
print("ManimGL Wrapper - Enhanced with History")
print("=" * 40)
print()
print("Usage:")
print(" python manimgl_wrapper.py [script.py] [SceneName] [options]")
print(" python manimgl_wrapper.py --history [--limit N]")
print(" python manimgl_wrapper.py --replay ID")
print()
print("History Commands:")
print(" --history Show recent animation history")
print(" --history --limit N Show last N animations (default: 10)")
print(" --replay ID Replay animation with given ID")
print()
print("Examples:")
print(" manimgl_wrapper.py fibonacci_spiral.py FibonacciSpiral")
print(" manimgl_wrapper.py --history")
print(" manimgl_wrapper.py --replay 5")
print()
print("All other ManimGL options are passed through:")
def main():
"""Main wrapper function"""
try:
# Ensure directories exist first
scripts_dir, visualizations_dir = ensure_directories()
# Initialize history with scripts directory
history = ManimHistory(scripts_dir)
# Handle history commands
if "--history" in sys.argv:
limit = 10
if "--limit" in sys.argv:
try:
limit_idx = sys.argv.index("--limit") + 1
limit = int(sys.argv[limit_idx])
except (IndexError, ValueError):
limit = 10
history.list_history(limit)
return
if "--replay" in sys.argv:
try:
replay_idx = sys.argv.index("--replay") + 1
entry_id = int(sys.argv[replay_idx])
success = history.replay_entry(entry_id)
sys.exit(0 if success else 1)
except (IndexError, ValueError):
print("❌ Please provide a valid animation ID to replay.")
print("Use --history to see available animations.")
sys.exit(1)
if "--help" in sys.argv or "-h" in sys.argv:
show_help()
print()
print("ManimGL Help:")
print("-" * 40)
# Also show ManimGL help
subprocess.run([sys.executable, "-m", "manimlib", "--help"])
return
# Normal ManimGL execution
# Change to scripts directory
os.chdir(scripts_dir)
print(f"✓ Working directory: {scripts_dir}")
# Build the ManimGL command
manimgl_args = [
sys.executable, "-m", "manimlib"
]
# Add the video_dir argument
manimgl_args.extend(["--video_dir", str(visualizations_dir)])
# Add any additional arguments passed to this wrapper
user_args = []
if len(sys.argv) > 1:
user_args = sys.argv[1:]
manimgl_args.extend(user_args)
print(f"✓ Running: {' '.join(manimgl_args)}")
# Extract script file and scene name for history
script_file = ""
scene_name = ""
if len(user_args) >= 1:
script_file = user_args[0]
if len(user_args) >= 2:
scene_name = user_args[1]
# Add to history if we have both script and scene
if script_file and scene_name and not any(arg.startswith('-') for arg in [script_file, scene_name]):
entry_id = history.add_entry(script_file, scene_name, user_args, scripts_dir)
print(f"📝 Added to history as #{entry_id}")
# Execute ManimGL
result = subprocess.run(manimgl_args)
sys.exit(result.returncode)
except Exception as e:
print(f"❌ Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
# ManimGL MCP Integration Setup Script
# Automatically sets up ManimGL with Cursor MCP integration
# Author: AI Assistant
# Version: 1.0
param(
[string]$ProjectPath = (Get-Location),
[switch]$SkipMcpUpdate,
[switch]$Force
)
Write-Host "🎬 ManimGL MCP Integration Setup" -ForegroundColor Cyan
Write-Host "================================" -ForegroundColor Cyan
Write-Host ""
# Function to check if running as administrator
function Test-Administrator {
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $currentUser
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
}
# Function to check Python installation
function Test-Python {
try {
$pythonVersion = python --version 2>&1
if ($pythonVersion -match "Python (\d+)\.(\d+)") {
$major = [int]$matches[1]
$minor = [int]$matches[2]
if ($major -ge 3 -and $minor -ge 8) {
Write-Host "✓ Python $($matches[0]) found" -ForegroundColor Green
return $true
}
else {
Write-Host "❌ Python 3.8+ required, found $($matches[0])" -ForegroundColor Red
return $false
}
}
}
catch {
Write-Host "❌ Python not found in PATH" -ForegroundColor Red
return $false
}
return $false
}
# Function to check ManimGL installation
function Test-ManimGL {
try {
$result = python -c "import manimlib; print('ManimGL installed')" 2>&1
if ($result -match "ManimGL installed") {
Write-Host "✓ ManimGL is installed" -ForegroundColor Green
return $true
}
}
catch {
# Silent catch
}
Write-Host "❌ ManimGL not found" -ForegroundColor Red
return $false
}
# Function to install ManimGL
function Install-ManimGL {
Write-Host "📦 Installing ManimGL..." -ForegroundColor Yellow
try {
python -m pip install manimgl
Write-Host "✓ ManimGL installed successfully" -ForegroundColor Green
return $true
}
catch {
Write-Host "❌ Failed to install ManimGL" -ForegroundColor Red
Write-Host "Please install manually with: pip install manimgl" -ForegroundColor Yellow
return $false
}
}
# Function to create directory structure
function New-ProjectStructure {
param([string]$basePath)
Write-Host "📁 Creating directory structure..." -ForegroundColor Yellow
$scriptsDir = Join-Path $basePath "scripts\manim"
$visualsDir = Join-Path $basePath "visualizations\manim"
try {
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
New-Item -ItemType Directory -Path $visualsDir -Force | Out-Null
Write-Host "✓ Created: $scriptsDir" -ForegroundColor Green
Write-Host "✓ Created: $visualsDir" -ForegroundColor Green
return $true
}
catch {
Write-Host "❌ Failed to create directories" -ForegroundColor Red
return $false
}
}
# Function to create wrapper script
function New-WrapperScript {
param([string]$projectPath)
$wrapperPath = Join-Path $projectPath "manimgl_wrapper.py"
Write-Host "🔧 Creating wrapper script at: $wrapperPath" -ForegroundColor Yellow
$wrapperContent = @'
#!/usr/bin/env python3
"""
ManimGL Wrapper Script for MCP
Ensures proper directory structure exists before running ManimGL
Includes history tracking and replay functionality
"""
import os
import sys
import subprocess
import json
import datetime
from pathlib import Path
class ManimHistory:
def __init__(self, scripts_dir):
self.scripts_dir = Path(scripts_dir)
self.history_file = self.scripts_dir / ".manim_history.json"
self.history = self.load_history()
def load_history(self):
"""Load animation history from file"""
if self.history_file.exists():
try:
with open(self.history_file, 'r') as f:
return json.load(f)
except:
return []
return []
def save_history(self):
"""Save animation history to file"""
with open(self.history_file, 'w') as f:
json.dump(self.history, f, indent=2)
def add_entry(self, script_file, scene_name, args, working_dir):
"""Add a new entry to history"""
entry = {
"timestamp": datetime.datetime.now().isoformat(),
"script_file": str(script_file),
"scene_name": scene_name,
"args": args,
"working_dir": str(working_dir),
"id": len(self.history) + 1
}
self.history.append(entry)
self.save_history()
return entry["id"]
def list_history(self, limit=10):
"""List recent animation history"""
print("📜 Recent ManimGL Animation History:")
print("=" * 60)
if not self.history:
print("No previous animations found.")
return
recent = self.history[-limit:] if len(self.history) > limit else self.history
for entry in reversed(recent):
timestamp = datetime.datetime.fromisoformat(entry["timestamp"])
print(f"[{entry['id']:2d}] {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
print(f" 📄 {entry['script_file']}")
print(f" 🎬 {entry['scene_name']}")
if entry.get('args'):
args_str = " ".join(entry['args'])
if len(args_str) > 50:
args_str = args_str[:47] + "..."
print(f" ⚙️ {args_str}")
print()
def get_entry(self, entry_id):
"""Get a specific history entry by ID"""
for entry in self.history:
if entry["id"] == entry_id:
return entry
return None
def replay_entry(self, entry_id):
"""Replay a specific animation by ID"""
entry = self.get_entry(entry_id)
if not entry:
print(f"❌ Animation with ID {entry_id} not found.")
return False
print(f"🔄 Replaying animation #{entry_id}:")
print(f" 📄 {entry['script_file']}")
print(f" 🎬 {entry['scene_name']}")
# Change to the working directory
os.chdir(entry["working_dir"])
# Build the command
cmd = [sys.executable, "-m", "manimlib"] + entry["args"]
print(f"✓ Running: {' '.join(cmd)}")
result = subprocess.run(cmd)
return result.returncode == 0
def ensure_directories():
"""Create the required directory structure if it doesn't exist"""
# Get the project root (where this script is located)
project_root = Path.cwd()
# Define the required directories
scripts_dir = project_root / "scripts" / "manim"
visualizations_dir = project_root / "visualizations" / "manim"
# Create directories if they don't exist
scripts_dir.mkdir(parents=True, exist_ok=True)
visualizations_dir.mkdir(parents=True, exist_ok=True)
print(f"✓ Scripts directory: {scripts_dir}")
print(f"✓ Visualizations directory: {visualizations_dir}")
return scripts_dir, visualizations_dir
def show_help():
"""Show custom help for the wrapper"""
print("ManimGL Wrapper - Enhanced with History")
print("=" * 40)
print()
print("Usage:")
print(" python manimgl_wrapper.py [script.py] [SceneName] [options]")
print(" python manimgl_wrapper.py --history [--limit N]")
print(" python manimgl_wrapper.py --replay ID")
print()
print("History Commands:")
print(" --history Show recent animation history")
print(" --history --limit N Show last N animations (default: 10)")
print(" --replay ID Replay animation with given ID")
print()
print("Examples:")
print(" manimgl_wrapper.py fibonacci_spiral.py FibonacciSpiral")
print(" manimgl_wrapper.py --history")
print(" manimgl_wrapper.py --replay 5")
print()
print("All other ManimGL options are passed through:")
def main():
"""Main wrapper function"""
try:
# Ensure directories exist first
scripts_dir, visualizations_dir = ensure_directories()
# Initialize history with scripts directory
history = ManimHistory(scripts_dir)
# Handle history commands
if "--history" in sys.argv:
limit = 10
if "--limit" in sys.argv:
try:
limit_idx = sys.argv.index("--limit") + 1
limit = int(sys.argv[limit_idx])
except (IndexError, ValueError):
limit = 10
history.list_history(limit)
return
if "--replay" in sys.argv:
try:
replay_idx = sys.argv.index("--replay") + 1
entry_id = int(sys.argv[replay_idx])
success = history.replay_entry(entry_id)
sys.exit(0 if success else 1)
except (IndexError, ValueError):
print("❌ Please provide a valid animation ID to replay.")
print("Use --history to see available animations.")
sys.exit(1)
if "--help" in sys.argv or "-h" in sys.argv:
show_help()
print()
print("ManimGL Help:")
print("-" * 40)
# Also show ManimGL help
subprocess.run([sys.executable, "-m", "manimlib", "--help"])
return
# Normal ManimGL execution
# Change to scripts directory
os.chdir(scripts_dir)
print(f"✓ Working directory: {scripts_dir}")
# Build the ManimGL command
manimgl_args = [
sys.executable, "-m", "manimlib"
]
# Add the video_dir argument
manimgl_args.extend(["--video_dir", str(visualizations_dir)])
# Add any additional arguments passed to this wrapper
user_args = []
if len(sys.argv) > 1:
user_args = sys.argv[1:]
manimgl_args.extend(user_args)
print(f"✓ Running: {' '.join(manimgl_args)}")
# Extract script file and scene name for history
script_file = ""
scene_name = ""
if len(user_args) >= 1:
script_file = user_args[0]
if len(user_args) >= 2:
scene_name = user_args[1]
# Add to history if we have both script and scene
if script_file and scene_name and not any(arg.startswith('-') for arg in [script_file, scene_name]):
entry_id = history.add_entry(script_file, scene_name, user_args, scripts_dir)
print(f"📝 Added to history as #{entry_id}")
# Execute ManimGL
result = subprocess.run(manimgl_args)
sys.exit(result.returncode)
except Exception as e:
print(f"❌ Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
'@
try {
$wrapperContent | Out-File -FilePath $wrapperPath -Encoding UTF8
Write-Host "✓ Wrapper script created successfully" -ForegroundColor Green
return $wrapperPath
}
catch {
Write-Host "❌ Failed to create wrapper script" -ForegroundColor Red
return $null
}
}
# Function to update MCP configuration
function Update-McpConfig {
param([string]$wrapperPath)
$mcpPath = "$env:USERPROFILE\.cursor\mcp.json"
Write-Host "⚙️ Updating MCP configuration..." -ForegroundColor Yellow
try {
# Read existing config or create new one
$mcpConfig = @{}
if (Test-Path $mcpPath) {
$mcpContent = Get-Content $mcpPath -Raw | ConvertFrom-Json
$mcpConfig = @{
mcpServers = $mcpContent.mcpServers
}
}
else {
$mcpConfig = @{
mcpServers = @{}
}
}
# Add or update ManimGL server
$mcpConfig.mcpServers.manimgl = @{
command = "python"
args = @($wrapperPath)
cwd = $ProjectPath
env = @{
MANIMGL_LOG_LEVEL = "INFO"
}
}
# Create directory if it doesn't exist
$mcpDir = Split-Path $mcpPath -Parent
if (!(Test-Path $mcpDir)) {
New-Item -ItemType Directory -Path $mcpDir -Force | Out-Null
}
# Write updated config
$mcpConfig | ConvertTo-Json -Depth 4 | Out-File -FilePath $mcpPath -Encoding UTF8
Write-Host "✓ MCP configuration updated at: $mcpPath" -ForegroundColor Green
return $true
}
catch {
Write-Host "❌ Failed to update MCP configuration: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
# Function to create sample animation
function New-SampleAnimation {
param([string]$scriptsPath)
$samplePath = Join-Path $scriptsPath "sample_animation.py"
Write-Host "🎨 Creating sample animation..." -ForegroundColor Yellow
$sampleContent = @'
from manimlib import *
class WelcomeAnimation(Scene):
def construct(self):
# Welcome text
welcome = Text("Welcome to ManimGL!", font_size=48)
welcome.set_color(YELLOW)
# Circle that grows
circle = Circle(radius=0.5, color=BLUE)
circle.set_fill(BLUE, opacity=0.3)
# Square that rotates
square = Square(side_length=1.5, color=RED)
square.rotate(PI/4)
square.set_stroke(RED, width=3)
# Animations
self.play(Write(welcome))
self.wait(1)
self.play(welcome.animate.to_edge(UP))
self.play(ShowCreation(circle))
self.play(circle.animate.scale(3))
self.play(ShowCreation(square))
self.play(Rotate(square, PI))
self.play(FadeOut(circle), FadeOut(square))
self.play(welcome.animate.scale(1.5).set_color(GREEN))
self.wait(2)
class QuickTest(Scene):
def construct(self):
# Quick test scene for verification
text = Text("ManimGL MCP Setup Complete!", font_size=36)
text.set_color(GREEN)
self.play(Write(text))
self.wait(2)
'@
try {
$sampleContent | Out-File -FilePath $samplePath -Encoding UTF8
Write-Host "✓ Sample animation created: $samplePath" -ForegroundColor Green
return $samplePath
}
catch {
Write-Host "❌ Failed to create sample animation" -ForegroundColor Red
return $null
}
}
# Main setup process
try {
Write-Host "🔍 Checking prerequisites..." -ForegroundColor Yellow
# Check Python
if (-not (Test-Python)) {
Write-Host "Please install Python 3.8+ and add it to your PATH" -ForegroundColor Red
exit 1
}
# Check/Install ManimGL
if (-not (Test-ManimGL)) {
$installChoice = Read-Host "ManimGL not found. Install it now? (y/N)"
if ($installChoice -eq 'y' -or $installChoice -eq 'Y') {
if (-not (Install-ManimGL)) {
exit 1
}
}
else {
Write-Host "ManimGL is required. Please install with: pip install manimgl" -ForegroundColor Red
exit 1
}
}
# Verify project path
if (-not (Test-Path $ProjectPath)) {
Write-Host "❌ Project path does not exist: $ProjectPath" -ForegroundColor Red
exit 1
}
Write-Host "📍 Setting up in: $ProjectPath" -ForegroundColor Cyan
# Create directory structure
if (-not (New-ProjectStructure -basePath $ProjectPath)) {
exit 1
}
# Create wrapper script
$wrapperPath = New-WrapperScript -projectPath $ProjectPath
if (-not $wrapperPath) {
exit 1
}
# Update MCP configuration
if (-not $SkipMcpUpdate) {
if (-not (Update-McpConfig -wrapperPath $wrapperPath)) {
Write-Host "⚠️ MCP update failed, but you can update manually" -ForegroundColor Yellow
}
}
# Create sample animation
$scriptsPath = Join-Path $ProjectPath "scripts\manim"
$samplePath = New-SampleAnimation -scriptsPath $scriptsPath
Write-Host ""
Write-Host "🎉 Setup completed successfully!" -ForegroundColor Green
Write-Host "================================" -ForegroundColor Green
Write-Host ""
Write-Host "📂 Project structure created:" -ForegroundColor Cyan
Write-Host " - scripts/manim/ (your animation scripts)" -ForegroundColor Gray
Write-Host " - visualizations/manim/ (rendered outputs)" -ForegroundColor Gray
Write-Host " - manimgl_wrapper.py (enhanced wrapper)" -ForegroundColor Gray
Write-Host ""
Write-Host "🧪 Test your setup:" -ForegroundColor Cyan
Write-Host " python manimgl_wrapper.py sample_animation.py QuickTest" -ForegroundColor Gray
Write-Host ""
Write-Host "📜 View history:" -ForegroundColor Cyan
Write-Host " python manimgl_wrapper.py --history" -ForegroundColor Gray
Write-Host ""
Write-Host "🔄 Replay animations:" -ForegroundColor Cyan
Write-Host " python manimgl_wrapper.py --replay 1" -ForegroundColor Gray
Write-Host ""
Write-Host "⚡ Restart Cursor to load the new MCP server!" -ForegroundColor Yellow
Write-Host ""
}
catch {
Write-Host "❌ Setup failed: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment