diff --git a/affection.cabal b/affection.cabal
--- a/affection.cabal
+++ b/affection.cabal
@@ -6,7 +6,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.0.0.5
+version:             0.0.0.6
 synopsis:            A simple Game Engine using SDL
 description:         This package contains Affection, a simple game engine
                      written in Haskell using SDL and GEGL.
@@ -41,6 +41,8 @@
                      , Affection.Types
                      , Affection.StateMachine
                      , Affection.MouseInteractable
+                     , Affection.Property
+                     , Affection.Actor
   default-extensions:  OverloadedStrings
 
   -- Modules included in this library but not exported.
@@ -63,6 +65,7 @@
                      , gegl
                      , babl
                      , monad-loops
+                     , monad-parallel
                      , containers
                      , clock
                      , glib
@@ -105,6 +108,23 @@
 executable example02
   hs-source-dirs:    examples
   main-is:           example02.hs
+  ghc-options:       -threaded -Wall
+  default-language:  Haskell2010
+  default-extensions: OverloadedStrings
+  if flag(examples)
+    build-depends:     base
+                     , affection
+                     , sdl2
+                     , gegl
+                     , babl
+                     , containers
+                     , mtl
+  else
+    buildable:       False
+
+executable example02.1
+  hs-source-dirs:    examples
+  main-is:           example02.1.hs
   ghc-options:       -threaded -Wall
   default-language:  Haskell2010
   default-extensions: OverloadedStrings
diff --git a/examples/example00.hs b/examples/example00.hs
--- a/examples/example00.hs
+++ b/examples/example00.hs
@@ -29,8 +29,9 @@
     , windowTitle    = "Affection: example00"
     , windowConfig   = SDL.defaultWindow
     , preLoop        = return ()
-    , drawLoop       = draw
+    , eventLoop      = handle
     , updateLoop     = update
+    , drawLoop       = draw
     , loadState      = load
     , cleanUp        = clean
     }
@@ -45,18 +46,18 @@
   traceM "loading"
   root <- G.gegl_node_new
   traceM "new root node"
-  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation
-    [ G.Property "color1" $ G.PropertyColor $ G.RGBA 0.4 0.4 0.4 1
-    , G.Property "color2" $ G.PropertyColor $ G.RGBA 0.6 0.6 0.6 1
-    ]
+  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation $
+    props $ do
+        prop "color1" $ G.RGBA 0.4 0.4 0.4 1
+        prop "color2" $ G.RGBA 0.6 0.6 0.6 1
   traceM "checkerboard"
   over <- G.gegl_node_new_child root G.defaultOverOperation
   traceM "over"
-  text <- G.gegl_node_new_child root $ G.textOperation
-    [ G.Property "string" $ G.PropertyString "Hello world!"
-    , G.Property "color"  $ G.PropertyColor $ G.RGBA 0 0 1 0.5
-    , G.Property "size"   $ G.PropertyDouble 40
-    ]
+  text <- G.gegl_node_new_child root $ G.textOperation $
+    props $ do
+        prop "string" ("Hello world!"::String)
+        prop "color" $ G.RGBA 0 0 1 0.5
+        prop "size" (40::Int)
   traceM "text"
   G.gegl_node_link checkerboard over
   G.gegl_node_connect_to text "output" over "aux"
@@ -96,11 +97,16 @@
   liftIO $ SDL.unlockSurface drawSurface
   liftIO $ SDL.updateWindowSurface drawWindow
 
-update :: Double -> [SDL.Event] -> Affection UserData ()
-update sec _ = do
+handle :: SDL.EventPayload -> Affection UserData ()
+handle = const $ return ()
+
+update :: Affection UserData ()
+update = do
   traceM "updating"
   ad <- get
   ud@UserData{..} <- getAffection
+
+  sec <- getDelta
   traceM $ (show $ 1 / sec) ++ " FPS"
   when (elapsedTime ad > 5) $
     put $ ad
diff --git a/examples/example01.hs b/examples/example01.hs
--- a/examples/example01.hs
+++ b/examples/example01.hs
@@ -29,8 +29,9 @@
     , windowTitle    = "Affection: example00"
     , windowConfig   = SDL.defaultWindow
     , preLoop        = return ()
-    , drawLoop       = draw
+    , eventLoop      = const $ return ()
     , updateLoop     = update
+    , drawLoop       = draw
     , loadState      = load
     , cleanUp        = clean
     }
@@ -39,6 +40,7 @@
 data UserData = UserData
   { nodeGraph   :: M.Map String G.GeglNode
   , foreground  :: G.GeglBuffer
+  -- , lastTick    :: Double
   }
 
 load :: SDL.Surface -> IO UserData
@@ -46,25 +48,25 @@
   traceM "loading"
   root <- G.gegl_node_new
   traceM "new root node"
-  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation
-    [ G.Property "color1" $ G.PropertyColor $ G.RGBA 0.4 0.4 0.4 1
-    , G.Property "color2" $ G.PropertyColor $ G.RGBA 0.6 0.6 0.6 1
-    ]
+  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation $
+    props $ do
+        prop "color1" $ G.RGBA 0.4 0.4 0.4 1
+        prop "color2" $ G.RGBA 0.6 0.6 0.6 1
   traceM "checkerboard"
   over <- G.gegl_node_new_child root G.defaultOverOperation
   traceM "over"
   buffer <- G.gegl_buffer_new (Just $ G.GeglRectangle 0 0 800 600) =<<
     B.babl_format (B.PixelFormat B.RGBA B.CFfloat)
-  sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer"
-    [ G.Property "buffer" $ G.PropertyBuffer buffer
-    ]
+  sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer" $
+    props $
+    prop "buffer" buffer
   traceM "buffer-source"
   nop <- G.gegl_node_new_child root $ G.Operation "gegl:nop" []
   traceM "nop"
-  crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop"
-    [ G.Property "width" $ G.PropertyDouble 800
-    , G.Property "height" $ G.PropertyDouble 600
-    ]
+  crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop" $
+    props $ do
+        prop "width" (800::Double)
+        prop "height" (600.0::Double)
   G.gegl_node_link_many [checkerboard, over, crop, sink]
   G.gegl_node_connect_to nop "output" over "aux"
   traceM "connections made"
@@ -80,6 +82,7 @@
   return $ UserData
     { nodeGraph = myMap
     , foreground = buffer
+    -- , lastTick = 0
     }
 
 draw :: Affection UserData ()
@@ -87,19 +90,20 @@
   traceM "drawing"
   UserData{..} <- getAffection
   drawRect (nodeGraph M.! "nop") (G.RGB 1 0 0) Fill (G.GeglRectangle 10 10 500 500) foreground
-  liftIO $ G.gegl_node_process $ nodeGraph M.! "sink"
+  process $ nodeGraph M.! "sink"
 
-update :: Double -> [SDL.Event] -> Affection UserData ()
-update sec _ = do
+update :: Affection UserData ()
+update = do
   traceM "updating"
