packages feed

reanimate 0.5.0.1 → 1.0.0.0

raw patch · 69 files changed

+544/−407 lines, 69 filesbinary-addedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Reanimate: sceneAnimation :: (forall s. Scene s a) -> Animation
- Reanimate.Scene: sceneAnimation :: (forall s. Scene s a) -> Animation
+ Reanimate: scene :: (forall s. Scene s a) -> Animation
+ Reanimate.Scene: oCenterX :: Lens' (ObjectData a) Double
+ Reanimate.Scene: oCenterY :: Lens' (ObjectData a) Double
+ Reanimate.Scene: oTranslateX :: Lens' (ObjectData a) Double
+ Reanimate.Scene: oTranslateY :: Lens' (ObjectData a) Double
- Reanimate.Scene: cameraFocus :: Object s Camera -> (Double, Double) -> Scene s ()
+ Reanimate.Scene: cameraFocus :: Object s Camera -> V2 Double -> Scene s ()
- Reanimate.Scene: cameraPan :: Object s Camera -> Duration -> (Double, Double) -> Scene s ()
+ Reanimate.Scene: cameraPan :: Object s Camera -> Duration -> V2 Double -> Scene s ()
- Reanimate.Scene: cameraSetPan :: Object s Camera -> (Double, Double) -> Scene s ()
+ Reanimate.Scene: cameraSetPan :: Object s Camera -> V2 Double -> Scene s ()
- Reanimate.Scene: oCenterXY :: Lens' (ObjectData a) (Double, Double)
+ Reanimate.Scene: oCenterXY :: Lens' (ObjectData a) (V2 Double)
- Reanimate.Scene: oScaleOrigin :: Lens' (ObjectData a) (Double, Double)
+ Reanimate.Scene: oScaleOrigin :: Lens' (ObjectData a) (V2 Double)
- Reanimate.Scene: oTranslate :: Lens' (ObjectData a) (Double, Double)
+ Reanimate.Scene: oTranslate :: Lens' (ObjectData a) (V2 Double)

Files

ChangeLog.md view
@@ -6,6 +6,20 @@ project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) +## 1.0.0.0 -- 2020-09-20++### Changed++ * Objects: Use Linear.V2 instead of tuples.+ * Reanimate.Scene.sceneAnimation -> Reanimate.Scene.scene++### Other/Non-visible++ * Improved object documentation.+ * CI stability improvements.+ * Add interactive tutorial.+ * Minor playground improvements.+ ## 0.5.0.0 -- 2020-09-09  ### Added@@ -14,7 +28,7 @@  ### Changed -* Improve efficiency of time variables (thanks to ).+* Improve efficiency of time variables (thanks to Shaurya Gupta). * Major refactoring of SVG interface. * Haddock improvements. * Improve consistency of object bounding-box calculations.
+ docs/gifs/doc_oGrow.gif view

binary file changed (absent → 68106 bytes)

+ docs/gifs/doc_oHideWith.gif view

binary file changed (absent → 53397 bytes)

