Commits: 7

Fix cartesian plane's Y axis

index 83986b5..6e4ad58 100644
--- a/src/CartesianPlane.elm
+++ b/src/CartesianPlane.elm
@@ -40,7 +40,7 @@ graph size shapes =
=                , line
=                    [ x1 "0"
=                    , x2 "0"
-                    , x2 (String.fromFloat top)
+                    , y1 (String.fromFloat top)
=                    , y2 (String.fromFloat bottom)
=                    , stroke "black"
=                    , strokeWidth (String.fromFloat hairline)

Create simple SVG transformations example

Not interactive yet

new file mode 100644
index 0000000..80a3718
--- /dev/null
+++ b/src/Transformations.elm
@@ -0,0 +1,137 @@
+module Transformations exposing (main)
+
+import Browser
+import Browser.Events
+import CartesianPlane
+import Dict exposing (Dict)
+import Element
+import Html exposing (Html)
+import Json.Decode exposing (Decoder)
+import List.Extra as List
+import Svg exposing (..)
+import Svg.Attributes exposing (..)
+
+
+main =
+    Browser.element
+        { init = init
+        , view = view
+        , update = update
+        , subscriptions = subscriptions
+        }
+
+
+type alias Flags =
+    ()
+
+
+type alias Model =
+    List Transformation
+
+
+type Transformation
+    = Identity
+    | Scale Float Float
+    | Translate Float Float
+    | Rotate Float
+
+
+type Msg
+    = Progress Float
+    | Regress Float
+
+
+init : Flags -> ( Model, Cmd Msg )
+init () =
+    ( [ Identity
+      , Scale 2 2
+      , Translate 20 0
+      ]
+    , Cmd.none
+    )
+
+
+view : Model -> Html Msg
+view model =
+    let
+        wrapper element =
+            Element.el
+                [ Element.width (Element.maximum 600 Element.fill), Element.centerX ]
+                (Element.html element)
+
+        shape =
+            g [ transform (apply model) ]
+                [ line
+                    [ x1 "0"
+                    , x2 "100"
+                    , y1 "0"
+                    , y2 "0"
+                    , stroke "red"
+                    , strokeWidth "1"
+                    ]
+                    []
+                , circle [ cx "0", cy "0", r "2", fill "red" ] []
+
+                -- , rect [ x "", y "-2", width "1", height "4" ] []
+                ]
+    in
+    shape
+        |> List.singleton
+        |> CartesianPlane.graph 600
+        |> wrapper
+        |> Element.layout
+            [ Element.height Element.fill
+            , Element.width Element.fill
+            ]
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+    case msg of
+        Progress delta ->
+            ( model
+            , Cmd.none
+            )
+
+        Regress delta ->
+            ( model
+            , Cmd.none
+            )
+
+
+subscriptions : Model -> Sub Msg
+subscriptions model =
+    Sub.none
+
+
+apply : List Transformation -> String
+apply transformations =
+    let
+        toString : Transformation -> String
+        toString transformation =
+            case transformation of
+                Identity ->
+                    ""
+
+                Scale x y ->
+                    "scale("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Translate x y ->
+                    "translate("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Rotate angle ->
+                    "rotate("
+                        ++ String.fromFloat angle
+                        ++ ")"
+    in
+    transformations
+        |> List.map toString
+        |> String.join " "

Expand conspect to slides

index b6f46a0..c58cd80 100644
--- a/index.md
+++ b/index.md
@@ -6,7 +6,9 @@ presentation:
=
=<!-- slide -->
=
-## Conspect
+## Before the course begins
+
+<!-- slide -->
=
=- Setup the development environment
=
@@ -20,7 +22,13 @@ presentation:
=
=  - Atom
=
-Day 1
+<!-- slide -->
+
+## Day 1
+
+Let's make a dot!
+
+<!-- slide -->
=
=- Setup the project
=
@@ -38,12 +46,17 @@ Day 1
=
=  - Web browser
=
+<!-- slide -->
+
+### Introduce a problem
=
-- Let's make a dot!
+We want to have a dot on the screen
=
-  - Introduce a problem: We want to have a dot on the screen
+<!-- slide -->
+
+Show complete code
=
-  - Show complete code
+<!-- slide -->
=
=  - Explain:
=
@@ -53,6 +66,7 @@ Day 1
=
=  - Introduce SVG
=
+<!-- slide -->
=
=- Give  a color to the dot
=
@@ -60,6 +74,7 @@ Day 1
=
=  - Everyone can pick a color
=
+<!-- slide -->
=
=- Multiple dots
=
@@ -67,7 +82,9 @@ Day 1
=
=  - Explain a list, and show there is already a list there (with one item)
=
-    Do you see any other lists?
+<!-- slide -->
+
+Do you see any other lists?
=
=  - Element takes a list of children
=
@@ -79,487 +96,664 @@ Day 1
=
=  - Exercise: make 3 more dots (5 total)
=
+<!-- slide -->
=
-Day 2
+## Day 2
=
-- Place the dots in a circle
+Place the dots in a circle
=
-  - Introduce a problem: We want to place the dots in a circle: show an example in the slides
+<!-- slide -->
=
-  - How we will get there: we will change the cartesian coordinates of the dots, nothing else! But figuring out the right coordinates is a bit tricky
=
-  - How can we figure out the correct cartesian coordinates?
+Introduce a problem: We want to place the dots in a circle: show an example in the slides
+
+How we will get there: we will change the cartesian coordinates of the dots, nothing else! But figuring out the right coordinates is a bit tricky
+
+How can we figure out the correct cartesian coordinates?
+
+<!-- slide -->
+
+Story about the flowerpot and the table: two ways to measure relative position, one is distance from a x and y axis (cartesian coordinates), the other is angle and distance relative to origin (polar coordinates)
=
-    - Story about the flowerpot and the table: two ways to measure relative position, one is distance from a x and y axis (cartesian coordinates), the other is angle and distance relative to origin (polar coordinates)
+<!-- slide -->
=
-    - What does this have to do with a circle? Do you know the expression 'I did a 180'. Where would you be looking if you did two 180s (a "360"). We see that circles and angles are closely related!
+What does this have to do with a circle? Do you know the expression 'I did a 180'. Where would you be looking if you did two 180s (a "360"). We see that circles and angles are closely related!
=
-    - Exercise with compass and 5 objects, place objects evenly along compass. How many degrees apart are they? (observe if we multiply the result by 5, we're back to 360)
+<!-- slide -->
=
-    - We have one part of it (angle), we now need the distance. Notice they are all the same distance from the origin (the center dot) of the compass. Definition of circle: points that are an equal distance from a center. Actually, the distance doesn't matter, so long as they all have the same distance. You can have a big circle or a small circle, they're both circles
+Exercise with compass and 5 objects, place objects evenly along compass. How many degrees apart are they? (observe if we multiply the result by 5, we're back to 360)
=
-    - Ok great, we're done! Now, does anyone know how to give an angle and distance to svg? Oh... no? We don't either... you can't. You can only give x and y values relative to the origin
+<!-- slide -->
=
-    - So we already know that angle and length are just another way of describing x and y. But we need some way of translating between the two
+We have one part of it (angle), we now need the distance. Notice they are all the same distance from the origin (the center dot) of the compass. Definition of circle: points that are an equal distance from a center. Actually, the distance doesn't matter, so long as they all have the same distance. You can have a big circle or a small circle, they're both circles
=
-      Using a visual demonstration, if you draw a line from your object to the x axis, you have a triangle. Same if you draw a line to the y axis. You can figure out the point on the axis using sin and cos functions and multiplying the result by the length.
+<!-- slide -->
=
-      Let's use a chart to figure out the sin and cos of our angles
+Ok great, we're done! Now, does anyone know how to give an angle and distance to svg? Oh... no? We don't either... you can't. You can only give x and y values relative to the origin
=
-      *It's important to get a chart, otherwise we have to use calculators which work with radians*
+<!-- slide -->
=
-    - Now we are done... we can plug in our x and y values, and presto, our dots are arranged in a circle. But we don't see most of them...
+So we already know that angle and length are just another way of describing x and y. But we need some way of translating between the two
=
-    - Our origin is in the top left corner. This means any dots with negative x or y values are off the screen.
=
-      We can shift the dots so they are on the screen, or shift the screen so that it covers the dots. We will be shifting the screen
+<!-- slide -->
=
-      Sample viewbox program to demonstrate
+Using a visual demonstration, if you draw a line from your object to the x axis, you have a triangle. Same if you draw a line to the y axis. You can figure out the point on the axis using sin and cos functions and multiplying the result by the length.
=
-      Create a viewbox with correct perimeters (must be more than the radius of the circle plus the radius of a dot in each direction, and width and height are circumference)
+<!-- slide -->
=
-      ```elm
-      svg [ viewbox "-100 -100 200 200" ] []
-      ```
+Let's use a chart to figure out the sin and cos of our angles
=
-Day 3
+*It's important to get a chart, otherwise we have to use calculators which work with radians*
=
-- Let the computer do the math
+<!-- slide -->
=
-  - Introduce the problem: Can we avoid all these repetitive and manual steps?
+Now we are done... we can plug in our x and y values, and presto, our dots are arranged in a circle. But we don't see most of them...
=
-  - What is a program made of? (in the REPL):
+<!-- slide -->
=
-    - Values and names
+Our origin is in the top left corner. This means any dots with negative x or y values are off the screen.
=
-      ```
-      5
-      10.4
-      "Hello World"
-      [1, 2, 3, 4, 5]
-      ```
+We can shift the dots so they are on the screen, or shift the screen so that it covers the dots. We will be shifting the screen
=
-      Numbers, strings, lists containing numbers and strings are all values. They are self-referential. They simply state what they are. There are other kinds of values that we will see later.
+<!-- slide -->
=
-      You can give (or assign) a name to a value, as shown.
+Sample viewbox program to demonstrate
=
-      ```
-      family = 5
-      price = 10.4
-      morningGreeting = "Hello World"
-      fingers = [1, 2, 3, 4, 5]
-      ```
+<!-- slide -->
=
-      Here, `family` is a name and `5` is the value assigned to `family`.
+Create a viewbox with correct perimeters (must be more than the radius of the circle plus the radius of a dot in each direction, and width and height are circumference)
=
-      You can get the value back by calling its name.
+```elm
+svg [ viewbox "-100 -100 200 200" ] []
+```
=
-      ```
-      ---- Elm 0.19.0 ----------------------------------------------------------------
-      Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
-      --------------------------------------------------------------------------------
-      > family = 5
-      5 : number
-      > family
-      5 : number
-      ```
+<!-- slide -->
=
-    - Operators (+, -, ++)
+## Day 3
=
-      ```
-      > 2 + 5
-      7 : number
-      ```
+Let the computer do the math
=
-      ```
-      > 4 - 6
-      -2 : number
-      ```
+<!-- slide -->
=
-      ```
-      > "Hello" ++ " world!"
-      "Hello world!" : String
-      ```
+Introduce the problem: Can we avoid all these repetitive and manual steps?
=
-      ```
-      > 1 :: [2, 3, 4, 5]
-      [1,2,3,4,5] : List number
-      ```
+<!-- slide -->
=
-      Operators take two values and return a new value. We know that names refer to values, so we can use them in place of values:
+What is a program made of? (in the REPL):
=
-      ```
-      > family = 5
-      5 : number
-      > family + 2
-      7 : number
-      ```
+<!-- slide -->
=
-      You can also give a name to the value returned by an operator:
+Values and names
=
-      ```
-      > family = 5
-      5 : number
-      > familyAndPets = family + 2
-      7 : number
-      > familyAndPets
-      7 : number
-      ```
+```
+5
+10.4
+"Hello World"
+[1, 2, 3, 4, 5]
+```
=
-      Note that different values have different types.
+* Numbers like `5`, `10.4`
+* strings like `"Hello world"`
+* and lists containing numbers or strings
=
-      ```
-      5 : number
-      10.4 : Float
-      "Hello World" : String
-      [1,2,3,4,5] : List number
-      ```
-      Different operators work on different types. Adding a number and a string doesn't make sense. So if you try, Elm will complain (and give a helpful hint):
+are all values
=
-      ```
-      > "Hello " + 5
-      -- TYPE MISMATCH ----------------------------------------------------------- elm
+<!-- slide -->
=
-      I cannot do addition with String values like this one:
+They are self-referential. They simply state what they are. There are other kinds of values that we will see later.
=
-      5|   "Hello " + 5
-           ^^^^^^^^
-      The (+) operator only works with Int and Float values.
+<!-- slide -->
=
-      Hint: Switch to the (++) operator to append strings!
-      ```
+You can give (or assign) a name to a value, as shown.
=
-      (Int and Float are both types representing numbers)
+```
+family = 5
+price = 10.4
+morningGreeting = "Hello World"
+fingers = [1, 2, 3, 4, 5]
+```
=
+Here, `family` is a name and `5` is the value assigned to `family`.
=
-    - Functions
+<!-- slide -->
=
-      ```elm
-      fun something = something ++ " is fun."
-      ```
+You can get the value back by calling its name.
=
-      Explain: a function is a thing that takes some values (called arguments) and return one value. So it's similar to operators. In fact operators are functions!
+```
+---- Elm 0.19.0 ----------------------------------------------------------------
+Read <https://elm-lang.org/0.19.0/repl> to learn more: exit, help, imports, etc.
+--------------------------------------------------------------------------------
+> family = 5
+5 : number
+> family
+5 : number
+```
=
-      ```elm
-      (-) 5 10
-      5 - 10
-      ```
+<!-- slide -->
=
-      You can think of a function as a machine. You put something in the machine, and it produces something in return. For example think about a machine that produces rubber ducks. You put a bucket of white plastic pellets and a bucket of red paint, and you get a bunch of red rubber ducks!
+Operators (`+`, `-`, `++`, `::`)
=
-      What you get will depends on what you put. The color of the ducks depends on the paint you put. Quantity of ducks depends on how much plastic you put in.
+```
+> 2 + 5
+7 : number
+```
=
-      ```elm
-      makeMeSomeDucks color plastic =
-          String.fromInt plastic ++ " " ++ color ++ " rubber ducks"
-      ```
+```
+> 4 - 6
+-2 : number
+```
=
-      Once you have a function, you can call it like this:
+```
+> "Hello" ++ " world!"
+"Hello world!" : String
+```
=
-      ```elm
-      > makeMeSomeDucks "blue" 12
-      "12 blue rubber ducks" : String
-      ```
+```
+> 1 :: [2, 3, 4, 5]
+[1,2,3,4,5] : List number
+```
=
-      Note: functions help organize code into nice reusable chunks.
+<!-- slide -->
=
-      How do you get functions? There are three ways.
+Operators take two values and return a new value. We know that names refer to values, so we can use them in place of values:
=
-        1.  Some functions are always there for you, e.g. `(+)`, `(-)`
+```
+> family = 5
+5 : number
+> family + 2
+7 : number
+```
=
-        2.  Some functions you can import using code like this:
+<!-- slide -->
=
-            ```elm
-            import Svg
-            ```
+You can also give a name to the value returned by an operator:
=
-            and then
+```
+> family = 5
+5 : number
+> familyAndPets = family + 2
+7 : number
+> familyAndPets
+7 : number
+```
=
-            ```
-            Svg.circle [ cx "10", cy "10", r "20" ] [ ]
-            ```
+<!-- slide -->
=
-            To call a function that was imported, you have to prefix it with the name of the module (in this example `Svg`).
+Note that different values have different types.
=
-        3.  Finally, you will write some functions, just like we saw in the `fun` and `makeMeSomeDucks` examples.
+```
+5 : number
+10.4 : Float
+"Hello World" : String
+[1,2,3,4,5] : List number
+```
=
+<!-- slide -->
=
-      Finally there is one special thing: the first line of the program is a module declaration. For now it's enough for us to know, that it has to be there and it has to match the name of the file.
+Different operators work on different types. Adding a number and a string doesn't make sense. So if you try, Elm will complain (and give a helpful hint):
=
-  - Exercise: In our Main.elm, try to identify some values, names and function calls:
+```
+> "Hello " + 5
+-- TYPE MISMATCH ----------------------------------------------------------- elm
=
-    Hint: `"darkred"` is a value, `main` is a name, `width` is a function.
+I cannot do addition with String values like this one:
=
-    Hint: There is nothing else there now, but we will soon introduce our own functions.
+5|   "Hello " + 5
+     ^^^^^^^^
+The (+) operator only works with Int and Float values.
=
-  - Where can we use some functions?
+Hint: Switch to the (++) operator to append strings!
+```
=
-    As we said before, functions are good when we have some repetitive operation that can be parametrized (like rubber ducks production).
+(Int and Float are both types representing numbers)
=
-    Obviously calculating `x` and `y` coordinates is repetitive and can be parametrized (parameters are `radius` and `angle`).
+<!-- slide -->
=
-  - Apply to our trigonometry calculations
+Functions
=
-    - Compose and copy and paste the trigonometry functions to calculate cx and cy:
+```elm
+fun something = something ++ " is fun."
+```
=
-      ```elm
-      cx (String.fromFloat (cos (degrees 72) * 100))
-      cy (String.fromFloat (sin (degrees 72) * 100))
-      ```
+<!-- slide -->
=
-    - Eliminate repetition:
+Explain: a function is a thing that takes some values (called arguments) and return one value. So it's similar to operators. In fact operators are functions!
=
-      - define and reuse radius (100)
+```elm
+(-) 5 10
+5 - 10
+```
=
-        Assign a value of `100` to a name `radius`:
+<!-- slide -->
=
-        ```
-        radius = 100
-        ```
+You can think of a function as a machine. You put something in the machine, and it produces something in return. For example think about a machine that produces rubber ducks. You put a bucket of white plastic pellets and a bucket of red paint, and you get a bunch of red rubber ducks!
=
-        and plug it to our functions:
+What you get will depends on what you put. The color of the ducks depends on the paint you put. Quantity of ducks depends on how much plastic you put in.
=
-        ```elm
-        cx (String.fromFloat (cos (degrees 72) * radius))
-        cy (String.fromFloat (sin (degrees 72) * radius))
-        ```
+<!-- slide -->
=
-        As you see the names are good for repetitive things too.
+```elm
+makeMeSomeDucks color plastic =
+    String.fromInt plastic ++ " " ++ color ++ " rubber ducks"
+```
=
-      - define and reuse `x : angle -> cx` and `y : angle -> cy`
+Once you have a function, you can call it like this:
=
+```elm
+> makeMeSomeDucks "blue" 12
+"12 blue rubber ducks" : String
+```
=
-        ```elm
-        x angle =
-          String.fromFloat (cos (degrees angle) * radius)
-        ```
+<!-- slide -->
=
-        ```elm
-        y angle =
-          String.fromFloat (sin (degrees angle) * radius)
-        ```
+Note: functions help organize code into nice reusable chunks.
=
-        Then plug it into the code making circles:
+<!-- slide -->
=
-        ```elm
-        circle
-          [ cx (x 72)
-          , cy (y 72)
-          , r "10"
-          , fill "darkred"
-          ]
-        ```
+How do you get functions? There are three ways.
=
-      - define and reuse `dot : angle -> color -> Svg`
+<!-- slide -->
=
+Some functions are always there for you
=
-        ```elm
-        dot angle color =
-            circle
-                [ cx (x angle)
-                , cy (y angle)
-                , r "10"
-                , fill color
-                ]
-        ```
+`(+)`, `(-)`
=
-        and plug it into our SVG picture:
+<!-- slide -->
=
+2.  Some functions you can import using code like this:
=
-        ```
-        svg [ viewbox "-100 -100 200 200" ]
-          [ dot 0 "darkred"
-          , dot 72 "fuchsia"
-          , dot 144 "saddlebrown"
-          , dot 216 "deepskyblue"
-          , dot 288 "gold"
-          ]
-        ```
+```elm
+import Svg
+```
=
-        Want some more cool color inspiration. Check out https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Color_keywords
+and then
=
-    - Make it more general
+```
+Svg.circle [ cx "10", cy "10", r "20" ] [ ]
+```
=
-      - Show List and list operations (map and indexedMap)
+To call a function that was imported, you have to prefix it with the name of the module (in this example `Svg`).
=
-        There are a number of functions that operate on lists, for example `List.length` and `List.map`.
+<!-- slide -->
=
-        Examples of a map: a shopping list, after you find each item and place it in your basket, you are 'mapping' from a list of needed items to a list of items in your basket. Now you have two lists, and they are related. One is your original shopping list, the other the list of items in the basket.
+Finally, you will write some functions, just like we saw in the `fun` and `makeMeSomeDucks` examples.
=
-        Demonstrate:
+<!-- slide -->
=
-        ```elm
-        > things = ["Programming", "Swimming", "Dancing", "Saddle brown"]    
-        ["Programming","Swimming","Dancing","Saddle brown"]
-            : List String
+Finally there is one special thing: the first line of the program is a module declaration. For now it's enough for us to know, that it has to be there and it has to match the name of the file.
=
+<!-- slide -->
=
-        > List.length things
-        4 : Int
+Exercise: In our Main.elm, try to identify some values, names and function calls:
=
-        > List.map fun things
-        ["Programming is fun!","Swimming is fun!","Dancing is fun!","Saddle brown is fun!"]
-            : List String
+Hint: `"darkred"` is a value, `main` is a name, `width` is a function.
=
-        > things
-        ["Programming","Swimming","Dancing","Saddle brown"]
-            : List String
-        ```
+Hint: There is nothing else there now, but we will soon introduce our own functions.
=
-        Notice our original `things` list is unchanged. This is different from our rubber duck machine. The rubber duck turns the plastic and paint into rubber ducks. A function on the other hand 'creates' the value it gives you. You don't loose the original value given to it.
+<!-- slide -->
=
-      - Make a `palette : List color`
+#### Where can we use some functions?
=
-        ```elm
-        palette =
-          [ "darkred"
-          , "fuchsia"
-          , "saddlebrown"
-          , "deepskyblue"
-          , "gold"
-          ]
-        ```
+As we said before, functions are good when we have some repetitive operation that can be parametrized (like rubber ducks production).
=
-      - Use `List.indexedMap dot palette` to generate the dots
+Obviously calculating `x` and `y` coordinates is repetitive and can be parametrized (parameters are `radius` and `angle`).
=
-        Another function that operates on lists is `List.indexedMap`. Let's see it at work:
+<!-- slide -->
=
-        ```elm
-        dot index color =
-            circle
-                [ cx (x ((360 / (List.length palette)) * index))
-                , cy (y ((360 / (List.length palette)) * index))
-                , r "10"
-                , fill color
-                ]
+#### Apply to our trigonometry calculations
=
-        List.indexedMap dot palette
-        ```
-
-        We can introduce a `let` block to make our code more readable and avoid repetition.
-
-        ```elm
-        dot index color =
-            let
-                angle =
-                    (360 / count) * index
-
-                count =
-                    List.length palette
-            in
-            circle
-                [ cx (x angle)
-                , cy (y angle)
-                , r "10"
-                , fill color
-                ]
-        ```
+Compose and copy and paste the trigonometry functions to calculate cx and cy:
+
+```elm
+cx (String.fromFloat (cos (degrees 72) * 100))
+cy (String.fromFloat (sin (degrees 72) * 100))
+```
+
+<!-- slide -->
+
+#### Eliminate the repetition:
+
+Assign a value of `100` to a name `radius`:
+
+```
+radius = 100
+```
+
+and plug it to our functions:
+
+```elm
+cx (String.fromFloat (cos (degrees 72) * radius))
+cy (String.fromFloat (sin (degrees 72) * radius))
+```
+
+<!-- slide -->
+
+As you see the names are good for repetitive things too.
+
+Define and reuse
+
+- `x : angle -> cx`
+
+  ```elm
+  x angle =
+      String.fromFloat (cos (degrees angle) * radius)
+  ```
+
+- `y : angle -> cy`
+
+  ```elm
+  y angle =
+      String.fromFloat (sin (degrees angle) * radius)
+  ```
+
+<!-- slide -->
+
+Then plug it into the code making circles:
+
+```elm
+circle
+  [ cx (x 72)
+  , cy (y 72)
+  , r "10"
+  , fill "darkred"
+  ]
+```
+
+<!-- slide -->
+
+define and reuse `dot : angle -> color -> Svg`
+
+```elm
+dot angle color =
+    circle
+        [ cx (x angle)
+        , cy (y angle)
+        , r "10"
+        , fill color
+        ]
+```
+
+
+<!-- slide -->
+
+and plug it into our SVG picture:
+
+```
+svg [ viewbox "-100 -100 200 200" ]
+  [ dot 0 "darkred"
+  , dot 72 "fuchsia"
+  , dot 144 "saddlebrown"
+  , dot 216 "deepskyblue"
+  , dot 288 "gold"
+  ]
+```
+
+For more cool colors check out [Color keywords page at Mozilla Developer's Network](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Color_keywords)
+
+<!-- slide -->
+
+- Make it more general
+
+  - Show List and list operations (map and indexedMap)
+
+    There are a number of functions that operate on lists, for example `List.length` and `List.map`.
+
+<!-- slide -->
+
+Examples of a map: a shopping list, after you find each item and place it in your basket, you are 'mapping' from a list of needed items to a list of items in your basket. Now you have two lists, and they are related. One is your original shopping list, the other the list of items in the basket.
+
+<!-- slide -->
+
+Demonstrate:
+
+```elm
+> things = ["Programming", "Swimming", "Dancing", "Saddle brown"]    
+["Programming","Swimming","Dancing","Saddle brown"]
+    : List String
+
+
+> List.length things
+4 : Int
=
-        Take a look at the [documentation for `List.indexedMap`](https://package.elm-lang.org/packages/elm/core/latest/List#indexedMap).
+> List.map fun things
+["Programming is fun!","Swimming is fun!","Dancing is fun!","Saddle brown is fun!"]
+    : List String
=
+> things
+["Programming","Swimming","Dancing","Saddle brown"]
+    : List String
+```
+
+<!-- slide -->
+
+Notice our original `things` list is unchanged. This is different from our rubber duck machine. The rubber duck turns the plastic and paint into rubber ducks. A function on the other hand 'creates' the value it gives you. You don't loose the original value given to it.
+
+<!-- slide -->
=
-Day 4
+Make a `palette : List color`
+
+```elm
+palette =
+  [ "darkred"
+  , "fuchsia"
+  , "saddlebrown"
+  , "deepskyblue"
+  , "gold"
+  ]
+```
+
+<!-- slide -->
+
+Use `List.indexedMap dot palette` to generate the dots
+
+<!-- slide -->
+
+Another function that operates on lists is `List.indexedMap`. Let's see it at work:
+
+```elm
+dot index color =
+    circle
+        [ cx (x ((360 / (List.length palette)) * index))
+        , cy (y ((360 / (List.length palette)) * index))
+        , r "10"
+        , fill color
+        ]
+
+List.indexedMap dot palette
+```
+
+<!-- slide -->
+
+We can introduce a `let` block to make our code more readable and avoid repetition.
+
+```elm
+dot index color =
+    let
+        angle =
+            (360 / count) * index
+
+        count =
+            List.length palette
+    in
+    circle
+        [ cx (x angle)
+        , cy (y angle)
+        , r "10"
+        , fill color
+        ]
+```
+
+<!-- slide -->
+
+Take a look at the [documentation for `List.indexedMap`](https://package.elm-lang.org/packages/elm/core/latest/List#indexedMap).
+
+<!-- slide -->
+
+## Day 4
+
+<!-- slide -->
=
=Introduce SVG groups
=
-    - We'll need one group for the dots and one group for the lines
+We'll need one group for the dots and one group for the lines
=
-    ```elm
-    svg [ viewBox "-100 -100 200 200" ]
-        [ Svg.g [] (List.indexedMap dot pallete)
-        , Svg.g [] [ Svg.line [ x1 "123", y1 "112", x2 "41", y2 "11", stroke "black" ] [] ]
+```elm
+svg [ viewBox "-100 -100 200 200" ]
+    [ Svg.g [] (List.indexedMap dot pallete)
+    , Svg.g [] [ Svg.line [ x1 "123", y1 "112", x2 "41", y2 "11", stroke "black" ] [] ]
+    ]
+```
+
+<!-- slide -->
+
+Exercise: add a few lines with different colors
+
+Now we'll learn how to color a line with a gradient (going from one color to another)
+
+<!-- slide -->
+
+```
+svg [ width "600", height "600", viewBox "-300 -300 600 600" ]
+    [ Svg.g [] (List.indexedMap dot pallete)
+    , Svg.defs []
+        [ Svg.linearGradient [ Svg.Attributes.id "MyGradient", x1 "0", y1 "0", x2 "1", y2 "0" ]
+            [ Svg.stop [ Svg.Attributes.offset "0", Svg.Attributes.stopColor "saddlebrown" ] []
+            , Svg.stop [ Svg.Attributes.offset "1", Svg.Attributes.stopColor "pink" ] []
+            ]
+        ]
+    , Svg.g []
+        [ Svg.line [ x1 "0", y1 "0", x2 "100", y2 "100", stroke "url(#MyGradient)" ] []
+        , Svg.line [ x1 "0", y1 "0", x2 "-100", y2 "-100", stroke "url(#MyGradient)" ] []
=        ]
-    ```
+    ]
+```
+
+<!-- slide -->
=
-    Exercise: add a few lines with different colors
+We see a problem here. The gradient always goes from saddlebrown to pink from top left to bottom right. If we want to use the same gradient to connect different points, we'll need to be creative.
=
-    Now we'll learn how to color a line with a gradient (going from one color to another)
+<!-- slide -->
=
-    ```
+```
+main =
=    svg [ width "600", height "600", viewBox "-300 -300 600 600" ]
=        [ Svg.g [] (List.indexedMap dot pallete)
=        , Svg.defs []
-            [ Svg.linearGradient [ Svg.Attributes.id "MyGradient", x1 "0", y1 "0", x2 "1", y2 "0" ]
+            [ Svg.linearGradient [ Svg.Attributes.id "MyGradient", x1 "0", y1 "0", x2 "1", y2 "0", gradientUnits "userSpaceOnUse" ]
=                [ Svg.stop [ Svg.Attributes.offset "0", Svg.Attributes.stopColor "saddlebrown" ] []
=                , Svg.stop [ Svg.Attributes.offset "1", Svg.Attributes.stopColor "pink" ] []
=                ]
=            ]
=        , Svg.g []
-            [ Svg.line [ x1 "0", y1 "0", x2 "100", y2 "100", stroke "url(#MyGradient)" ] []
-            , Svg.line [ x1 "0", y1 "0", x2 "-100", y2 "-100", stroke "url(#MyGradient)" ] []
+            [ Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(45),scale(100,1)", stroke "url(#MyGradient)" ] []
+            , Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(180),scale(100,1)", stroke "url(#MyGradient)" ] []
+            , Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(270),scale(100,1)", stroke "url(#MyGradient)" ] []
=            ]
=        ]
-    ```
-
-    We see a problem here. The gradient always goes from saddlebrown to pink from top left to bottom right. If we want to use the same gradient to connect different points, we'll need to be creative.
-
-    ```
-    main =
-        svg [ width "600", height "600", viewBox "-300 -300 600 600" ]
-            [ Svg.g [] (List.indexedMap dot pallete)
-            , Svg.defs []
-                [ Svg.linearGradient [ Svg.Attributes.id "MyGradient", x1 "0", y1 "0", x2 "1", y2 "0", gradientUnits "userSpaceOnUse" ]
-                    [ Svg.stop [ Svg.Attributes.offset "0", Svg.Attributes.stopColor "saddlebrown" ] []
-                    , Svg.stop [ Svg.Attributes.offset "1", Svg.Attributes.stopColor "pink" ] []
-                    ]
-                ]
-            , Svg.g []
-                [ Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(45),scale(100,1)", stroke "url(#MyGradient)" ] []
-                , Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(180),scale(100,1)", stroke "url(#MyGradient)" ] []
-                , Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform "rotate(270),scale(100,1)", stroke "url(#MyGradient)" ] []
-                ]
-            ]
-    ```
+```
+
+TODO: We need to fix the viewbox!
=
-    We need to fix the viewbox!
+<!-- slide -->
=
-    Here's the trick: we have the lines initially match the gradient. We're using the same x and y values for all the lines and the gradient. Then we transform the lines to position them where we'd like them. We're actually using our old friend polar coordinates here.
=
-    If you're interested in what `gradientUnits "userSpaceOnUse"` does, come see me after the lesson.
+Here's the trick: we have the lines initially match the gradient. We're using the same x and y values for all the lines and the gradient. Then we transform the lines to position them where we'd like them. We're actually using our old friend polar coordinates here.
=
-    ```elm
-    gradient : Int -> String -> Svg msg
-    gradient index color =
-        Svg.linearGradient [ Svg.Attributes.id ("Gradient-" ++ String.fromInt index), x1 "0", y1 "0", x2 "1", y2 "0", gradientUnits "userSpaceOnUse" ]
-            [ Svg.stop [ Svg.Attributes.offset "0", Svg.Attributes.stopColor "saddlebrown" ] []
-            , Svg.stop [ Svg.Attributes.offset "1", Svg.Attributes.stopColor color ] []
+If you're interested in what `gradientUnits "userSpaceOnUse"` does, come see me after the lesson.
+
+<!-- slide -->
+
+```elm
+gradient : Int -> String -> Svg msg
+gradient index color =
+    Svg.linearGradient
+        [ id ("Gradient-" ++ String.fromInt index)
+        , x1 "0"
+        , y1 "0"
+        , x2 "1"
+        , y2 "0"
+        , gradientUnits "userSpaceOnUse"
+        ]
+        [ Svg.stop
+            [ Svg.Attributes.offset "0"
+            , Svg.Attributes.stopColor "saddlebrown"
+            ]
+            []
+        , Svg.stop
+            [ Svg.Attributes.offset "1"
+            , Svg.Attributes.stopColor color
=            ]
+            []
+        ]
+```
+
+<!-- slide -->
+
+```
+line : Int -> String -> Svg msg
+line index color =
+    let
+        count =
+            List.length pallete
=
+        angle =
+            (360 / toFloat count) * toFloat index
=
-    line : Int -> String -> Svg msg
-    line index color =
-        let
-            angle =
-                (360 / toFloat (List.length pallete)) * toFloat index
+        transformation =
+            "rotate("
+                ++ String.fromFloat angle
+                ++ "), scale("
+                ++ String.fromInt radius
+                ++ ", 1)"
=
-            transformation =
-                "rotate(" ++ String.fromFloat angle ++ "),scale(" ++ String.fromInt radius ++ ",1)"
+        url =
+            "url(#Gradient-" ++ String.fromInt index ++ ")"
+    in
+    Svg.line
+        [ x1 "0"
+        , y1 "0"
+        , x2 "1"
+        , y2 "0"
+        , transform transformation
+        , stroke url
+        ]
+        []
+```
=
-            url =
-                "url(#Gradient-" ++ String.fromInt index ++ ")"
-        in
-        Svg.line [ x1 "0", y1 "0", x2 "1", y2 "0", transform transformation, stroke url ] []
+<!-- slide -->
=
+```
+main =
+    svg [ width "600", height "600", viewBox "-300 -300 600 600" ]
+        [ Svg.g [] (List.indexedMap dot pallete)
+        , Svg.defs [] (List.indexedMap gradient pallete)
+        , Svg.g [] (List.indexedMap line pallete)
+        ]
+```
=
-    main =
-        svg [ width "600", height "600", viewBox "-300 -300 600 600" ]
-            [ Svg.g [] (List.indexedMap dot pallete)
-            , Svg.defs [] (List.indexedMap gradient pallete)
-            , Svg.g [] (List.indexedMap line pallete)
-            ]
-    ```
+<!-- slide -->
=
=    This may look like a lot, but our `gradient` and `line` functions are very similar to our `dot` function from earlier. In fact we see an essential principle of good programming design here. We spent a lot of time banging our heads over gradients. Now that we've done that work, we can hide the implementation in our gradient and line functions. Now, if we want to draw a new dot, line, and gradient going from the center to the dot, we only need to add a new item to our palette. Our functions do the rest for us. Our functions conceal our complexity. We can forget about the implementation, so long as we know how to operate them. They're like black boxes, we know what goes in and what comes out, but we don't have to know how they work on the inside.
=
+<!-- slide -->
=
-Day 5
+## Day 5
+
+Let's make a beautiful tree!
+
+<!-- slide -->
=
=Our project is looking pretty good at this point. We've created some interesting graphical elements, and learned some interesting ways to place them programatically. However, it doesn't take user input like many of the programs we use. We'll be doing some pretty interesting things with user input later in this workshop, but for now we'll start with a deceptively simple step: setting the background color.
=
=I say this step is deceptively simple, because we'll need to make some big changes to our program and introduce a number of new concepts.
=
+<!-- slide -->
+
=Show complete code.
=
+<!-- slide -->
+
=There's a lot going on here, and it's not obvious how it all works.
=
=Our `main` value has changed.
@@ -574,8 +768,15 @@ main =
=        }
=```
=
-Previously, the value of `main` was an SVG element. Now it contains a call to `Browser.sandbox`. A sandbox is a basic interactive program. For a program to be interactive, it need more than just a SVG element. It also needs a `state`. The state of an application is basically the information used to determine how the application should be rendered. Think about the Atom program we are all running at the moment. We know we are all running the same program, however we are not all looking at exactly the same thing. The text in our neighbors editor might be slightly different than the text in our own. If they opened another file, a letter to a friend for example, the text would be very different. The text input is part of the state of the Atom application. Maybe your neighbor has scrolled to another point in the screen. The scroll point is also part of the state of the Atom application. The cursor might be on another line in their viewport. The cursor position is also part of the state of the Atom application. Atom uses all of this state information to render exactly what you are seeing on your computer screen. Anything that can change will be represented in a state variable. If you input or delete text, move the cursor, scroll up or down, or change any of the application settings, you are updating
-the state of the Atom application.
+<!-- slide -->
+
+Previously, the value of `main` was an SVG element. Now it contains a call to `Browser.sandbox` function.
+
+<!-- slide -->
+
+A sandbox is a basic interactive program. For a program to be interactive, it need more than just a SVG element.
+
+<!-- slide -->
=
=```
=type alias State =
@@ -588,8 +789,12 @@ type alias Color =
=
=Here we create something called a type alias. We've already discussed types. A type alias is basically a way to give an alternative name for a type. We give the alias `Color` to `String` and the alias `State` to `Color`. So in the end all three names point to the same type!
=
+<!-- slide -->
+
=Why are we doing this? All of these types are strings, and Elm will treat them all as strings. But it will make our code more readable to use these aliases. We are writing an application that allows the user to change the background color. That should explain why our `State` is a `Color`.
=
+<!-- slide -->
+
=Our `Browser.sandbox` takes something with the name `init`. This is our initial state. Let's take a look at the value of `init`.
=
=```
@@ -598,8 +803,12 @@ init =
=    "white"
=```
=
+<!-- slide -->
+
=We see that the initial state is `"white"`. We'll see how our application uses this value in a moment.
=
+<!-- slide -->
+
=Looking back at our `sandbox`, we see it also takes a `view`. Let's take a look at our view function:
=
=```
@@ -617,14 +826,24 @@ view color =
=        ]
=```
=
+<!-- slide -->
+
=You'll notice that this `view` function looks very similar to the `main` variable from earlier. Before, our application was only a view. Now the view is only one piece of our interactive application.
=
+<!-- slide -->
+
=One important way our `view` function differs from the `main` variable from ealier is that `view` is a function. We see it takes a variable of type `State` (a string), which we have named `color`. In an Elm sandbox project the `view` always takes a variable with the same type as the `init` variable. This is the current state of the application. `view` can use the state to render the application properly, just as Atom uses its state to render text for its user.
=
+<!-- slide -->
+
=We see that we've added a line to the svg attributes, `Svg.Attributes.style ("background: " ++ color)`. Here we use the state of the application to set the background color of the svg element.
=
+<!-- slide -->
+
=All we need now is some way to update the state (the background color) of the application.
=
+<!-- slide -->
+
=Taking a look at our `main` function, we see that it take a third and final function, `update`. Let's look at our update function:
=
=```
@@ -640,58 +859,147 @@ update msg state =
=
=```
=
+<!-- slide -->
+
=We see our `update` function takes two variables, of type `Msg` and `State`. If we think of update as a machine which takes an old state and spits out a new state, this state variable corresponds to the old state.
=
+<!-- slide -->
+
=The `msg` variable is something new. Looking above, we see that we have defined a `Msg` variable type. This is similar to our `State` and `Color` union types, in that we have defined a new type that Elm understands. However, unlike the `type alias` constructor, the `type` constructor does not simply give a new name for an existing type. Instead, here we define a completely unique type. We see values with type Msg must have the form `SetBackground Color`. `SetBackground "white"`, `SetBackground "blue"`, `SetBackground "saddlebrown"` are all valid values of the type `Msg`.
=
+<!-- slide -->
+
=What is important to understand is that our `msg` variable is used by `update` to determine how it should update the state. We see that update first checks that `msg` has the form `SetBackground color`, and then returns the value of `color`. This will become our new state. Every time update is called, the sandbox will re-render our view with the new state.
=
+<!-- slide -->
+
=So now we see how our application changes the background color of the svg element. However, we haven't seen when it will update the background color. Well, we want to change the background color by clicking a dot. So let's take a look at our `dot` function to see if we can find a hint there.
=
-- `Model`:
+<!-- slide -->
=
-  the structure of the state of the program
+<dl>
+<dt>Model
+<dd>the structure of the state of the program
+</dl>
=
-  TODO: Consistently use `Model` and `model` instead of less standard `State` to make it easier to our participants.
+> TODO: Consistently use `Model` and `model` instead of less standard `State` to make it easier to our participants.
=
-- `Msg`
+<!-- slide -->
=
+<dl>
+<dt>Msg
+<dd>
=  What events can there be in the program. Currently have only one possible event - setting the background to a given color.
+</dl>
+
+<!-- slide -->
=
=- `update`
=
=  the instructions of how to change the state when a particular message comes in.
=
+<!-- slide -->
+
=- `view`
=
=  the instruction of what to display on the screen. It also contains instructions of what messages to send when certain events (like clicks on elements) happen. Every time the state changes the instructions will be applied.
=
+<!-- slide -->
+
=- `init`
=
=  What is the initial state right after the program is started.
=
+<!-- slide -->
+
=- `main`
=
=  glues it all together.
=
-Next steps:
+<!-- slide -->
=
=- How do we model the tree
=
-  - introduces the model for later interactive program
+<!-- slide -->
+
+A tree is a composition of segments. A segment can be either a twig or a branch. Twig is a terminal segment of a tree. When the tree is very young it consists of a single twig. Later this twig will evolve into a branch and will grow it's own twigs, that in turn will evolve into branches. So a branch is a segment of a tree that ends with some other  segments (twigs or branches).
+
+<!-- slide -->
+
+Note that a branch can split to several branches that each in turn can split into several branches and so on. This way a tree can be as complex as we want. Note that real trees are like that. It's difficult to say how many generations of branches it can have from the trunk to the smallest little twigs on top of the crown. This kind of structure is called recursive. It repeats the same pattern.
+
+<!-- slide -->
=
-  - naturally introduces union types
+Each segment (a twig or a branch) has length, a direction (represented as an angle) and a color (so that it's beautiful despite having no leafs or flowers).
=
+Here is how we can represent it in code:
=
-- Make a tree grow
+```
+type alias Segment =
+    { length : Float
+    , direction : Float
+    , color : Color
+    }
+```
=
-  - Make a function that given the age of the tree and rules returns a tree
+<!-- slide -->
=
-  - Use time subscription to make the tree grow
+If you consider that a branch can split into more branches or twigs, and then that a trunk of a tree is just a first branch or a twig if the tree is very young, then you can see that each segment separated from the parent branch can be considered a tree.
=
=<!-- slide -->
=
-``
+So we can reuse the same structure to represent a tree or any of it's segments!
+
+Look:
+
+```
+type Tree
+    = Twig Segment
+    | Branch Segment (List Tree)
+```
+
+<!-- slide -->
+
+Think about it! A tree is a twig (when it's young) or a branch that splits into __a zero, one or many__ __twigs or branches__.
+
+  - zero, one or many: a list
+  - twig or branch: a tree
+
+So a Twig is just a Segment while a branch is a Segment with a list of Trees!
+
+<!-- slide -->
+
+Let's encode a simple tree by hand:
+
+```elm
+tree =
+  Branch { length = 10, direction = degrees -90, color = "brown" }
+      [ Branch { length = 6, direction = degrees -45, color = "lightbrown" }
+          [ Twig { length = 2, direction = degrees -30, color = "green" }
+          , Twig { length = 2, direction = degrees -60, color = "green" }
+          ]
+      , Branch { length = 6, direction = degrees -135, color = "lightbrown" }
+          [ Twig { length = 2, direction = degrees -120, color = "green" }
+          , Twig { length = 2, direction = degrees -150, color = "green" }
+          ]
+      ]
+```
+
+<!-- slide -->
+
+## Day 6
+
+Make the tree grow!
+
+<!-- slide -->
+
+Make a function that given the age of the tree and rules returns a tree
+
+<!-- slide -->
+
+Use time subscription to make the tree grow
+
+<!-- slide -->
=
=```
=dot : Int -> String -> Svg Msg
@@ -712,12 +1020,18 @@ dot index color =
=
=We see there is a new line here:
=
+<!-- slide -->
+
=```
=Svg.Events.onClick (SetBackground color)
=```
=
+<!-- slide -->
+
=`onClick` is an event. It basically tells our svg element to listen for someone to click on it. It will then handle the event by emitting the Msg `SetBackground color`. We know `color` is the color of the dot. We see then that when someone clicks on the dot, the Msg will be emitted, `update` will be called with this Msg and will update our state. Our sandbox will rerender the view with this new state. The user will see the svg element with a new background color.
=
+<!-- slide -->
+
=Notice that our `view` function, as well as all the functions that call functions responsible for rendering svg elements, including `gradient`, `line`, and `dot` have return values with type `Svg Msg` or `Html Msg`. This is because svg element can emit Msgs which will be handled by `update`.
=
=

Complete the Tree program using only SVG transformations

No trigonometry anymore!

index 5e5f50b..2ec5008 100644
--- a/src/Tree.elm
+++ b/src/Tree.elm
@@ -5,6 +5,7 @@ import Browser.Events
=import Dict exposing (Dict)
=import Html exposing (Html)
=import Json.Decode exposing (Decoder)
+import List.Extra as List
=import Svg exposing (..)
=import Svg.Attributes exposing (..)
=
@@ -50,18 +51,15 @@ type alias Rules =
=
=init : Flags -> ( Model, Cmd Msg )
=init () =
-    ( { time = 0
+    ( { time = 20000
=      , rules =
=            Dict.fromList
=                [ ( "red"
-                  , [ Segment "green" 15 0.2
-                    , Segment "green" 175 0.1
-                    ]
+                  , [ Segment "brown" -90 6 ]
=                  )
-                , ( "green", [ Segment "blue" 15 0.3 ] )
-                , ( "blue"
-                  , [ Segment "red" 15 0.7
-                    , Segment "purple" 45 0.1
+                , ( "brown"
+                  , [ Segment "brown" 45 3
+                    , Segment "brown" -45 3
=                    ]
=                  )
=                ]
@@ -72,17 +70,58 @@ init () =
=
=view : Model -> Html Msg
=view model =
+    let
+        gradients : List (Svg Msg)
+        gradients =
+            model.rules
+                |> Dict.map
+                    (\parentColor children ->
+                        children
+                            |> List.map (\child -> ( parentColor, child.color ))
+                    )
+                |> Dict.values
+                |> List.concat
+                |> List.unique
+                |> List.map
+                    (\(( start, end ) as colors) ->
+                        linearGradient
+                            [ id (gradientId colors)
+                            , x1 "0"
+                            , y1 "0"
+                            , x2 "1"
+                            , y2 "0"
+                            , gradientUnits "userSpaceOnUse"
+                            ]
+                            [ stop
+                                [ stopColor start, offset "0.2" ]
+                                []
+                            , stop
+                                [ stopColor end, offset "0.8" ]
+                                []
+                            ]
+                    )
+
+        tree =
+            "red"
+                |> svgTree model.rules (model.time / 5000) (model.time / 5000)
+                |> g
+                    [ transform
+                        ("scale("
+                            ++ String.fromFloat (model.time / 1000)
+                            ++ ")"
+                        )
+                    ]
+    in
=    Html.div []
=        [ Html.h1 [] [ Html.text <| String.fromFloat model.time ]
-        , "red"
-            |> svgTree model.rules (model.time / 5000) (model.time / 5000)
-            |> g [ transform ("scale(" ++ String.fromFloat (model.time / 1000) ++ ")") ]
-            |> List.singleton
-            |> svg
-                [ viewBox "-1000 -1000 2000 2000"
-                , height "800px"
-                , width "800px"
-                ]
+        , svg
+            [ viewBox "-1000 -1000 2000 2000"
+            , height "800px"
+            , width "800px"
+            ]
+            [ defs [] gradients
+            , tree
+            ]
=        ]
=
=
@@ -145,17 +184,41 @@ svgTree rules treeAge branchAge color =
=                                ++ String.fromFloat segment.angle
=                                ++ ")"
=                                ++ ", scale("
-                                ++ String.fromFloat ((branchAge - 1) / treeAge)
+                                ++ String.fromFloat (branchAge / treeAge)
=                                ++ ")"
=                                ++ ", translate("
-                                ++ String.fromFloat (segment.length * branchAge)
+                                ++ String.fromFloat segment.length
=                                ++ ", 0)"
=                    in
=                    g
=                        [ transform transformation ]
-                        (svgTree rules treeAge (branchAge - 1) segment.color)
+                        (line
+                            [ stroke ("url(#" ++ gradientId ( color, segment.color ) ++ ")")
+                            , x1 <| String.fromFloat 0
+                            , x2 <| String.fromFloat 1
+                            , y1 <| String.fromFloat 0
+                            , y2 <| String.fromFloat 0
+                            , strokeWidth "1"
+                            , transform
+                                ("translate("
+                                    ++ String.fromFloat (0 - segment.length)
+                                    ++ ", 0)"
+                                    ++ ", "
+                                    ++ "scale("
+                                    ++ String.fromFloat segment.length
+                                    ++ ", 1)"
+                                )
+                            ]
+                            []
+                            :: svgTree rules treeAge (branchAge - 1) segment.color
+                        )
=                )
-            |> (::) (circle [ cx "0", cy "0", fill color, r "1" ] [])
+            |> (::) (circle [ cx "0", cy "0", fill color, r "0.5" ] [])
=
=    else
=        []
+
+
+gradientId : ( Color, Color ) -> String
+gradientId ( start, end ) =
+    "connection-" ++ start ++ "-" ++ end

Define Transformation as union type and use applyTransformations function to create Svg.Attribute for transformations

index 2ec5008..711307f 100644
--- a/src/Tree.elm
+++ b/src/Tree.elm
@@ -51,7 +51,7 @@ type alias Rules =
=
=init : Flags -> ( Model, Cmd Msg )
=init () =
-    ( { time = 20000
+    ( { time = 0
=      , rules =
=            Dict.fromList
=                [ ( "red"
@@ -178,20 +178,13 @@ svgTree rules treeAge branchAge color =
=            |> Maybe.withDefault []
=            |> List.map
=                (\segment ->
-                    let
-                        transformation =
-                            "rotate("
-                                ++ String.fromFloat segment.angle
-                                ++ ")"
-                                ++ ", scale("
-                                ++ String.fromFloat (branchAge / treeAge)
-                                ++ ")"
-                                ++ ", translate("
-                                ++ String.fromFloat segment.length
-                                ++ ", 0)"
-                    in
=                    g
-                        [ transform transformation ]
+                        [ applyTransformations
+                            [ Rotate segment.angle
+                            , Scale (branchAge / treeAge) (branchAge / treeAge)
+                            , Translate segment.length 0
+                            ]
+                        ]
=                        (line
=                            [ stroke ("url(#" ++ gradientId ( color, segment.color ) ++ ")")
=                            , x1 <| String.fromFloat 0
@@ -199,15 +192,10 @@ svgTree rules treeAge branchAge color =
=                            , y1 <| String.fromFloat 0
=                            , y2 <| String.fromFloat 0
=                            , strokeWidth "1"
-                            , transform
-                                ("translate("
-                                    ++ String.fromFloat (0 - segment.length)
-                                    ++ ", 0)"
-                                    ++ ", "
-                                    ++ "scale("
-                                    ++ String.fromFloat segment.length
-                                    ++ ", 1)"
-                                )
+                            , applyTransformations
+                                [ Translate (0 - segment.length) 0
+                                , Scale segment.length 1
+                                ]
=                            ]
=                            []
=                            :: svgTree rules treeAge (branchAge - 1) segment.color
@@ -219,6 +207,47 @@ svgTree rules treeAge branchAge color =
=        []
=
=
+type Transformation
+    = Identity
+    | Scale Float Float
+    | Translate Float Float
+    | Rotate Float
+
+
+applyTransformations : List Transformation -> Svg.Attribute Msg
+applyTransformations transformations =
+    let
+        toString : Transformation -> String
+        toString transformation =
+            case transformation of
+                Identity ->
+                    ""
+
+                Scale x y ->
+                    "scale("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Translate x y ->
+                    "translate("
+                        ++ String.fromFloat x
+                        ++ ", "
+                        ++ String.fromFloat y
+                        ++ ")"
+
+                Rotate angle ->
+                    "rotate("
+                        ++ String.fromFloat angle
+                        ++ ")"
+    in
+    transformations
+        |> List.map toString
+        |> String.join " "
+        |> transform
+
+
=gradientId : ( Color, Color ) -> String
=gradientId ( start, end ) =
=    "connection-" ++ start ++ "-" ++ end

Make subtrees scale linearly

Code reformatting

index 711307f..9f15a49 100644
--- a/src/Tree.elm
+++ b/src/Tree.elm
@@ -103,7 +103,7 @@ view model =
=
=        tree =
=            "red"
-                |> svgTree model.rules (model.time / 5000) (model.time / 5000)
+                |> svgTree model.rules (model.time / 5000)
=                |> g
=                    [ transform
=                        ("scale("
@@ -170,41 +170,52 @@ subscriptions model =
=        ]
=
=
-svgTree : Rules -> Float -> Float -> Color -> List (Svg Msg)
-svgTree rules treeAge branchAge color =
-    if branchAge > 0 then
-        rules
-            |> Dict.get color
-            |> Maybe.withDefault []
-            |> List.map
-                (\segment ->
-                    g
-                        [ applyTransformations
-                            [ Rotate segment.angle
-                            , Scale (branchAge / treeAge) (branchAge / treeAge)
-                            , Translate segment.length 0
-                            ]
-                        ]
-                        (line
-                            [ stroke ("url(#" ++ gradientId ( color, segment.color ) ++ ")")
-                            , x1 <| String.fromFloat 0
-                            , x2 <| String.fromFloat 1
-                            , y1 <| String.fromFloat 0
-                            , y2 <| String.fromFloat 0
-                            , strokeWidth "1"
-                            , applyTransformations
-                                [ Translate (0 - segment.length) 0
-                                , Scale segment.length 1
-                                ]
-                            ]
-                            []
-                            :: svgTree rules treeAge (branchAge - 1) segment.color
-                        )
-                )
-            |> (::) (circle [ cx "0", cy "0", fill color, r "0.5" ] [])
+svgTree : Rules -> Float -> Color -> List (Svg Msg)
+svgTree rules age color =
+    if age <= 0 then
+        []
=
=    else
-        []
+        let
+            subtrees =
+                rules
+                    |> Dict.get color
+                    |> Maybe.withDefault []
+                    |> List.map subtree
+
+            subtree segment =
+                let
+                    gradient =
+                        "url(#" ++ gradientId ( color, segment.color ) ++ ")"
+
+                    scale =
+                        age / (age + 1)
+                in
+                g
+                    [ applyTransformations
+                        [ Rotate segment.angle
+                        , Scale scale scale
+                        , Translate segment.length 0
+                        ]
+                    ]
+                    (line
+                        [ stroke gradient
+                        , x1 "0"
+                        , x2 "1"
+                        , y1 "0"
+                        , y2 "0"
+                        , strokeWidth "1"
+                        , applyTransformations
+                            [ Translate (0 - segment.length) 0
+                            , Scale segment.length 1
+                            ]
+                        ]
+                        []
+                        :: svgTree rules (age - 1) segment.color
+                    )
+        in
+        circle [ cx "0", cy "0", fill color, r "0.5" ] []
+            :: subtrees
=
=
=type Transformation

Remove circles and use round linecap instead.

index 9f15a49..a7f36d8 100644
--- a/src/Tree.elm
+++ b/src/Tree.elm
@@ -51,15 +51,25 @@ type alias Rules =
=
=init : Flags -> ( Model, Cmd Msg )
=init () =
-    ( { time = 0
+    ( { time = 50000
=      , rules =
=            Dict.fromList
-                [ ( "red"
-                  , [ Segment "brown" -90 6 ]
+                [ ( "brown"
+                  , [ Segment "green" -115 1
+                    , Segment "green" -65 1
+                    , Segment "saddlebrown" 90 2
+                    ]
+                  )
+                , ( "green"
+                  , [ Segment "green" 20 3
+                    , Segment "green" -20 3
+                    , Segment "red" 90 1
+                    , Segment "red" -90 1
+                    ]
=                  )
-                , ( "brown"
-                  , [ Segment "brown" 45 3
-                    , Segment "brown" -45 3
+                , ( "saddlebrown"
+                  , [ Segment "saddlebrown" 20 3
+                    , Segment "saddlebrown" -20 3
=                    ]
=                  )
=                ]
@@ -93,16 +103,16 @@ view model =
=                            , gradientUnits "userSpaceOnUse"
=                            ]
=                            [ stop
-                                [ stopColor start, offset "0.2" ]
+                                [ stopColor start, offset "0" ]
=                                []
=                            , stop
-                                [ stopColor end, offset "0.8" ]
+                                [ stopColor end, offset "1" ]
=                                []
=                            ]
=                    )
=
=        tree =
-            "red"
+            "brown"
=                |> svgTree model.rules (model.time / 5000)
=                |> g
=                    [ transform
@@ -204,7 +214,8 @@ svgTree rules age color =
=                        , x2 "1"
=                        , y1 "0"
=                        , y2 "0"
-                        , strokeWidth "1"
+                        , strokeWidth "0.2"
+                        , strokeLinecap "round"
=                        , applyTransformations
=                            [ Translate (0 - segment.length) 0
=                            , Scale segment.length 1
@@ -214,8 +225,7 @@ svgTree rules age color =
=                        :: svgTree rules (age - 1) segment.color
=                    )
=        in
-        circle [ cx "0", cy "0", fill color, r "0.5" ] []
-            :: subtrees
+        subtrees
=
=
=type Transformation