-  -- liftIO $ delaySec 5
-  ad <- get
-  ud@UserData{..} <- getAffection
-  traceM $ (show $ 1 / sec) ++ " FPS"
-  when (elapsedTime ad > 20) $
-    put $ ad
-      { quitEvent = True
-      }
+  ud <- getAffection
+  -- let last = lastTick ud
+  -- tick <- getTick
+  -- putAffection $ ud { lastTick = tick }
+  dt <- getDelta
+  traceM $ (show $ 1 / dt) ++ " FPS"
+  elapsed <- getElapsedTime
+  when (elapsed > 20) $
+    quit
 
 clean :: UserData -> IO ()
 clean _ = return ()
diff --git a/examples/example02.1.hs b/examples/example02.1.hs
new file mode 100644
--- /dev/null
+++ b/examples/example02.1.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE RecordWildCards #-}
+
+import Affection
+import qualified SDL
+import qualified GEGL as G
+import qualified BABL as B
+import qualified Data.Map.Strict as M
+
+import Debug.Trace
+
+main :: IO ()
+main = do
+  conf <- return $ AffectionConfig
+    { initComponents = All
+    , windowTitle    = "Affection: example00"
+    , windowConfig   = SDL.defaultWindow
+    , preLoop        = return ()
+    , eventLoop      = handle
+    , updateLoop     = update
+    , drawLoop       = draw
+    , loadState      = load
+    , cleanUp        = clean
+    }
+  withAffection conf
+
+data UserData = UserData
+  -- { nodeGraph   :: M.Map String G.GeglNode
+  -- , foreground  :: G.GeglBuffer
+  -- , lastTick    :: Double
+  -- }
+  { coordinates :: (Double, Double)
+  , lastTick    :: Double
+  }
+
+load :: SDL.Surface -> IO UserData
+load _ = do
+  -- traceM "loading"
+  -- root <- G.gegl_node_new
+  -- traceM "new root node"
+  -- checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation $
+  --   props $ do
+  --       prop "color1" $ G.RGBA 0.4 0.4 0.4 1
+  --       prop "color2" $ G.RGBA 0.6 0.6 0.6 1
+  -- traceM "checkerboard"
+  -- over <- G.gegl_node_new_child root G.defaultOverOperation
+  -- traceM "over"
+  -- buffer <- G.gegl_buffer_new (Just $ G.GeglRectangle 0 0 800 600) =<<
+  --   B.babl_format (B.PixelFormat B.RGBA B.CFfloat)
+  -- sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer" $
+  --   props $
+  --   prop "buffer" buffer
+  -- traceM "buffer-sink"
+  -- rect <- G.gegl_node_new_child root $ G.Operation "gegl:rectangle" $
+  --   props $ do
+  --       prop "x" (0::Double)
+  --       prop "y" (0::Double)
+  --       prop "width" (20::Double)
+  --       prop "height" (20::Double)
+  --       prop "color" $ G.RGBA 1 0 0 0.5
+  -- traceM "rect"
+  -- crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop" $
+  --   props $ do
+  --       prop "width" (800::Double)
+  --       prop "height" (600::Double)
+  -- G.gegl_node_link_many [checkerboard, over, crop, sink]
+  -- _ <- G.gegl_node_connect_to rect "output" over "aux"
+  -- traceM "connections made"
+  -- myMap <- return $ M.fromList
+  --   [ ("root"        , root)
+  --   , ("over"        , over)
+  --   , ("background"  , checkerboard)
+  --   , ("sink"        , sink)
+  --   , ("rect"        , rect)
+  --   , ("crop"        , crop)
+  --   ]
+  -- traceM "loading complete"
+  -- return $ UserData
+  --   { nodeGraph = myMap
+  --   , foreground = buffer
+  --   , lastTick = 0
+  --   }
+  return $ UserData
+    { coordinates = (400, 300)
+    , lastTick = 0
+    }
+
+-- drawInit :: Affection UserData ()
+-- drawInit = do
+--   UserData{..} <- getAffection
+--   present (GeglRectangle 0 0 800 600) foreground True
+
+draw :: Affection UserData ()
+draw = do
+  UserData{..} <- getAffection
+  traceM "loading"
+  root <- liftIO $ G.gegl_node_new
+  traceM "new root node"
+  checkerboard <- liftIO $ G.gegl_node_new_child root $ G.checkerboardOperation $
+    props $ do
+        prop "color1" $ G.RGBA 0.4 0.4 0.4 1
+        prop "color2" $ G.RGBA 0.6 0.6 0.6 1
+  traceM "checkerboard"
+  over <- liftIO $ G.gegl_node_new_child root G.defaultOverOperation
+  traceM "over"
+  buffer <- liftIO $ G.gegl_buffer_new (Just $ G.GeglRectangle 0 0 800 600) =<<
+    B.babl_format (B.PixelFormat B.RGBA B.CFfloat)
+  sink <- liftIO $ G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer" $
+    props $
+    prop "buffer" buffer
+  traceM "buffer-sink"
+  rect <- liftIO $ G.gegl_node_new_child root $ G.Operation "gegl:rectangle" $
+    props $ do
+        prop "x" $ fst coordinates
+        prop "y" $ snd coordinates
+        prop "width" (20::Double)
+        prop "height" (20::Double)
+        prop "color" $ G.RGBA 1 0 0 0.5
+  traceM "rect"
+  crop <- liftIO $ G.gegl_node_new_child root $ G.Operation "gegl:crop" $
+    props $ do
+        prop "width" (800::Double)
+        prop "height" (600::Double)
+  liftIO $ G.gegl_node_link_many [checkerboard, over, crop, sink]
+  _ <- liftIO $ G.gegl_node_connect_to rect "output" over "aux"
+  traceM "connections made"
+  myMap <- return $ M.fromList
+    [ ("root"        , root)
+    , ("over"        , over)
+    , ("background"  , checkerboard)
+    , ("sink"        , sink)
+    , ("rect"        , rect)
+    , ("crop"        , crop)
+    ]
+  traceM "loading complete"
+  process (myMap M.! "sink")
+  present (GeglRectangle 0 0 800 600) buffer True
+
+update :: Affection UserData ()
+update = do
+  traceM "updating"
+
+  tick <- getElapsedTime
+  ud <- getAffection
+  putAffection $ ud { lastTick = tick }
+
+  let dt = tick - lastTick ud
+  return ()
+  traceM $ (show $ 1 / dt) ++ " FPS"
+
+handle (SDL.MouseMotionEvent dat) = do
+  let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
+  ud <- getAffection
+  putAffection ud
+    { coordinates = (fromIntegral (x - 10), fromIntegral (y - 10))
+    }
+  -- liftIO $ G.gegl_node_set (nodeGraph ud M.! "rect") $ G.Operation "" $
+  --   props $ do
+  --       prop "x" (fromIntegral (x - 10) :: Double)
+  --       prop "y" $ (fromIntegral (y - 10) :: Double)
+
+handle (SDL.WindowClosedEvent _) = do
+  traceM "seeya!"
+  quit
+
+handle _ =
+  return ()
+
+clean :: UserData -> IO ()
+clean _ = return ()
diff --git a/examples/example02.hs b/examples/example02.hs
--- a/examples/example02.hs
+++ b/examples/example02.hs
@@ -3,25 +3,21 @@
 import Affection
 import qualified SDL
 import qualified GEGL as G
