;; Feathered blend - blend two same-size frames with distance-based falloff ;; Center shows overlay, edges show background, with smooth transition (require-primitives "xector") (define-effect xector_feathered_blend :params ( (inner-radius :type float :default 0.3 :range [0 1] :desc "Radius where overlay is 100% (fraction of size)") (fade-width :type float :default 0.2 :range [0 0.5] :desc "Width of fade region (fraction of size)") (overlay :type frame :default nil :desc "Frame to blend in center") ) (let* ( ;; Get normalized distance from center (0 at center, ~1 at corners) (dist (dist-from-center frame)) (max-dist (βmax dist)) (dist-norm (α/ dist max-dist)) ;; Calculate blend factor: ;; - 1.0 when dist-norm < inner-radius (fully overlay) ;; - 0.0 when dist-norm > inner-radius + fade-width (fully background) ;; - linear ramp between (t (α/ (α- dist-norm inner-radius) fade-width)) (blend (α- 1 (αclamp t 0 1))) (inv-blend (α- 1 blend)) ;; Background channels (bg-r (red frame)) (bg-g (green frame)) (bg-b (blue frame))) (if (nil? overlay) ;; No overlay - visualize the blend mask (let ((vis (α* blend 255))) (rgb vis vis vis)) ;; Blend overlay with background using the mask (let* ((ov-r (red overlay)) (ov-g (green overlay)) (ov-b (blue overlay)) ;; lerp: bg * (1-blend) + overlay * blend (r-out (α+ (α* bg-r inv-blend) (α* ov-r blend))) (g-out (α+ (α* bg-g inv-blend) (α* ov-g blend))) (b-out (α+ (α* bg-b inv-blend) (α* ov-b blend)))) (rgb r-out g-out b-out)))))