diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for dyna-gloss
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2022
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# dyna-gloss
+
+FRP bindings for library `gloss` which is great
+to create 2D animation and graphics. It features declarative
+and functional approach to drawing the pictures and here we
+make it even more declarative with FRP style.
+
+## Tutorial
+
+* [Introduction](https://github.com/anton-k/dyna-frp/blob/main/dyna-gloss/tutorial/00-intro.md)
+* [Example](https://github.com/anton-k/dyna-frp/blob/main/dyna-gloss/tutorial/01-example.md)
+* [Quick reference](https://github.com/anton-k/dyna-frp/blob/main/dyna-gloss/tutorial/101-reference.md)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/dyna-gloss.cabal b/dyna-gloss.cabal
new file mode 100644
--- /dev/null
+++ b/dyna-gloss.cabal
@@ -0,0 +1,83 @@
+cabal-version: 1.12
+
+name:           dyna-gloss
+version:        0.1.0.0
+synopsis:       FRP for gloss graphics and animation library
+description:    Defines FRP for gloss graphics and animation library
+homepage:       https://github.com/anton-k/dyna-gloss#readme
+bug-reports:    https://github.com/anton-k/dyna-gloss/issues
+author:         Anton Kholomiov
+maintainer:     anton.kholomiov@gmail.com
+category:       Graphics, FRP
+copyright:      2022 Anton Kholomiov
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+source-repository head
+  type: git
+  location: https://github.com/anton-k/dyna-frp/dyna-gloss
+
+library
+  exposed-modules:
+      Dyna.Gloss
+      Dyna.Gloss.Data.Picture
+      Dyna.Gloss.Data.Point
+      Dyna.Gloss.Data.Vec
+      Dyna.Gloss.Geometry.Line
+      Dyna.Gloss.Frp
+      Dyna.Gloss.Run
+  other-modules:
+      Dyna.Gloss.Types
+      Paths_dyna_gloss
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <5
+    , Boolean
+    , dyna
+    , gloss
+    , lifted-base
+    , monad-control
+    , mtl
+    , stm
+    , temporal-media
+    , time
+    , transformers-base
+    , vector-space
+    , unagi-chan
+    , random
+    , MonadRandom
+  default-language: Haskell2010
+  default-extensions:
+    GADTs
+    RankNTypes
+    LambdaCase
+    FlexibleContexts
+    FlexibleInstances
+    ExistentialQuantification
+    MultiParamTypeClasses
+    TypeApplications
+    TypeFamilies
+    TupleSections
+    GeneralizedNewtypeDeriving
+    UndecidableInstances
+    ImportQualifiedPost
+    RecordWildCards
+
+
+test-suite dyna-gloss-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_dyna_gloss
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , dyna-gloss
+  default-language: Haskell2010
diff --git a/src/Dyna/Gloss.hs b/src/Dyna/Gloss.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss.hs
@@ -0,0 +1,25 @@
+module Dyna.Gloss(
+  module X
+) where
+
+import Data.AdditiveGroup as X
+import Data.AffineSpace as X
+import Data.Basis as X
+import Data.Cross as X
+import Data.VectorSpace as X
+import Temporal.Class as X
+
+import Graphics.Gloss.Data.Bitmap as X
+import Graphics.Gloss.Data.Color as X
+import Graphics.Gloss.Data.Display as X
+import Graphics.Gloss.Data.ViewPort as X
+import Graphics.Gloss.Data.ViewState as X
+import Graphics.Gloss.Geometry.Angle as X
+import Graphics.Gloss.Interface.Environment as X
+
+import Dyna.Gloss.Frp as X
+import Dyna.Gloss.Run as X
+import Dyna.Gloss.Data.Vec as X
+import Dyna.Gloss.Data.Point as X
+import Dyna.Gloss.Data.Picture as X
+import Dyna.Gloss.Geometry.Line as X
diff --git a/src/Dyna/Gloss/Data/Picture.hs b/src/Dyna/Gloss/Data/Picture.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Data/Picture.hs
@@ -0,0 +1,198 @@
+module Dyna.Gloss.Data.Picture
+        ( Picture       (..)
+        , Point, Vec, Path
+
+        -- * Aliases for Picture constructors
+        , blank
+        , polygon
+        , line
+        , circle, thickCircle
+        , arc,    thickArc
+        , text
+        , bitmap
+        , bitmapSection
+        -- , bitmap
+        , color
+        , translate, rotate, scale
+        , pictures
+
+        -- * Compound shapes
+        , lineLoop
+        , circleSolid
+        , arcSolid
+        , sectorWire
+        , rectanglePath
+        , rectangleWire
+        , rectangleSolid
+        , rectangleUpperPath
+        , rectangleUpperWire
+        , rectangleUpperSolid
+        )
+where
+
+import Data.VectorSpace
+import Graphics.Gloss.Data.Bitmap
+import Graphics.Gloss.Data.Color
+import Graphics.Gloss.Data.Picture (Picture(..))
+import Graphics.Gloss.Geometry.Angle
+import Dyna.Gloss.Data.Point
+import Dyna.Gloss.Data.Vec
+
+-- Constructors ----------------------------------------------------------------
+-- NOTE: The docs here should be identical to the ones on the constructors.
+
+-- | A blank picture, with nothing in it.
+blank :: Picture
+blank   = Blank
+
+-- | A convex polygon filled with a solid color.
+polygon :: Path -> Picture
+polygon = Polygon . fmap toTuple
+
+-- | A line along an arbitrary path.
+line :: Path -> Picture
+line = Line . fmap toTuple
+
+-- | A circle with the given radius.
+circle  :: Float  -> Picture
+circle  = Circle
+
+-- | A circle with the given thickness and radius.
+--   If the thickness is 0 then this is equivalent to `Circle`.
+thickCircle  :: Float -> Float -> Picture
+thickCircle = ThickCircle
+
+-- | A circular arc drawn counter-clockwise between two angles (in degrees)
+--   at the given radius.
+arc     :: Float -> Float -> Float -> Picture
+arc = Arc
+
+-- | A circular arc drawn counter-clockwise between two angles (in degrees),
+--   with the given radius  and thickness.
+--   If the thickness is 0 then this is equivalent to `Arc`.
+thickArc :: Float -> Float -> Float -> Float -> Picture
+thickArc = ThickArc
+
+-- | Some text to draw with a vector font.
+text :: String -> Picture
+text = Text
+
+-- | A bitmap image
+bitmap  :: BitmapData -> Picture
+bitmap bitmapData = Bitmap bitmapData
+
+-- | a subsection of a bitmap image
+--   first argument selects a sub section in the bitmap
+--   second argument determines the bitmap data
+bitmapSection  :: Rectangle -> BitmapData -> Picture
+bitmapSection = BitmapSection
+
+-- | A picture drawn with this color.
+color :: Color -> Picture -> Picture
+color = Color
+
+-- | A picture translated by the given x and y coordinates.
+translate :: Vec -> Picture -> Picture
+translate (Vec x y) = Translate x y
+
+-- | A picture rotated clockwise by the given angle (in tau's).
+-- 1 Tau is full circle.
+rotate  :: Float -> Picture -> Picture
+rotate x = Rotate (360 * x)
+
+-- | A picture scaled by the given x and y factors.
+scale   :: Vec -> Picture -> Picture
+scale (Vec x y) = Scale x y
+
+-- | A picture consisting of several others.
+pictures :: [Picture] -> Picture
+pictures = Pictures
+
+
+-- Other Shapes ---------------------------------------------------------------
+-- | A closed loop along a path.
+lineLoop :: Path -> Picture
+lineLoop xs     = line $ case xs of
+   []     -> []
+   (x:xs) -> (x:xs) ++ [x]
+
+
+-- Circles and Arcs -----------------------------------------------------------
+-- | A solid circle with the given radius.
+circleSolid :: Float -> Picture
+circleSolid r
+        = thickCircle (r/2) r
+
+
+-- | A solid arc, drawn counter-clockwise between two angles at the given radius.
+arcSolid  :: Float -> Float -> Float -> Picture
+arcSolid a1 a2 r
+        = thickArc a1 a2 (r/2) r
+
+
+-- | A wireframe sector of a circle.
+--   An arc is draw counter-clockwise from the first to the second angle at
+--   the given radius. Lines are drawn from the origin to the ends of the arc.
+---
+--   NOTE: We take the absolute value of the radius incase it's negative.
+--   It would also make sense to draw the sector flipped around the
+--   origin, but I think taking the absolute value will be less surprising
+--   for the user.
+--
+sectorWire :: Float -> Float -> Float -> Picture
+sectorWire a1 a2 r_
+ = let r        = abs r_
+   in  Pictures
+        [ Arc a1 a2 r
+        , line [0, r *^ unitVecAtAngle (degToRad a1) ]
+        , line [0, r *^ unitVecAtAngle (degToRad a2) ]
+        ]
+
+-- Rectangles -----------------------------------------------------------------
+-- NOTE: Only the first of these rectangle functions has haddocks on the
+--       arguments to reduce the amount of noise in the extracted docs.
+
+-- | A path representing a rectangle centered about the origin
+rectanglePath
+        :: Float        -- ^ width of rectangle
+        -> Float        -- ^ height of rectangle
+        -> Path
+rectanglePath sizeX sizeY
+ = let  sx      = sizeX / 2
+        sy      = sizeY / 2
+   in   [Vec (-sx) (-sy), Vec (-sx) sy, Vec sx sy, Vec sx (-sy)]
+
+-- | A wireframe rectangle centered about the origin.
+rectangleWire :: Float -> Float -> Picture
+rectangleWire sizeX sizeY
+        = lineLoop $ rectanglePath sizeX sizeY
+
+-- | A wireframe rectangle in the y > 0 half of the x-y plane.
+rectangleUpperWire :: Float -> Float -> Picture
+rectangleUpperWire sizeX sizeY
+        = lineLoop $ rectangleUpperPath sizeX sizeY
+
+-- | A path representing a rectangle in the y > 0 half of the x-y plane.
+rectangleUpperPath :: Float -> Float -> Path
+rectangleUpperPath sizeX sy
+ = let  sx      = sizeX / 2
+   in   [Vec (-sx) 0, Vec (-sx) sy, Vec sx sy, Vec sx 0]
+
+-- | A solid rectangle centered about the origin.
+rectangleSolid :: Float -> Float -> Picture
+rectangleSolid sizeX sizeY
+        = Polygon $ rectanglePath' sizeX sizeY
+  where
+    rectanglePath' sizeX sizeY =
+        let  sx      = sizeX / 2
+             sy      = sizeY / 2
+        in   [(-sx, -sy), (-sx, sy), (sx, sy), (sx, -sy)]
+
+-- | A solid rectangle in the y > 0 half of the x-y plane.
+rectangleUpperSolid :: Float -> Float -> Picture
+rectangleUpperSolid sizeX sizeY = Polygon $ path sizeX sizeY
+  where
+    path sizeX sy
+      = let  sx      = sizeX / 2
+        in   [(-sx, 0), (-sx, sy), (sx, sy), (sx, 0)]
+
diff --git a/src/Dyna/Gloss/Data/Point.hs b/src/Dyna/Gloss/Data/Point.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Data/Point.hs
@@ -0,0 +1,30 @@
+module Dyna.Gloss.Data.Point
+        ( Point, Path
+        , pointInBox)
+where
+
+import Dyna.Gloss.Data.Vec
+
+type Point = Vec
+type Path = [Point]
+
+-- | Test whether a point lies within a rectangular box that is oriented
+--   on the x-y plane. The points P1-P2 are opposing points of the box,
+--   but need not be in a particular order.
+--
+-- @
+--    P2 +-------+
+--       |       |
+--       | + P0  |
+--       |       |
+--       +-------+ P1
+-- @
+--
+pointInBox :: Point -> Point -> Point -> Bool
+pointInBox (Vec x0 y0) (Vec x1 y1) (Vec x2 y2)
+  =  x0 >= min x1 x2
+  && x0 <= max x1 x2
+  && y0 >= min y1 y2
+  && y0 <= max y1 y2
+
+
diff --git a/src/Dyna/Gloss/Data/Vec.hs b/src/Dyna/Gloss/Data/Vec.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Data/Vec.hs
@@ -0,0 +1,168 @@
+module Dyna.Gloss.Data.Vec(
+    Vec(..)
+  , magV
+  , argV
+  , dotV
+  , detV
+  , mulSV
+  , rotateV
+  , angleVV
+  , normalizeV
+  , unitVecAtAngle
+  , e
+  , VecBasis(..)
+  , fromTuple
+  , toTuple
+  ) where
+
+import Graphics.Gloss.Geometry.Angle
+import Dyna (BasisArity(..))
+import Data.AdditiveGroup
+import Data.AffineSpace
+import Data.Basis
+import Data.Cross
+import Data.VectorSpace
+
+-- | Pair of unboxed floats. All operations on vectors are strict
+-- which is more suitable for computation intensive domains such as computer graphics.
+data Vec = Vec
+  { vec'x :: {-# UNPACK #-} !Float
+  , vec'y :: {-# UNPACK #-} !Float
+  }
+  deriving (Show, Eq, Ord)
+
+-- | Converts vector to tuple of Floats
+toTuple :: Vec -> (Float, Float)
+toTuple (Vec x y) = (x, y)
+
+-- | Converts tuple of floats to vector
+fromTuple :: (Float, Float) -> Vec
+fromTuple (x, y) = Vec x y
+
+lift0 :: Float -> Vec
+lift0 a = Vec a a
+
+lift1 :: (Float -> Float) -> Vec -> Vec
+lift1 f (Vec a b) = Vec (f a) (f b)
+
+lift2 :: (Float -> Float -> Float) -> Vec -> Vec -> Vec
+lift2 f (Vec a1 b1) (Vec a2 b2) = Vec (f a1 a2) (f b1 b2)
+
+-- numeric instances
+
+instance Num Vec where
+  fromInteger = lift0 . fromInteger
+  (+) = lift2 (+)
+  (*) = lift2 (*)
+  (-) = lift2 (-)
+  negate = lift1 negate
+  abs = lift1 abs
+  signum = lift1 signum
+
+instance Fractional Vec where
+  fromRational = lift0 . fromRational
+  recip = lift1 recip
+  (/) = lift2 (/)
+
+-- vector space instances
+
+instance AdditiveGroup Vec where
+  zeroV = lift0 zeroV
+  (^+^) = lift2 (^+^)
+  (^-^) = lift2 (^-^)
+  negateV = lift1 negateV
+
+instance VectorSpace Vec where
+  type Scalar Vec = Float
+  (*^) k = lift1 (k *^)
+
+instance AffineSpace Vec where
+  type Diff Vec = Vec
+  (.-.) = lift2 (.-.)
+  (.+^) = lift2 (.+^)
+
+instance BasisArity Vec where
+  basisArity _ = 2
+
+data VecBasis = VecX | VecY
+
+instance HasBasis Vec where
+  type Basis Vec = VecBasis
+  basisValue = \case
+    VecX -> Vec 1 0
+    VecY -> Vec 0 1
+
+  decompose (Vec x y) = [(VecX, x), (VecY, y)]
+
+  decompose' (Vec x y) = \case
+    VecX -> x
+    VecY -> y
+
+instance HasNormal Vec where
+  normalVec = normalizeV
+
+instance HasCross2 Vec where
+  cross2 (Vec x y) = Vec (negate y) x -- or @(y,-x)@?
+
+-------------------------------------------------------------------
+-- gloss functions on Vectors
+
+-- | Normalise a vector, so it has a magnitude of 1.
+normalizeV :: Vec -> Vec
+normalizeV v = lift1 ((1 / magV v) * ) v
+{-# INLINE normalizeV #-}
+
+-- | The magnitude of a vector.
+magV :: Vec -> Float
+magV (Vec x y) = sqrt (x * x + y * y)
+{-# INLINE magV #-}
+
+-- | The angle of this vector, relative to the +ve x-axis.
+argV :: Vec -> Float
+argV (Vec x y) = normalizeAngle $ atan2 y x
+{-# INLINE argV #-}
+
+-- | The dot product of two vectors.
+dotV :: Vec -> Vec -> Float
+dotV (Vec x1 x2) (Vec y1 y2) = x1 * y1 + x2 * y2
+{-# INLINE dotV #-}
+
+-- | The determinant of two vectors.
+detV :: Vec -> Vec -> Float
+detV (Vec x1 y1) (Vec x2 y2) = x1 * y2 - y1 * x2
+{-# INLINE detV #-}
+
+-- | Multiply a vector by a scalar.
+mulSV :: Float -> Vec -> Vec
+mulSV s (Vec x y) = Vec (s * x) (s * y)
+{-# INLINE mulSV #-}
+
+-- | Rotate a vector by an angle (in radians). +ve angle is counter-clockwise.
+rotateV :: Float -> Vec -> Vec
+rotateV r (Vec x y)
+ = Vec (x * cos r - y * sin r)
+       (x * sin r + y * cos r)
+{-# INLINE rotateV #-}
+
+-- | Compute the inner angle (in radians) between two vectors.
+angleVV :: Vec -> Vec -> Float
+angleVV p1 p2
+ = let  m1      = magV p1
+        m2      = magV p2
+        d       = p1 `dotV` p2
+        aDiff   = acos $ d / (m1 * m2)
+
+   in   aDiff
+{-# INLINE angleVV #-}
+
+-- | Produce a unit vector at a given angle relative to the +ve x-axis.
+--      The provided angle is in radians.
+unitVecAtAngle :: Float -> Vec
+unitVecAtAngle r = Vec (cos r) (sin r)
+{-# INLINE unitVecAtAngle #-}
+
+-- | Shortcut for @unitVecAtAngle@
+e :: Float -> Vec
+e = unitVecAtAngle
+{-# INLINE e #-}
+
diff --git a/src/Dyna/Gloss/Frp.hs b/src/Dyna/Gloss/Frp.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Frp.hs
@@ -0,0 +1,655 @@
+-- | FRP main types and combinators
+module Dyna.Gloss.Frp(
+  -- * Events
+  Evt,
+  once,
+  never,
+  -- * Dynamics
+  Dyn,
+  constDyn,
+  -- ** Observing the Dyn
+  DynRef,
+  runDyn,
+  readDyn,
+  cancelDyn,
+
+  -- * Control
+  newEvt,
+  newDyn,
+
+  -- * API
+  -- * Event API
+  scan,
+  scanMay,
+  mapMay,
+  foldMap,
+  accum,
+  accumB,
+  accumMay,
+  filters,
+  filterJust,
+  whens,
+  splits,
+  lefts,
+  rights,
+  iterates,
+  withIterates,
+
+  fix1,
+  fix2,
+  fix3,
+  fix4,
+  switch,
+  joins,
+
+  delay,
+  delayFork,
+
+  sums,
+  sumD,
+  integrate,
+  integrate2,
+  products,
+  count,
+  withCount,
+  appends,
+  takes,
+  drops,
+  takesWhile,
+  dropsWhile,
+  cycles,
+  listAt,
+  toToggle,
+
+  races,
+  forks,
+  forevers,
+  folds,
+  foldls,
+  foldls',
+  foldrs,
+  foldrs',
+  prints,
+  putStrLns,
+  -- * Event/Dynamic interaction
+  hold,
+  unhold,
+  scanD,
+  scanMayD,
+  switchD,
+  switchDyn,
+  apply,
+  applyMay,
+  snap,
+  attach,
+  attachWith,
+  attachWithMay,
+  (<@>),
+  (<@),
+  -- * Effectful API
+  RunFunctor(..),
+  foreach,
+  posteach,
+  iterates',
+  scan',
+  scanMay',
+  accum',
+  accumMay',
+  filters',
+  mapMay',
+  apply',
+  applyMay',
+  -- * Utilities
+
+  -- **  Channels (interaction with the world)
+  mchanEvt,
+  tchanEvt,
+  uchanEvt,
+
+  -- ** Clock
+  clock,
+  pulse,
+  ticks,
+  timer,
+  timerD,
+  -- ** Random
+  toRandom,
+  toRandomR,
+  withRandom,
+  withRandomR,
+  oneOf,
+  withOneOf,
+  freqOf,
+  withFreqOf,
+  randSkip,
+  randSkipBy,
+
+  -- * Re-exports
+  liftA2,
+  liftA3,
+) where
+
+import Control.Applicative (liftA2, liftA3)
+import Control.Concurrent.Chan qualified as M
+import Control.Concurrent.STM
+import Control.Concurrent.Chan.Unagi (InChan)
+import Data.Bifunctor
+import Data.Time
+import System.Random
+import Data.VectorSpace
+
+import Dyna.Gloss.Types
+import Dyna qualified as D
+
+infixl 4 <@>
+infixl 4 <@
+
+-- | Reference to running dynamic process by which we can query values (@readDyn@).
+-- Also note that we no longer need the reference we should release the resources
+-- by calling @cancelDyn@.
+newtype DynRef a = DynRef { unDynRef :: D.DynRef Run a }
+
+-- | Runs dynamic within the scope of the function.
+-- It provides a callback with dyn getter as argument and after
+-- callback finishes it shutdowns the dyn process.
+withDyn :: Dyn a -> (Run a -> Run b) -> Run b
+withDyn (Dyn dyn) f = D.withDyn dyn f
+
+-- | Dyn that is constructed from effectful callback.
+constDyn :: Run a -> Dyn a
+constDyn act = Dyn $ D.constDyn act
+
+-- | Executes dynamic for observation. The dynamic is step-wise constant
+-- function that is driven by some event stream. The function runs the event stream
+-- process in background and samples the updated state.
+--
+-- We can observe the value with @readDyn@. We need to shut down the stream when
+-- we no longer need it with @cancelDyn@ function.
+runDyn :: Dyn a -> Run (DynRef a)
+runDyn (Dyn d) = DynRef <$> D.runDyn d
+--
+-- | Event that happens only once and happens right away.
+once :: Run a -> Evt a
+once ask = Evt $ D.once ask
+
+-- | Event that never happens. Callback function is ignored.
+never :: Evt a
+never = Evt D.never
+
+-- | Runs the argument event stream as background process
+-- and produces event stream that is fed with events over channel (unagi-channel package).
+-- When result event stream shuts down the background process also shuts down.
+newEvt :: Evt a -> Run (Evt a)
+newEvt (Evt evt) = Evt <$> D.newEvt evt
+
+-- | Runs the dynamic process in background and returns dynamic
+-- that just samples the background proces with @readDyn@.
+newDyn :: Dyn a -> Run (Dyn a)
+newDyn (Dyn dyn) = Dyn <$> D.newDyn dyn
+
+-- | Accumulate over event stream.
+accum :: (a -> s -> (b, s)) -> s -> Evt a -> Evt b
+accum f s (Evt evt) = Evt $ D.accum f s evt
+
+-- | Accumulate over event stream.
+accum' :: (a -> s -> Run (b, s)) -> s -> Evt a -> Evt b
+accum' f s (Evt evt) = Evt $ D.accum' f s evt
+
+-- | Accumulate over event stream.
+accumMay :: (a -> s -> Maybe (b, s)) -> s -> Evt a -> Evt b
+accumMay f s (Evt evt) = Evt $ D.accumMay f s evt
+
+-- | Accumulate over event stream.
+accumMay' :: (a -> s -> Run (Maybe (b, s))) -> s -> Evt a -> Evt b
+accumMay' f s (Evt evt) = Evt $ D.accumMay' f s evt
+
+-- | scan over event stream. Example:
+--
+-- > naturals = scan (+) 0 pulse
+scan :: (a -> b -> b) -> b -> Evt a -> Evt b
+scan f s (Evt evt) = Evt $ D.scan f s  evt
+
+-- | scan over event stream with effectful function.
+scan' :: (a -> b -> Run b) -> b -> Evt a -> Evt b
+scan' f s (Evt evt) = Evt $ D.scan' f s evt
+
+-- | scan combined with filter. If accumulator function produces @Nothing@ on event then
+-- that event is ignored and state is kept to previous state.
+scanMay :: (a -> b -> Maybe b) -> b -> Evt a -> Evt b
+scanMay f s (Evt evt) = Evt $ D.scanMay f s evt
+
+-- | scan combined with filter for effectful function. See @scanMay@ for details.
+scanMay' :: (a -> b -> Run (Maybe b)) -> b -> Evt a -> Evt b
+scanMay' f s (Evt evt) = Evt $ D.scanMay' f s evt
+
+-- | Combo of @fmap@ and @appends@
+foldMaps :: Monoid b => (a -> b) -> Evt a -> Evt b
+foldMaps f evt = appends (fmap f evt)
+
+-- | Repeatedly executes the same event stream
+races :: Evt a -> Evt a -> Evt a
+races (Evt evtA) (Evt evtB) = Evt (D.races evtA evtB)
+
+-- | Repeatedly executes the same event stream
+forks :: Evt a -> Evt a
+forks (Evt evt) = Evt (D.forks evt)
+
+-- | Repeatedly executes the same event stream
+forevers :: Evt a -> Evt a
+forevers (Evt evt) = Evt (D.forevers evt)
+
+-- | Iterates over event stream. It's like scan but it ignores the values of underying stream
+-- and starts with initial value as first element.
+iterates :: (a -> a) -> a -> Evt b -> Evt a
+iterates f val (Evt evt) = Evt $ D.iterates f val evt
+
+withIterates :: (a -> a) -> a -> Evt b -> Evt (a, b)
+withIterates f val (Evt evt) = Evt $ D.withIterates f val evt
+
+-- | Effectful version for @iterateE@.
+iterates' :: (a -> Run a) -> a -> Evt b -> Evt a
+iterates' f val (Evt evt) = Evt $ D.iterates' f val evt
+
+-- | Reads current dynamic value.
+readDyn :: DynRef  a -> Run a
+readDyn (DynRef ref) = D.readDyn ref
+
+-- | Shuts down the background process for dynamic and releases resulrces for
+-- event stream that drives the dynamic.
+cancelDyn :: DynRef a -> Run ()
+cancelDyn (DynRef ref) = D.cancelDyn ref
+
+-- | Turns event stream to dynamic. It holds the values of
+-- events until the next event happen. It starts with initial value.
+--
+-- > hold initVal events = ...
+hold :: a -> Evt a -> Dyn a
+hold s (Evt evt) = Dyn $ D.hold s evt
+
+-- | Counts how many events accured so far on the stream.
+count :: Evt a -> Evt Int
+count (Evt evt) = Evt (D.count evt)
+
+withCount :: Evt a -> Evt (Int, a)
+withCount (Evt evt) = Evt (D.withCount evt)
+
+-- | Turns dynamic into event stream of underlying events
+-- that trigger dynamic updates.
+unhold :: Dyn a -> Evt a
+unhold (Dyn dyn) = Evt $ D.unhold dyn
+
+-- | scans over event stream and converts it to dynamic.
+scanD :: (a -> b -> b) -> b -> Evt a -> Dyn b
+scanD f s (Evt evt) = Dyn $ D.scanD f s evt
+
+-- | Accumulates the values with event stream that produce functions.
+accumB :: a -> Evt (a -> a) -> Dyn a
+accumB a (Evt evt) = Dyn $ D.accumB a evt
+
+-- | Dynamic scan that can also filter out events. If Nothing is produced then the event is skipped.
+scanMayD :: (a -> b -> Maybe b) -> b -> Evt a -> Dyn b
+scanMayD f s (Evt evt) = Dyn $ D.scanMayD f s evt
+
+-- | Adds some procedure to callback. Procedure is called prior to callback execution.
+foreach :: (a -> Run ()) -> Evt a -> Evt a
+foreach call (Evt evt) = Evt $ D.foreach call evt
+
+-- | Adds some procedure to callback. Procedure is called after callback execution.
+posteach :: (a -> Run ()) -> Evt a -> Evt a
+posteach call (Evt evt) = Evt $ D.posteach call evt
+
+--------------------------------------------------------------------------------
+-- applications
+
+-- | Applies a function to event stream value. The function is sampled
+-- from dynamic process.
+apply :: Dyn (a -> b) -> Evt a -> Evt b
+apply (Dyn dyn) (Evt evt) = Evt $ D.apply dyn evt
+
+-- | Effectful variant of @apply@.
+apply' :: Dyn (a -> Run b) -> Evt a -> Evt b
+apply' (Dyn dyn) (Evt evt) = Evt $ D.apply' dyn evt
+
+-- | Infix variant of @apply@
+(<@>) :: Dyn (a -> b) -> Evt a -> Evt b
+(<@>) = apply
+
+-- | Infix variant of @snap@.
+(<@) :: Dyn a -> Evt b -> Evt a
+(<@) = snap
+
+-- | Apply combined with filter.
+applyMay :: Dyn (a -> Maybe b) -> Evt a -> Evt b
+applyMay (Dyn dyn) (Evt evt) = Evt $ D.applyMay dyn evt
+
+-- | Effectful @applyMay@.
+applyMay' :: Dyn (a -> Run (Maybe b)) -> Evt a -> Evt b
+applyMay' (Dyn dyn) (Evt evt) = Evt $ D.applyMay' dyn evt
+
+-- | Snapshot of dynamic process with event stream. All values
+-- in the event stream are substituted with current value of dynamic.
+snap :: Dyn a -> Evt b -> Evt a
+snap (Dyn dyn) (Evt evt) = Evt (D.snap dyn evt)
+
+-- | Kind of @zipWith@ function for dynamics and event streams.
+attach :: Dyn a -> Evt b -> Evt (a, b)
+attach (Dyn dyn) (Evt evt) = Evt $ D.attach dyn evt
+
+-- | Kind of @zipWith@ function for dynamics and event streams.
+attachWith :: (a -> b -> c) -> Dyn a -> Evt b -> Evt c
+attachWith f (Dyn dyn) (Evt evt) = Evt $ D.attachWith f dyn evt
+
+-- | Attach with filtering. When @Nothing@ is produced event is omitted from the stream.
+attachWithMay :: (a -> b -> Maybe c) -> Dyn a -> Evt b -> Evt c
+attachWithMay f (Dyn dyn) (Evt evt) = Evt $ D.attachWithMay f dyn evt
+
+-- | Map with filtering. When @Nothing@ is produced event is omitted from the stream.
+mapMay :: (a -> Maybe b) -> Evt a -> Evt b
+mapMay f (Evt evt) = Evt $ D.mapMay f evt
+
+-- | Map with filtering. When @Nothing@ is produced event is omitted from the stream.
+mapMay' :: (a -> Run (Maybe b)) -> Evt a -> Evt b
+mapMay' f (Evt evt) = Evt $ D.mapMay' f evt
+
+--------------------------------------------------------------------------------
+-- filters
+
+-- | Filtering of the event strewams. Only events that produce True remain in the stream.
+filters :: (a -> Bool) -> Evt a -> Evt a
+filters f (Evt evt) = Evt $ D.filters f evt
+
+-- | Effectful filtering for event streams.
+filters' :: (a -> Run Bool) -> Evt a -> Evt a
+filters' f (Evt evt) = Evt $ D.filters' f evt
+
+-- | Filters based on Maybe. If @Nothing@ is produced forthe event it is omitted from the stream.
+filterJust :: Evt (Maybe a) -> Evt a
+filterJust (Evt evt) = Evt $ D.filterJust evt
+
+-- | Filters with dynamic. When dynamic is true events pass through and when it's false
+-- events are omitted.
+whens :: Dyn Bool -> Evt a -> Evt a
+whens (Dyn dyn) (Evt evt) = Evt $ D.whens dyn evt
+
+-- | Splits the either event stream.
+splits :: Evt (Either a b) -> (Evt a, Evt b)
+splits evt = (lefts evt, rights evt)
+
+-- | Gets all left events from the stream
+lefts :: Evt (Either a b) -> Evt a
+lefts (Evt evt) = Evt $ D.lefts evt
+
+-- | Gets all right events from the stream
+rights :: Evt (Either a b) -> Evt b
+rights (Evt evt) = Evt $ D.rights evt
+
+-- | Takes only so many events from the stream
+takes :: Int -> Evt a -> Evt a
+takes n (Evt evt) = Evt $ D.takes n evt
+
+-- | Takes only so many events from the stream
+drops :: Int -> Evt a -> Evt a
+drops n (Evt evt) = Evt $ D.drops n evt
+
+-- | Takes events only while predicate is true.
+takesWhile :: (a -> Bool) -> Evt a -> Evt a
+takesWhile pred (Evt evt) = Evt $ D.takesWhile pred evt
+
+-- | Takes events only while predicate is true.
+dropsWhile :: (a -> Bool) -> Evt a -> Evt a
+dropsWhile pred (Evt evt) = Evt $ D.dropsWhile pred evt
+
+-- | Takes elements from the list by index. If index is out of bounds the event is omitted.
+listAt :: [a] -> Evt Int -> Evt a
+listAt vals (Evt evt) = Evt $ D.listAt vals evt
+
+-- | Turns event stream to toggle stream. It produce cyclic sequence of [True, False]
+toToggle :: Evt a -> Evt Bool
+toToggle (Evt evt) = Evt (D.toToggle evt)
+
+-- | Cycles the values in the list over event sream.
+cycles :: [a] -> Evt b -> Evt a
+cycles vals (Evt evt) = Evt (D.cycles vals evt)
+
+-- | Sums all the elements in the event stream
+sums :: (Num a) => Evt a -> Evt a
+sums = scan (+) 0
+
+-- | Sums all the elements in the event stream
+sumD :: (Num a) => Float -> Dyn a -> Dyn a
+sumD dt (Dyn dyn) = Dyn (D.sumD (realToFrac dt) dyn)
+
+integrate :: (VectorSpace v, Scalar v ~ Float) => Float -> Dyn v -> Dyn v
+integrate dt (Dyn dyn) = Dyn $ D.integrate dt dyn
+
+integrate2 :: (VectorSpace v, Scalar v ~ Float) => Float -> Dyn v -> Dyn v
+integrate2 dt (Dyn dyn) = Dyn $ D.integrate2 dt dyn
+
+-- | Finds the product of all elements in the event stream.
+products :: (Num a) => Evt a -> Evt a
+products = scan (*) 1
+
+-- | Monoidal append of all elements in the stream
+appends :: (Monoid a) => Evt a -> Evt a
+appends (Evt evt) = Evt (D.appends evt)
+
+-- | Monoidal fold for event streams, note that stream have to be finite for
+-- the function to complete
+folds :: Monoid a => Evt a -> Run a
+folds = foldls (<>) mempty
+
+-- | Left fold for event streams, note that stream have to be finite for
+-- the function to complete
+foldls :: (b -> a -> b) -> b -> Evt a -> Run b
+foldls f s (Evt evt) = D.foldls f s evt
+
+-- | Effectful left fold
+foldls' :: (b -> a -> Run b) -> b -> Evt a -> Run b
+foldls' f s (Evt evt) = D.foldls' f s evt
+
+-- | Right fold for event streams, note that stream have to be finite for
+-- the function to complete
+foldrs :: (a -> b -> b) -> b -> Evt a -> Run b
+foldrs f s (Evt evt) = D.foldrs f s evt
+
+-- | Effectful right fold
+foldrs' :: (a -> b -> Run b) -> b -> Evt a -> Run b
+foldrs' f s (Evt evt) = D.foldrs' f s evt
+
+-- | Starts event stream process and as callback prints it values.
+prints :: (Show a) => Evt a -> Run ()
+prints (Evt evt) = D.prints evt
+
+-- | Starts event stream process and as callback prints it values.
+putStrLns :: Evt String -> Run ()
+putStrLns (Evt evt) = D.putStrLns evt
+
+-- | Queries the event stream form dynamic and runs it all next event streams are ignored.
+switchDyn :: Dyn (Evt a) -> Evt a
+switchDyn (Dyn dyn) = Evt $ D.switchDyn $ fmap unEvt dyn
+
+-- | Joins event stream of streams. If stream is started it runs until the end.
+joins :: Evt (Evt a) -> Evt a
+joins (Evt evt) = Evt $ D.joins $ fmap unEvt evt
+
+-- | Recursion on event streams. As event streams are functions we can not use
+-- normal recursion that haskell provides. It will stuck the execution.
+-- But we can use @fix1@ to create event stream that feeds back the events to itself.
+--
+-- Note that any sort of recursion can be implemented with @fix1@.
+-- For example if we need 3-recursive event stream:
+--
+--  > fixE3 ::
+--  >      (Evt a -> Evt b -> Evt c -> (Evt a, Evt b, Evt c))
+--  >   -> (Evt a, Evt b, Evt c)
+--
+-- we can use sum tpye tags
+-- to join it to single stream:
+--
+-- > data Tag a b c = TagA a | TagB b | TagC c
+--
+-- > fix3 f = unwrap $ fix1 g
+-- >   where
+-- >      g x = wrap (f (unwrapA x) (unwrapB x) (unwrapC x))
+-- >
+-- >      wrap a b c = mconcat [TagA <$> a, TagB <$> b, TagC <$> c]
+-- >      unwrap evt = (unwrapA evt, unwrapB evt, unwrapC evt)
+-- >
+-- >      unwrapA = flip mapMay $ \x -> case x of
+-- >                                  TagA a -> Just a
+-- >                                  _      -> Nothing
+--
+-- We can use this trck with any number of streams. There are helper functions: @fix2@, @fix3@, @fix4@
+fix1 :: (Evt a -> Run (Evt a)) -> Evt a
+fix1 f = Evt $ D.fix1 (fmap unEvt . f . Evt)
+
+-- | Recursion for binary functions
+fix2 :: (Evt a -> Evt b -> Run (Evt a, Evt b)) -> (Evt a, Evt b)
+fix2 f = bimap Evt Evt $ D.fix2 (\a b -> bimap unEvt unEvt <$> f (Evt a) (Evt b))
+
+-- | Recursion for ternary functions
+fix3 ::
+     (Evt a -> Evt b -> Evt c -> Run (Evt a, Evt b, Evt c))
+  -> (Evt a, Evt b, Evt c)
+fix3 f = wrap $ D.fix3 (\a b c -> unwrap <$> f (Evt a) (Evt b) (Evt c))
+  where
+    wrap (a, b, c) = (Evt a, Evt b, Evt c)
+    unwrap (a, b, c) = (unEvt a, unEvt b, unEvt c)
+
+-- | Recursion for functions of four arguments
+fix4 ::
+     (Evt a -> Evt b -> Evt c -> Evt d -> Run (Evt a, Evt b, Evt c, Evt d))
+  -> (Evt a, Evt b, Evt c, Evt d)
+fix4 f = wrap $ D.fix4 (\a b c d -> unwrap <$> f (Evt a) (Evt b) (Evt c) (Evt d))
+  where
+    wrap (a, b, c, d) = (Evt a, Evt b, Evt c, Evt d)
+    unwrap (a, b, c, d) = (unEvt a, unEvt b, unEvt c, unEvt d)
+
+-- | Flattens event stream producer by switching between event streams.
+-- When next event stream happens it shuts down the previous one.
+switch :: Evt (Evt a) -> Evt a
+switch (Evt evt) = Evt $ D.switch $ fmap unEvt evt
+
+-- | Switches between dynamic producers.
+switchD :: Dyn a -> Evt (Dyn a) -> Dyn a
+switchD (Dyn d) (Evt evts) = Dyn $ D.switchD d (fmap unDyn evts)
+
+---------------------------------------------------------
+-- channels
+
+-- | Creates the event stream that listens to MVar based channel.
+-- If any value is put chan the event stream fires the callback.
+mchanEvt :: M.Chan a -> Evt a
+mchanEvt mchan = Evt $ D.mchanEvt mchan
+
+-- | Creates the event stream that listens to MVar based channel.
+-- If any value is put chan the event stream fires the callback.
+tchanEvt :: TChan a -> Evt a
+tchanEvt tchan = Evt $ D.tchanEvt tchan
+
+-- | Creates the event stream that listens to unagi channel (package @unagi-chan@).
+-- If any value is put chan the event stream fires the callback.
+uchanEvt :: InChan a -> Evt a
+uchanEvt uchan = Evt $ D.uchanEvt uchan
+
+---------------------------------------------------------------------------
+-- utilities
+
+-- | Queries current time periodically with given period in seconds.
+clock :: NominalDiffTime -> Evt UTCTime
+clock t = Evt $ D.clock t
+
+-- | Produces pulse events with given period in seconds.
+pulse :: NominalDiffTime -> Evt ()
+pulse t = Evt $ D.pulse t
+
+-- | Produces pulse events with given period in seconds
+-- and also tells how many seconds exactly has passed.
+-- It can be useful for simulations of models that are based on differential equations.
+-- As event streams carries how much time has passed between simulation steps.
+ticks :: Float -> Evt Float
+ticks t = Evt $ realToFrac <$> D.ticks (realToFrac t)
+
+-- | Timer behaves like tocks only it produces accumulated time since beginning
+-- of the process. It calculates them by querying current time and suntracting start time from it.
+--
+-- It can be though of as:
+--
+-- > sumE ticks
+timer :: Float -> Evt Float
+timer t = Evt $ realToFrac <$> D.timer (realToFrac t)
+
+-- | Continuous timeline updated at given interval.
+timerD :: Float -> Dyn Float
+timerD t = Dyn $ realToFrac <$> D.timerD (realToFrac t)
+
+--------------------------------------------------------------------------------
+
+-- | Substitutes values in event stream with random values.
+toRandom :: (Random b) => Evt a -> Evt b
+toRandom (Evt evt) = Evt $ D.toRandom evt
+
+-- | Substitutes values in event stream with random values from the given range.
+toRandomR :: (Random b) => (b, b) -> Evt a -> Evt b
+toRandomR range (Evt evt) = Evt $ D.toRandomR range evt
+
+-- | Substitutes values in event stream with random values.
+withRandom :: (Random b) => Evt a -> Evt (b, a)
+withRandom (Evt evt) = Evt $ D.withRandom evt
+
+-- | Substitutes values in event stream with random values from the given range.
+withRandomR :: Random b => (b, b) -> Evt a -> Evt (b, a)
+withRandomR range (Evt evt) = Evt $ D.withRandomR range evt
+
+-- | Picks at random one element from the list
+oneOf :: [a] -> Evt b -> Evt a
+oneOf xs (Evt evt) = Evt $ D.oneOf xs evt
+
+-- | Picks at random one element from the list
+withOneOf :: [a] -> Evt b -> Evt (a, b)
+withOneOf xs (Evt evt) = Evt (D.withOneOf xs evt)
+
+-- | Picks at random one element from the list. We also provide distribution of events.
+-- Probability to pick up the element. Sum of probabilities should equal to 1.
+freqOf :: Dyn [(a, Rational)] -> Evt b -> Evt a
+freqOf (Dyn dynVals) (Evt evts) = Evt $ D.freqOf dynVals evts
+
+-- | Picks at random one element from the list. We also provide distribution of events.
+-- Probability to pick up the element. Sum of probabilities should equal to 1.
+withFreqOf :: Dyn [(a, Rational)] -> Evt b -> Evt (a, b)
+withFreqOf (Dyn dynVals) (Evt evts) = Evt $ D.withFreqOf dynVals evts
+
+-- | Skips at random elements from the list. We provide frequency to skip events with dynamic first argument.
+randSkip :: Dyn Double -> Evt a -> Evt a
+randSkip (Dyn prob) (Evt evt) = Evt $ D.randSkip prob evt
+
+-- | Skips elements at random. The probability to skip element depends on the element itself.
+randSkipBy :: Dyn (a -> Double) -> Evt a -> Evt a
+randSkipBy  (Dyn prob) (Evt evt) = Evt $ D.randSkipBy prob evt
+
+--------------------------------------------------------------------------------
+
+-- | Delays in the thread of execution. Note that it can interfere
+-- and screw up functions like clock, timer, pulse, ticks
+delay :: NominalDiffTime -> Evt a -> Evt a
+delay dt (Evt evt) = Evt $ D.delay dt evt
+
+-- | Delays in background by forking on each event.
+-- Note tht if delayed event was put into background prior
+-- to stopping of the main event stream it will fire anyway.
+-- There is no way to stop it.
+delayFork :: NominalDiffTime -> Evt a -> Evt a
+delayFork dt (Evt evt) = Evt $ D.delayFork dt evt
+
+--------------------------------------------------------------------------------
+-- effectful functor
+
+class RunFunctor f where
+  fmap' :: (a -> Run b) -> f a -> f b
+
+instance RunFunctor Evt where
+  fmap' f (Evt evt) = Evt $ D.fmap' f evt
+
+instance RunFunctor Dyn where
+  fmap' f (Dyn dyn) = Dyn $ D.fmap' f dyn
+
diff --git a/src/Dyna/Gloss/Geometry/Line.hs b/src/Dyna/Gloss/Geometry/Line.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Geometry/Line.hs
@@ -0,0 +1,323 @@
+{-# LANGUAGE PatternGuards #-}
+
+-- | Geometric functions concerning lines and segments.
+--
+--   A @Line@ is taken to be infinite in length, while a @Seg@ is finite length
+--   line segment represented by its two endpoints.
+module Dyna.Gloss.Geometry.Line
+        ( segClearsBox
+
+        -- * Closest points
+        , closestPointOnLine
+        , closestPointOnLineParam
+
+        -- * Line-Line intersection
+        , intersectLineLine
+
+        -- * Seg-Line intersection
+        , intersectSegLine
+        , intersectSegHorzLine
+        , intersectSegVertLine
+
+        -- * Seg-Seg intersection
+        , intersectSegSeg
+        , intersectSegHorzSeg
+        , intersectSegVertSeg)
+
+where
+import Dyna.Gloss.Data.Point
+import Dyna.Gloss.Data.Vec
+
+-- | Check if line segment (P1-P2) clears a box (P3-P4) by being well outside it.
+segClearsBox
+        :: Point        -- ^ P1 First point of segment.
+        -> Point        -- ^ P2 Second point of segment.
+        -> Point        -- ^ P3 Lower left point of box.
+        -> Point        -- ^ P4 Upper right point of box.
+        -> Bool
+
+segClearsBox (Vec x1 y1) (Vec x2 y2) (Vec xa ya) (Vec xb yb)
+        | x1 < xa, x2 < xa      = True
+        | x1 > xb, x2 > xb      = True
+        | y1 < ya, y2 < ya      = True
+        | y1 > yb, y2 > yb      = True
+        | otherwise             = False
+
+
+-- | Given an infinite line which intersects `P1` and `P1`,
+--      return the point on that line that is closest to `P3`
+closestPointOnLine
+        :: Point        -- ^ `P1`
+        -> Point        -- ^ `P2`
+        -> Point        -- ^ `P3`
+        -> Point        -- ^ the point on the line P1-P2 that is closest to `P3`
+
+{-# INLINE closestPointOnLine #-}
+
+closestPointOnLine p1 p2 p3
+        = p1 + (u `mulSV` (p2 - p1))
+        where   u       = closestPointOnLineParam p1 p2 p3
+
+
+-- | Given an infinite line which intersects P1 and P2,
+--      let P4 be the point on the line that is closest to P3.
+--
+--      Return an indication of where on the line P4 is relative to P1 and P2.
+--
+-- @
+--      if P4 == P1 then 0
+--      if P4 == P2 then 1
+--      if P4 is halfway between P1 and P2 then 0.5
+-- @
+--
+-- @
+--        |
+--       P1
+--        |
+--     P4 +---- P3
+--        |
+--       P2
+--        |
+-- @
+--
+{-# INLINE closestPointOnLineParam #-}
+closestPointOnLineParam
+        :: Point        -- ^ `P1`
+        -> Point        -- ^ `P2`
+        -> Point        -- ^ `P3`
+        -> Float
+
+closestPointOnLineParam p1 p2 p3
+        = (p3 - p1) `dotV` (p2 - p1)
+        / (p2 - p1) `dotV` (p2 - p1)
+
+
+
+-- Line-Line intersection -----------------------------------------------------
+
+-- | Given four points specifying two lines, get the point where the two lines
+--   cross, if any. Note that the lines extend off to infinity, so the
+--   intersection point might not line between either of the two pairs of points.
+--
+-- @
+--     \\      /
+--      P1  P4
+--       \\ /
+--        +
+--       / \\
+--      P3  P2
+--     /     \\
+-- @
+--
+intersectLineLine
+        :: Point        -- ^ `P1`
+        -> Point        -- ^ `P2`
+        -> Point        -- ^ `P3`
+        -> Point        -- ^ `P4`
+        -> Maybe Point
+
+intersectLineLine (Vec x1 y1) (Vec x2 y2) (Vec x3 y3) (Vec x4 y4)
+ = let  dx12    = x1 - x2
+        dx34    = x3 - x4
+
+        dy12    = y1 - y2
+        dy34    = y3 - y4
+
+        den     = dx12 * dy34  - dy12 * dx34
+
+   in if den == 0
+        then Nothing
+        else let
+                det12   = x1*y2 - y1*x2
+                det34   = x3*y4 - y3*x4
+
+                numx    = det12 * dx34 - dx12 * det34
+                numy    = det12 * dy34 - dy12 * det34
+             in Just (Vec (numx / den) (numy / den))
+
+
+-- Segment-Line intersection --------------------------------------------------
+-- | Get the point where a segment @P1-P2@ crosses an infinite line @P3-P4@,
+--   if any.
+--
+intersectSegLine
+        :: Point        -- ^ `P1`
+        -> Point        -- ^ `P2`
+        -> Point        -- ^ `P3`
+        -> Point        -- ^ `P4`
+        -> Maybe Point
+
+intersectSegLine p1 p2 p3 p4
+        -- TODO: merge closest point check with intersection, reuse subterms.
+        | Just p0       <- intersectLineLine p1 p2 p3 p4
+        , t12           <- closestPointOnLineParam p1 p2 p0
+        , t12 >= 0 && t12 <= 1
+        = Just p0
+
+        | otherwise
+        = Nothing
+
+
+-- | Get the point where a segment crosses a horizontal line, if any.
+--
+-- @
+--                + P1
+--               /
+--       -------+---------
+--             /        y0
+--         P2 +
+-- @
+--
+intersectSegHorzLine
+        :: Point        -- ^ P1 First point of segment.
+        -> Point        -- ^ P2 Second point of segment.
+        -> Float        -- ^ y value of line.
+        -> Maybe Point
+intersectSegHorzLine (Vec x1 y1) (Vec x2 y2) y0
+
+        -- seg is on line
+        | y1 == y0, y2 == y0    = Nothing
+
+        -- seg is above line
+        | y1 > y0,  y2 > y0     = Nothing
+
+        -- seg is below line
+        | y1 < y0,  y2 < y0     = Nothing
+
+        -- seg is a single point on the line.
+        -- this should be caught by the first case,
+        -- but we'll test for it anyway.
+        | y2 - y1 == 0
+        = Just (Vec x1 y1)
+
+        | otherwise
+        = Just (Vec ((y0 - y1) * (x2 - x1) / (y2 - y1) + x1)
+                y0)
+
+
+
+-- | Get the point where a segment crosses a vertical line, if any.
+--
+-- @
+--              |
+--              |   + P1
+--              | /
+--              +
+--            / |
+--       P2 +   |
+--              | x0
+-- @
+--
+intersectSegVertLine
+        :: Point        -- ^ P1 First point of segment.
+        -> Point        -- ^ P2 Second point of segment.
+        -> Float        -- ^ x value of line.
+        -> Maybe Point
+
+intersectSegVertLine (Vec x1 y1) (Vec x2 y2) x0
+
+        -- seg is on line
+        | x1 == x0, x2 == x0    = Nothing
+
+        -- seg is to right of line
+        | x1 > x0,  x2 > x0     = Nothing
+
+        -- seg is to left of line
+        | x1 < x0,  x2 < x0     = Nothing
+
+        -- seg is a single point on the line.
+        -- this should be caught by the first case,
+        -- but we'll test for it anyway.
+        | x2 - x1 == 0
+        = Just (Vec x1 y1)
+
+        | otherwise
+        = Just (Vec x0
+               ((x0 - x1) * (y2 - y1) / (x2 - x1) + y1))
+
+
+-- Segment-Segment intersection -----------------------------------------------
+
+-- | Get the point where a segment @P1-P2@ crosses another segement @P3-P4@,
+--   if any.
+intersectSegSeg
+        :: Point        -- ^ `P1`
+        -> Point        -- ^ `P2`
+        -> Point        -- ^ `P3`
+        -> Point        -- ^ `P4`
+        -> Maybe Point
+
+intersectSegSeg p1 p2 p3 p4
+        -- TODO: merge closest point checks with intersection, reuse subterms.
+        | Just p0       <- intersectLineLine p1 p2 p3 p4
+        , t12           <- closestPointOnLineParam p1 p2 p0
+        , t23           <- closestPointOnLineParam p3 p4 p0
+        , t12 >= 0 && t12 <= 1
+        , t23 >= 0 && t23 <= 1
+        = Just p0
+
+        | otherwise
+        = Nothing
+
+
+-- | Check if an arbitrary segment intersects a horizontal segment.
+--
+-- @
+--                 + P2
+--                /
+-- (xa, y3)  +---+----+ (xb, y3)
+--              /
+--          P1 +
+-- @
+
+intersectSegHorzSeg
+        :: Point        -- ^ P1 First point of segment.
+        -> Point        -- ^ P2 Second point of segment.
+        -> Float        -- ^ (y3) y value of horizontal segment.
+        -> Float        -- ^ (xa) Leftmost x value of horizontal segment.
+        -> Float        -- ^ (xb) Rightmost x value of horizontal segment.
+        -> Maybe Point  -- ^ (x3, y3) Intersection point, if any.
+
+intersectSegHorzSeg p1@(Vec x1 y1) p2@(Vec x2 y2) y0 xa xb
+        | segClearsBox p1 p2 (Vec xa y0) (Vec xb y0)
+        = Nothing
+
+        | x0 < xa       = Nothing
+        | x0 > xb       = Nothing
+        | otherwise     = Just (Vec x0 y0)
+
+        where x0 | (y2 - y1) == 0 = x1
+                 | otherwise      = (y0 - y1) * (x2 - x1) / (y2 - y1) + x1
+
+
+-- | Check if an arbitrary segment intersects a vertical segment.
+--
+-- @
+--      (x3, yb) +
+--               |   + P1
+--               | /
+--               +
+--             / |
+--        P2 +   |
+--               + (x3, ya)
+-- @
+
+intersectSegVertSeg
+        :: Point        -- ^ P1 First point of segment.
+        -> Point        -- ^ P2 Second point of segment.
+        -> Float        -- ^ (x3) x value of vertical segment
+        -> Float        -- ^ (ya) Lowest y value of vertical segment.
+        -> Float        -- ^ (yb) Highest y value of vertical segment.
+        -> Maybe Point  -- ^ (x3, y3) Intersection point, if any.
+
+intersectSegVertSeg p1@(Vec x1 y1) p2@(Vec x2 y2) x0 ya yb
+        | segClearsBox p1 p2 (Vec x0 ya) (Vec x0 yb)
+        = Nothing
+
+        | y0 < ya       = Nothing
+        | y0 > yb       = Nothing
+        | otherwise     = Just (Vec x0 y0)
+
+        where y0 | (x2 - x1) == 0 = y1
+                 | otherwise      = (x0 - x1) * (y2 - y1) / (x2 - x1) + y1
+
diff --git a/src/Dyna/Gloss/Run.hs b/src/Dyna/Gloss/Run.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Run.hs
@@ -0,0 +1,208 @@
+-- | Run the game application.
+module Dyna.Gloss.Run(
+  -- * App execution
+  Run,
+  Spec(..),
+  defSpec,
+  runApp,
+  -- * IO interface
+  mouse,
+  mouseV,
+  isDrag,
+  drag,
+  dragV,
+  mouseA,
+  mouseRight,
+  mouseLeft,
+  mouseWheel,
+  Click(..),
+  getClicks,
+  getFrames,
+  getResize,
+  keyUp, keyDown,
+  charUp, charDown,
+  -- * Re-exports
+  Key(..),
+  SpecialKey(..),
+  MouseButton(..),
+  KeyState(..),
+  Modifiers(..),
+) where
+
+import Control.Exception.Lifted
+import Control.Concurrent.Chan.Unagi qualified as U
+import Control.Monad.Reader
+import Data.IORef
+
+import Graphics.Gloss
+import Graphics.Gloss.Interface.IO.Game
+import Dyna qualified as D
+import Dyna.Gloss.Types
+import Dyna.Gloss.Data.Vec
+
+-- | Initial parameters for the Game.
+data Spec = Spec
+  { spec'display    :: Display   -- ^ display settings
+  , spec'background :: Color     -- ^ background color to clear each frame
+  , spec'steps      :: Int       -- ^ number of steps for simulation
+  }
+
+-- | Default settings. Runs in ullscreen mode.
+defSpec :: Spec
+defSpec = Spec FullScreen white 1
+
+-- | Run the aplication. It accepts initial settings
+-- and the dynamic value of pictures wrapped in the Run monad.
+--
+-- Note that to work properly we need to compile to executable with
+-- options -O2 and -threaded. The function does not work in ghci or with runhaskell
+-- because it requires support for multiple threads.
+--
+-- Define the application with the Main module. Then compie it:
+--
+-- > stack exec -- ghc -O2 -threaded dyna-gloss/examples/Ball.hs
+--
+-- And run the result:
+--
+-- > 	./dyna-gloss/examples/Ball
+--
+-- How it works? It runs the dynamic process at the background thread and
+-- every time the gloss function requests new frame it takes a snapshot of the current
+-- value of the main dynamic process which produces pictures. It's exactly what gloss
+-- simulation function needs to render it on the screen.
+runApp :: Spec -> Run (Dyn Picture) -> IO ()
+runApp Spec{..} dynAct = do
+  env <- newEnv
+  ref <- runReaderT (unRun $ D.runDyn . unDyn =<< dynAct) env
+  playIO spec'display spec'background spec'steps ref (draw env) (onEvents env) (onIterate env)
+    `finally` (runReaderT (unRun $ D.cancelDyn ref) env)
+  where
+    draw env ref = runReaderT (unRun $ D.readDyn ref) env
+
+    onEvents Env{..} evt ref = do
+      case evt of
+        EventResize sizes      -> U.writeChan (fst env'resizeChan) sizes
+        EventMotion (x, y)     -> do
+          let pos = Vec x y
+          prevPos  <- readIORef env'mousePos
+          prevDif1 <- readIORef env'mouseDif1
+          let dif1 = pos - prevPos
+          writeIORef env'mousePos pos
+          writeIORef env'mouseDif1 dif1
+          writeIORef env'mouseDif2 (dif1 - prevDif1)
+        EventKey k st mods pos -> U.writeChan (fst env'keyChan) (Click k st mods (fromTuple pos))
+      pure ref
+
+    onIterate Env{..} time ref = do
+      U.writeChan (fst env'frameChan) time
+      pure ref
+
+----------------------------------------------------------------
+
+-- | Read mouse positions. It produces dynamic of vectors. @(0, 0)@ is a center of the screen.
+mouse :: Dyn Vec
+mouse = Dyn $ D.constDyn $ do
+  ref <- asks env'mousePos
+  liftIO $ readIORef ref
+
+-- | Mouse velocity or displacement
+mouseV :: Dyn Vec
+mouseV = Dyn $ D.constDyn $ do
+  ref <- asks env'mouseDif1
+  liftIO $ readIORef ref
+
+-- | Mouse accelartion or speed of displacement
+mouseA :: Dyn Vec
+mouseA = Dyn $ D.constDyn $ do
+  ref <- asks env'mouseDif2
+  liftIO $ readIORef ref
+
+isDrag :: MouseButton -> Dyn Bool
+isDrag btn = Dyn $ D.scanD collect False $ D.mapMay go $ unEvt getClicks
+  where
+    go (Click key st mods pos) = case key of
+      MouseButton mbtn | mbtn == btn -> Just st
+      _                              -> Nothing
+
+    collect a st = case a of
+      Up   -> False
+      Down -> True
+
+
+-- | Displacement on drag, if no drag it becomes zero
+dragV :: MouseButton -> Dyn Vec
+dragV btn = (\x -> if x then id else const 0) <$> isDrag btn <*> mouseV
+
+-- | Position of the mouse during drag, if no drag it becomes zero
+drag :: MouseButton -> Dyn Vec
+drag btn = (\x -> if x then id else const 0) <$> isDrag btn <*> mouse
+
+-- | Event stream of clicks of the mouse right button
+mouseRight :: Evt Vec
+mouseRight = Evt $ D.mapMay go $ unEvt getClicks
+  where
+    go = \case
+      Click (MouseButton RightButton) Down mods pos -> Just pos
+      _                                             -> Nothing
+
+-- | Event stream of key up actions
+keyUp :: Key -> Evt Modifiers
+keyUp = keyBy Up
+
+-- | Event stream of key down actions
+keyDown :: Key -> Evt Modifiers
+keyDown = keyBy Down
+
+-- | Event stream of char press up actions
+charUp :: Char -> Evt Modifiers
+charUp = keyUp . Char
+
+-- | Event stream of char press down actions
+charDown :: Char -> Evt Modifiers
+charDown = keyDown . Char
+
+keyBy :: KeyState -> Key -> Evt Modifiers
+keyBy st' key' = Evt $ D.mapMay go $ unEvt getClicks
+  where
+    go (Click key st mods pos)
+      | key == key' && st == st' = Just mods
+      | otherwise                = Nothing
+
+-- | Event stream of clicks of the mouse left button
+mouseLeft :: Evt Vec
+mouseLeft = Evt $ D.mapMay go $ unEvt getClicks
+  where
+    go = \case
+      Click (MouseButton LeftButton) Down mods pos -> Just pos
+      _                                            -> Nothing
+
+-- | Mouse wheel displacement.
+-- If positive then it goes up, if negative then it goes down.
+mouseWheel :: Evt Float
+mouseWheel = Evt $ D.mapMay go $ unEvt getClicks
+  where
+    go (Click key st mods pos) = case key of
+      MouseButton WheelUp   -> Just 1
+      MouseButton WheelDown -> Just (-1)
+      _                     -> Nothing
+
+-- | Reads generic click events
+getClicks :: Evt Click
+getClicks = Evt $ D.Evt $ \go -> do
+  keyChan <- asks env'keyChan
+  D.runEvt (D.uchanEvt (fst keyChan)) go
+
+-- | Reads frame updates. Value of the event is a time that has passed since the previous frame.
+--
+-- Note that if we want to use the sort of event stream as a timeline for the game or simulation
+-- we can also use time utilities from the FRP library: @clock@, @pulse@, @ticks@, @timer@.
+getFrames :: Evt Float
+getFrames = Evt $ D.Evt $ \go -> do
+  frameChan <- asks env'frameChan
+  D.runEvt (D.uchanEvt (fst frameChan)) go
+
+-- | Reads window resize events
+getResize :: Evt (Int, Int)
+getResize = Evt $ D.Evt $ \go -> do
+  resizeChan <- asks env'resizeChan
+  D.runEvt (D.uchanEvt $ fst resizeChan) go
diff --git a/src/Dyna/Gloss/Types.hs b/src/Dyna/Gloss/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Dyna/Gloss/Types.hs
@@ -0,0 +1,165 @@
+-- | Types of the gloss application
+module Dyna.Gloss.Types(
+  Run(..),
+  Evt(..),
+  Dyn(..),
+  Env(..),
+  newEnv,
+  Click(..),
+) where
+
+import Prelude hiding ((<*))
+import Control.Applicative (liftA2, liftA3)
+import Control.Concurrent.Chan.Unagi
+import Control.Monad.Reader
+import Control.Monad.Base
+import Control.Monad.Random.Class
+import Control.Monad.Trans.Control (MonadBaseControl(..))
+import Data.IORef
+import Data.String
+import Data.Boolean
+import Data.AdditiveGroup
+import Data.AffineSpace
+import Data.VectorSpace
+import Data.Basis
+import Data.Cross
+import Temporal.Class
+
+import Graphics.Gloss
+import Graphics.Gloss.Interface.IO.Game
+
+import Dyna qualified as D
+import Dyna.Gloss.Data.Vec
+
+-- | Monad that drives the application
+newtype Run a = Run { unRun :: ReaderT Env IO a }
+  deriving (Functor, Applicative, Monad, MonadReader Env, MonadIO, MonadBase IO, MonadRandom)
+
+newtype StMRun a = StMRun { unStMRun :: StM (ReaderT Env IO) a }
+
+instance MonadBaseControl IO Run where
+    type StM Run a = StMRun a
+    liftBaseWith f = Run $ liftBaseWith $ \q -> f (fmap StMRun . q . unRun)
+    restoreM = Run . restoreM . unStMRun
+
+instance D.Frp Run where
+  type Ref Run = IORef
+
+-------------------------------------------------------------------------------
+-- FRP type wrappers
+
+-- | Event stream. The meaning of an event is a callback consumer function.
+-- If we give callback to it it will do something useful based on it.
+--
+-- The main function is runEvt:
+--
+-- > runEvt :: Evt m a -> (a -> m ()) -> m ()
+-- > runEvt events callback = ...
+--
+-- Let's look at simple examples of the event streams:
+--
+-- Event that never produce anything:
+--
+-- > never = Evt {
+-- >    runEvt _ = pure ()
+-- >  }
+--
+-- So it just ignores the callback and returns right away.
+--
+-- Event that happens only once:
+--
+-- > once :: m a -> Evt m a
+-- > once get = Evt {
+-- >     runEvt go = go =<< get
+-- >  }
+--
+-- It just gets the value right away and applies callback to it.
+-- We can try it out in the interpreter:
+--
+-- > putStrLnE $ fmap ("Your message: " <> ) $ once getLine
+--
+-- We have useful functions to print out the events: @putStrLnE@ and @printE@.
+--
+-- Also we have event streams that happen periodically:
+--
+-- > printE $ clock 1  -- prints time every second
+--
+-- ## Duplication of the events.
+--
+-- Note that event streams are functions that do side-effects within some monad.
+-- We use them as values but it means that two values with the same event stream definition
+-- can produce different results. For example:
+--
+-- > a = toRandomR (0, 10) $ clock 1
+-- > b = a
+--
+-- Note that a and b will each have their own copy of underlying random event stream.
+-- So if you use it in the code don't expect values to be the same.
+--
+-- But if we want them to be the same we can copy event from it's definition with function:
+--
+-- > newEvt :: Evt m a -> m (Evt m a)
+--
+-- It starts the underying event stream process n background and sends all events
+-- to the result by channel. With nice property of when we shut down the result event the
+-- background process also shuts down.
+--
+-- > a <- newEvt toRandomR (0, 10) $ clock 1
+-- > b = a
+--
+-- In this example event streams @a@ and @b@ will have the same events during execution.
+newtype Evt a = Evt { unEvt :: D.Evt Run a }
+  deriving (Functor, Semigroup, Monoid, Applicative, Monad, Melody, Harmony, Compose, Loop)
+
+type instance DurOf (Evt a) = Float
+
+instance Limit (Evt a) where
+  lim t (Evt evt) = Evt $ lim (realToFrac t) evt
+
+-- | Dynamic step-wise continuous process
+newtype Dyn a = Dyn { unDyn :: D.Dyn Run a }
+  deriving (Functor, Applicative, Num, Fractional, Semigroup, Monoid, IsString,
+            Boolean, AdditiveGroup, VectorSpace, HasNormal, HasCross2, HasCross3, AffineSpace, HasBasis)
+
+type instance BooleanOf (Dyn a) = Dyn (BooleanOf a)
+
+instance (IfB a) => IfB (Dyn a) where
+  ifB = liftA3 ifB
+
+instance (EqB a) => EqB (Dyn a) where
+  (==*) = liftA2 (==*)
+
+instance (OrdB a) => OrdB (Dyn a) where
+  (<*) = liftA2 (<*)
+  (>*) = liftA2 (>*)
+  (<=*) = liftA2 (<=*)
+  (>=*) = liftA2 (>=*)
+
+-------------------------------------------------------------------------------
+
+-- | All sorts of clicks
+data Click = Click Key KeyState Modifiers Vec
+
+-- | Applicaition environment
+data Env = Env
+  { env'frameChan   :: D.UChan Float
+  , env'eventChan   :: D.UChan Event
+  , env'resizeChan  :: D.UChan (Int, Int)
+  , env'keyChan     :: D.UChan Click
+  , env'mousePos    :: IORef Vec
+  , env'mouseDif1   :: IORef Vec
+  , env'mouseDif2   :: IORef Vec
+  }
+
+-- | Create new environment
+newEnv :: IO Env
+newEnv = do
+  env'frameChan <- newChan
+  env'eventChan <- newChan
+  env'resizeChan <- newChan
+  env'keyChan <- newChan
+  env'mousePos <- newIORef (Vec 0 0)
+  env'mouseDif1 <- newIORef (Vec 0 0)
+  env'mouseDif2 <- newIORef (Vec 0 0)
+  pure Env{..}
+
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
