{"id":16710622,"url":"https://github.com/mdgriffith/elm-html-animation","last_synced_at":"2025-07-10T17:31:34.376Z","repository":{"id":62418789,"uuid":"59211467","full_name":"mdgriffith/elm-html-animation","owner":"mdgriffith","description":"DEPRECATED:  Use https://github.com/mdgriffith/elm-style-animation if you're on elm 0.17","archived":false,"fork":false,"pushed_at":"2016-05-19T15:55:53.000Z","size":576,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T16:05:17.147Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mdgriffith.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-19T13:59:06.000Z","updated_at":"2018-02-24T09:05:34.000Z","dependencies_parsed_at":"2022-11-01T16:46:14.743Z","dependency_job_id":null,"html_url":"https://github.com/mdgriffith/elm-html-animation","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/mdgriffith/elm-html-animation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdgriffith%2Felm-html-animation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdgriffith%2Felm-html-animation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdgriffith%2Felm-html-animation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdgriffith%2Felm-html-animation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mdgriffith","download_url":"https://codeload.github.com/mdgriffith/elm-html-animation/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdgriffith%2Felm-html-animation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264619021,"owners_count":23638394,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T20:09:08.237Z","updated_at":"2025-07-10T17:31:31.407Z","avatar_url":"https://github.com/mdgriffith.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# elm-style-animation\n\nA library to simplify creating html and svg animations in elm. My focus was to create something I could use as a UI designer to prototype animations quickly, accurately, and without sneaky errors.  \n\n\u003e __Note__ - elm-style-animation is for Elm 0.17 only at the moment.  There are also some breaking syntax changes vs elm-html-animation v3.0.4.  [Here's an overview if you want to port code.](https://github.com/mdgriffith/elm-style-animation/blob/master/FROM-3.0.4.md)\n\n  1. Showing a menu on hover - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/SideMenu.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/SideMenu.elm)\n  2. Chaining Keyframes - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Chaining.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Chaining.elm)\n  3. Updating based on Current Style.\n  4. Animating a List of Elements - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Showcase.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Showcase.elm)\n      * Staggering animations - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Stagger.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Stagger.elm)\n  5. Stacking transformations for complex animations - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/StackingTransforms.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/StackingTransforms.elm)\n  6. Animating SVG\n      * Morphing Shapes - Elm Logo [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Logo.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Logo.elm)\n      * Morphing Batman Logos - [inspiration](http://tavmjong.free.fr/blog/?p=741) / [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Batman.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Batman.elm)\n  7. Realistic scenario (flower menu) (separate repo) - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/FlowerMenu/) / [view code](https://github.com/mdgriffith/elm-html-animation-flower-menu/blob/master/FlowerMenu.elm)\n\n\n## Installation\n\nFirst have [Elm installed](http://elm-lang.org/install), then\n\nIf you just want to play with the examples, run the following in a console:\n\n```bash\ngit clone https://github.com/mdgriffith/elm-style-animation.git\ncd elm-style-animation/examples\nelm-reactor\n# Make sure to cd into the examples folder.\n# The library and the examples have different dependencies\n# So, running elm-reactor on the base folder will not work\n# if you just want to run examples.\n```\n\nOr, if you want to install the package in one of your elm projects.\n\n```bash\nelm-package install mdgriffith/elm-style-animation\n```\n\n\n## The Basics\n\nI recommend checking out [the Elm Architecture](https://github.com/evancz/elm-architecture-tutorial/) if you haven't already.  These examples will be much easier if you're already familiar with Elm in general and the standard `model`, `update`, `view` pattern.\n\nSo, with all that in mind, here's a basic overview of what you'll need to do to use this library.\n\nTo add animations to a module, you'll need to do the following:\n\n  * Store the styling data in your `model`, and define an initial style.\n  * Subscribe to the browser's animation frame\n\n__Note__ all properties that are going to be animated need to be accounted for in the initial style.\n\n```elm\n\nimport Html.App as Html\nimport Html exposing (..)\nimport Html.Attributes exposing (..)\nimport Color exposing (rgba)\nimport AnimationFrame\nimport Time exposing (Time)\nimport Style\nimport Style.Properties exposing (..)\n\ntype alias Model = { style : Style.Animation }\n\ninit : Model\ninit = { style =\n            Style.init\n                [ Left -350.0 Px\n                , Opacity 0.0\n                , Color (rgba 50 50 50 1.0)\n                ]\n        }\n\n-- Create a subscription to the browser's animation frame\nsubscriptions : Model -\u003e Sub Msg\nsubscriptions model =\n    AnimationFrame.times Animate\n\n\nmain =\n    Html.program\n        { init = init\n        , view = view\n        , update = update\n        , subscriptions = subscriptions\n        }\n\n```\n\n\n * In your `view`, render the animation as a css style.\n\n```elm\nview : Model -\u003e Html Msg\nview model =\n      div [ style (Style.render model.style) ] []\n\n```\n\n\n  * Add a new action to your Action type to allow updates to be sent to an animation.\n\n```elm\ntype Msg = Show -- This message triggers the animation\n         | Animate Time -- This message forwards all updates to the elm-style-animation core.\n\n-- In our update function, we can use the helper function trigger animations\n-- and to pass updates to an animation\nupdate : Msg -\u003e Model -\u003e ( Model, Cmd Msg )\nupdate action model =\n  case action of\n\n    Show -\u003e\n      let\n          style =\n              Style.animate\n                 |\u003e Style.to [ Opacity 1]\n                 |\u003e Style.on model.style\n      in\n        ( { model | style = style}\n        , Cmd.none\n        )\n\n     -- for each animation frame, update the style.\n     -- If we have multiple styles to manage, they will need to be updated in this action.\n     Animate time -\u003e\n        ( { model\n              | style = Style.tick time model.style\n          }\n        , Cmd.none\n        )\n```\n\n\n  * Now that we're set up, we can begin animating.\n\n\n# Example 1: Showing a Menu on Hover\n\n[demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/SideMenu.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/SideMenu.elm)\n\nOur first example is a menu that is shown when the mouse enters a certain area, and hides when the mouse leaves.\n\nSo, our first step is to add two values to our Action type, `Show` and `Hide`, and in the update function, we start an animation when those actions occur.  Let's take a look at how we construct an animation.\n\n\n```elm\n-- ... we add this to the case statement in our update function.\n\n    Style.animate\n    -- |\u003e Style.delay (0.5*second)\n       |\u003e Style.to\n           [ Left 0 Px\n           , Opacity 1\n           ]\n       |\u003e Style.on model.style\n\n\n```\n\nNotice we are programming declaratively by defining what style property should be by using `Style.to`.  A delay is present but commented out.\n\nInstead of using a duration and an easing function, this library defaults to animating by using a __spring__.  By modeling real-world springs, we can create organic animations by defining two numbers, _stiffness_ and _damping_.\n\n\n```elm\n-- ... we add this to the case statement in our update function.\n    Style.animate\n    -- |\u003e Style.spring Style.Spring.Preset.wobbly -- you can use a UI preset\n    -- or specify manually.\n       |\u003e Style.spring\n            { stiffness = 400\n            , damping = 28\n            }\n       |\u003e Style.to\n           [ Left 0 Px\n           , Opacity 1\n           ]\n       |\u003e Style.on model.style\n\n```\n\n\n\u003e Alternatively, we also have the option of defining a _duration_, and an _easing function_.  I've generally found that springs are a more natural way for animating user interfaces, but there are some cases where easing and duration could be preferable.  Here's how it's done.\n\n ```elm\n       Style.animate\n           |\u003e Style.easing (\\x -\u003e x)  -- linear easing\n           |\u003e Style.duration (0.5*second)\n           |\u003e Style.to\n               [ Left 0 Px\n               , Opacity 1\n               ]\n           |\u003e Style.on model.style\n  ```\n\u003e\n\u003e __Note__ The duration you provide will not do anything unless you also provide an easing function.  This is because spring based animations set the duration dynamically.\n\u003e Make sure to check out the [elm community easing library](http://package.elm-lang.org/packages/elm-community/easing-functions/latest) if you're looking for easing functions.\n\nNow that we have this animation, it has a few properties that may not be immediately apparent.  If a `Hide` action is called halfway through execution of the `Show` animation, the animation will be smoothly interrupted.\n\nThere may be a situation where we don't want our animation to be interrupted and instead we want an animation to queue up after a currently running animation.  To do this, we would use `Style.queue` instead of `Style.animate`\n\n\n# Example 2: Chaining Keyframes\n\n[demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Chaining.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Chaining.elm)\n\nWhat we've been doing is creating a single keyframe animation, but we also have the option of adding more keyframes.  \n\nWe use `Style.andThen` to create a new keyframe.  This new keyframe will have it's own independent delay, properties, and spring (or easing + duration).  Again, it can be interrupted smoothely at any point.\n\n\n```elm\n-- we need to import Color to begin working with color.\nimport Color exposing (rgba)\n\n-- in our update function, we'd change our animation to:\n      Style.animate\n        |\u003e Style.to\n            [ BackgroundColor (rgba 100 100 100 1.0) ]\n        |\u003e Style.andThen -- create a new keyframe\n        |\u003e Style.to\n            [ BackgroundColor (rgba 178 201 14 1.0) ]\n        |\u003e Style.andThen\n        |\u003e Style.to\n            [ BackgroundColor (rgba 58 40 69 1.0) ]\n        |\u003e on model.menuStyle\n\n```\n\n\n\n\n# Example 3: Animating Lists of Elements\n\n[demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Showcase.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Showcase.elm)\n\nWe can animate a list of styles by updating the styles either with `List.map` or `List.indexedMap`.\n\nFirst, our model would be something like this:\n\n```elm\n\ntype alias Model = { widgets : List Style.Animation }\n\n-- Later, in our update statement...\n      -- where j is the index of the widget we want to animate.\n      let\n        widgets =\n            List.indexedMap\n              (\\i widget -\u003e\n                  -- only update a specific widget in a list.\n                  if i == j then\n                     Style.animate\n                        |\u003e Style.duration (5*second)\n                        |\u003e Style.to\n                            [ Opacity 0  \n                            ]\n                        |\u003e Style.on widget\n                  else\n                    widget\n              ) model.widgets\n\n\n      in\n        ( { model | widgets = widgets }\n        , Cmd.none )\n\n-- Later in the `Animate` section of our `update` function, we need to send updates to every style we're animating.\n\n    Animate time -\u003e\n        ( { model\n            | widgets =\n                List.map\n                    (\\widget -\u003e\n                        Style.tick time widget\n                    )\n                    model.widgets\n          }\n        , Cmd.none\n        )\n\n\n```\n\nBy using `List.map` and `List.indexedMap` we have a natural way to do things like staggering a series of animations.  We can just calculate the delay of an animation based on it's index in a list.\n\nStaggering animations - [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Stagger.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Stagger.elm)\n\n```elm\n    List.indexedMap\n        (\\i widget -\u003e\n           Style.animate\n             |\u003e Style.delay (i * 0.05 * second) -- stagger this animation.\n             |\u003e Style.duration (0.3 * second)\n             |\u003e Style.to\n                 [ Left 200 Px\n                 ]\n             |\u003e Style.on widget\n        ) model.widgets\n\n```\n\n\n\n# Example 4: Stacking Transformations\n\n[demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/StackingTransforms.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/StackingTransforms.elm)\n\nCSS has support for `transforms` such as `translate`, `rotate`, and `scale`.  We also have access to some more complicated transformations such as `rotate3d` and `transform3d`.\n\nWhen using these transformations in normal css, you're able to stack them.  So, in your css file you can have something like the following:\n\n```css\n.transformed {\n  transform: rotate(20deg) translateY(100px) rotate(-20deg)\n}\n```\n\nIn this case, the transforms are performed in order. Rotate by 20deg, translateY (which is now angled 20deg) by 100px, and then rotate again -20deg.\n\nThis can be very useful, especially if we can animate each transform element individually.\n\nHere's how we're able to do this in Html.Animation.\n\nFirst, we define our initial style.  This will define the order that the transforms will appear.\n\n```elm\ninitialWidgetStyle =\n        Style.init\n            [ Rotate 0 Deg\n            , TranslateY 0 Px\n            , Rotate 0 Deg\n            ]\n\n```\n\n\nNow let's animate these properties.  Let's say we want do the following animation:\n\n  1. Make the first `Style.Rotate` move to 20deg.  \n  2. Once that's finished, we want to translateY to -200px\n  3. Now we want to rotate 1 revolution locally\n  4. Now we want to rotate 1 revolution around the original center\n  5. Then once that's finished, reset everything to 0.\n\n```elm\n  Style.animate\n      |\u003e Style.duration (0.5*second)\n      |\u003e Style.to\n          [ Rotate 20 Deg\n          ]\n      |\u003e Style.andThen\n      |\u003e Style.duration (0.7*second)\n      |\u003e Style.props\n          [ TranslateY -200 Px\n          ]\n      |\u003e Style.andThen\n      |\u003e Style.duration (0.7*second)\n      |\u003e Style.update\n          (\\index prop -\u003e\n              case prop of\n                  Rotate angle unit -\u003e\n                     -- make this update apply to the second rotate only.\n                     if index == 2 then\n                        Rotate 360.0 unit\n                    else\n                        Rotate angle unit\n                  _ -\u003e prop\n          )\n\n      |\u003e Style.andThen\n      |\u003e Style.duration (0.7*second)\n      |\u003e Style.to\n          [ Rotate 380 Deg\n          ]\n      |\u003e Style.andThen\n      |\u003e Style.delay (1*second)\n      |\u003e Style.to\n          [ Rotate 0 Deg\n          , TranslateY 0 Px\n          , Rotate 0 Deg\n          ]\n\n```\n\n## Animating SVG\n\nAnimating svg has to be handled slightly differently than animating html because the majority of the interesting properties that we'd want to animate are actually attributes that can't be controlled by CSS.\n\nHowever there's an easy solution.  Just use `Style.renderAttr` instead of `Style.render`, and everything will be take care of.  For example:\n\n```\nimport Color exposing (blue, green)\nimport Style\nimport Style.Properties exposing (..)\n\n-- Style.Propeties also exposes svg properties\nmodel {\n    svgStyle = Style.init\n          [ Fill blue\n          , Cx 200\n          , Cy 300\n          , R 50\n          ]\n}\n\n...in your view function, use Style.renderAttr like so.\n\n    svg []\n        [ circle (Style.renderAttr model.svgStyle) []\n        ]\n\n```\n\nEverything else that you learned applies exactly the same to svg properties.  Only the render function changes.\n\nHere are the properties you can use in svg animations.\n   * X\n   * Y\n   * Cx\n   * Cy\n   * R\n   * Rx\n   * Ry\n   * D\n   * Points\n   * Fill\n   * Stroke\n\n\n\n## Morphing Shapes\nElm Logo [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Logo.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Logo.elm)\n\nIf you create an svg polygon you can animate using the `points` attribute.  Elm-style-animation will automatically convert between polygons with differing numbers of points.  \n\n```elm\n-- We can define two polygon styles and morph between them\n\n      [ Points\n              \u003c| alignStartingPoint\n                  [ ( 161.649, 152.782 )\n                  , ( 231.514, 82.916 )\n                  , ( 91.783, 82.916 )\n                  ]\n        , Fill palette.orange\n        ]\n      , [ Points\n              \u003c| alignStartingPoint\n                  [ ( 8.867, 0 )\n                  , ( 79.241, 70.375 )\n                  , ( 232.213, 70.375 )\n                  , ( 161.838, 0 )\n                  ]\n        , Fill palette.green\n        ]\n\n\n\n```\n\nTo smoothly morph between two polygons, we need to align the starting points.  Fortunately we can do that with `alignStartingPoint`, which rotates a list of coordinates to that the one closest to the origin comes first and the rest follow.  \n\n\n## Morphing Paths - Batman Logos\n[inspiration](http://tavmjong.free.fr/blog/?p=741) / [demo](https://mdgriffith.github.io/elm-style-animation/1.0.0/Batman.html) / [view code](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Batman.elm)\n\nYou can also morph between svg [paths](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) using the `d` property.  Unlike the points property we were just talking about, we can't animate between two paths unless they have the same number of path commands.\n\nPaths are defined using the following.\n```elm\nmodel = {\n  myPath = Style.init\n      [ D [ MoveTo 256 213\n          , CurveTo [(245,181), (206,187), (234,262), (147,181), (169,71.2), (233,18)]\n          , Close\n          ]\n      ]      \n}\n```\n\nCheck out the [batman morphing example](https://github.com/mdgriffith/elm-style-animation/blob/master/examples/Batman.elm) to dive in.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdgriffith%2Felm-html-animation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmdgriffith%2Felm-html-animation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdgriffith%2Felm-html-animation/lists"}