Add S-expression based video effects pipeline with modular effect definitions, constructs, and recipe files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
63 lines
1.4 KiB
Python
63 lines
1.4 KiB
Python
# /// script
|
|
# requires-python = ">=3.10"
|
|
# dependencies = ["numpy"]
|
|
# ///
|
|
"""
|
|
@effect invert
|
|
@version 1.0.0
|
|
@author artdag
|
|
|
|
@description
|
|
Inverts the colors of each frame. Can be partial (blended with original)
|
|
based on intensity parameter. Useful for beat-reactive flashing effects.
|
|
|
|
@param intensity float
|
|
@range 0 100
|
|
@default 100
|
|
Intensity of the inversion effect (0 = original, 100 = fully inverted).
|
|
Bind to audio analysis for reactive effects.
|
|
|
|
@example
|
|
(effect invert)
|
|
|
|
@example
|
|
(effect invert :intensity 50)
|
|
|
|
@example
|
|
;; Beat-reactive inversion
|
|
(effect invert :intensity (bind bass :range [0 100] :transform sqrt))
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
|
|
def process_frame(frame: np.ndarray, params: dict, state: dict) -> tuple:
|
|
"""
|
|
Invert colors of a video frame.
|
|
|
|
Args:
|
|
frame: Input frame as numpy array (H, W, 3) RGB uint8
|
|
params: Effect parameters
|
|
- intensity: 0-100, how much to invert (default 100)
|
|
state: Persistent state dict (unused for this effect)
|
|
|
|
Returns:
|
|
Tuple of (processed_frame, new_state)
|
|
"""
|
|
intensity = params.get("intensity", 100)
|
|
|
|
# Normalize intensity to 0-1
|
|
t = intensity / 100.0
|
|
|
|
if t <= 0:
|
|
return frame, state
|
|
|
|
if t >= 1:
|
|
return (255 - frame), state
|
|
|
|
# Partial inversion: blend between original and inverted
|
|
inverted = 255 - frame
|
|
result = (frame * (1 - t) + inverted * t).astype(np.uint8)
|
|
|
|
return result, state
|