-import qualified GEGL.FFI.Buffer as G
 import qualified BABL as B
 import qualified Data.Map.Strict as M
 
-import Foreign.C.Types
-import Foreign.Marshal.Utils (new)
-import Foreign.Ptr (castPtr)
-
 import Debug.Trace
 
 main :: IO ()
 main = do
-  conf <- return $ AffectionConfig
+  conf <- return AffectionConfig
     { initComponents = All
     , windowTitle    = "Affection: example00"
     , windowConfig   = SDL.defaultWindow
     , preLoop        = return ()
-    , drawLoop       = draw
+    , eventLoop      = handle
     , updateLoop     = update
+    , drawLoop       = draw
     , loadState      = load
     , cleanUp        = clean
     }
@@ -29,8 +25,9 @@
 
 data UserData = UserData
   { nodeGraph   :: M.Map String G.GeglNode
+  , actors      :: M.Map String Actor
   , foreground  :: G.GeglBuffer
-  , coordinates :: Maybe (Int, Int)
+  , lastTick    :: Double
   }
 
 load :: SDL.Surface -> IO UserData
@@ -38,88 +35,107 @@
   traceM "loading"
   root <- G.gegl_node_new
   traceM "new root node"
-  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation
-    [ G.Property "color1" $ G.PropertyColor $ G.RGBA 0.4 0.4 0.4 1
-    , G.Property "color2" $ G.PropertyColor $ G.RGBA 0.6 0.6 0.6 1
-    ]
+  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation $
+    props $ do
+      prop "color1" $ G.RGBA 0.4 0.4 0.4 1
+      prop "color2" $ G.RGBA 0.6 0.6 0.6 1
   traceM "checkerboard"
   over <- G.gegl_node_new_child root G.defaultOverOperation
   traceM "over"
   buffer <- G.gegl_buffer_new (Just $ G.GeglRectangle 0 0 800 600) =<<
     B.babl_format (B.PixelFormat B.RGBA B.CFfloat)
-  sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer"
-    [ G.Property "buffer" $ G.PropertyBuffer buffer
-    ]
+  sink <- G.gegl_node_new_child root $ G.Operation "gegl:copy-buffer" $
+    props $
+    prop "buffer" buffer
   traceM "buffer-sink"
-  nop <- G.gegl_node_new_child root $ G.Operation "gegl:nop" []
-  traceM "nop"
-  crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop"
-    [ G.Property "width" $ G.PropertyDouble 800
-    , G.Property "height" $ G.PropertyDouble 600
-    ]
+  rectProps <- return $
+    props $ do
+      prop "x" (0::Double)
+      prop "y" (0::Double)
+      prop "width" (20::Double)
+      prop "height" (20::Double)
+      prop "color" $ G.RGBA 1 0 0 0.5
+  rect <- G.gegl_node_new_child root $ G.Operation "gegl:rectangle" rectProps
+  traceM "rect"
+  crop <- G.gegl_node_new_child root $ G.Operation "gegl:crop" $
+    props $ do
+      prop "width" (800::Double)
+      prop "height" (600::Double)
   G.gegl_node_link_many [checkerboard, over, crop, sink]
-  G.gegl_node_connect_to nop "output" over "aux"
+  _ <- G.gegl_node_connect_to rect "output" over "aux"
+  let rectActor = Actor rectProps rect
   traceM "connections made"
   myMap <- return $ M.fromList
     [ ("root"        , root)
     , ("over"        , over)
     , ("background"  , checkerboard)
     , ("sink"        , sink)
-    , ("nop"         , nop)
+    , ("rect"        , rect)
     , ("crop"        , crop)
     ]
   traceM "loading complete"
-  return $ UserData
+  actorMap <- return $ M.fromList
+    [ ("rect", rectActor)
+    ]
+  return UserData
     { nodeGraph = myMap
+    , actors    = actorMap
     , foreground = buffer
-    , coordinates = Nothing
+    , lastTick = 0
     }
 
 -- drawInit :: Affection UserData ()
 -- drawInit = do
 --   UserData{..} <- getAffection
---   present (nodeGraph M.! "over") foreground (GeglRectangle 0 0 800 600) True
+--   present (GeglRectangle 0 0 800 600) foreground True
 
 draw :: Affection UserData ()
 draw = do
-  traceM "drawing"
-  ad <- get
   UserData{..} <- getAffection
-  SDL.V2 (CInt rw) (CInt rh) <- SDL.surfaceDimensions $ drawSurface ad
-  let (w, h) = (fromIntegral rw, fromIntegral rh)
-  liftIO $ clearArea foreground (GeglRectangle 0 0 w h)
-  maybe (return ()) (\(x, y) ->
-    drawRect
-      (nodeGraph M.! "nop")
-      (G.RGBA 1 0 0 0.5)
-      (Fill)
-      (G.GeglRectangle (x - 10) (y - 10) 20 20)
-      foreground
-    ) coordinates
-  liftIO $ G.gegl_node_process $ nodeGraph M.! "sink"
+  mapM_ (\(Actor ps node) -> liftIO $ G.gegl_node_set node $ G.Operation "" ps) actors
+  process (nodeGraph M.! "sink")
+  present (GeglRectangle 0 0 800 600) foreground True
 
-update :: Double -> [SDL.Event] -> Affection UserData ()
-update sec evs = do
+update :: Affection UserData ()
+update = do
   traceM "updating"
-  ad <- get
+
+  tick <- getElapsedTime
   ud <- getAffection
-  traceM $ (show $ 1 / sec) ++ " FPS"
-  -- ev <- liftIO $ SDL.pollEvent
-  mapM_ (\e ->
-    case SDL.eventPayload e of
-      SDL.MouseMotionEvent dat -> do
-        let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
-        putAffection $ ud
-          { coordinates = Just (fromIntegral x, fromIntegral y)
-          }
-      SDL.WindowClosedEvent _ -> do
-        traceM "seeya!"
-        put $ ad
-          { quitEvent = True
-          }
-      _ ->
-        return ()
-    ) evs
+  putAffection $ ud { lastTick = tick }
+
+  let dt = tick - lastTick ud
+  return ()
+  traceM $ show (1 / dt) ++ " FPS"
+
+handle :: SDL.EventPayload -> Affection UserData ()
+handle (SDL.MouseMotionEvent dat) = do
+  let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
+  ud <- getAffection
+  
+  nmap <- return $ M.adjust
+    (Actor (props $ do
+      prop "y" (fromIntegral (y - 10) :: Double)
+      prop "x" (fromIntegral (x - 10) :: Double)
+      )
+      . actorNode
+      )
+    "rect"
+    (actors ud)
+  putAffection ud
+    { actors = nmap
+    }
+  -- liftIO $ G.gegl_node_set (nodeGraph ud M.! "rect") $ G.Operation "" $
+  --   props $ do
+  --     prop "x" (fromIntegral (x - 10) :: Double)
+  --     prop "y" $ (fromIntegral (y - 10) :: Double)
+
+handle (SDL.WindowClosedEvent _) = do
+  traceM "seeya!"
+  quit
+
+handle _ =
+  return ()
 
 clean :: UserData -> IO ()
 clean _ = return ()
