diff --git a/glapp.cabal b/glapp.cabal
--- a/glapp.cabal
+++ b/glapp.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.1.0.0
+version:             0.1.0.1
 
 -- A short (one-line) description of the package.
 synopsis:            An OpenGL micro framework.
@@ -56,17 +56,30 @@
     type: git
     location: https://github.com/schell/glapp
 
-
 library
+  -- Modules exported by the library.
+  exposed-modules:     Main, Data.Glapp, Data.Glapp.Internal, Data.Glapp.Types, Example.Editor
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- LANGUAGE extensions used by modules in this package.
+  other-extensions:    TemplateHaskell
+
+  -- Other library packages from which modules are imported.
+  build-depends:       base         >=4.7   && <4.8,
+                       GLFW-b       >=1.4   && <1.5,
+                       OpenGL       >=2.9   && <2.10,
+                       mtl          >=2.1   && <2.2,
+                       lens         >=4.0   && <4.1,
+                       containers   >=0.5   && <0.6
+
+  -- Directories containing source files.
   hs-source-dirs:      src
-  exposed-modules:     Data.Glapp
+
+  -- Base language which the package is written in.
   default-language:    Haskell2010
-  build-depends:       base         >=4.7       && <4.8,
-                       OpenGL       >=2.9.1.0   && <2.10,
-                       lens         >=4.0       && <4.1,
-                       GLFW-b       >=1.4.6     && <1.5,
-                       mtl          >=2.1.2     && <2.2,
-                       containers   >=0.5.3.1   && <0.6
+
 
 
 executable example
diff --git a/src/Data/Glapp/Internal.hs b/src/Data/Glapp/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Glapp/Internal.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Data.Glapp.Internal where
+
+import Graphics.UI.GLFW
+import Graphics.Rendering.OpenGL
+import Control.Monad
+import Control.Monad.State
+import Control.Concurrent
+import Control.Lens
+import Data.Maybe
+import Data.Glapp.Types
+import qualified Data.Set as S
+
+
+data AppWindow a = AppWindow { _appWindowId       :: Id
+                             , _appWindow         :: Window
+                             , _appUserWindowMVar :: MVar (UserWindow a)
+                             } deriving (Eq)
+makeLenses ''AppWindow
+
+
+instance Ord (AppWindow a) where
+    compare (AppWindow a _ _) (AppWindow b _ _) = compare a b
+
+
+data App a b = App { _userApp      :: UserApp a b
+                   , _windows      :: S.Set (AppWindow b)
+                   , _nextWindowId :: Id
+                   }
+makeLenses ''App
+
diff --git a/src/Data/Glapp/Types.hs b/src/Data/Glapp/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Glapp/Types.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Data.Glapp.Types where
+
+import Graphics.UI.GLFW
+import Control.Monad
+import Control.Monad.State
+import Control.Concurrent
+import Control.Lens
+import Data.Maybe
+
+
+data Id = Id { _unId :: Int } deriving (Show, Eq, Ord)
+
+instance Enum Id where
+    toEnum = Id
+    fromEnum = _unId
+
+
+data InputEvent = CharEvent Char
+                | WindowSizeEvent Int Int
+                | KeyEvent Key Int KeyState ModifierKeys
+                | MouseButtonEvent MouseButton MouseButtonState ModifierKeys
+                | CursorMoveEvent Double Double
+                | CursorEnterEvent CursorState
+                | ScrollEvent Double Double
+
+
+data UserWindow a = UserWindow { _windowData :: a
+                               --, _windowShouldClose :: a -> Bool
+                               , _windowRender :: a -> IO ()
+                               , _windowStep :: a -> IO a
+                               , _windowInput :: a -> InputEvent -> a
+                               }
+makeLenses ''UserWindow
+
+
+type UserWindowId a = (Id, UserWindow a)
+
+
+data UserWindowConfig = UserWindowConfig { _windowSize  :: (Int, Int)
+                                         , _windowPos   :: (Int, Int)
+                                         , _windowTitle :: String
+                                         } deriving (Show, Eq, Ord)
+
+
+type NewWindow a = (UserWindowConfig, UserWindow a)
+
+
+data UserApp a b = UserApp { _userAppData       :: a
+                           , _userAppShouldQuit :: a -> Bool
+                           , _userAppStep       :: a -> [UserWindow b] -> IO a
+                           , _userAppNewWindows :: a -> [NewWindow b]
+                           }
+makeLenses ''UserApp
+
diff --git a/src/Example/Editor.hs b/src/Example/Editor.hs
new file mode 100644
--- /dev/null
+++ b/src/Example/Editor.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Example.Editor where
+
+import Graphics.UI.GLFW
+import Graphics.Rendering.OpenGL
+import Control.Monad
+import Control.Monad.State
+import Control.Concurrent
+import Control.Lens
+import Data.Maybe
+import System.Exit
+import qualified Data.Set as S
+import Data.Glapp
+
+
+data Editor = Editor { _editorWindowCount :: Int
+                     , _editorKeys        :: S.Set Key
+                     } deriving (Show)
+makeLenses ''Editor
+
+
+data EditorWindow = EditorWindow { _windowKeys :: S.Set Key
+                                 , _windowBuffer :: String
+                                 } deriving (Show, Eq, Ord)
+makeLenses ''EditorWindow
+
+
+myWindowInput :: EditorWindow -> InputEvent -> EditorWindow
+myWindowInput (EditorWindow keys buff) (CharEvent c) = EditorWindow keys $ c:buff
+myWindowInput (EditorWindow keys buff) (KeyEvent k _ ks mod)
+    | ks == KeyState'Pressed = EditorWindow (S.insert k keys) buff
+    | ks == KeyState'Released = EditorWindow (S.delete k keys) buff
+myWindowInput s _ = s
+
+
+myWindowRender :: EditorWindow -> IO ()
+myWindowRender = const $ return ()
+
+
+myWindowStep :: EditorWindow -> IO EditorWindow
+myWindowStep = return
+
+
+myWindow :: UserWindow EditorWindow
+myWindow = UserWindow { _windowData = EditorWindow S.empty ""
+                      , _windowRender = myWindowRender
+                      , _windowInput = myWindowInput
+                      , _windowStep = myWindowStep
+                      }
+
+
+myAppStep :: Editor -> [UserWindow EditorWindow] -> IO Editor
+myAppStep e ws = do
+    print e
+    return $ flip execState e $ do
+        -- Gather all the keys down on the windows.
+        editorKeys .= foldl (\acc w -> acc `S.union` (w^.windowData.windowKeys)) S.empty ws
+        -- Update the window count to the number of user windows.
+        editorWindowCount .= length ws
+
+
+myNewWindows :: Editor -> [NewWindow EditorWindow]
+myNewWindows (Editor 0 _) = [(UserWindowConfig (800,800) (100,100) "Editor0", myWindow)]
+myNewWindows (Editor i keys) =
+    if S.fromList [Key'LeftSuper,Key'N] `S.isSubsetOf` keys
+      then [(UserWindowConfig (800,800) (100,100) ("Editor" ++ show i), myWindow)]
+      else []
+myNewWindows _ = []
+
+
+shouldMyAppQuit :: Editor -> Bool
+shouldMyAppQuit (Editor 0 _) = True
+shouldMyAppQuit _ = False
+
+
+myApp :: UserApp Editor EditorWindow
+myApp = UserApp { _userAppData = Editor 0 S.empty
+                , _userAppStep = myAppStep
+                , _userAppShouldQuit = shouldMyAppQuit
+                , _userAppNewWindows = myNewWindows
+                }
+
+