examples/bug_play1.hs view
@@ -6,6 +6,6 @@  -- This should give circle. main :: IO ()-main = reanimate $ signalA (constantS 0) $ sceneAnimation $ do+main = reanimate $ signalA (constantS 0) $ scene $ do   play $ animate $ const $ mkCircle 1   play $ animate $ const $ mkRect 1 1
examples/bug_play2.hs view
@@ -6,6 +6,6 @@  -- This should give rect. main :: IO ()-main = reanimate $ signalA (constantS 0.5) $ sceneAnimation $ do+main = reanimate $ signalA (constantS 0.5) $ scene $ do   play $ animate $ const $ mkCircle 1   play $ animate $ const $ mkRect 1 1
examples/bug_play3.hs view
@@ -6,6 +6,6 @@  -- This should give rect. main :: IO ()-main = reanimate $ signalA (constantS 1) $ sceneAnimation $ do+main = reanimate $ signalA (constantS 1) $ scene $ do   play $ animate $ const $ mkCircle 1   play $ animate $ const $ mkRect 1 1
examples/bug_quad.hs view
@@ -8,7 +8,7 @@ import Reanimate.Morph.Linear  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do     play $ animate $ \t -> morph rawLinear src dst t   where     src = mkPathString "M 0 0 q 1 1, 2 0 z"
examples/demo_stars.hs view
@@ -23,7 +23,7 @@ import qualified Data.Vector                   as V  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   play $ trails 0.05 starAnimation 
examples/doc_applyVar.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- fork $ newSpriteA drawBox   v <- newVar 0   applyVar v s rotate
examples/doc_cameraAttach.hs view
@@ -8,7 +8,7 @@ import Control.Lens  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   cam <- newObject Camera   circ <- newObject $ Circle 2   oModifyS circ $
examples/doc_cameraFocus.hs view
@@ -6,20 +6,21 @@ import Reanimate.Builtin.Documentation import Reanimate.Scene import Control.Lens+import Linear.V2  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   cam <- newObject Camera   circ <- newObject $ Circle 2; oShow circ-  oModify circ $ oTranslate .~ (-3,0)+  oModify circ $ oTranslate .~ V2 (-3) 0   box <- newObject $ Rectangle 4 4; oShow box-  oModify box $ oTranslate .~ (3,0)+  oModify box $ oTranslate .~ V2 3 0    cameraAttach cam circ   cameraAttach cam box-  cameraFocus cam (-3,0)+  cameraFocus cam (V2 (-3) 0)   cameraZoom cam 2 2   cameraZoom cam 2 1-  cameraFocus cam (3,0)+  cameraFocus cam (V2 3 0)   cameraZoom cam 2 2   cameraZoom cam 2 1
examples/doc_destroySprite.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- newSpriteSVG $ withFillOpacity 1 $ mkCircle 1   fork $ wait 1 >> destroySprite s   play drawBox
examples/doc_fork.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   fork $ play drawBox   play drawCircle
examples/doc_newSprite.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   _ <- newSprite $ mkCircle <$> spriteT -- Circle sprite where radius=time.   wait 2
examples/doc_newSpriteA'.hs view
@@ -7,7 +7,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   _ <- fork $ newSpriteA' SyncFreeze drawCircle   play drawBox   play $ reverseA drawBox
examples/doc_newSpriteA.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   _ <- fork $ newSpriteA drawCircle   play drawBox   play $ reverseA drawBox
examples/doc_newSpriteSVG.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   _ <- newSpriteSVG $ mkBackground "lightblue"   play drawCircle
examples/doc_oDraw.hs view
@@ -9,8 +9,6 @@ import Control.Lens  main :: IO ()--- main = reanimate $ docEnv $ oDraw $---   withFillOpacity 1 $ withStrokeWidth (defaultStrokeWidth*0) $ center $ scale 2 $ latex "oDraw" main = reanimate $ docEnv $ scene $ do   txt <- oNew $ withStrokeWidth 0 $ withFillOpacity 1 $     center $ scale 4 $ latex "oDraw"
+ examples/doc_oGrow.hs view
@@ -0,0 +1,15 @@+#!/usr/bin/env stack+-- stack runghc --package reanimate+{-# LANGUAGE OverloadedStrings #-}+module Main(main) where++import Reanimate+import Reanimate.Scene+import Reanimate.Builtin.Documentation++main :: IO ()+main = reanimate $ docEnv $ scene $ do+  txt <- oNew $ withStrokeWidth 0 $ withFillOpacity 1 $+    center $ scale 3 $ latex "oGrow"+  oShowWith txt oGrow+  wait 1; oHideWith txt oFadeOut
examples/doc_play.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   play drawBox   play drawCircle
examples/doc_queryNow.hs view
@@ -8,7 +8,7 @@ import qualified Data.Text as T  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do     now <- play drawCircle *> queryNow     play $ staticFrame 1 $ scale 2 $ withStrokeWidth 0.05 $       mkText $ "Now=" <> T.pack (show now)
examples/doc_simpleVar.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   var <- simpleVar mkCircle 0   tweenVar var 2 $ \val -> fromToS val (screenHeight/2)
examples/doc_spriteE.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- fork $ newSpriteA drawCircle   spriteE s $ overBeginning 1 fadeInE   spriteE s $ overEnding 0.5 fadeOutE
examples/doc_spriteMap.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- fork $ newSpriteA drawCircle   wait 1   spriteMap s flipYAxis
examples/doc_spriteScope.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   -- the rect lives through the entire 3s animation   newSpriteSVG_ $ translate (-3) 0 $ mkRect 4 4   wait 1
examples/doc_spriteTween.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- fork $ newSpriteA drawCircle   spriteTween s 1 $ \val -> translate (screenWidth*0.3*val) 0
examples/doc_spriteVar.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s <- fork $ newSpriteA drawBox   v <- spriteVar s 0 rotate   tweenVar v 2 $ \val -> fromToS val 90
examples/doc_spriteZ.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   s1 <- newSpriteSVG $ withFillOpacity 1 $ withFillColor "blue" $ mkCircle 3   _ <- newSpriteSVG $ withFillOpacity 1 $ withFillColor "red" $ mkRect 8 3   wait 1
examples/doc_unVar.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   v <- newVar 0   _ <- newSprite $ mkCircle <$> unVar v   tweenVar v 1 $ \val -> fromToS val 3
examples/doc_wait.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   fork $ play drawBox   wait 1   play drawCircle
examples/doc_waitOn.hs view
@@ -6,6 +6,6 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   waitOn $ fork $ play drawBox   play drawCircle
examples/doc_writeVar.hs view
@@ -6,7 +6,7 @@ import Reanimate.Builtin.Documentation  main :: IO ()-main = reanimate $ docEnv $ sceneAnimation $ do+main = reanimate $ docEnv $ scene $ do   v <- newVar 0   _ <- newSprite $ mkCircle <$> unVar v   writeVar v 1; wait 1
examples/fe_bleed.hs view
@@ -61,7 +61,7 @@   scaleToHeight screenHeight $ center $ unpackImage githubIcon  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do     newSpriteSVG_ $ mkBackground "white"     -- newSpriteSVG_ $     --   mkClipPath "clip" $
examples/fe_morph.hs view
@@ -22,7 +22,7 @@ import           Reanimate  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do     newSpriteSVG_ $ mkBackground "white"     let circles =           [ (900, 0.3)
examples/intro_canvas.hs view
@@ -18,7 +18,7 @@ import           Text.Printf  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   newSpriteSVG_ static   dotPath  <- newVar (QuadBezier (V2 0 0) (V2 0 0) (V2 0 0))
examples/intro_canvas_square.hs view
@@ -22,7 +22,7 @@ newHeight = 8  main :: IO ()-main = reanimate $ mapA squareViewBox $ sceneAnimation $ do+main = reanimate $ mapA squareViewBox $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   newSpriteSVG_ static   dotPath  <- newVar (QuadBezier (V2 0 0) (V2 0 0) (V2 0 0))
examples/knock_knock.hs view
@@ -12,7 +12,7 @@ import           Reanimate.Scene  main :: IO ()-main = reanimate $ docEnv $ mapA (withFillOpacity 1) $ sceneAnimation $ do+main = reanimate $ docEnv $ mapA (withFillOpacity 1) $ scene $ do   line1 <- newLaTeX ["$>$ ", "knock!", " ", "knock!"]   oModifyMany line1 $     oTopY .~ screenTop
examples/latex_wheel.hs view
@@ -15,7 +15,7 @@     bg = animate $ const $ mkBackground "black"  mainScene :: Animation-mainScene = sceneAnimation $ mdo+mainScene = scene $ mdo     play $ drawCircle       & setDuration drawCircleT       & applyE (constE $ scaleXY (-1) 1)
examples/morphology_closest.hs view
@@ -23,7 +23,7 @@   mapA (withStrokeColor "black") $   mapA (withStrokeLineJoin JoinRound) $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       _ <- newSpriteSVG $         withStrokeWidth 0 $ translate (-4) 4 $         center $ latex "no-op"
examples/morphology_color.hs view
@@ -19,7 +19,7 @@   setDuration 5 $   mapA (withStrokeWidth 0) $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       doMorph yellow blue       doMorph blue yellow   where
examples/morphology_intro.hs view
@@ -19,7 +19,7 @@   mapA (withStrokeWidth 0) $   mapA (withStrokeColor "black") $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       play $ step stage1 stage2       play $ step stage2 stage3       play $ step stage3 stage4
examples/morphology_linear.hs view
@@ -22,7 +22,7 @@   mapA (withStrokeColor "black") $   mapA (withStrokeLineJoin JoinRound) $   mapA (withFillOpacity 1) $-    sceneAnimation $+    scene $       showPair (stages ++ take 1 stages)   where     showPair (from:to:rest) =
examples/morphology_object_correspondence.hs view
@@ -19,7 +19,7 @@   mapA (withStrokeWidth 0) $   mapA (withStrokeColor "black") $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       let showLabel label = do             fork $ play $ staticFrame 4 (center $ latex label)               & mapA (translate 0 4)
examples/morphology_point_correspondence.hs view
@@ -26,7 +26,7 @@   mapA (withStrokeWidth 0) $   mapA (withStrokeColor "black") $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       let pl1 = translate (-4) 0 $ mkGroup             [ lowerTransformations $ scale 3 $ withFillOpacity 1 $               withStrokeColor "black" $
examples/morphology_rotational.hs view
@@ -24,7 +24,7 @@   mapA (withStrokeColor "black") $   mapA (withStrokeLineJoin JoinRound) $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       _ <- newSpriteSVG $         withStrokeWidth 0 $ translate (-3) 4 $         center $ latex "linear"
examples/morphology_rotational_intro.hs view
@@ -43,7 +43,7 @@   mapA (withStrokeColor "black") $   mapA (withStrokeLineJoin JoinRound) $   mapA (withFillOpacity 1) $-    sceneAnimation $ do+    scene $ do       _ <- newSpriteSVG $         withStrokeWidth 0 $ translate (-4) 4 $         center $ latex "linear"
examples/scene_camera.hs view
@@ -7,101 +7,10 @@ import Reanimate.Builtin.Documentation import Reanimate.Scene import Control.Lens+import Linear.V2  main :: IO ()-{--main = reanimate $ docEnv $ mapA (withFillOpacity 1) $ sceneAnimation $ do-  cam <- newObject Camera--  newSpriteSVG_ $ withStrokeWidth (defaultStrokeWidth*0.5) $ mkGroup-    [ mkLine (0, screenBottom) (0, screenTop)-    , mkLine (screenLeft, 0) (screenRight, 0)-    ]--  box <- newObject $ Rectangle 1 1-  cameraAttach cam box-  oModify box $ oContext .~ withFillColor "green"-  oModify box $ oMargin .~ (0,0,0,0)-  oModify box $ oLeftX .~ 0-  oModify box $ oBottomY .~ 0-  oModify box $ oContext .~ withStrokeWidth 0--  box2 <- newObject $ Rectangle 1 1-  cameraAttach cam box2-  oModify box2 $ oContext .~ withFillColor "blue"-  oModify box2 $ oMargin .~ (0,0,0,0)-  oModify box2 $ oCenterXY .~ (-2,2)-  oModify box2 $ oContext .~ withStrokeWidth 0--  dot <- newObject $ Circle 0.05-  cameraAttach cam dot-  oModify dot $ oContext .~ withFillColor "red"-  oModify dot $ oMargin .~ (0,0,0,0)-  oModify dot $ oCenterXY .~ (0.5,0.5)-  oModify dot $ oContext .~ withStrokeWidth 0--  dot2 <- newObject $ Circle 0.05-  cameraAttach cam dot2-  oModify dot2 $ oContext .~ withFillColor "red"-  oModify dot2 $ oMargin .~ (0,0,0,0)-  oModify dot2 $ oCenterXY .~ (-2,2)-  oModify dot2 $ oContext .~ withStrokeWidth 0-  -  oShow box-  oShow box2-  oShow dot-  oShow dot2--  wait 1--  cameraSetFocus cam (0.5, 0.5)-  waitOn $ do-    fork $ cameraPan cam 1 (0.5, 0.5)-    fork $ cameraZoom cam 1 2-  wait 1-  cameraSetFocus cam (-2,2)-  cameraZoom cam 0.5 1.5-  cameraZoom cam 0.5 2-  wait 1-  -- cameraSetFocus cam (-0.5,0.5)-  waitOn $ do-    fork $ cameraPan cam 1 (-2, 2)-    fork $ cameraZoom cam 1 0.5-  -- oTweenS cam 2 $ \t -> do-  --   oScale %= \v -> fromToS v 3 t-  -  -- cameraSetFocus cam (0.5,0.5)-  -  -- oTweenS cam 1 $ \t -> do-  --   oScale %= \v -> fromToS v 1 t-  -- wait 4-  -- oTweenS cam 2 $ \t -> do-  --   oScaleOrigin .= (fromToS 0.5 (-2) t, fromToS 0.5 2 t)-  --   oScale .= fromToS 2 1 t-  --   oTranslate . _1 %= \v -> fromToS v (-2) t-  --   oTranslate . _2 %= \v -> fromToS v 2 t-  {--    Origin: (-2,2)-    Translate: (3, -1)-    New origin: (0.5, 0.5)--    (0.5, 0.5)-    (0.5+2, 0.5-2)-    (2.5, -1.5)      origin move-    (2.5*3, -1.5*3)-    (7.5, -4.5)      scale-    (7.5-2, -4.5+2)-    (5.5, -2.5)      origin move back-    (5.5-3, -2.5+1)-    (2.5, -1.5)      translate--    (0.5-2.5, 0.5-(-1.5))-    (-2, 2)-  -}--  wait 1--}-main = reanimate $ docEnv $ mapA (withFillOpacity 1) $ sceneAnimation $ do+main = reanimate $ docEnv $ mapA (withFillOpacity 1) $ scene $ do   cam <- newObject Camera    txt <- newObject $ center $ latex "Fixed (non-cam)"@@ -141,4 +50,4 @@   waitOn $ do     fork $ cameraZoom cam 3 1   waitOn $ do-    fork $ cameraPan cam 1 (0,0)+    fork $ cameraPan cam 1 (V2 0 0)
+ examples/tut_eq_final.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Control.Lens+import Control.Monad+import Reanimate+import Reanimate.Scene++main :: IO ()+main = reanimate animation++animation :: Animation+animation = env $+  scene $ do+    symbols <-+      mapM+        oNew+        [symb_e, symb_eq, symb_m, symb_c2]+    mapM_ oShow symbols+    wait 1++    forM_ (zip symbols yPositions) $+      \(obj, yPos) -> do+        fork $+          oTweenS obj 1 $ \t -> do+            oScale %= \origin -> fromToS origin scaleFactor t+            oLeftX %= \origin -> fromToS origin screenLeft t+            oCenterY %= \origin -> fromToS origin yPos t+        wait 0.3++    wait 1++    ls <- mapM oNew [energy, equals, mass, speedOfLight]++    -- Maybe show lines with the same center as the symbols.+    -- Then show how to align the baselines.+    forM_ (zip ls yPositions) $+      \(obj, nth) -> do+        --bot <- oRead (symbols!!nth) oBottomY+        --margin <- oRead (symbols!!nth) oMarginBottom+        oModifyS obj $ do+          oLeftX .= -4+          --oTranslateY .= bot+margin+          oCenterY .= nth+        oShowWith obj oDraw++    wait 2++    forM_ ls $ \obj ->+      fork $ oHideWith obj oFadeOut++    forM_ (reverse symbols) $ \obj -> do+      fork $+        oTweenS obj 1 $ \t -> do+          oScale %= \origin -> fromToS origin 1 t+          (oTranslate . _1) %= \pos -> fromToS pos 0 t+          (oTranslate . _2) %= \pos -> fromToS pos 0 t+      wait 0.3+    wait 2++scaleFactor :: Double+scaleFactor = 0.7++symb_e :: SVG+symb_e = snd $ splitGlyphs [0] svg++symb_eq :: SVG+symb_eq = snd $ splitGlyphs [1] svg++symb_m :: SVG+symb_m = snd $ splitGlyphs [2] svg++symb_c2 :: SVG+symb_c2 = snd $ splitGlyphs [3, 4] svg++svg :: SVG+svg =+  scale 3 $+    center $+      latexAlign "E = mc^2"++energy :: SVG+energy =+  scale 1.5 $+    centerX $+      latex "Energy"++equals :: SVG+equals =+  scale 1.5 $+    centerX $+      latex "equals"++mass :: SVG+mass =+  scale 1.5 $+    centerX $+      latex "mass times"++speedOfLight :: SVG+speedOfLight =+  scale 1.5 $+    centerX $+      latex "speed of light$^2$"++yPositions :: [Double]+yPositions = [3, 1, -1, -3]++env :: Animation -> Animation+env =+  addStatic (mkBackground "lightblue")+    . mapA (withStrokeWidth defaultStrokeWidth)+    . mapA (withStrokeColor "black")
examples/tut_glue_blender.hs view
@@ -22,7 +22,7 @@ -- spritePercent = (/) <$> spriteT <*> spriteDur  main :: IO ()-main = seq texture $ reanimate $ pauseAtEnd 1 $ addStatic bg $ sceneAnimation $ do+main = seq texture $ reanimate $ pauseAtEnd 1 $ addStatic bg $ scene $ do     bend <- newVar 0     trans <- newVar 0     rotX <- newVar 0@@ -200,7 +200,7 @@   latexExample :: Animation-latexExample = sceneAnimation $ do+latexExample = scene $ do     -- Draw equation     play $ drawAnimation strokedSvg     sprites <- forM glyphs $ \(fn, _, elt) ->@@ -250,7 +250,7 @@ drawAnimation = drawAnimation' Nothing 0.5 0.3  drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation-drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do+drawAnimation' mbSeed fillDur step svg = scene $ do   forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do     let sWidth =           case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
examples/tut_glue_fourier.hs view
@@ -12,7 +12,7 @@  -- layer 3 main :: IO ()-main = reanimate $ setDuration 30 $ sceneAnimation $ do+main = reanimate $ setDuration 30 $ scene $ do     _ <- newSpriteSVG $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)     play $ fourierA (fromToS 0 5)      -- Rotate 15 times       & setDuration 50
examples/tut_glue_keyframe.hs view
@@ -21,7 +21,7 @@     bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)  mainScene :: Animation-mainScene = sceneAnimation $ mdo+mainScene = scene $ mdo     play $ drawCircle       & setDuration drawCircleT       & applyE (constE flipXAxis)
examples/tut_glue_latex.hs view
@@ -22,7 +22,7 @@     bg = animate $ const $ mkBackgroundPixel (PixelRGBA8 252 252 252 0xFF)  latexExample :: Animation-latexExample = sceneAnimation $ do+latexExample = scene $ do     -- Draw equation     play $ drawAnimation strokedSvg     sprites <- forM glyphs $ \(fn, _, elt) ->@@ -72,7 +72,7 @@ drawAnimation = drawAnimation' Nothing 0.5 0.3  drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation-drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do+drawAnimation' mbSeed fillDur step svg = scene $ do   forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do     let sWidth =           case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
examples/tut_glue_potrace.hs view
@@ -15,7 +15,7 @@ import           NeatInterpolation  main :: IO ()-main = reanimate $ parA bg $ sceneAnimation $ do+main = reanimate $ parA bg $ scene $ do     play $ mkAnimation drawDuration $ \t -> partialSvg t (wireframe (-45) 220)     xRot <- newVar (-45)     yRot <- newVar 220
examples/tut_glue_povray.hs view
@@ -23,7 +23,7 @@   main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do     newSpriteSVG $ mkBackgroundPixel $ PixelRGBA8 252 252 252 0xFF     zPos <- newVar 0     xRot <- newVar 0@@ -93,7 +93,7 @@   latexExample :: Animation-latexExample = sceneAnimation $ do+latexExample = scene $ do     -- Draw equation     play $ drawAnimation strokedSvg     sprites <- forM glyphs $ \(fn, _, elt) ->@@ -143,7 +143,7 @@ drawAnimation = drawAnimation' Nothing 0.5 0.3  drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation-drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do+drawAnimation' mbSeed fillDur step svg = scene $ do   forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do     let sWidth =           case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
examples/tut_glue_povray_ortho.hs view
@@ -23,7 +23,7 @@   main :: IO ()-main = reanimate $ parA bg $ sceneAnimation $ do+main = reanimate $ parA bg $ scene $ do     xRot <- newVar (-30)     yRot <- newVar 180     zRot <- newVar 0@@ -131,7 +131,7 @@   latexExample :: Animation-latexExample = sceneAnimation $ do+latexExample = scene $ do     -- Draw equation     play $ drawAnimation strokedSvg     sprites <- forM glyphs $ \(fn, _, elt) ->@@ -181,7 +181,7 @@ drawAnimation = drawAnimation' Nothing 0.5 0.3  drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation-drawAnimation' mbSeed fillDur step svg = sceneAnimation $ do+drawAnimation' mbSeed fillDur step svg = scene $ do   forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do     let sWidth =           case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of
examples/voice_advanced.hs view
@@ -19,7 +19,7 @@ transcript = loadTranscript "voice_advanced.txt"  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   bg <- newSpriteSVG $ mkBackgroundPixel rtfdBackgroundColor   spriteZ bg (-100)   newSpriteSVG_ $ mkGroup
examples/voice_fake.hs view
@@ -21,7 +21,7 @@     \during development"  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   waitOn $ forM_ (splitTranscript transcript) $ \(svg, tword) -> do     highlighted <- newVar 0
examples/voice_transcript.hs view
@@ -15,7 +15,7 @@ transcript = loadTranscript "voice_transcript.txt"  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   waitOn $ forM_ (splitTranscript transcript) $ \(svg, tword) -> fork $ do     let render v = centerUsing (latex $ transcriptText transcript) $ masked
examples/voice_triggers.hs view
@@ -20,7 +20,7 @@   translate (-4) 0 . centerUsing (latex $ transcriptText transcript)  main :: IO ()-main = reanimate $ sceneAnimation $ do+main = reanimate $ scene $ do   newSpriteSVG_ $ mkBackgroundPixel rtfdBackgroundColor   waitOn $ forM_ (splitTranscript transcript) $ \(svg, tword) -> do     let render v = transformer $ masked (wordKey tword)
reanimate.cabal view
@@ -3,7 +3,7 @@ --  see http://haskell.org/cabal/users-guide/  name:                reanimate-version:             0.5.0.1+version:             1.0.0.0 -- synopsis: -- description: license:             PublicDomain
src/Reanimate.hs view
@@ -77,7 +77,7 @@     -- ** Scenes     Scene   , ZIndex-  , sceneAnimation    -- :: (forall s. Scene s a) -> Animation+  , scene             -- :: (forall s. Scene s a) -> Animation   , play              -- :: Animation -> Scene s ()   , fork              -- :: Scene s a -> Scene s a   , queryNow          -- :: Scene s Time
src/Reanimate/GeoProjection.hs view
@@ -376,7 +376,7 @@   where     forward (LonLat lam phi) =       XYCoord ((lam+pi)/tau)-        (min 1 $ max 0 $ ((log(tan(pi/4+phi/2))) + pi)/tau)+        (min 1 $ max 0 $ (log(tan(pi/4+phi/2)) + pi)/tau)     inverse (XYCoord x y) = LonLat xPi (atan (sinh yPi))       where         xPi = fromToS (-pi) pi x@@ -384,7 +384,7 @@  thetas :: V.Vector Double thetas = V.fromList $-  map (find_theta_fast . fromIndex) [0 .. granularity]+  map (findThetaFast . fromIndex) [0 .. granularity]  granularity :: Int granularity = 50000@@ -421,9 +421,9 @@         lam = pi*x/(2*sqrt2*cos theta)         phi = asin ((2*theta+sin(2*theta))/pi) -find_theta_fast :: Double -> Double-find_theta_fast !phi | abs phi == pi/2 = signum phi * halfPi-find_theta_fast (D# phi) = go phi+findThetaFast :: Double -> Double+findThetaFast !phi | abs phi == pi/2 = signum phi * halfPi+findThetaFast (D# phi) = go phi   where     !(D# pi#) = pi     go acc =
src/Reanimate/Render.hs view
@@ -68,7 +68,7 @@         now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth         frame = frameAt (if frameCount <= 1 then 0 else now) ani         path = folder </> show nth <.> "svg"-        ~svg = renderSvg Nothing Nothing frame+        svg = renderSvg Nothing Nothing frame      idempotentFile path $       writeFile path svg
src/Reanimate/Scene.hs view
@@ -1,10 +1,3 @@-{-# LANGUAGE ApplicativeDo #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}- -- | -- Module      : Reanimate.Scene -- Copyright   : Written by David Himmelstrup@@ -19,7 +12,6 @@     Scene,     ZIndex,     scene, -- :: (forall s. Scene s a) -> Animation-    sceneAnimation, -- :: (forall s. Scene s a) -> Animation     play, -- :: Animation -> Scene s ()     fork, -- :: Scene s a -> Scene s a     queryNow, -- :: Scene s Time@@ -77,6 +69,8 @@      -- ** Object Properties     oTranslate,+    oTranslateX,+    oTranslateY,     oSVG,     oContext,     oMargin,@@ -100,29 +94,31 @@     oLeftX,     oRightX,     oCenterXY,+    oCenterX,+    oCenterY,     oValue,      -- ** Graphics object methods     oShow,     oHide,+    oShowWith,+    oHideWith,     oFadeIn,     oFadeOut,     oGrow,     oShrink,     oTransform,-    oShowWith,-    oHideWith,     Origin,     oScaleIn,     oScaleIn',     oScaleOut,     oScaleOut',+    oDraw,     oSim,     oStagger,     oStaggerRev,     oStagger',     oStaggerRev',-    oDraw,     -- , oBalloon      -- ** Pre-defined objects
src/Reanimate/Scene/Core.hs view
@@ -43,6 +43,7 @@ instance MonadFix (Scene s) where   mfix fn = M $ \t -> mfix (\v -> let (a, _s, _p, _gens) = v in unM (fn a) t) +-- | Lift ST action into the Scene monad. liftST :: ST s a -> Scene s a liftST action = M $ \_ -> action >>= \a -> return (a, 0, 0, []) @@ -54,11 +55,7 @@  -- | Render a 'Scene' to an 'Animation'. scene :: (forall s. Scene s a) -> Animation-scene = sceneAnimation---- | Render a 'Scene' to an 'Animation'.-sceneAnimation :: (forall s. Scene s a) -> Animation-sceneAnimation action =+scene action =   runST     ( do         (_, s, p, gens) <- unM action 0@@ -82,8 +79,8 @@ --   Example: -- -- @--- do 'fork' $ 'play' 'Reanimate.Builtin.Documentation.drawBox'---    'play' 'Reanimate.Builtin.Documentation.drawCircle'+-- do 'fork' $ 'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawBox'+--    'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawCircle' -- @ -- --   <<docs/gifs/doc_fork.gif>>@@ -97,8 +94,8 @@ --   Example: -- -- @--- do now \<- 'play' 'Reanimate.Builtin.Documentation.drawCircle' *\> 'queryNow'---    'play' $ 'staticFrame' 1 $ 'scale' 2 $ 'withStrokeWidth' 0.05 $+-- do now \<- 'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawCircle' *\> 'queryNow'+--    'Reanimate.Scene.play' $ 'staticFrame' 1 $ 'scale' 2 $ 'withStrokeWidth' 0.05 $ --      'mkText' $ "Now=" <> T.pack (show now) -- @ --@@ -111,9 +108,9 @@ --   Example: -- -- @--- do 'fork' $ 'play' 'Reanimate.Builtin.Documentation.drawBox'+-- do 'fork' $ 'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawBox' --    'wait' 1---    'play' 'Reanimate.Builtin.Documentation.drawCircle'+--    'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawCircle' -- @ -- --   <<docs/gifs/doc_wait.gif>>@@ -131,8 +128,8 @@ --   Example: -- -- @--- do 'waitOn' $ 'fork' $ 'play' 'Reanimate.Builtin.Documentation.drawBox'---    'play' 'Reanimate.Builtin.Documentation.drawCircle'+-- do 'waitOn' $ 'fork' $ 'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawBox'+--    'Reanimate.Scene.play' 'Reanimate.Builtin.Documentation.drawCircle' -- @ -- --   <<docs/gifs/doc_waitOn.gif>>
src/Reanimate/Scene/Object.hs view
@@ -2,6 +2,8 @@ {-# LANGUAGE RecordWildCards #-} module Reanimate.Scene.Object where +import Linear.V2+import Linear.Vector import Control.Lens import Control.Monad (forM_, void) import Control.Monad.State (State, execState)@@ -46,7 +48,7 @@  -- | Container for object properties. data ObjectData a = ObjectData-  { _oTranslate :: (Double, Double),+  { _oTranslate :: V2 Double,     _oValueRef :: a,     _oSVG :: SVG,     _oContext :: SVG -> SVG,@@ -58,7 +60,7 @@     _oZIndex :: Int,     _oEasing :: Signal,     _oScale :: Double,-    _oScaleOrigin :: (Double, Double)+    _oScaleOrigin :: V2 Double   }  -- Basic lenses@@ -66,9 +68,17 @@ -- FIXME: Maybe 'position' is a better name.  -- | Object position. Default: \<0,0\>-oTranslate :: Lens' (ObjectData a) (Double, Double)+oTranslate :: Lens' (ObjectData a) (V2 Double) oTranslate = lens _oTranslate $ \obj val -> obj {_oTranslate = val} +-- | Object X position. Default: 0+oTranslateX :: Lens' (ObjectData a) Double+oTranslateX = oTranslate . _x++-- | Object Y position. Default: 0+oTranslateY :: Lens' (ObjectData a) Double+oTranslateY = oTranslate . _y+ -- | Rendered SVG node of an object. Does not include context --   or object properties. Read-only. oSVG :: Getter (ObjectData a) SVG@@ -112,7 +122,7 @@ oScale = lens _oScale $ \obj val -> oComputeBB obj {_oScale = val}  -- | Origin point for scaling. Default: \<0,0\>-oScaleOrigin :: Lens' (ObjectData a) (Double, Double)+oScaleOrigin :: Lens' (ObjectData a) (V2 Double) oScaleOrigin = lens _oScaleOrigin $ \obj val -> oComputeBB obj {_oScaleOrigin = val}  -- Smart lenses@@ -184,7 +194,7 @@       obj & (oTranslate . _1) +~ val - getter obj  -- | Derived location of an object's center point.-oCenterXY :: Lens' (ObjectData a) (Double, Double)+oCenterXY :: Lens' (ObjectData a) (V2 Double) oCenterXY = lens getter setter   where     getter obj =@@ -192,13 +202,21 @@           miny = obj ^. oBBMinY           w = obj ^. oBBWidth           h = obj ^. oBBHeight-          (dx, dy) = obj ^. oTranslate-       in (dx + minx + w / 2, dy + miny + h / 2)-    setter obj (dx, dy) =-      let (x, y) = getter obj+          V2 dx dy = obj ^. oTranslate+       in V2 (dx + minx + w / 2) (dy + miny + h / 2)+    setter obj (V2 dx dy) =+      let V2 x y = getter obj        in obj & (oTranslate . _1) +~ dx - x             & (oTranslate . _2) +~ dy - y +-- | Derived location of an object's center X value.+oCenterX :: Lens' (ObjectData a) Double+oCenterX = oCenterXY . _x++-- | Derived location of an object's center Y value.+oCenterY :: Lens' (ObjectData a) Double+oCenterY = oCenterXY . _y+ -- | Object's top margin. oMarginTop :: Lens' (ObjectData a) Double oMarginTop = oMargin . _1@@ -278,7 +296,7 @@   ref <-     newVar       ObjectData-        { _oTranslate = (0, 0),+        { _oTranslate = V2 0 0,           _oValueRef = val,           _oSVG = svg,           _oContext = id,@@ -289,14 +307,14 @@           _oZIndex = 1,           _oEasing = curveS 2,           _oScale = 1,-          _oScaleOrigin = (0, 0)+          _oScaleOrigin = V2 0 0         }   sprite <- newSprite $ do     ~obj@ObjectData {..} <- unVar ref     pure $       if _oShown         then-          uncurry translate _oTranslate $+          uncurryV2 translate _oTranslate $             oScaleApply obj $               withGroupOpacity _oOpacity $                 mkGroup [_oContext _oSVG]@@ -314,10 +332,13 @@  oScaleApply :: ObjectData a -> (SVG -> SVG) oScaleApply ObjectData {..} =-  uncurry translate (_oScaleOrigin & both %~ negate)+  uncurryV2 translate (negate _oScaleOrigin)     . scale _oScale-    . uncurry translate _oScaleOrigin+    . uncurryV2 translate _oScaleOrigin +uncurryV2 :: (a -> a -> b) -> V2 a -> b+uncurryV2 fn (V2 a b) = fn a b+ ------------------------------------------------------------------------------- -- Graphical transformations @@ -329,6 +350,10 @@ oHide :: Object s a -> Scene s () oHide o = oModify o $ oShown .~ False +-- | Show object with an animator function. The animator is responsible for+--   transitioning the object from invisible to having its final shape.+--   If this doesn't hold true for the animator function then the final+--   animation will be discontinuous. oShowWith :: Object s a -> (SVG -> Animation) -> Scene s () oShowWith o fn = do   oModify o $ oShown .~ True@@ -338,6 +363,10 @@     obj {_oSVG = getAnimationFrame SyncStretch ani t 1}   oModify o $ \obj -> obj {_oSVG = initSVG} +-- | Hide object with an animator function. The animator is responsible for+--   transitioning the object from visible to invisible.+--   If this doesn't hold true for the animator function then the final+--   animation will be discontinuous. oHideWith :: Object s a -> (SVG -> Animation) -> Scene s () oHideWith o fn = do   initSVG <- oRead o oSVG@@ -356,6 +385,17 @@ oFadeOut = reverseA . oFadeIn  -- | Scale in object over a set duration.+--+--   Example:+--+-- @+-- do txt <- 'oNew' $ 'withStrokeWidth' 0 $ 'withFillOpacity' 1 $+--      'center' $ 'scale' 3 $ 'Reanimate.LaTeX.latex' "oGrow"+--    'oShowWith' txt 'oGrow'+--    'wait' 1; 'oHideWith' txt 'oFadeOut'+-- @+--+--    <<docs/gifs/doc_oGrow.gif>> oGrow :: SVG -> Animation oGrow svg = animate $ \t -> scale t svg @@ -363,6 +403,7 @@ oShrink :: SVG -> Animation oShrink = reverseA . oGrow +-- | Relative coordinates for an SVG node. type Origin = (Double, Double)  svgOrigin :: SVG -> Origin -> (Double, Double)@@ -373,9 +414,22 @@         polyY + polyHeight * originY       ) +-- | Scale in children from left to right, with an origin at the top of each child.+--+--   Example:+--+-- @+-- do txt <- 'oNew' $ 'withStrokeWidth' 0 $ 'withFillOpacity' 1 $+--      'center' $ 'scale' 3 $ 'Reanimate.LaTeX.latex' "oScaleIn"+--    'oShowWith' txt $ 'adjustDuration' (*2) . 'oScaleIn'+--    'wait' 1; 'oHideWith' txt 'oFadeOut'+-- @+--+--   <<docs/gifs/doc_oScaleIn.gif>> oScaleIn :: SVG -> Animation oScaleIn = oScaleIn' (curveS 2) (0.5, 1) +-- | Like 'oScaleIn' but takes an easing function and an origin. oScaleIn' :: Signal -> Origin -> SVG -> Animation oScaleIn' easing origin = oStagger' 0.05 $ \svg ->   let (cx, cy) = svgOrigin svg origin@@ -388,35 +442,66 @@                 (- cy)                 svg +-- | Scale out children from left to right, with an origin at the bottom of each child.+--+--   Example:+--+-- @+-- do txt <- 'oNew' $ 'withStrokeWidth' 0 $ 'withFillOpacity' 1 $+--      'center' $ 'scale' 3 $ 'Reanimate.LaTeX.latex' "oScaleOut"+--    'oShowWith' txt 'oFadeIn'+--    'oHideWith' txt $ 'adjustDuration' (*2) . 'oScaleOut'+-- @+--+--   <<docs/gifs/doc_oScaleOut.gif>> oScaleOut :: SVG -> Animation oScaleOut = reverseA . oStaggerRev' 0.05 (oScaleIn' (curveS 2) (0.5, 0)) +-- | Like 'oScaleOut' but takes an easing function and an origin. oScaleOut' :: Signal -> Origin -> SVG -> Animation oScaleOut' easing origin = reverseA . oStaggerRev' 0.05 (oScaleIn' easing origin) +-- | Animate each child node in parallel. oSim :: (SVG -> Animation) -> SVG -> Animation oSim = oStagger' 0  -- oSim (oStagger fn) = oSim fn -- oStagger (oStagger fn) = oStagger fn+-- | Animate each child node in parallel, staggered by 0.2 seconds. oStagger :: (SVG -> Animation) -> SVG -> Animation oStagger = oStagger' 0.2 +-- | Animate each child node in parallel, staggered by 0.2 seconds and in reverse order. oStaggerRev :: (SVG -> Animation) -> SVG -> Animation oStaggerRev = oStaggerRev' 0.2 +-- | Animate each child node in parallel, staggered by a given duration. oStagger' :: Duration -> (SVG -> Animation) -> SVG -> Animation oStagger' staggerDelay fn svg = scene $   forM_ (svgGlyphs svg) $ \(ctx, _attr, node) -> do     void $ fork $ newSpriteA' SyncFreeze (fn $ ctx node)     wait staggerDelay +-- | Animate each child node in parallel, staggered by given duration and in reverse order. oStaggerRev' :: Duration -> (SVG -> Animation) -> SVG -> Animation oStaggerRev' staggerDelay fn svg = scene $   forM_ (reverse $ svgGlyphs svg) $ \(ctx, _attr, node) -> do     void $ fork $ newSpriteA' SyncFreeze (fn $ ctx node)     wait staggerDelay +-- | Render SVG by first drawing outlines and then filling shapes.+--+--   Example:+--+-- @+-- do txt <- 'oNew' $ 'withStrokeWidth' 0 $ 'withFillOpacity' 1 $+--      'center' $ 'scale' 4 $ 'Reanimate.LaTeX.latex' "oDraw"+--    'oModify' txt $ 'oEasing' .~ id+--    'oShowWith' txt 'oDraw'; 'wait' 1+--    'oHideWith' txt 'oFadeOut'+-- @+--+--   <<docs/gifs/doc_oDraw.gif>> oDraw :: SVG -> Animation oDraw = oStagger $ \svg -> scene $   forM_ (svgGlyphs $ pathify svg) $ \(ctx, attr, node) -> do@@ -463,13 +548,10 @@     oShown .= True     oEasing .= srcEase     oTranslate .= srcLoc-  fork $ oTween m d $ \t -> oTranslate %~ moveTo t dstLoc+  fork $ oTween m d $ \t -> oTranslate %~ lerp t dstLoc   oTweenV m d $ \t -> morphDelta .~ t   oModify m $ oShown .~ False   oModify dst $ oShown .~ True-  where-    moveTo t (dstX, dstY) (srcX, srcY) =-      (fromToS srcX dstX t, fromToS srcY dstY t)  ------------------------------------------------------------------------------- -- Built-in objects@@ -547,12 +629,12 @@   spriteModify (objectSprite obj) $ do     camData <- unVar (objectData cam)     return $ \(svg, zindex) ->-      let (x, y) = camData ^. oTranslate+      let V2 x y = camData ^. oTranslate           ctx =             translate (- x) (- y)-              . uncurry translate (camData ^. oScaleOrigin)+              . uncurryV2 translate (camData ^. oScaleOrigin)               . scale (camData ^. oScale)-              . uncurry translate (camData ^. oScaleOrigin & both %~ negate)+              . uncurryV2 translate (negate $ camData ^. oScaleOrigin)        in (ctx svg, zindex)  -- |@@ -576,15 +658,15 @@ -- @ -- --   <<docs/gifs/doc_cameraFocus.gif>>-cameraFocus :: Object s Camera -> (Double, Double) -> Scene s ()-cameraFocus cam (x, y) = do-  (ox, oy) <- oRead cam oScaleOrigin-  (tx, ty) <- oRead cam oTranslate+cameraFocus :: Object s Camera -> V2 Double -> Scene s ()+cameraFocus cam new = do+  origin <- oRead cam oScaleOrigin+  t <- oRead cam oTranslate   s <- oRead cam oScale-  let newLocation = (x - ((x - ox) * s + ox - tx), y - ((y - oy) * s + oy - ty))+  let newLocation = new - ((new - origin) ^* s + origin - t)   oModifyS cam $ do     oTranslate .= newLocation-    oScaleOrigin .= (x, y)+    oScaleOrigin .= new  -- | Instantaneously set camera zoom level. cameraSetZoom :: Object s Camera -> Double -> Scene s ()@@ -599,14 +681,13 @@     oScale %= \v -> fromToS v s t  -- | Instantaneously set camera location.-cameraSetPan :: Object s Camera -> (Double, Double) -> Scene s ()+cameraSetPan :: Object s Camera -> V2 Double -> Scene s () cameraSetPan cam location =   oModifyS cam $     oTranslate .= location  -- | Change camera location over a set duration.-cameraPan :: Object s Camera -> Duration -> (Double, Double) -> Scene s ()-cameraPan cam d (x, y) =-  oTweenS cam d $ \t -> do-    oTranslate . _1 %= \v -> fromToS v x t-    oTranslate . _2 %= \v -> fromToS v y t+cameraPan :: Object s Camera -> Duration -> V2 Double -> Scene s ()+cameraPan cam d pos =+  oTweenS cam d $ \t ->+    oTranslate %= lerp t pos
src/Reanimate/Scene/Sprite.hs view
@@ -29,7 +29,7 @@     fork,     liftST,     queryNow,-    sceneAnimation,+    scene,     wait,   ) import Reanimate.Scene.Var (unpackVar, Var (..), newVar, readVar)@@ -41,8 +41,8 @@ --   Example: -- -- @--- do var \<- 'simpleVar' 'mkCircle' 0---    'tweenVar' var 2 $ \\val -> 'fromToS' val ('Reanimate.Constants.screenHeight'/2)+-- do var \<- 'simpleVar' 'Reanimate.Svg.Constructors.mkCircle' 0+--    'Reanimate.Scene.tweenVar' var 2 $ \\val -> 'Reanimate.fromToS' val ('Reanimate.Constants.screenHeight'/2) -- @ -- --   <<docs/gifs/doc_simpleVar.gif>>@@ -98,9 +98,9 @@ -- -- @ -- do v \<- 'newVar' 0---    'newSprite' $ 'mkCircle' \<$\> 'unVar' v---    'tweenVar' v 1 $ \\val -> 'fromToS' val 3---    'tweenVar' v 1 $ \\val -> 'fromToS' val 0+--    'newSprite' $ 'Reanimate.Svg.Constructors.mkCircle' \<$\> 'unVar' v+--    'Reanimate.Scene.tweenVar' v 1 $ \\val -> 'Reanimate.fromToS' val 3+--    'Reanimate.Scene.tweenVar' v 1 $ \\val -> 'Reanimate.fromToS' val 0 -- @ -- --   <<docs/gifs/doc_unVar.gif>>@@ -123,7 +123,7 @@ --   Example: -- -- @--- do 'newSprite' $ 'mkCircle' \<$\> 'spriteT' -- Circle sprite where radius=time.+-- do 'newSprite' $ 'Reanimate.Svg.Constructors.mkCircle' \<$\> 'spriteT' -- Circle sprite where radius=time. --    'wait' 2 -- @ --@@ -169,7 +169,7 @@ -- @ -- do 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawCircle' --    'play' 'Reanimate.Builtin.Documentation.drawBox'---    'play' $ 'reverseA' 'Reanimate.Builtin.Documentation.drawBox'+--    'play' $ 'Reanimate.Animation.reverseA' 'Reanimate.Builtin.Documentation.drawBox' -- @ -- --   <<docs/gifs/doc_newSpriteA.gif>>@@ -182,9 +182,9 @@ --   Example: -- -- @--- do 'fork' $ 'newSpriteA'' 'SyncFreeze' 'Reanimate.Builtin.Documentation.drawCircle'+-- do 'fork' $ 'newSpriteA'' 'Reanimate.Animation.SyncFreeze' 'Reanimate.Builtin.Documentation.drawCircle' --    'play' 'Reanimate.Builtin.Documentation.drawBox'---    'play' $ 'reverseA' 'Reanimate.Builtin.Documentation.drawBox'+--    'play' $ 'Reanimate.Animation.reverseA' 'Reanimate.Builtin.Documentation.drawBox' -- @ -- --   <<docs/gifs/doc_newSpriteA'.gif>>@@ -198,7 +198,7 @@ --   Example: -- -- @--- do 'newSpriteSVG' $ 'mkBackground' "lightblue"+-- do 'newSpriteSVG' $ 'Reanimate.Svg.Constructors.mkBackground' "lightblue" --    'play' 'Reanimate.Builtin.Documentation.drawCircle' -- @ --@@ -219,8 +219,8 @@ -- @ -- do s \<- 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawBox' --    v \<- 'newVar' 0---    'applyVar' v s 'rotate'---    'tweenVar' v 2 $ \\val -> 'fromToS' val 90+--    'applyVar' v s 'Reanimate.Svg.Constructors.rotate'+--    'Reanimate.Scene.tweenVar' v 2 $ \\val -> 'Reanimate.fromToS' val 90 -- @ -- --   <<docs/gifs/doc_applyVar.gif>>@@ -235,7 +235,7 @@ --   Example: -- -- @--- do s <- 'newSpriteSVG' $ 'withFillOpacity' 1 $ 'mkCircle' 1+-- do s <- 'newSpriteSVG' $ 'Reanimate.Svg.Constructors.withFillOpacity' 1 $ 'Reanimate.Svg.Constructors.mkCircle' 1 --    'fork' $ 'wait' 1 \>\> 'destroySprite' s --    'play' 'Reanimate.Builtin.Documentation.drawBox' -- @@@ -267,7 +267,7 @@ -- @ -- do s \<- 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawCircle' --    'wait' 1---    'spriteMap' s 'flipYAxis'+--    'spriteMap' s 'Reanimate.Svg.Constructors.flipYAxis' -- @ -- --   <<docs/gifs/doc_spriteMap.gif>>@@ -285,7 +285,7 @@ -- -- @ -- do s \<- 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawCircle'---    'spriteTween' s 1 $ \\val -> 'translate' ('Reanimate.Constants.screenWidth'*0.3*val) 0+--    'spriteTween' s 1 $ \\val -> 'Reanimate.Svg.Constructors.translate' ('Reanimate.Constants.screenWidth'*0.3*val) 0 -- @ -- --   <<docs/gifs/doc_spriteTween.gif>>@@ -309,8 +309,8 @@ -- -- @ -- do s \<- 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawBox'---    v \<- 'spriteVar' s 0 'rotate'---    'tweenVar' v 2 $ \\val -> 'fromToS' val 90+--    v \<- 'spriteVar' s 0 'Reanimate.Svg.Constructors.rotate'+--    'Reanimate.Scene.tweenVar' v 2 $ \\val -> 'Reanimate.fromToS' val 90 -- @ -- --   <<docs/gifs/doc_spriteVar.gif>>@@ -326,8 +326,8 @@ -- -- @ -- do s <- 'fork' $ 'newSpriteA' 'Reanimate.Builtin.Documentation.drawCircle'---    'spriteE' s $ 'overBeginning' 1 'fadeInE'---    'spriteE' s $ 'overEnding' 0.5 'fadeOutE'+--    'spriteE' s $ 'Reanimate.Effect.overBeginning' 1 'Reanimate.Effect.fadeInE'+--    'spriteE' s $ 'Reanimate.Effect.overEnding' 0.5 'Reanimate.Effect.fadeOutE' -- @ -- --   <<docs/gifs/doc_spriteE.gif>>@@ -349,8 +349,8 @@ --   Example: -- -- @--- do s1 \<- 'newSpriteSVG' $ 'withFillOpacity' 1 $ 'withFillColor' "blue" $ 'mkCircle' 3---    'newSpriteSVG' $ 'withFillOpacity' 1 $ 'withFillColor' "red" $ 'mkRect' 8 3+-- do s1 \<- 'newSpriteSVG' $ 'Reanimate.Svg.Constructors.withFillOpacity' 1 $ 'Reanimate.Svg.Constructors.withFillColor' "blue" $ 'Reanimate.Svg.Constructors.mkCircle' 3+--    'newSpriteSVG' $ 'Reanimate.Svg.Constructors.withFillOpacity' 1 $ 'Reanimate.Svg.Constructors.withFillColor' "red" $ 'Reanimate.Svg.Constructors.mkRect' 8 3 --    'wait' 1 --    'spriteZ' s1 1 --    'wait' 1@@ -375,13 +375,13 @@ -- -- @ -- do -- the rect lives through the entire 3s animation---    'newSpriteSVG_' $ 'translate' (-3) 0 $ 'mkRect' 4 4+--    'newSpriteSVG_' $ 'Reanimate.Svg.Constructors.translate' (-3) 0 $ 'Reanimate.Svg.Constructors.mkRect' 4 4 --    'wait' 1 --    'spriteScope' $ do --      -- the circle only lives for 1 second.---      local \<- 'newSpriteSVG' $ 'translate' 3 0 $ 'mkCircle' 2---      'spriteE' local $ 'overBeginning' 0.3 'fadeInE'---      'spriteE' local $ 'overEnding' 0.3 'fadeOutE'+--      local \<- 'newSpriteSVG' $ 'Reanimate.Svg.Constructors.translate' 3 0 $ 'Reanimate.Svg.Constructors.mkCircle' 2+--      'spriteE' local $ 'Reanimate.Effect.overBeginning' 0.3 'Reanimate.Effect.fadeInE'+--      'spriteE' local $ 'Reanimate.Effect.overEnding' 0.3 'Reanimate.Effect.fadeOutE' --      'wait' 1 --    'wait' 1 -- @@@ -402,7 +402,7 @@ asAnimation :: (forall s'. Scene s' a) -> Scene s Animation asAnimation s = do   now <- queryNow-  return $ dropA now (sceneAnimation (wait now >> s))+  return $ dropA now (scene (wait now >> s))  -- | Apply a transformation with a given overlap. This makes sure --   to keep timestamps intact such that events can still be timed
src/Reanimate/Scene/Var.hs view
@@ -5,7 +5,6 @@  import Control.Monad.ST (ST) import qualified Data.Map as M-import Data.Maybe (fromMaybe) import Data.STRef import Reanimate.Animation (Duration, Time) import Reanimate.Scene.Core (Scene, liftST, queryNow, wait)@@ -34,7 +33,7 @@ --   earlier than when the variable was created. For example: -- -- @--- do v \<- 'fork' ('wait' 10 \>\> 'newVar' 0) -- Create a variable at timestamp '10'.+-- do v \<- 'Reanimate.Scene.fork' ('wait' 10 \>\> 'newVar' 0) -- Create a variable at timestamp '10'. --    'readVar' v                       -- Read the variable at timestamp '0'. --                                    -- The value of the variable will be '0'. -- @@@ -54,7 +53,7 @@ -- -- @ -- do v \<- 'newVar' 0---    'newSprite' $ 'mkCircle' \<$\> 'unVar' v+--    'Reanimate.Scene.newSprite' $ 'Reanimate.Svg.Constructors.mkCircle' \<$\> 'Reanimate.Scene.unVar' v --    'writeVar' v 1; 'wait' 1 --    'writeVar' v 2; 'wait' 1 --    'writeVar' v 3; 'wait' 1@@ -129,7 +128,7 @@ elseVar var1 var2   | Just t <- evarLastTime var1 =     let afterTimeline = evarTimeline var1-        joinAt = fromMaybe t . fmap fst $ M.lookupMin afterTimeline+        joinAt = maybe t fst $ M.lookupMin afterTimeline         beforeTimeline = case keepBefore joinAt var2 of           x             | Just lastTime <- evarLastTime x, lastTime < joinAt -> M.insert lastTime (StaticValue $ evarLastValue x) $ evarTimeline x@@ -139,7 +138,7 @@  -- Restrict a var to a given time interval. keepInRange :: Maybe Time -> Maybe Time -> VarData a -> VarData a-keepInRange st nd = fromMaybe id (keepFrom <$> st) . fromMaybe id (keepBefore <$> nd)+keepInRange st nd = maybe id keepFrom st . maybe id keepBefore nd  -- Restrict a var to start at given timestamp. keepFrom :: Time -> VarData a -> VarData a@@ -167,4 +166,4 @@       lastTime = case lastModifier of         Just (t, TweenValue dur _) -> Just $ min nd (t + dur)         _ -> min nd <$> evarLastTime-   in VarData evarDefault timeline'' lastTime (fromMaybe evarDefault $ fmap (readVarData var) lastTime)+   in VarData evarDefault timeline'' lastTime (maybe evarDefault (readVarData var) lastTime)
src/Reanimate/Svg/LineCommand.hs view
@@ -1,30 +1,31 @@-{-|-Copyright   : Written by David Himmelstrup-License     : Unlicense-Maintainer  : lemmih@gmail.com-Stability   : experimental-Portability : POSIX--}+-- |+-- Copyright   : Written by David Himmelstrup+-- License     : Unlicense+-- Maintainer  : lemmih@gmail.com+-- Stability   : experimental+-- Portability : POSIX module Reanimate.Svg.LineCommand-  ( CmdM-  , LineCommand(..)-  , lineLength-  , toLineCommands-  , lineToPath-  , lineToPoints-  , partialSvg-  ) where+  ( CmdM,+    LineCommand (..),+    lineLength,+    toLineCommands,+    lineToPath,+    lineToPoints,+    partialSvg,+  )+where -import           Control.Lens              ((%~), (&), (.~))-import           Control.Monad.Fix-import           Control.Monad.State-import           Data.Functor-import qualified Data.Vector.Unboxed       as V+import Control.Lens ((%~), (&), (.~))+import Control.Monad.Fix+import Control.Monad.State+import Data.Functor+import Data.Maybe+import qualified Data.Vector.Unboxed as V import qualified Geom2D.CubicBezier.Linear as Bezier-import           Graphics.SvgTree-import           Linear.Metric-import           Linear.V2                 hiding (angle)-import           Linear.Vector+import Graphics.SvgTree+import Linear.Metric+import Linear.V2 hiding (angle)+import Linear.Vector  -- | Line command monad used for keeping track of the current location. type CmdM a = State RPoint a@@ -32,8 +33,8 @@ -- | Simplified version of a PathCommand where all points are absolute. data LineCommand   = LineMove RPoint-  -- | LineDraw RPoint-  | LineBezier [RPoint]+  | -- | LineDraw RPoint+    LineBezier [RPoint]   | LineEnd RPoint   deriving (Show) @@ -41,34 +42,34 @@ lineToPath :: [LineCommand] -> [PathCommand] lineToPath = map worker   where-    worker (LineMove p)         = MoveTo OriginAbsolute [p]+    worker (LineMove p) = MoveTo OriginAbsolute [p]     -- worker (LineDraw p)         = LineTo OriginAbsolute [p]-    worker (LineBezier [a,b,c]) = CurveTo OriginAbsolute [(a,b,c)]-    worker (LineBezier [a,b])   = QuadraticBezier OriginAbsolute [(a,b)]-    worker (LineBezier [a])     = LineTo OriginAbsolute [a]-    worker LineBezier{}         = error "Reanimate.Svg.lineToPath: invalid bezier curve"-    worker LineEnd{}            = EndPath+    worker (LineBezier [a, b, c]) = CurveTo OriginAbsolute [(a, b, c)]+    worker (LineBezier [a, b]) = QuadraticBezier OriginAbsolute [(a, b)]+    worker (LineBezier [a]) = LineTo OriginAbsolute [a]+    worker LineBezier {} = error "Reanimate.Svg.lineToPath: invalid bezier curve"+    worker LineEnd {} = EndPath  -- | Using @n@ control points, approximate the path of the curves. lineToPoints :: Int -> [LineCommand] -> [RPoint] lineToPoints nPoints cmds =-    map lineEnd lineSegments+  mapMaybe lineEnd lineSegments   where-    lineSegments = [ partialLine (fromIntegral n/ fromIntegral nPoints) cmds | n <- [0 .. nPoints-1] ]-    lineEnd [LineBezier pts] = last pts-    lineEnd (_:xs)           = lineEnd xs-    lineEnd _                = error "invalid line"+    lineSegments = [partialLine (fromIntegral n / fromIntegral nPoints) cmds | n <- [0 .. nPoints -1]]+    lineEnd [] = Nothing+    lineEnd [LineBezier pts] = Just (last pts)+    lineEnd (_ : xs) = lineEnd xs  partialLine :: Double -> [LineCommand] -> [LineCommand] partialLine alpha cmds = evalState (worker 0 cmds) zero   where     worker _d [] = pure []-    worker d (cmd:xs) = do+    worker d (cmd : xs) = do       from <- get       len <- lineLength cmd-      let frac = (targetLen-d) / len+      let frac = (targetLen - d) / len       if len == 0 || frac >= 1-        then (cmd:) <$> worker (d+len) xs+        then (cmd :) <$> worker (d + len) xs         else pure [adjustLineLength frac from cmd]     totalLen = evalState (sum <$> mapM lineLength cmds) zero     targetLen = totalLen * alpha@@ -76,51 +77,51 @@ adjustLineLength :: Double -> RPoint -> LineCommand -> LineCommand adjustLineLength alpha from cmd =   case cmd of-    LineBezier points -> LineBezier $ drop 1 $ partialBezierPoints (from:points) 0 alpha-    LineMove p        -> LineMove p+    LineBezier points -> LineBezier $ drop 1 $ partialBezierPoints (from : points) 0 alpha+    LineMove p -> LineMove p     -- LineDraw t -> LineDraw (lerp alpha t from)-    LineEnd p         -> LineBezier [lerp alpha p from]+    LineEnd p -> LineBezier [lerp alpha p from]  -- | Estimated length of all segments in a line. lineLength :: LineCommand -> CmdM Double lineLength cmd =   case cmd of-    LineMove to       -> 0 <$ put to+    LineMove to -> 0 <$ put to     -- Straight line:     LineBezier [dst] -> gets (distance dst) <* put dst     -- Some kind of curve:     LineBezier lst -> do       from <- get-      let bezier = rpointsToBezier (from:lst)+      let bezier = rpointsToBezier (from : lst)           tol = 0.0001       put (last lst)       pure $ Bezier.arcLength bezier 1 tol-    LineEnd to        -> gets (distance to) <* put to+    LineEnd to -> gets (distance to) <* put to  rpointsToBezier :: [RPoint] -> Bezier.CubicBezier Double rpointsToBezier lst =   case lst of-    [a,b]     -> Bezier.CubicBezier a a b b-    [a,b,c]   -> Bezier.quadToCubic (Bezier.QuadBezier a b c)-    [a,b,c,d] -> Bezier.CubicBezier a b c d-    _         -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst+    [a, b] -> Bezier.CubicBezier a a b b+    [a, b, c] -> Bezier.quadToCubic (Bezier.QuadBezier a b c)+    [a, b, c, d] -> Bezier.CubicBezier a b c d+    _ -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst  -- | Convert from path commands to line commands. toLineCommands :: [PathCommand] -> [LineCommand] toLineCommands ps = evalState (worker zero Nothing ps) zero   where     worker _startPos _mbPrevControlPt [] = pure []-    worker startPos mbPrevControlPt (cmd:cmds) = do+    worker startPos mbPrevControlPt (cmd : cmds) = do       lcmds <- toLineCommand startPos mbPrevControlPt cmd       let startPos' =             case lcmds of               [LineMove pos] -> pos-              _              -> startPos-      (lcmds++) <$> worker startPos' (cmdToControlPoint $ last lcmds) cmds+              _ -> startPos+      (lcmds ++) <$> worker startPos' (cmdToControlPoint $ last lcmds) cmds  cmdToControlPoint :: LineCommand -> Maybe RPoint cmdToControlPoint (LineBezier points) = Just (last (init points))-cmdToControlPoint _                   = Nothing+cmdToControlPoint _ = Nothing  mkStraightLine :: RPoint -> LineCommand mkStraightLine p = LineBezier [p]@@ -128,152 +129,164 @@ toLineCommand :: RPoint -> Maybe RPoint -> PathCommand -> CmdM [LineCommand] toLineCommand startPos mbPrevControlPt cmd =   case cmd of-    MoveTo OriginAbsolute []  -> pure []-    MoveTo OriginAbsolute lst -> put (last lst) *> gets (pure.LineMove)-    MoveTo OriginRelative lst -> modify (+ sum lst) *> gets (pure.LineMove)+    MoveTo OriginAbsolute [] -> pure []+    MoveTo OriginAbsolute lst -> put (last lst) *> gets (pure . LineMove)+    MoveTo OriginRelative lst -> modify (+ sum lst) *> gets (pure . LineMove)     LineTo OriginAbsolute lst -> forM lst (\to -> put to $> mkStraightLine to)-    LineTo OriginRelative lst -> forM lst (\to -> modify (+to) *> gets mkStraightLine)+    LineTo OriginRelative lst -> forM lst (\to -> modify (+ to) *> gets mkStraightLine)     HorizontalTo OriginAbsolute lst ->       forM lst $ \x -> modify (_x .~ x) *> gets mkStraightLine     HorizontalTo OriginRelative lst ->-      forM lst $ \x -> modify (_x %~ (+x)) *> gets mkStraightLine+      forM lst $ \x -> modify (_x %~ (+ x)) *> gets mkStraightLine     VerticalTo OriginAbsolute lst ->       forM lst $ \y -> modify (_y .~ y) *> gets mkStraightLine     VerticalTo OriginRelative lst ->-      forM lst $ \y -> modify (_y %~ (+y)) *> gets mkStraightLine+      forM lst $ \y -> modify (_y %~ (+ y)) *> gets mkStraightLine     CurveTo OriginAbsolute quads ->-      forM quads $ \(a,b,c) -> put c $> LineBezier [a,b,c]+      forM quads $ \(a, b, c) -> put c $> LineBezier [a, b, c]     CurveTo OriginRelative quads ->-      forM quads $ \(a,b,c) -> do-        from <- get <* modify (+c)-        pure $ LineBezier $ map (+from) [a,b,c]+      forM quads $ \(a, b, c) -> do+        from <- get <* modify (+ c)+        pure $ LineBezier $ map (+ from) [a, b, c]     SmoothCurveTo o lst -> mfix $ \result -> do       let ctrl = mbPrevControlPt : map cmdToControlPoint result-      forM (zip lst ctrl) $ \((c2,to), mbControl) -> do+      forM (zip lst ctrl) $ \((c2, to), mbControl) -> do         from <- get <* adjustPosition o to         let c1 = maybe (makeAbsolute o from c2) (mirrorPoint from) mbControl-        pure $ LineBezier [c1,makeAbsolute o from c2,makeAbsolute o from to]+        pure $ LineBezier [c1, makeAbsolute o from c2, makeAbsolute o from to]     QuadraticBezier OriginAbsolute pairs ->-      forM pairs $ \(a,b) -> put b $> LineBezier [a,b]+      forM pairs $ \(a, b) -> put b $> LineBezier [a, b]     QuadraticBezier OriginRelative pairs ->-      forM pairs $ \(a,b) -> do-        from <- get <* modify (+b)-        pure $ LineBezier $ map (+from) [a,b]+      forM pairs $ \(a, b) -> do+        from <- get <* modify (+ b)+        pure $ LineBezier $ map (+ from) [a, b]     SmoothQuadraticBezierCurveTo o lst -> mfix $ \result -> do       let ctrl = mbPrevControlPt : map cmdToControlPoint result       forM (zip lst ctrl) $ \(to, mbControl) -> do         from <- get <* adjustPosition o to         let c1 = maybe from (mirrorPoint from) mbControl-        pure $ LineBezier [c1,makeAbsolute o from to]-    EllipticalArc o points -> concat <$>-      forM points (\(rotX, rotY, angle, largeArc, sweepFlag, to) -> do-        from <- get <* adjustPosition o to-        return $ convertSvgArc from rotX rotY angle largeArc sweepFlag (makeAbsolute o from to))+        pure $ LineBezier [c1, makeAbsolute o from to]+    EllipticalArc o points ->+      concat+        <$> forM+          points+          ( \(rotX, rotY, angle, largeArc, sweepFlag, to) -> do+              from <- get <* adjustPosition o to+              return $ convertSvgArc from rotX rotY angle largeArc sweepFlag (makeAbsolute o from to)+          )     EndPath -> put startPos $> [LineEnd startPos]   where-    mirrorPoint c p = c*2-p-    adjustPosition OriginRelative p = modify (+p)+    mirrorPoint c p = c * 2 - p+    adjustPosition OriginRelative p = modify (+ p)     adjustPosition OriginAbsolute p = put p     makeAbsolute OriginAbsolute _from p = p-    makeAbsolute OriginRelative from p  = from+p-+    makeAbsolute OriginRelative from p = from + p  calculateVectorAngle :: Double -> Double -> Double -> Double -> Double calculateVectorAngle ux uy vx vy-    | tb >= ta-        = tb - ta-    | otherwise-        = pi * 2 - (ta - tb)-    where-        ta = atan2 uy ux-        tb = atan2 vy vx+  | tb >= ta =+    tb - ta+  | otherwise =+    pi * 2 - (ta - tb)+  where+    ta = atan2 uy ux+    tb = atan2 vy vx  -- ported from: https://github.com/vvvv/SVG/blob/master/Source/Paths/SvgArcSegment.cs {- HLINT ignore convertSvgArc -} convertSvgArc :: RPoint -> Coord -> Coord -> Coord -> Bool -> Bool -> RPoint -> [LineCommand] convertSvgArc (V2 x0 y0) radiusX radiusY angle largeArcFlag sweepFlag (V2 x y)-    | x0 == x && y0 == y-        = []-    | radiusX == 0.0 && radiusY == 0.0-        = [LineBezier [V2 x y]]-    | otherwise-        = calcSegments x0 y0 theta1' segments'-    where-        sinPhi = sin (angle * pi/180)-        cosPhi = cos (angle * pi/180)+  | x0 == x && y0 == y =+    []+  | radiusX == 0.0 && radiusY == 0.0 =+    [LineBezier [V2 x y]]+  | otherwise =+    calcSegments x0 y0 theta1' segments'+  where+    sinPhi = sin (angle * pi / 180)+    cosPhi = cos (angle * pi / 180) -        x1dash = cosPhi * (x0 - x) / 2.0 + sinPhi * (y0 - y) / 2.0-        y1dash = -sinPhi * (x0 - x) / 2.0 + cosPhi * (y0 - y) / 2.0+    x1dash = cosPhi * (x0 - x) / 2.0 + sinPhi * (y0 - y) / 2.0+    y1dash = - sinPhi * (x0 - x) / 2.0 + cosPhi * (y0 - y) / 2.0 -        numerator = radiusX * radiusX * radiusY * radiusY - radiusX * radiusX * y1dash * y1dash - radiusY * radiusY * x1dash * x1dash+    numerator = radiusX * radiusX * radiusY * radiusY - radiusX * radiusX * y1dash * y1dash - radiusY * radiusY * x1dash * x1dash -        s = sqrt(1.0 - numerator / (radiusX * radiusX * radiusY * radiusY))-        rx   = if (numerator < 0.0) then (radiusX * s) else radiusX-        ry   = if (numerator < 0.0) then (radiusY * s) else radiusY-        root = if (numerator < 0.0)-                then (0.0)-                else ((if ((largeArcFlag && sweepFlag) || (not largeArcFlag && not sweepFlag)) then (-1.0) else 1.0) *-                        sqrt(numerator / (radiusX * radiusX * y1dash * y1dash + radiusY * radiusY * x1dash * x1dash)))+    s = sqrt (1.0 - numerator / (radiusX * radiusX * radiusY * radiusY))+    rx = if (numerator < 0.0) then (radiusX * s) else radiusX+    ry = if (numerator < 0.0) then (radiusY * s) else radiusY+    root =+      if (numerator < 0.0)+        then (0.0)+        else+          ( (if ((largeArcFlag && sweepFlag) || (not largeArcFlag && not sweepFlag)) then (-1.0) else 1.0)+              * sqrt (numerator / (radiusX * radiusX * y1dash * y1dash + radiusY * radiusY * x1dash * x1dash))+          ) -        cxdash = root * rx * y1dash / ry-        cydash = -root * ry * x1dash / rx+    cxdash = root * rx * y1dash / ry+    cydash = - root * ry * x1dash / rx -        cx = cosPhi * cxdash - sinPhi * cydash + (x0 + x) / 2.0-        cy = sinPhi * cxdash + cosPhi * cydash + (y0 + y) / 2.0+    cx = cosPhi * cxdash - sinPhi * cydash + (x0 + x) / 2.0+    cy = sinPhi * cxdash + cosPhi * cydash + (y0 + y) / 2.0 -        theta1'  = calculateVectorAngle 1.0 0.0 ((x1dash - cxdash) / rx) ((y1dash - cydash) / ry)-        dtheta' = calculateVectorAngle ((x1dash - cxdash) / rx) ((y1dash - cydash) / ry) ((-x1dash - cxdash) / rx) ((-y1dash - cydash) / ry)-        dtheta  = if (not sweepFlag && dtheta' > 0)-                    then  (dtheta' - 2 * pi)-                    else  (if (sweepFlag && dtheta' < 0) then dtheta' + 2 * pi else dtheta')+    theta1' = calculateVectorAngle 1.0 0.0 ((x1dash - cxdash) / rx) ((y1dash - cydash) / ry)+    dtheta' = calculateVectorAngle ((x1dash - cxdash) / rx) ((y1dash - cydash) / ry) ((- x1dash - cxdash) / rx) ((- y1dash - cydash) / ry)+    dtheta =+      if (not sweepFlag && dtheta' > 0)+        then (dtheta' - 2 * pi)+        else (if (sweepFlag && dtheta' < 0) then dtheta' + 2 * pi else dtheta') -        segments' = ceiling (abs (dtheta / (pi / 2.0)))-        delta = dtheta / fromInteger segments'-        t = 8.0 / 3.0 * sin(delta / 4.0) * sin(delta / 4.0) / sin(delta / 2.0)+    segments' = ceiling (abs (dtheta / (pi / 2.0)))+    delta = dtheta / fromInteger segments'+    t = 8.0 / 3.0 * sin (delta / 4.0) * sin (delta / 4.0) / sin (delta / 2.0) -        calcSegments startX startY theta1 segments-            | segments == 0-                = []-            | otherwise-                = LineBezier [ V2 (startX + dx1) (startY + dy1)-                             , V2 (endpointX + dxe) (endpointY + dye)-                             , V2 endpointX endpointY ] : calcSegments endpointX endpointY theta2 (segments - 1)-            where-                cosTheta1 = cos theta1-                sinTheta1 = sin theta1-                theta2 = theta1 + delta-                cosTheta2 = cos theta2-                sinTheta2 = sin theta2+    calcSegments startX startY theta1 segments+      | segments == 0 =+        []+      | otherwise =+        LineBezier+          [ V2 (startX + dx1) (startY + dy1),+            V2 (endpointX + dxe) (endpointY + dye),+            V2 endpointX endpointY+          ] :+        calcSegments endpointX endpointY theta2 (segments - 1)+      where+        cosTheta1 = cos theta1+        sinTheta1 = sin theta1+        theta2 = theta1 + delta+        cosTheta2 = cos theta2+        sinTheta2 = sin theta2 -                endpointX = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx-                endpointY = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy+        endpointX = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx+        endpointY = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy -                dx1 = t * (-cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1)-                dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1)+        dx1 = t * (- cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1)+        dy1 = t * (- sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1) -                dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2)-                dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2)+        dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2)+        dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2)  partialBezierPoints :: [RPoint] -> Double -> Double -> [RPoint] partialBezierPoints ps a b =   let c1 = Bezier.AnyBezier (V.fromList ps)       Bezier.AnyBezier os = Bezier.bezierSubsegment c1 a b-  in V.toList os--{- | Create an image showing portion of a path.-     Note that this only affects paths (see 'Reanimate.Svg.Constructors.mkPath').-     You can also use this with other SVG shapes if you convert them to path first (see 'Reanimate.Svg.pathify').--     Typical usage:+   in V.toList os -    > animate $ \t -> partialSvg t myPath--}-partialSvg :: Double -- ^ number between 0 and 1 inclusively, determining what portion of the path to show-           -> Tree -- ^ Image representing a path, of which we only want to display a portion determined by the first argument-           -> Tree+-- | Create an image showing portion of a path.+--     Note that this only affects paths (see 'Reanimate.Svg.Constructors.mkPath').+--     You can also use this with other SVG shapes if you convert them to path first (see 'Reanimate.Svg.pathify').+--+--     Typical usage:+--+--    > animate $ \t -> partialSvg t myPath+partialSvg ::+  -- | number between 0 and 1 inclusively, determining what portion of the path to show+  Double ->+  -- | Image representing a path, of which we only want to display a portion determined by the first argument+  Tree ->+  Tree partialSvg alpha | alpha >= 1 = id partialSvg alpha = mapTree worker   where     worker (PathTree path) =-        PathTree $ path & pathDefinition %~ lineToPath . partialLine alpha . toLineCommands+      PathTree $ path & pathDefinition %~ lineToPath . partialLine alpha . toLineCommands     worker t = t