#!/usr/bin/env stack -- stack runghc --package reanimate {-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ParallelListComp #-} module Main(main) where import Text.Printf {- FE articles/demos scatter: https://codepen.io/mullany/pen/JmgbRB distortion: https://codepen.io/mullany/pen/BWKePz variable stroke width: https://codepen.io/mullany/pen/qaONQm variable stroke gradient: https://codepen.io/mullany/pen/XXBMJd heart: https://codepen.io/yoksel/pen/MLVjoB elastic stroke: https://codepen.io/yoksel/pen/XJbzrO -} import Codec.Picture.Types import Control.Lens hiding (magma) import Graphics.SvgTree import Reanimate main :: IO () main = reanimate $ sceneAnimation $ do newSpriteSVG_ $ mkBackground "white" let circles = [ (900, 0.3) , (760, 0.5) , (670, 0.4) , (600, 0.6) , (450, 0.7) ] play $ pauseAtEnd 2 $ mkAnimation 10 $ \t -> mkGroup [ mkGooeyFilter 0.2 -- fromToS 0.1 0.2 $ oscillateS t , mkGroup [ lowerTransformations $ center $ withFillColor "black" $ latex "Text" , mkGroup [rotate (t*rot) $ translate (fromToS 0 3.5 $ bellS 2 $ t) 0 $ withFillColorPixel (promotePixel c) $ mkCircle (size*1.5) | (n,(rot, size)) <- zip [0..] circles , let c = turbo (n/fromIntegral (length circles-1)) ] ] & filterRef .~ pure (Ref "gooey") ] -- wait 1 mkGooeyFilter :: Double -> SVG mkGooeyFilter blur = FilterTree $ mkFilter ("gooey") [ FEGaussianBlur $ defaultSvg & gaussianBlurStdDeviationX .~ Num blur & gaussianBlurEdgeMode .~ EdgeNone & filterResult .~ Just "blur" , FEColorMatrix $ defaultSvg & colorMatrixType .~ Matrix & colorMatrixValues .~ printf "1 0 0 0 0 \ \0 1 0 0 0 \ \0 0 1 0 0 \ \0 0 0 %f %f" mul sub & colorMatrixIn .~ pure (SourceRef "blur") & filterResult .~ Just "colormatrix" ] where -- Increase alpha contrast. Turns alphaMin to 0x00 and alphaMax to 0xFF. -- Increasing alphaDiff makes the shapes softer. Decreasing it gives more -- contrast. -- alphaMin*mul + sub*255 = 0 -- alphaMax*mul + sub*255 = 255 -- alphaDiff*mul = 255 -- mul = 255/alphaDiff -- sub = -alphaMin*mul/255 mul = 255/alphaDiff sub = -alphaMin*mul/255 alphaCenter = 255/2 :: Double alphaDiff = 20 :: Double alphaMin = alphaCenter - alphaDiff/2 -- alphaMax = alphaCenter + alphaDiff/2 mkFilter :: String -> [FilterElement] -> Filter mkFilter ident fe = defaultSvg & filterChildren .~ fe & attrId ?~ ident