;; N-way weighted blend effect ;; Streaming-compatible: pass inputs as a list of frames ;; Usage: (blend_multi :inputs [(read a) (read b) (read c)] :weights [0.3 0.4 0.3]) ;; ;; Parameters: ;; inputs - list of N frames to blend ;; weights - list of N floats, one per input (resolved per-frame) ;; mode - blend mode applied when folding each frame in: ;; "alpha" — pure weighted average (default) ;; "multiply" — darken by multiplication ;; "screen" — lighten (inverse multiply) ;; "overlay" — contrast-boosting midtone blend ;; "soft-light" — gentle dodge/burn ;; "hard-light" — strong dodge/burn ;; "color-dodge" — brightens towards white ;; "color-burn" — darkens towards black ;; "difference" — absolute pixel difference ;; "exclusion" — softer difference ;; "add" — additive (clamped) ;; "subtract" — subtractive (clamped) ;; "darken" — per-pixel minimum ;; "lighten" — per-pixel maximum ;; resize_mode - how to match frame dimensions (fit, crop, stretch) ;; ;; Uses a left-fold over inputs[1..N-1]. At each step the running ;; opacity is: w[i] / (w[0] + w[1] + ... + w[i]) ;; which produces the correct normalised weighted result. (require-primitives "image" "blending") (define-effect blend_multi :params ( (inputs :type list :default []) (weights :type list :default []) (mode :type string :default "alpha") (resize_mode :type string :default "fit") ) (let [n (len inputs) ;; Target dimensions from first frame target-w (image:width (nth inputs 0)) target-h (image:height (nth inputs 0)) ;; Fold over indices 1..n-1 ;; Accumulator is (list blended-frame running-weight-sum) seed (list (nth inputs 0) (nth weights 0)) result (reduce (range 1 n) seed (lambda (pair i) (let [acc (nth pair 0) running (nth pair 1) w (nth weights i) new-running (+ running w) opacity (/ w (max new-running 0.001)) f (image:resize (nth inputs i) target-w target-h "linear") ;; Apply blend mode then mix with opacity blended (if (= mode "alpha") (blending:blend-images acc f opacity) (blending:blend-images acc (blending:blend-mode acc f mode) opacity))] (list blended new-running))))] (nth result 0)))