diff --git a/examples/example03.hs b/examples/example03.hs
--- a/examples/example03.hs
+++ b/examples/example03.hs
@@ -23,8 +23,9 @@
     , windowTitle    = "Affection: example00"
     , windowConfig   = SDL.defaultWindow
     , preLoop        = drawInit
-    , drawLoop       = draw
+    , eventLoop      = handle
     , updateLoop     = update
+    , drawLoop       = draw
     , loadState      = load
     , cleanUp        = clean
     }
@@ -41,10 +42,14 @@
   traceM "loading"
   root <- G.gegl_node_new
   traceM "new root node"
-  checkerboard <- G.gegl_node_new_child root $ G.checkerboardOperation
-    [ G.Property "color1" $ G.PropertyColor $ G.RGBA 0.4 0.4 0.4 1
-    , G.Property "color2" $ G.PropertyColor $ G.RGBA 0.6 0.6 0.6 1
-    ]
+  rect <- G.gegl_node_new_child root $ G.Operation "gegl:rectangle" $
+    props $ do
+      prop "x" (0 :: Double)
+      prop "y" (0 :: Double)
+      prop "width" (800 :: Double)
+      prop "height" (600 :: Double)
+      prop "color" $ G.RGB 0 0 0
+  traceM "rect"
   traceM "checkerboard"
   over <- G.gegl_node_new_child root G.defaultOverOperation
   traceM "over"
@@ -61,13 +66,12 @@
     , G.Property "height" $ G.PropertyDouble 600
     ]
   traceM "crop"
-  G.gegl_node_link_many [checkerboard, over, crop, sink]
+  G.gegl_node_link_many [rect, over, crop, sink]
   G.gegl_node_connect_to nop "output" over "aux"
   traceM "connections made"
   myMap <- return $ M.fromList
     [ ("root"        , root)
     , ("over"        , over)
-    , ("background"  , checkerboard)
     , ("sink"        , sink)
     , ("nop"         , nop)
     , ("crop"        , crop)
@@ -80,105 +84,94 @@
     }
 
 drawInit :: Affection UserData ()
-drawInit = do
-  UserData{..} <- getAffection
-  present (GeglRectangle 0 0 800 600) foreground True
+drawInit = return ()
+-- drawInit = do
+--   UserData{..} <- getAffection
+--   present (GeglRectangle 0 0 800 600) foreground True
 
 draw :: Affection UserData ()
 draw = do
   traceM "drawing"
   UserData{..} <- getAffection
-  liftIO $ G.gegl_node_process $ nodeGraph M.! "sink"
-  -- ad <- get
-  -- ud <- getAffection
-  -- drawParticles partDraw $ particles ud
-  -- SDL.V2 (CInt rw) (CInt rh) <- SDL.surfaceDimensions $ drawSurface ad
-  -- let (w, h) = (fromIntegral rw, fromIntegral rh)
-  -- liftIO $ clearArea (foreground ud) (GeglRectangle 0 0 w h)
-  -- maybe (return ()) (\(x, y) ->
-  --   drawRect
-  --     (foreground ud)
-  --     (nodeGraph ud M.! "over")
-  --     (G.RGBA 1 0 0 0.5)
-  --     (Line 7)
-  --     (G.GeglRectangle (x - 10) (y - 10) 20 20)
-  --   ) $ coordinates ud
+  drawParticleSystem partsys partDraw
+  process $ nodeGraph M.! "sink"
+  present
+    (G.GeglRectangle 0 0 800 600)
+    foreground
+    True
 
-update :: Double -> [SDL.Event] -> Affection UserData ()
-update sec evs = do
+update :: Affection UserData ()
+update = do
   traceM "updating"
   ad <- get
   ud <- getAffection
-  -- let newPart = updateParticles sec partUpd $ particles ud
-  -- putAffection $ ud { particles = newPart }
-  traceM $ (show $ 1 / sec) ++ " FPS"
-  -- ev <- liftIO $ SDL.pollEvents
-  mapM_ (\e ->
-    case SDL.eventPayload e of
-      SDL.MouseMotionEvent dat ->
-        if SDL.ButtonLeft `elem` SDL.mouseMotionEventState dat
-        then do
-          let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
-          vx <- liftIO $ randomRIO (-20, 20)
-          vy <- liftIO $ randomRIO (-20, 20)
-          life <- liftIO $ randomRIO (1, 5)
-          r <- liftIO $ randomRIO (0,1)
-          g <- liftIO $ randomRIO (0,1)
-          b <- liftIO $ randomRIO (0,1)
-          tempRoot <- liftIO $ G.gegl_node_new
-          tempOver <- liftIO $ G.gegl_node_new_child tempRoot
-            G.defaultOverOperation
-          tempRect <- liftIO $ G.gegl_node_new_child tempRoot $ G.Operation
-            "gegl:rectangle"
-            [ G.Property "x"      $ G.PropertyDouble $ fromIntegral x - 10
-            , G.Property "y"      $ G.PropertyDouble $ fromIntegral y - 10
-            , G.Property "width"  $ G.PropertyDouble 20
-            , G.Property "height" $ G.PropertyDouble 20
-            , G.Property "color"  $ G.PropertyColor  $ (G.RGBA r g b 0.5)
-            ]
-          liftIO $ G.gegl_node_connect_to tempRect "output" tempOver "aux"
-          -- traceM $ "position is: " ++ show x ++ " " ++ show y
-          -- traceM $ "velocity is: " ++ show vx ++ " " ++ show vy
-          ips <- insertParticle (partsys ud) $
-            Particle
-              { particleTimeToLive = life
-              , particleCreation   = elapsedTime ad
-              , particlePosition   = (fromIntegral x, fromIntegral y)
-              , particleRotation   = Rad 0
-              , particleVelocity   = (vx, vy)
-              , particlePitchRate  = Rad 0
-              , particleRootNode   = tempRoot
-              , particleNodeGraph  = M.fromList
-                [ ("root", tempRoot)
-                , ("over", tempOver)
-                , ("rect", tempRect)
-                ]
-              , particleStackCont  = tempOver
-              , particleDrawFlange = tempOver
-              }
-          putAffection $ ud
-            { partsys = ips
-            }
-          -- when (not $ null $ psParts $ partsys ud) $
-          --   liftIO $ G.gegl_node_link
-          --     tempOver
-          --     (particleStackCont $ head $ psParts $ partsys ud)
-        else
-          return ()
-      SDL.WindowClosedEvent _ -> do
-        traceM "seeya!"
-        put $ ad
-          { quitEvent = True
-          }
-      _ ->
-        return ()
-    ) evs
+  delta <- getDelta
+  traceM $ (show $ 1 / delta) ++ " FPS"
   ud2 <- getAffection
