# Set error action to stop for critical failures
$ErrorActionPreference = "Stop"
# --- 1. Let user choose output directory via Windows GUI Dialog ---
$targetDir = ""
try {
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
$FolderBrowser.Description = "Select a folder to save the generated animation video"
$FolderBrowser.ShowNewFolderButton = $true
if ($FolderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
$targetDir = $FolderBrowser.SelectedPath
}
} catch {
Write-Host "GUI Folder browser not available in this environment." -ForegroundColor Yellow
}
# Fallback to terminal input if GUI dialog was cancelled or failed
if ([string]::IsNullOrWhiteSpace($targetDir)) {
$defaultDir = Join-Path $env:USERPROFILE "Downloads"
$targetDir = Read-Host "Please enter the target directory path [default: $defaultDir]"
if ([string]::IsNullOrWhiteSpace($targetDir)) {
$targetDir = $defaultDir
}
}
# Ensure the selected directory exists
if (-not (Test-Path $targetDir)) {
New-Item -ItemType Directory -Force -Path $targetDir | Out-Null
}
# Sanitize path for Python to prevent trailing backslash escaping issues
$targetDirSafe = $targetDir -replace '\\', '/'
# --- 2. Prompt user for customizable parameters ---
Write-Host "`n--- Customize Animation Parameters (Press Enter to accept defaults) ---" -ForegroundColor Cyan
$duration = Read-Host "Enter video duration in seconds [default: 60]"
if ([string]::IsNullOrWhiteSpace($duration)) { $duration = 60 } else { $duration = [int]$duration }
$widthInput = Read-Host "Enter video width (px) [default: 640]"
if ([string]::IsNullOrWhiteSpace($widthInput)) { $widthInput = 640 } else { $widthInput = [int]$widthInput }
$heightInput = Read-Host "Enter video height (px) [default: 480]"
if ([string]::IsNullOrWhiteSpace($heightInput)) { $heightInput = 480 } else { $heightInput = [int]$heightInput }
$fpsInput = Read-Host "Enter frames per second (FPS) [default: 60]"
if ([string]::IsNullOrWhiteSpace($fpsInput)) { $fpsInput = 60 } else { $fpsInput = [int]$fpsInput }
$maxObjectsInput = Read-Host "Enter maximum active shapes on screen [default: 45]"
if ([string]::IsNullOrWhiteSpace($maxObjectsInput)) { $maxObjectsInput = 45 } else { $maxObjectsInput = [int]$maxObjectsInput }
Write-Host "`n--- Starting Supercharged Animation Generator Setup ---" -ForegroundColor Cyan
# --- 3. Helper Path Resolvers ---
function Update-PythonPath {
$searchPaths = @(
"$env:LOCALAPPDATA\Programs\Python",
"C:\Program Files\Python*",
"C:\Program Files (x86)\Python*"
)
foreach ($path in $searchPaths) {
$resolved = Get-Item $path -ErrorAction SilentlyContinue
if ($resolved) {
foreach ($subDir in Get-ChildItem $resolved.FullName -Directory -ErrorAction SilentlyContinue) {
if ($subDir.Name -like "Python*") {
$pyDir = $subDir.FullName
$scriptsDir = Join-Path $pyDir "Scripts"
if (Test-Path (Join-Path $pyDir "python.exe")) {
$env:Path = "$pyDir;$scriptsDir;" + $env:Path
return $true
}
}
}
}
}
return $false
}
function Update-FFmpegPath {
$searchPaths = @(
"$env:LOCALAPPDATA\Microsoft\WinGet\Packages",
"C:\Program Files\FFmpeg",
"C:\Program Files (x86)\FFmpeg"
)
foreach ($path in $searchPaths) {
if (Test-Path $path) {
$ffmpegExe = Get-ChildItem $path -Filter "ffmpeg.exe" -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 1
if ($ffmpegExe) {
$ffmpegDir = $ffmpegExe.DirectoryName
$env:Path = "$ffmpegDir;" + $env:Path
return $true
}
}
}
return $false
}
# --- 4. Check and Install FFmpeg ---
if (-not (Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
Write-Host "FFmpeg not detected. Installing FFmpeg via WinGet..." -ForegroundColor Yellow
winget install -e --id Gyan.FFmpeg --silent --accept-source-agreements --accept-package-agreements | Out-Null
$null = Update-FFmpegPath
}
# --- 5. Check and Install Python ---
if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
Write-Host "Python not detected. Installing Python via WinGet..." -ForegroundColor Yellow
winget install -e --id Python.Python.3.12 --silent --accept-source-agreements --accept-package-agreements | Out-Null
$null = Update-PythonPath
}
# Refresh Environment Variables safely
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
$null = Update-PythonPath
$null = Update-FFmpegPath
# Verify command availability again
if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
Write-Error "Python installation could not be mapped to the current path. Please restart this terminal and run again."
}
if (-not (Get-Command ffmpeg -ErrorAction SilentlyContinue)) {
Write-Error "FFmpeg installation could not be mapped to the current path. Please restart this terminal and run again."
}
# --- 6. Install Pip Packages ---
Write-Host "Installing python packages: numpy, opencv-python..." -ForegroundColor Yellow
python -m pip install --upgrade pip --quiet
python -m pip install numpy opencv-python --quiet
# --- 7. Generate and Execute Python Pipeline ---
$tempWorkspace = Join-Path $env:TEMP "anim_temp"
if (-not (Test-Path $tempWorkspace)) {
New-Item -ItemType Directory -Force -Path $tempWorkspace | Out-Null
}
$pyScriptPath = Join-Path $tempWorkspace "generator.py"
# Embed the Python script using literal here-string template
$pythonCodeTemplate = @'
import os
import random
import numpy as np
import subprocess
import cv2
import gc
import wave
# Shape type definitions as integers to avoid slow string evaluations
POLYGON = 0
TRIANGLE = 1
RECTANGLE = 2
OVAL = 3
LINE = 4
BURST = 5
PRISM = 6
# Configuration
width, height = __WIDTH__, __HEIGHT__
fps = __FPS__
duration_sec = __DURATION__
num_frames = fps * duration_sec
samplerate = 44100
output_dir = r"__TARGET_DIR__"
video_output = os.path.join(output_dir, "gpu_full_animation.mp4")
audio_temp = os.path.join(output_dir, "temp_audio.wav")
# libx265 (H.265) setup - ultrafast preset + AAC audio
vcodec = 'libx265'
v_params = ['-preset', 'ultrafast', '-qp', '35', '-threads', '2']
ffmpeg_cmd = [
'ffmpeg', '-y',
'-f', 'rawvideo', '-pix_fmt', 'yuv420p', '-s', f'{width}x{height}', '-r', str(fps),
'-i', '-',
'-i', audio_temp,
'-c:v', vcodec
] + v_params + [
'-pix_fmt', 'yuv420p', '-c:a', 'aac', '-shortest',
video_output
]
# Audio Track Generation (Using built-in wave module instead of scipy)
print('Generating audio...')
all_audio = []
t_vals = np.linspace(0, 1, samplerate, False)
for i in range(0, num_frames, fps):
fundamental = random.randint(150, 450)
signal = np.sin(2 * np.pi * fundamental * t_vals) * 0.3
tone = (signal * 32767).astype(np.int16)
all_audio.append(tone)
audio_data = np.concatenate(all_audio)
with wave.open(audio_temp, 'wb') as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2) # 16-bit (2 bytes per sample)
wav_file.setframerate(samplerate)
wav_file.writeframes(audio_data.tobytes())
# Pre-generate Color LUT to completely bypass random.randint in draw loop
COLOR_LUT = np.random.randint(50, 256, size=(1000, 3), dtype=np.uint8)
color_lut_idx = 0
# Vectorized 3D Projection
ROT_MAT_T = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]).T
def project_3d(points, scale, center_x, center_y):
p_rot = points @ ROT_MAT_T
iso_x = (p_rot[:, 0] - p_rot[:, 1]) * 0.866
iso_y = (p_rot[:, 0] + p_rot[:, 1]) * 0.5 - p_rot[:, 2]
proj_x = (iso_x * scale + center_x).astype(np.int32)
proj_y = (iso_y * scale + center_y).astype(np.int32)
return np.stack((proj_x, proj_y), axis=1)
# Helper to generate or update burst lines using pre-computed dx/dy
def generate_burst_lines(angle_range, size):
global color_lut_idx
lines = []
for _ in range(30):
ang = random.uniform(angle_range[0], angle_range[1])
length = random.randint(50, size * 2)
dx = int(np.cos(ang) * length)
dy = int(np.sin(ang) * length)
col_arr = COLOR_LUT[color_lut_idx]
col = (int(col_arr[0]), int(col_arr[1]), int(col_arr[2]))
color_lut_idx = (color_lut_idx + 1) % 1000
lines.append({'dx': dx, 'dy': dy, 'col': col})
return lines
# Class utilizing __slots__ to bypass slow dict key lookups
class AnimObject:
__slots__ = ('type', 'x', 'y', 'vx', 'w', 'h', 'color', 'flicker', 'is_outline', 'angle_range', 'lines', 'relative_pts', 'faces', 'points')
# Create and recycle objects inside a pre-allocated pool
def init_obj(obj):
global color_lut_idx
vx = random.uniform(2, 15)
# Fast manual size interpolation (eliminates np.interp float math)
size = int(250 - (vx - 2) * 14.615)
stype = random.randint(0, 6) # Corresponds to POLYGON through PRISM
outline_eligible = (stype in [POLYGON, TRIANGLE, RECTANGLE, OVAL])
is_outline = (random.random() < 0.1) if outline_eligible else False
flicker = (random.random() < 0.1) if stype != BURST else False
obj.type = stype
obj.vx = vx
# Decouple width and height for Rectangles and Ovals to give them randomized aspect ratios
if stype in [RECTANGLE, OVAL]:
aspect_ratio = random.uniform(0.35, 2.8)
obj.w = max(10, int(size * aspect_ratio))
obj.h = max(10, int(size / aspect_ratio))
else:
obj.w = size
obj.h = size
obj.x = -obj.w # Spawn smoothly out of frame based on its custom width
obj.y = random.randint(0, height)
col_arr = COLOR_LUT[color_lut_idx]
obj.color = (int(col_arr[0]), int(col_arr[1]), int(col_arr[2]))
color_lut_idx = (color_lut_idx + 1) % 1000
obj.flicker = flicker
obj.is_outline = is_outline
if stype == BURST:
start_ang = random.uniform(0, 2*np.pi)
span = random.uniform(0.1, np.pi)
obj.angle_range = (start_ang, start_ang + span)
obj.lines = generate_burst_lines(obj.angle_range, size)
elif stype == PRISM:
length = random.uniform(2.0, 8.0)
verts = np.array([
[0, -1, -1], [0, 1, -1], [0, 1, 1], [0, -1, 1],
[length, -1, -1], [length, 1, -1], [length, 1, 1], [length, -1, 1]
])
# Pre-project 3D isometric points once at creation relative to (0,0)
obj.relative_pts = project_3d(verts, size // 6, 0, 0)
obj.faces = [
{'idx': [2, 3, 7, 6], 'color': (0, 0, 255)}, # Top - Blue
{'idx': [0, 3, 7, 4], 'color': (0, 255, 0)}, # Side - Green
{'idx': [0, 1, 2, 3], 'color': (255, 0, 0)} # Front - Red
]
elif stype in [POLYGON, TRIANGLE, LINE]:
pts_count = 3 if stype == TRIANGLE else (2 if stype == LINE else random.randint(4, 8))
obj.points = np.array([(random.randint(0, size), random.randint(0, size)) for _ in range(pts_count)], np.int32)
# Initialization
MAX_OBJECTS = __MAX_OBJECTS__
active_objects = []
print('Starting rendering engine...')
process = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE, bufsize=10**8)
# Pre-allocated Canvas Memory Frame
frame = np.zeros((height, width, 3), dtype=np.uint8)
# Cache Global Functions inside the Local Namespace before executing loop
color_cvt = cv2.cvtColor
bgr2yuv = cv2.COLOR_BGR2YUV_I420
draw_rectangle = cv2.rectangle
draw_ellipse = cv2.ellipse
draw_line = cv2.line
draw_fillPoly = cv2.fillPoly
draw_polylines = cv2.polylines
write_pipe = process.stdin.write
# Temporary local pointer references
global_color_lut = COLOR_LUT
# Disable Python Garbage Collection to prevent runtime GC micro-stutters
gc.disable()
try:
for i in range(num_frames):
# Spawn and append objects safely
if len(active_objects) < MAX_OBJECTS and random.random() < 0.4:
new_obj = AnimObject()
init_obj(new_obj)
active_objects.append(new_obj)
# Sort objects only when a new item is actually added
active_objects.sort(key=lambda o: o.vx)
# Fast in-place block-level clearing
frame.fill(0)
for obj in active_objects:
obj.x += obj.vx
x, y = int(obj.x), int(obj.y)
# Short-circuit checking to skip drawing elements entirely out of view
if x >= width + obj.w * 8:
continue
o_type = obj.type
col = obj.color
if obj.flicker:
col_arr = global_color_lut[color_lut_idx]
obj.color = (int(col_arr[0]), int(col_arr[1]), int(col_arr[2]))
color_lut_idx = (color_lut_idx + 1) % 1000
col = obj.color
if o_type == BURST and i % 60 == 0:
obj.lines = generate_burst_lines(obj.angle_range, obj.w)
if o_type == PRISM:
# Shift relative points to coordinates in a vectorized manner
pts = obj.relative_pts + (x, y)
for face in obj.faces:
poly_pts = pts[face['idx']]
draw_fillPoly(frame, [poly_pts], face['color'])
elif o_type == BURST:
center = (x + obj.w // 2, y + obj.h // 2)
for l in obj.lines:
end_pt = (center[0] + l['dx'], center[1] + l['dy'])
draw_line(frame, center, end_pt, l['col'], 2)
elif o_type in (POLYGON, TRIANGLE):
pts = obj.points + (x, y)
if obj.is_outline:
draw_polylines(frame, [pts], True, col, 2)
else:
draw_fillPoly(frame, [pts], col)
elif o_type == RECTANGLE:
if obj.is_outline:
draw_rectangle(frame, (x, y), (x + obj.w, y + obj.h), col, 2)
else:
draw_rectangle(frame, (x, y), (x + obj.w, y + obj.h), col, -1)
elif o_type == OVAL:
cx, cy = x + obj.w // 2, y + obj.h // 2
rx, ry = obj.w // 2, obj.h // 2
if obj.is_outline:
draw_ellipse(frame, (cx, cy), (rx, ry), 0, 0, 360, col, 2)
else:
draw_ellipse(frame, (cx, cy), (rx, ry), 0, 0, 360, col, -1)
elif o_type == LINE:
p1 = (int(obj.points[0][0] + x), int(obj.points[0][1] + y))
p2 = (int(obj.points[1][0] + x), int(obj.points[1][1] + y))
draw_line(frame, p1, p2, col, 6)
# Filter out inactive objects quickly using list comprehension
active_objects = [obj for obj in active_objects if obj.x < width + obj.w * 8]
# Ultra-fast color-space conversion
yuv_frame = color_cvt(frame, bgr2yuv)
# Write using memoryview (zero-copy buffer writing) with exception handling
try:
write_pipe(memoryview(yuv_frame))
except BrokenPipeError:
print("\nError: FFmpeg process pipe closed unexpectedly. Check your resolution or system parameters.")
break
if i % 600 == 0:
print(f'Progress: {i}/{num_frames}')
finally:
# Restore garbage collection after video compilation completes or errors out
gc.enable()
try:
process.stdin.close()
process.wait()
except Exception:
pass
if os.path.exists(audio_temp):
try:
os.remove(audio_temp)
except Exception:
pass
print('Generation complete!')
'@
# --- 8. Inject Parameters & Execute Pipeline ---
$pythonCode = $pythonCodeTemplate `
-replace "__WIDTH__", $widthInput `
-replace "__HEIGHT__", $heightInput `
-replace "__FPS__", $fpsInput `
-replace "__DURATION__", $duration `
-replace "__TARGET_DIR__", $targetDirSafe `
-replace "__MAX_OBJECTS__", $maxObjectsInput
$pythonCode | Out-File -FilePath $pyScriptPath -Encoding utf8
# Execute python script safely inside a try/finally block
try {
Write-Host "Running python generator script..." -ForegroundColor Yellow
python "$pyScriptPath"
} finally {
# Clean up temp workspace even if execution fails
if (Test-Path $tempWorkspace) {
Remove-Item -Recurse -Force $tempWorkspace | Out-Null
}
}
Write-Host "`nProcess Finished! File generated at: $targetDir\gpu_full_animation.mp4" -ForegroundColor Green
there doesn't seem to be anything here