-  !nps <- updateParticleSystem (partsys ud2) sec partUpd partDraw
+  !nps <- updateParticleSystem (partsys ud2) delta partUpd
   putAffection $ ud2 { partsys = nps }
 
+handle (SDL.MouseMotionEvent dat) =
+  when (SDL.ButtonLeft `elem` SDL.mouseMotionEventState dat)
+  $ do
+    ad <- get
+    ud <- getAffection
+    let (SDL.P (SDL.V2 x y)) = SDL.mouseMotionEventPos dat
+    vx <- liftIO $ randomRIO (-20, 20)
+    vy <- liftIO $ randomRIO (-20, 20)
+    life <- liftIO $ randomRIO (1, 5)
+    r <- liftIO $ randomRIO (0,1)
+    g <- liftIO $ randomRIO (0,1)
+    b <- liftIO $ randomRIO (0,1)
+    tempRoot <- liftIO $ G.gegl_node_new
+    tempOver <- liftIO $ G.gegl_node_new_child tempRoot
+      G.defaultOverOperation
+    tempRect <- liftIO $ G.gegl_node_new_child tempRoot $ G.Operation
+      "gegl:rectangle"
+      [ G.Property "x"      $ G.PropertyDouble $ fromIntegral x - 10
+      , G.Property "y"      $ G.PropertyDouble $ fromIntegral y - 10
+      , G.Property "width"  $ G.PropertyDouble 20
+      , G.Property "height" $ G.PropertyDouble 20
+      , G.Property "color"  $ G.PropertyColor  $ (G.RGBA r g b 0.5)
+      ]
+    liftIO $ G.gegl_node_connect_to tempRect "output" tempOver "aux"
+    -- traceM $ "position is: " ++ show x ++ " " ++ show y
+    -- traceM $ "velocity is: " ++ show vx ++ " " ++ show vy
+    ips <- insertParticle (partsys ud) $
+      Particle
+        { particleTimeToLive = life
+        , particleCreation   = elapsedTime ad
+        , particlePosition   = (fromIntegral x, fromIntegral y)
+        , particleRotation   = Rad 0
+        , particleVelocity   = (vx, vy)
+        , particlePitchRate  = Rad 0
+        , particleRootNode   = tempRoot
+        , particleNodeGraph  = M.fromList
+          [ ("root", tempRoot)
+          , ("over", tempOver)
+          , ("rect", tempRect)
+          ]
+        , particleStackCont  = tempOver
+        , particleDrawFlange = tempOver
+        }
+    putAffection $ ud
+      { partsys = ips
+      }
+    -- when (not $ null $ psParts $ partsys ud) $
+    --   liftIO $ G.gegl_node_link
+    --     tempOver
+    --     (particleStackCont $ head $ psParts $ partsys ud)
+
+handle (SDL.WindowClosedEvent _) = do
+  traceM "seeya!"
+  quit
+
+handle _ =
+  return ()
+
 clean :: UserData -> IO ()
-clean _ = return ()
+clean ud = do
+  G.gegl_node_drop (nodeGraph ud M.! "root")
 
 partUpd :: Double -> Particle -> Affection UserData Particle
 partUpd sec p = do
@@ -192,15 +185,16 @@
   return np
 
 partDraw :: G.GeglBuffer -> G.GeglNode -> Particle -> Affection UserData ()
-partDraw buf node Particle{..} = do
-  present
-    (G.GeglRectangle (floor $ fst particlePosition - 10) (floor $ snd particlePosition - 10) 20 20)
-    buf
-    False
-  -- ud <- getAffection
-  -- drawRect'
-  --   particleDrawFlange
-  --   (G.RGBA 1 0 0 0.5)
-  --   (Fill)
-  --   (G.GeglRectangle ((floor $ fst particlePosition) - 10) ((floor $ snd particlePosition) -10) 20 20)
-  --   buf
+partDraw _ _ _ = return ()
+-- partDraw buf node Particle{..} = do
+--   present
+--     (G.GeglRectangle (floor $ fst particlePosition - 10) (floor $ snd particlePosition - 10) 20 20)
+--     buf
+--     False
+--   -- ud <- getAffection
+--   -- drawRect'
+--   --   particleDrawFlange
+--   --   (G.RGBA 1 0 0 0.5)
+--   --   (Fill)
+--   --   (G.GeglRectangle ((floor $ fst particlePosition) - 10) ((floor $ snd particlePosition) -10) 20 20)
+--   --   buf
diff --git a/src/Affection.hs b/src/Affection.hs
--- a/src/Affection.hs
+++ b/src/Affection.hs
@@ -9,6 +9,9 @@
     , delaySec
     , get
     , put
+    , getElapsedTime
+    , getDelta
+    , quit
     , module A
     ) where
 
@@ -23,6 +26,7 @@
 import System.Clock
 
 import Control.Monad.Loops
+import qualified Control.Monad.Parallel as MP
 import Control.Monad.State
 
 import Foreign.C.Types (CInt(..))
@@ -35,6 +39,8 @@
 import Affection.Particle as A
 import Affection.StateMachine as A
 import Affection.MouseInteractable as A
+import Affection.Property as A
+import Affection.Actor as A
 
 import qualified BABL as B
 
@@ -75,8 +81,8 @@
   pixelFormat <- liftIO $ peek . Raw.surfaceFormat =<< peek ptr
   SDL.V2 (CInt rw) (CInt rh) <- liftIO $ SDL.surfaceDimensions surface
   let (w, h) = (fromIntegral rw, fromIntegral rh)
-      stride = (fromIntegral $ Raw.pixelFormatBytesPerPixel pixelFormat) * w
-  pixels <- SDL.surfacePixels $ surface
+      stride = fromIntegral (Raw.pixelFormatBytesPerPixel pixelFormat) * w
+  pixels <- SDL.surfacePixels surface
   let bablFormat = B.PixelFormat B.RGBA B.CFu8
       cpp        = B.babl_components_per_pixel bablFormat
   format <- B.babl_format bablFormat
@@ -93,6 +99,7 @@
     , drawCPP         = cpp
     , drawStack       = []
     , elapsedTime     = 0
+    , dt              = 0
     }) <$> loadState surface
   (_, nState) <- runStateT ( A.runState $ do
     preLoop
@@ -109,18 +116,20 @@
         -- clean draw requests from last run
         mapM_ (invalidateDrawRequest (drawPixels ad) (drawStride ad) (drawCPP ad)) (drawStack ad)
         -- clean the renderer form last time
-        SDL.clear renderer
+        -- SDL.clear renderer
         -- compute dt and update elapsedTime
-        let !dt = (fromIntegral $ toNanoSecs $ diffTimeSpec lastTime now) / (fromIntegral 10 ^ 9)
+        let !dt = fromIntegral (toNanoSecs $ diffTimeSpec lastTime now) / (10 ^ 9)
             !ne = elapsedTime ad + dt
         put $ ad
           { drawStack = []
           , elapsedTime = ne
+          , dt = dt
           }
         -- poll events
         evs <- preHandleEvents =<< liftIO SDL.pollEvents
+        MP.mapM_ eventLoop evs
         -- execute user defined update loop
-        updateLoop dt evs
+        updateLoop
         -- execute user defined draw loop
         drawLoop
         -- handle all new draw requests
@@ -138,7 +147,7 @@
         -- clean the texture
         SDL.destroyTexture texture
         -- save new time
-        liftIO $ writeIORef execTime $ now
+        liftIO $ writeIORef execTime now
       )
     ) initContainer
   G.gegl_exit
@@ -150,11 +159,11 @@
 getSurfaces window = do
   oldSurf@(SDL.Surface ptr _) <- SDL.getWindowSurface window
   rawSurfacePtr <- Raw.convertSurfaceFormat ptr (SDL.toNumber SDL.ABGR8888) 0
-  let surface = (flip SDL.Surface Nothing) rawSurfacePtr
+  let surface = SDL.Surface rawSurfacePtr Nothing
   return (oldSurf, surface)
 
 -- Prehandle SDL events in case any window events occur
-preHandleEvents :: [SDL.Event] -> Affection us [SDL.Event]
+preHandleEvents :: [SDL.Event] -> Affection us [SDL.EventPayload]
 preHandleEvents evs =
   -- mapM handle evs
   -- where
@@ -165,7 +174,7 @@
   --         return e
   --       _ ->
   --         return e
-  return evs
+  return $ map SDL.eventPayload evs
 
 -- | Return the userstate to the user
 getAffection :: Affection us us
@@ -187,3 +196,17 @@
   :: Int -- ^ Number of seconds
   -> IO ()
 delaySec dur = SDL.delay (fromIntegral $ dur * 1000)
+
+-- | Get time since start but always the same in the current tick.
+getElapsedTime :: Affection us Double
+getElapsedTime =
+  elapsedTime <$> get
+
+getDelta :: Affection us Double
+getDelta =
+  dt <$> get
+
+quit :: Affection us ()
+quit = do
+  ad <- get
+  put $ ad { quitEvent = True }
diff --git a/src/Affection/Actor.hs b/src/Affection/Actor.hs
new file mode 100644
--- /dev/null
+++ b/src/Affection/Actor.hs
@@ -0,0 +1,12 @@
+-- | This module implements the Actor, a Datastructure binding a 'G.GeglNode'
+-- to a game asset
+module Affection.Actor
+ ( Actor(..)
+ ) where
+
+import qualified GEGL as G
+
+data Actor = Actor
+  { actorProperties :: [G.Property]
+  , actorNode       :: G.GeglNode
+  }
diff --git a/src/Affection/Draw.hs b/src/Affection/Draw.hs
--- a/src/Affection/Draw.hs
+++ b/src/Affection/Draw.hs
@@ -1,12 +1,13 @@
-{-# LANGUAGE RecordWildCards, BangPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
 
 -- | Module for drawing primitives
 module Affection.Draw
   ( drawRect
-  -- , clear
+  , clear
   , handleDrawRequest
   , invalidateDrawRequest
   , present
+  , process
   , clearArea
   ) where
 
@@ -39,7 +40,7 @@
   -> Affection us ()
 drawRect node color Fill rect@GeglRectangle{..} buf = do
   ad <- get
-  tempRoot <- liftIO $ G.gegl_node_new
+  tempRoot <- liftIO G.gegl_node_new
   opNode <- liftIO $ G.gegl_node_new_child tempRoot $ G.Operation "gegl:rectangle"
     [ G.Property "x"      $ G.PropertyDouble $ fromIntegral rectangleX
     , G.Property "y"      $ G.PropertyDouble $ fromIntegral rectangleY
@@ -50,7 +51,7 @@
   diw <- liftIO $ G.gegl_node_connect_to opNode "output" node "input"
   unless diw $ error "Affection.Draw.drawRect: connect failed"
   put $ ad
-    { drawStack = (DrawRequest rect buf (Kill (Just tempRoot))) : drawStack ad
+    { drawStack = DrawRequest rect buf (Kill (Just tempRoot)) : drawStack ad
     }
 
 -- | Force update of a specific region on screen
@@ -63,9 +64,35 @@
   ad <- get
   let k = if not kill then Kill Nothing else Persist
   put ad
-    { drawStack = (DrawRequest rect buf k) : drawStack ad
+    { drawStack = DrawRequest rect buf k : drawStack ad
     }
 
+process
+  :: G.GeglNode
+  -> Affection us ()
+process = liftIO . G.gegl_node_process
+
+putToSurface
+  :: Ptr a
+  -> G.GeglRectangle
+  -> Int
+  -> Int
+  -> DrawRequest
+  -> Affection us ()
+putToSurface pixels realRect stride cpp DrawRequest{..} = do
+  ad <- get
+  liftIO $ SDL.lockSurface $ drawSurface ad
+  liftIO $ G.gegl_buffer_get
+    requestBuffer
+    (Just realRect)
+    1
+    (Just $ drawFormat ad)
+    (pixels `plusPtr`
+      (rectangleX realRect * cpp + rectangleY realRect * stride))
+    stride
+    G.GeglAbyssNone
+  liftIO $ SDL.unlockSurface $ drawSurface ad
+
 -- | function for handling 'DrawRequest's and updating the output
 handleDrawRequest
   :: Ptr a           -- ^ Pixel buffer to blit to
@@ -79,20 +106,9 @@
   let surf = drawSurface ad
   mrealRect <- liftIO $ G.gegl_rectangle_intersect
     requestArea
-    (G.GeglRectangle 0 0 (fst $ drawDimensions ad) (snd $ drawDimensions ad))
-  maybe (return()) (\realRect -> do
-    liftIO $ SDL.lockSurface surf
-    liftIO $ G.gegl_buffer_get
-      requestBuffer
-      (Just realRect)
-      1
-      (Just $ drawFormat ad)
-      (pixels `plusPtr`
-        (rectangleX realRect * cpp + rectangleY realRect * stride))
-      stride
-      G.GeglAbyssNone
-    liftIO $ SDL.unlockSurface surf
-    -- liftIO $ SDL.updateWindowSurface $ drawWindow ad
+    (uncurry (G.GeglRectangle 0 0) (drawDimensions ad))
+  maybe (return()) (\realRect ->
+    putToSurface pixels realRect stride cpp dr
     ) mrealRect
   case requestPersist of
     Persist ->
@@ -112,21 +128,10 @@
   ad <- get
   mrealRect <- liftIO $ G.gegl_rectangle_intersect
     requestArea
-    (G.GeglRectangle 0 0 (fst $ drawDimensions ad) (snd $ drawDimensions ad))
+    (uncurry (G.GeglRectangle 0 0) (drawDimensions ad))
   maybe (return()) (\realRect -> do
-    let surf = drawSurface ad
     liftIO $ clearArea requestBuffer realRect
-    liftIO $ SDL.lockSurface surf
-    liftIO $ G.gegl_buffer_get
-      requestBuffer
-      (Just realRect)
-      1
-      (Just $ drawFormat ad)
-      (pixels `plusPtr`
-        (rectangleX realRect * cpp + rectangleY realRect * stride))
-      stride
-      G.GeglAbyssNone
-    liftIO $ SDL.unlockSurface surf
+    putToSurface pixels realRect stride cpp dr
     ) mrealRect
   case requestPersist of
     Kill (Just victim) ->
@@ -150,7 +155,7 @@
         G.RGB  r g b   -> (r, g, b)
       ca = case col of
         G.RGBA _ _ _ a -> a
-        G.RGB  _ _ _   -> 1
+        G.RGB{}        -> 1
       alpha = ca
       dst_a = ba
       da = alpha + dst_a * (1 - alpha)
@@ -162,7 +167,7 @@
     ( G.CVdouble $ CDouble $ red / da
     , G.CVdouble $ CDouble $ gre / da
     , G.CVdouble $ CDouble $ blu / da
-    , G.CVdouble $ CDouble $ ca
+    , G.CVdouble $ CDouble ca
     )
 
 unsafeColorize col =
@@ -172,12 +177,12 @@
       G.RGB  cr cg cb   -> (cr, cg, cb)
     a = case col of
       G.RGBA _ _ _ ca -> ca
-      G.RGB  _ _ _    -> 1
+      G.RGB{}         -> 1
   in
-    ( G.CVdouble $ CDouble $ r
-    , G.CVdouble $ CDouble $ g
-    , G.CVdouble $ CDouble $ b
-    , G.CVdouble $ CDouble $ a
+    ( G.CVdouble $ CDouble r
+    , G.CVdouble $ CDouble g
+    , G.CVdouble $ CDouble b
+    , G.CVdouble $ CDouble a
     )
 
 -- | Clear a specified area of a buffer from all data
@@ -186,3 +191,11 @@
   -> G.GeglRectangle -- ^ Area to clear
   -> IO ()
 clearArea = G.gegl_buffer_clear
+
+-- | Clear the whole drawing area
+clear :: G.GeglBuffer -> Affection us ()
+clear buffer = do
+  ad <- get
+  SDL.V2 (CInt rw) (CInt rh) <- SDL.surfaceDimensions $ drawSurface ad
+  let (w, h) = (fromIntegral rw, fromIntegral rh)
+  liftIO $ clearArea buffer (GeglRectangle 0 0 w h)
diff --git a/src/Affection/MouseInteractable.hs b/src/Affection/MouseInteractable.hs
--- a/src/Affection/MouseInteractable.hs
+++ b/src/Affection/MouseInteractable.hs
@@ -18,3 +18,25 @@
     -> SDL.InputMotion -- The 'SDL.InputMotion' of the click
     -> Int             -- The number of clicks
     -> Affection us ()
+
+-- | A helper function that checks wether provided clickables have been clicked.
+-- This function does not consume provided events, but passes them on.
+handleMouseClicks
+  :: (Foldable t, MouseClickable clickable us)
+  => SDL.Event                    -- ^ Piped event in
+  -> t clickable                  -- ^ 'MouseClickable' elemt to be checked
+  -> Affection us SDL.Event       -- ^ Unaltered event
+handleMouseClicks e clickables =
+  case SDL.eventPayload e of
+    SDL.MouseButtonEvent dat -> do
+      mapM_ (\clickable -> do
+        let SDL.P (SDL.V2 x y) = SDL.mouseButtonEventPos dat
+        onClick
+          clickable
+          (SDL.mouseButtonEventButton dat)
+          (fromIntegral x, fromIntegral y)
+          (SDL.mouseButtonEventMotion dat)
+          (fromIntegral $ SDL.mouseButtonEventClicks dat)
+        ) clickables
+      return e
+    _ -> return e
diff --git a/src/Affection/Particle.hs b/src/Affection/Particle.hs
--- a/src/Affection/Particle.hs
+++ b/src/Affection/Particle.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE BangPatterns #-}
 
 -- | This module introduces a simple particle system to Affection
@@ -6,6 +5,7 @@
   ( updateParticle
   , drawParticles
   , updateParticleSystem
+  , drawParticleSystem
   , insertParticle
   ) where
 
@@ -13,6 +13,7 @@
 
 import Control.Monad
 import Control.Monad.State (get)
+import qualified Control.Monad.Parallel as MP
 
 import Data.Maybe
 
@@ -25,42 +26,48 @@
 -- bother you.
 updateParticle
   :: Double
-    -- ^ Elapsed time in seconds
-  -> (Double -> Particle -> Affection us Particle) 
-    -- ^ Update function for a single 'Particle'
-    -- This Function should take the elapsed time
-    -- in seconds and the initial particle as arguments.
-  -- -> [Maybe Particle]
-  -> Particle
-    -- ^ 'Particle' to be processed
-  -- -> Affection us [Maybe Particle]
-  -> Affection us (Maybe Particle)
-    -- ^ resulting 'Particle'
-updateParticle time funct pa =
-  do
-    now <- elapsedTime <$> get
-    if particleCreation pa + particleTimeToLive pa < now
-    then do
+        -- ^ Elapsed time in seconds
+  -> (Double -> Particle -> Affection us Particle)
+        -- ^ Update function for each 'Particle'
+  -> [Particle]
+        -- ^ List of 'Particle's to be processed
+  -> Affection us [Particle]
+        -- ^ processed 'Particle's
+updateParticle time func l =
+  updateParticle' time func l
+  where
+    updateParticle' _  _   []     = return []
+    updateParticle' dt fun [p]    = do
+      now <- elapsedTime <$> get
+      if particleCreation p + particleTimeToLive p < now
+      then do
+        dropParticle p
+        return []
+      else
+        (: []) <$> func time p
+    updateParticle' dt fun (p:ps) = do
+      now <- elapsedTime <$> get
+      if particleCreation p + particleTimeToLive p < now
+      then do
+        dropParticle p
+        updateParticle' dt fun ps
+      else do
+        np <- fun dt p
+        (np :) <$> updateParticle' dt fun ps
+    dropParticle p = do
       mproducer <- liftIO $ G.gegl_node_get_producer
-        (particleStackCont pa)
+        (particleStackCont p)
         "input"
-      case mproducer of
-        Just (producer, padname) -> do
-          consumers <- liftIO $ G.gegl_node_get_consumers
-            (particleStackCont pa)
-            "output"
-          liftIO $ mapM_ (\(node, inpad)-> G.gegl_node_connect_to
-            producer
-            padname
-            node
-            inpad
-            ) consumers
-        Nothing -> return ()
-      liftIO $ G.gegl_node_drop $ particleRootNode pa
-      return $ Nothing
-    else do
-      np <- Just <$> funct time pa
-      return $ np
+      maybe (return ()) (\(producer, padname) -> do
+        consumers <- liftIO $ G.gegl_node_get_consumers
+          (particleStackCont p)
+          "output"
+        liftIO $ mapM_ (uncurry $ G.gegl_node_connect_to
+          producer
+          padname
+          ) consumers
+        ) mproducer
+      liftIO $ G.gegl_node_drop $ particleRootNode p
 
 -- | Get the next living particle from a list
 nextLiving
@@ -69,10 +76,7 @@
 nextLiving [] = Nothing
 nextLiving acc = case catMaybes acc of
   [] -> Nothing
-  ps -> Just $ head $ ps
-  -- if isNothing p
-  -- then nextLiving ps
-  -- else p
+  ps -> Just $ head ps
 
 drawParticles
   :: (Particle -> Affection us ())
@@ -84,25 +88,17 @@
   :: ParticleSystem
   -> Double
   -> (Double -> Particle -> Affection us Particle)
-  -> (G.GeglBuffer -> G.GeglNode -> Particle -> Affection us ())
   -> Affection us ParticleSystem
-updateParticleSystem sys sec upd draw = do
-  !x <- catMaybes <$> mapM (updateParticle sec upd) (partStorList $ partSysParts sys)
-  -- liftIO $ traceIO $ show $ length x
-  -- x <- catMaybes <$> foldM (updateParticle sec upd) [] (reverse $ psParts sys)
-  if (not $ null x)
+updateParticleSystem sys sec upd = do
+  !x <- updateParticle sec upd (partStorList $ partSysParts sys)
+  if not $ null x
     then do
-      -- liftIO $ G.gegl_node_link_many $ map particleStackCont (partStorList $ partSysParts sys)
-      -- liftIO $ traceIO "linking last node to output"
-      liftIO $ G.gegl_node_link (particleStackCont $ head x) (partSysNode sys)
-      mapM_ (draw (partSysBuffer sys) (partSysNode sys)) x
       return sys
         { partSysParts = (partSysParts sys)
           { partStorList = x
           }
         }
     else do
-      _ <- liftIO $ G.gegl_node_disconnect (partSysNode sys) "input"
       return sys
         { partSysParts = ParticleStorage
           { partStorList = []
@@ -110,6 +106,21 @@
           }
         }
 
+drawParticleSystem
+  :: ParticleSystem
+  -> (G.GeglBuffer -> G.GeglNode -> Particle -> Affection us ())
+  -> Affection us ()
+drawParticleSystem sys draw =
+  if not (null parts)
+    then do
+      liftIO $ G.gegl_node_link (particleStackCont $ head parts) (partSysNode sys)
+      MP.mapM_ (draw (partSysBuffer sys) (partSysNode sys)) parts
+    else do
+      _ <- liftIO $ G.gegl_node_disconnect (partSysNode sys) "input"
+      return ()
+  where
+    parts = partStorList (partSysParts sys)
+
 -- | Function for inserting a new 'Particle' into its 'PartileSystem'
 insertParticle
   :: ParticleSystem -- ^ 'ParticleSystem' to insert into
@@ -119,11 +130,7 @@
   now <- elapsedTime <$> get
   let newList = chronoInsert now (partStorList $ partSysParts ps) p
   liftIO $ G.gegl_node_link_many (reverse $ map particleStackCont newList)
-  -- when (not $ isNothing $ partStorLatest $ partSysParts ps) $ 
-  --   liftIO $ G.gegl_node_link
-  --     (particleStackCont p)
-  --     (particleStackCont $ fromJust $ partStorLatest $ partSysParts ps)
-  return $ ps
+  return ps
     { partSysParts = (partSysParts ps)
       { partStorLatest = Just p
       , partStorList   = newList
diff --git a/src/Affection/Property.hs b/src/Affection/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Affection/Property.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+module Affection.Property 
+  ( Props
+  , prop
+  , props
+  ) where
+
+import qualified GEGL as G
+import qualified BABL as B
+
+import Control.Monad.State.Lazy
+import Foreign.Ptr (Ptr)
+
+type Props a = State [G.Property] a
+
+props :: Props a -> [G.Property]
+props = flip execState []
+
+prop :: IsPropertyValue v => String -> v -> Props ()
+prop k v = do
+  ps <- get
+  put $ G.Property k (toPropertyValue v) : ps
+
+class IsPropertyValue v where
+  toPropertyValue :: v -> G.PropertyValue
+
+instance IsPropertyValue Int where
+  toPropertyValue = G.PropertyInt
+
+instance IsPropertyValue String where
+  toPropertyValue = G.PropertyString
+
+instance IsPropertyValue Double where
+  toPropertyValue = G.PropertyDouble
+
+instance IsPropertyValue G.Color where
+  toPropertyValue = G.PropertyColor
+
+instance IsPropertyValue B.PixelFormat where
+  toPropertyValue = G.PropertyFormat
+instance IsPropertyValue G.GeglBuffer where
+  toPropertyValue = G.PropertyBuffer
+
+instance IsPropertyValue (Ptr ()) where
+  toPropertyValue = G.PropertyPointer
diff --git a/src/Affection/Types.hs b/src/Affection/Types.hs
--- a/src/Affection/Types.hs
+++ b/src/Affection/Types.hs
@@ -40,6 +40,7 @@
 
 import Control.Monad.IO.Class
 import Control.Monad.State
+import qualified Control.Monad.Parallel as MP
 -- import Control.Monad.Reader
 
 -- import Control.Concurrent.MVar
@@ -56,10 +57,12 @@
       -- ^ Window configuration
   , preLoop        :: Affection us ()
       -- ^ Actions to be performed, before loop starts
+  , eventLoop     :: SDL.EventPayload -> Affection us ()
+      -- ^ Main update function. Takes fractions of a second as input.
+  , updateLoop     :: Affection us ()
+      -- ^ Main update function. Takes fractions of a second as input.
   , drawLoop       :: Affection us ()
       -- ^ Function for updating graphics.
-  , updateLoop     :: Double -> [SDL.Event] -> Affection us ()
-      -- ^ Main update function. Takes fractions of a second as input.
   , loadState      :: SDL.Surface -> IO us
       -- ^ Provide your own load function to create this data.
   , cleanUp        :: us -> IO ()
@@ -86,6 +89,7 @@
   , drawStride      :: Int                -- ^ Stride of target buffer
   , drawCPP         :: Int                -- ^ Number of components per pixel
   , elapsedTime     :: Double             -- ^ Elapsed time in seconds
+  , dt              :: Double             -- ^ Elapsed time in seconds since last tick
   }
 
 -- | This datatype stores information about areas of a 'G.GeglBuffer' to be updated
@@ -110,6 +114,8 @@
 newtype AffectionState us m a = AffectionState
   { runState :: AffectionStateInner us m a }
   deriving (Functor, Applicative, Monad, MonadIO, MonadState us)
+
+instance MP.MonadParallel m => MP.MonadParallel (AffectionState us m)
 
 type Affection us a = AffectionState (AffectionData us) IO a
 
