diff --git a/Graphics/Gloss.hs b/Graphics/Gloss.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss.hs
@@ -0,0 +1,40 @@
+
+-- | Gloss hides the pain of drawing simple vector graphics behind a nice data type and
+--	a few display functions. 
+--
+--   Getting something on the screen is as easy as:
+--
+--  @
+--    import Graphics.Gloss
+--    main = `displayInWindow` \"My Window\" (200, 200) (10, 10) `white` (`Circle` 80)
+--  @
+--
+--   Once the window is open you can use the following:
+--
+-- 	* Quit - esc-key.
+--
+--	* Move Viewport - left-click drag, arrow keys.
+--
+--	* Rotate Viewport - right-click drag, control-left-click drag, or home\/end-keys.
+--
+--	* Zoom Viewport - mouse wheel, or page up\/down-keys.
+--
+--   Animations and simulations can be constructed similarly using the `animateInWindow` 
+--   and `simulateInWindow` functions. 
+--
+--   Gloss uses OpenGL under the hood, but you don't have to worry about any of that.
+--
+module Graphics.Gloss 
+	( module Graphics.Gloss.Picture
+	, module Graphics.Gloss.Color
+	, module Graphics.Gloss.ViewPort
+	, displayInWindow 
+	, animateInWindow
+	, simulateInWindow)
+where
+import Graphics.Gloss.Picture
+import Graphics.Gloss.Color
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Internals.Interface.Display	(displayInWindow)
+import Graphics.Gloss.Internals.Interface.Animate	(animateInWindow)
+import Graphics.Gloss.Internals.Interface.Simulate	(simulateInWindow)
diff --git a/Graphics/Gloss/Color.hs b/Graphics/Gloss/Color.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Color.hs
@@ -0,0 +1,184 @@
+
+-- | Predefined and custom colors.
+module Graphics.Gloss.Color
+	( 
+	-- ** Color data type
+	  Color
+	, makeColor
+	, makeColor8
+	, rgbaOfColor
+
+	-- ** Color functions
+	, mixColors
+	, addColors
+	, dim,   bright
+	, light, dark
+
+	-- ** Pre-defined colors
+	, greyN,  black,  white
+	-- *** Primary
+	, red,    green,  blue
+	-- *** Secondary
+	, yellow,     cyan,       magenta
+	
+	-- *** Tertiary
+	, rose,   violet, azure, aquamarine, chartreuse, orange
+	)
+where
+
+import qualified Graphics.Rendering.OpenGL.GL	as GL
+
+-- | An abstract color value.
+--	We keep the type abstract so we can be sure that the components
+--	are in the required range. To make a custom color use 'makeColor'.
+data Color
+	-- | Holds the color components. All components lie in the range [0..1.
+	= RGBA  Float Float Float Float
+	deriving (Show, Eq)
+
+
+-- | Make a custom color. All components are clamped to the range  [0..1].
+makeColor 
+	:: Float 	-- ^ Red component.
+	-> Float 	-- ^ Green component.
+	-> Float 	-- ^ Blue component.
+	-> Float 	-- ^ Alpha component.
+	-> Color
+
+makeColor r g b a
+	= clampColor 
+	$ RGBA r g b a
+
+
+-- | Make a custom color. All components are clamped to the range [0..255].
+makeColor8 
+	:: Int 		-- ^ Red component.
+	-> Int 		-- ^ Green component.
+	-> Int 		-- ^ Blue component.
+	-> Int 		-- ^ Alpha component.
+	-> Color
+
+makeColor8 r g b a
+	= clampColor 
+	$ RGBA 	(fromIntegral r / 255) 
+		(fromIntegral g / 255)
+		(fromIntegral b / 255)
+		(fromIntegral a / 255)
+
+	
+-- | Take the RGBA components of a color.
+rgbaOfColor :: Color -> (Float, Float, Float, Float)
+rgbaOfColor (RGBA r g b a)	= (r, g, b, a)
+		
+
+-- Internal 
+
+-- | Clamp components of a color into the required range.
+clampColor :: Color -> Color
+clampColor cc
+ = let	(r, g, b, a)	= rgbaOfColor cc
+   in	RGBA (min 1 r) (min 1 g) (min 1 b) (min 1 a)
+
+-- | Normalise a color to the value of its largest RGB component.
+normaliseColor :: Color -> Color
+normaliseColor cc
+ = let	(r, g, b, a)	= rgbaOfColor cc
+	m		= maximum [r, g, b]
+   in	RGBA (r / m) (g / m) (b / m) a
+
+
+-- Color functions ------------------------------------------------------------
+
+-- | Mix two colors with the given ratios.
+mixColors 
+	:: Float 	-- ^ Ratio of first color.
+	-> Float 	-- ^ Ratio of second color.
+	-> Color 	-- ^ First color.
+	-> Color 	-- ^ Second color.
+	-> Color	-- ^ Resulting color.
+
+mixColors ratio1 ratio2 c1 c2
+ = let	RGBA r1 g1 b1 a1	= c1
+	RGBA r2 g2 b2 a2	= c2
+
+	total	= ratio1 + ratio2
+	m1	= ratio1 / total
+	m2	= ratio2 / total
+
+   in	RGBA 	(m1 * r1 + m2 * r2)
+		(m1 * g1 + m2 * g2)
+		(m1 * b1 + m2 * b2)
+		(m1 * a1 + m2 * a2)
+
+
+-- | Add RGB components of a color component-wise, then normalise
+--	them to the highest resulting one. The alpha components are averaged.
+addColors :: Color -> Color -> Color
+addColors c1 c2
+ = let	RGBA r1 g1 b1 a1	= c1
+	RGBA r2 g2 b2 a2	= c2
+
+   in	normaliseColor 
+	 $ RGBA (r1 + r2)
+		(g1 + g2)
+		(b1 + b2)
+		((a1 + a2) / 2)
+
+
+-- | Make a dimmer version of a color, scaling towards black.
+dim :: Color -> Color
+dim (RGBA r g b a)
+	= RGBA (r / 1.2) (g / 1.2) (b / 1.2) a
+
+	
+-- | Make a brighter version of a color, scaling towards white.
+bright :: Color -> Color
+bright (RGBA r g b a)
+	= clampColor
+	$ RGBA (r * 1.2) (g * 1.2) (b * 1.2) a
+
+
+-- | Lighten a color, adding white.
+light :: Color -> Color
+light (RGBA r g b a)
+	= clampColor
+	$ RGBA (r + 0.2) (g + 0.2) (b + 0.2) a
+	
+	
+-- | Darken a color, adding black.
+dark :: Color -> Color
+dark (RGBA r g b a)
+	= clampColor
+	$ RGBA (r - 0.2) (g - 0.2) (b - 0.2) a
+
+
+-- Pre-defined Colors ---------------------------------------------------------
+-- | A greyness of a given magnitude.
+greyN 	:: Float 	-- ^ Range is 0 = black, to 1 = white.
+	-> Color
+greyN n		= RGBA n   n   n   1.0
+
+black, white :: Color
+black		= RGBA 0.0 0.0 0.0 1.0
+white		= RGBA 1.0 1.0 1.0 1.0
+
+-- Colors from the additive color wheel.
+red, green, blue :: Color
+red		= RGBA 1.0 0.0 0.0 1.0
+green		= RGBA 0.0 1.0 0.0 1.0
+blue		= RGBA 0.0 0.0 1.0 1.0
+
+-- secondary
+yellow, cyan, magenta :: Color
+yellow		= addColors red   green
+cyan		= addColors green blue
+magenta		= addColors red   blue
+
+-- tertiary
+rose, violet, azure, aquamarine, chartreuse, orange :: Color
+rose		= addColors red     magenta
+violet		= addColors magenta blue
+azure		= addColors blue    cyan
+aquamarine	= addColors cyan    green
+chartreuse	= addColors green   yellow
+orange		= addColors yellow  red
diff --git a/Graphics/Gloss/Geometry.hs b/Graphics/Gloss/Geometry.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Geometry.hs
@@ -0,0 +1,10 @@
+
+module Graphics.Gloss.Geometry
+	( module Graphics.Gloss.Geometry.Angle
+	, module Graphics.Gloss.Geometry.Vector
+	, module Graphics.Gloss.Geometry.Line )
+where
+import Graphics.Gloss.Geometry.Angle
+import Graphics.Gloss.Geometry.Vector
+import Graphics.Gloss.Geometry.Line
+	
diff --git a/Graphics/Gloss/Geometry/Angle.hs b/Graphics/Gloss/Geometry/Angle.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Geometry/Angle.hs
@@ -0,0 +1,32 @@
+
+-- | Geometric functions concerning angles. If not otherwise specified, all angles are in radians.
+module Graphics.Gloss.Geometry.Angle
+	( degToRad
+	, radToDeg
+	, normaliseAngle )
+where
+
+-- | Convert degrees to radians
+{-# INLINE degToRad #-}
+degToRad :: Float -> Float
+degToRad d	= d * pi / 180
+
+
+-- | Convert radians to degrees
+{-# INLINE radToDeg #-}
+radToDeg :: Float -> Float
+radToDeg r	= r * 180 / pi
+
+
+-- | Normalise an angle to be between 0 and 2*pi radians
+{-# INLINE normaliseAngle #-}
+normaliseAngle :: Float -> Float
+normaliseAngle f
+	| f < 0	
+	= normaliseAngle (f + 2 * pi)
+	
+	| f > 2 * pi
+	= normaliseAngle (f - 2 * pi)
+
+	| otherwise
+	= f
diff --git a/Graphics/Gloss/Geometry/Line.hs b/Graphics/Gloss/Geometry/Line.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Geometry/Line.hs
@@ -0,0 +1,44 @@
+
+-- | Geometric functions concerning lines.
+module Graphics.Gloss.Geometry.Line
+	( closestPointOnLine
+	, closestPointOnLine_param )
+where
+import Graphics.Gloss.Picture	(Point)
+import Graphics.Gloss.Geometry.Vector
+
+-- | 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	= closestPointOnLine_param 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	  return 0
+--	if P4 == P2	  return 1
+--	if P4 is halfway between P1 and P2 then return 0.5
+-- @
+{-# INLINE closestPointOnLine_param #-}
+closestPointOnLine_param 
+	:: Point 	-- ^ `P1`
+	-> Point 	-- ^ `P2`
+	-> Point 	-- ^ `P3`
+	-> Float
+
+closestPointOnLine_param p1 p2 p3
+ 	= (p3 - p1) `dotV` (p2 - p1) 
+ 	/ (p2 - p1) `dotV` (p2 - p1)
diff --git a/Graphics/Gloss/Geometry/Vector.hs b/Graphics/Gloss/Geometry/Vector.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Geometry/Vector.hs
@@ -0,0 +1,94 @@
+{-# OPTIONS -fno-warn-missing-methods #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+-- | Geometric functions concerning vectors.
+module Graphics.Gloss.Geometry.Vector
+	( magV
+	, argV
+	, dotV
+	, detV
+	, mulSV
+	, rotateV
+	, angleVV
+	, normaliseV
+	, unitVectorAtAngle )
+where
+import Graphics.Gloss.Picture		(Vector)
+import Graphics.Gloss.Geometry.Angle
+
+
+-- | Pretend a vector is a number.
+--	Vectors aren't real numbes according to Haskell, because they don't
+--	support the multiply and divide field operators. We can pretend they
+--	are though, and use the (+) and (-) operators as component-wise
+--	addition and subtraction.
+--
+instance Num (Float, Float) where
+	(+) (x1, y1) (x2, y2)	= (x1 + x2, y1 + y2)
+ 	(-) (x1, y1) (x2, y2)	= (x1 - x2, y1 - y2)
+	negate (x, y)		= (negate x, negate y)	
+
+
+-- | The magnitude of a vector.
+magV :: Vector -> Float
+{-# INLINE magV #-}
+magV (x, y) 	
+	= sqrt (x * x + y * y)
+
+-- | The angle of this vector, relative to the +ve x-axis.
+argV :: Vector -> Float
+{-# INLINE argV #-}
+argV (x, y)
+	= normaliseAngle $ atan2 y x
+
+-- | The dot product of two vectors.
+dotV :: Vector -> Vector -> Float
+{-# INLINE dotV #-}
+dotV (x1, x2) (y1, y2)
+	= x1 * y1 + x2 * y2
+
+-- | The determinant of two vectors.
+detV :: Vector -> Vector -> Float
+{-# INLINE detV #-}
+detV (x1, y1) (x2, y2)
+	= x1 * y2 - y1 * x2
+
+-- | Multiply a vector by a scalar.
+mulSV :: Float -> Vector -> Vector
+{-# INLINE mulSV #-}
+mulSV s (x, y)		
+	= (s * x, s * y)
+
+-- | Rotate a vector by an angle (in radians). +ve angle is counter-clockwise.
+rotateV :: Float -> Vector -> Vector
+{-# INLINE rotateV #-}
+rotateV r (x, y)
+ = 	(  x * cos r - y * sin r
+        ,  x * sin r + y * cos r)
+
+
+-- | Compute the inner angle (in radians) between two vectors.
+angleVV :: Vector -> Vector -> Float
+{-# INLINE angleVV #-}
+angleVV p1@(x1, y1) p2@(x2, y2)
+ = let 	m1	= magV p1
+ 	m2	= magV p2
+	d	= p1 `dotV` p2
+	aDiff	= acos $ d / (m1 * m2)
+
+   in	aDiff	
+
+
+-- | Normalise a vector, so it has a magnitude of 1.
+normaliseV :: Vector -> Vector
+{-# INLINE normaliseV #-}
+normaliseV v	= mulSV (1 / magV v) v
+
+
+-- | Produce a unit vector at a given angle relative to the +ve x-axis.
+--	The provided angle is in radians.
+unitVectorAtAngle :: Float -> Vector
+{-# INLINE unitVectorAtAngle #-}
+unitVectorAtAngle r
+	= (cos r, sin r)
+
diff --git a/Graphics/Gloss/Internals/Color.hs b/Graphics/Gloss/Internals/Color.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Color.hs
@@ -0,0 +1,19 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Color where
+
+import Graphics.Gloss.Color
+import qualified Graphics.Rendering.OpenGL.GL		as GL
+
+import Unsafe.Coerce
+
+-- | Convert one of our Colors to OpenGL's representation.
+glColor4OfColor :: Fractional a => Color -> GL.Color4 a
+glColor4OfColor color
+ = case rgbaOfColor color of
+	(r, g, b, a)
+	 -> let	rF	= unsafeCoerce r
+		gF	= unsafeCoerce g
+		bF	= unsafeCoerce b
+		aF	= unsafeCoerce a
+   	    in	GL.Color4 rF gF bF aF
diff --git a/Graphics/Gloss/Internals/Interface/Animate.hs b/Graphics/Gloss/Internals/Interface/Animate.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Animate.hs
@@ -0,0 +1,80 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Animate
+	(animateInWindow)
+where	
+import Graphics.Gloss.Color
+import Graphics.Gloss.Picture
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Internals.Render.Picture
+import Graphics.Gloss.Internals.Render.ViewPort
+import Graphics.Gloss.Internals.Interface.Window
+import Graphics.Gloss.Internals.Interface.Common.Exit
+import Graphics.Gloss.Internals.Interface.ViewPort.KeyMouse
+import Graphics.Gloss.Internals.Interface.ViewPort.Motion
+import Graphics.Gloss.Internals.Interface.ViewPort.Reshape
+import Graphics.Gloss.Internals.Interface.Animate.Timing
+import qualified Graphics.Gloss.Internals.Render.Options			as RO
+import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
+import qualified Graphics.Gloss.Internals.Interface.Animate.State		as AN
+import qualified Graphics.Gloss.Internals.Interface.Callback			as Callback
+
+import qualified Graphics.UI.GLUT				as GLUT
+import Data.IORef
+import Control.Monad
+import System.Mem
+
+-- | Open a new window and display the given animation.
+--
+--   Once the window is open you can use the same commands as with @displayInWindow@.
+--
+animateInWindow
+	:: String		-- ^ Name of the window.
+	-> (Int, Int)		-- ^ Initial size of the window, in pixels.
+	-> (Int, Int)		-- ^ Initial position of the window, in pixels.
+	-> Color		-- ^ Background color.
+	-> (Float -> Picture)	-- ^ Function to produce the next frame of animation. 
+				--	It is passed the time in seconds since the program started.
+	-> IO ()
+
+animateInWindow name size pos backColor frameFun
+ = do	
+	viewSR		<- newIORef viewPortInit
+	viewControlSR	<- newIORef VPC.stateInit
+	renderSR	<- newIORef RO.optionsInit
+	animateSR	<- newIORef AN.stateInit
+
+ 	let displayFun = do
+		-- extract the current time from the state
+  	 	time		<- animateSR `getsIORef` AN.stateAnimateTime
+		let timeS	= (fromIntegral time / 1000)
+
+		-- call the user function to get the animation frame
+		let picture	= frameFun timeS 
+
+		renderS		<- readIORef renderSR
+		viewS		<- readIORef viewSR
+
+		-- render the frame
+		withViewPort
+			viewS
+			(renderPicture renderS viewS picture)
+
+		-- perform GC every frame to try and avoid long pauses
+		performGC
+
+	let callbacks
+	     = 	[ Callback.Display	(animateBegin animateSR)
+		, Callback.Display 	displayFun
+		, Callback.Display	(animateEnd   animateSR)
+		, Callback.Idle		(GLUT.postRedisplay Nothing)
+		, callback_exit () 
+		, callback_viewPort_keyMouse viewSR viewControlSR 
+		, callback_viewPort_motion   viewSR viewControlSR 
+		, callback_viewPort_reshape ]
+
+	createWindow name size pos backColor callbacks
+
+
+getsIORef ref fun
+ = liftM fun $ readIORef ref
diff --git a/Graphics/Gloss/Internals/Interface/Animate/State.hs b/Graphics/Gloss/Internals/Interface/Animate/State.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Animate/State.hs
@@ -0,0 +1,51 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Animate.State
+	( State (..) 
+	, stateInit )
+where
+
+-- | Animation State
+data State
+	= State
+	{
+	-- | Whether the animation is running.
+	  stateAnimate			:: Bool
+
+	-- | Whether this is the first frame of the animation.
+	, stateAnimateStart		:: Bool
+
+	-- | Number of msec the animation has been running for
+	, stateAnimateTime		:: Int
+
+	-- | The time when we entered the display callback for the current frame.
+	, stateDisplayTime		:: Int			
+	, stateDisplayTimeLast		:: Int
+
+	-- | Clamp the minimum time between frames to this value (in msec)
+	--	Most LCD monitors refresh at around 50Hz so setting
+	--	this to < 20msec probably isn't worthwhile.
+	--
+	, stateDisplayTimeClamp		:: Int			
+							
+	-- | The time when the last call to the users render function finished.
+	, stateGateTimeStart		:: Int
+
+	-- | The time when displayInWindow last finished (after sleeping to clamp fps).
+	, stateGateTimeEnd		:: Int 
+	
+	-- | How long it took to draw this frame
+	, stateGateTimeElapsed		:: Int }
+
+
+stateInit
+	= State
+	{ stateAnimate			= True
+	, stateAnimateStart		= True
+	, stateAnimateTime		= 0
+	, stateDisplayTime		= 0
+	, stateDisplayTimeLast		= 0 
+	, stateDisplayTimeClamp		= 20
+	, stateGateTimeStart		= 0
+	, stateGateTimeEnd		= 0 
+	, stateGateTimeElapsed		= 0 }
diff --git a/Graphics/Gloss/Internals/Interface/Animate/Timing.hs b/Graphics/Gloss/Internals/Interface/Animate/Timing.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Animate/Timing.hs
@@ -0,0 +1,81 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | Handles timing of animation.
+--	The main point is that we want to restrict the framerate to something
+--	sensible, instead of just displaying at the machines maximum possible
+--	rate and soaking up 100% cpu. 
+--
+--	We also keep track of the elapsed time since the start of the program,
+--	so we can pass this to the user's animation function.
+-- 
+module Graphics.Gloss.Internals.Interface.Animate.Timing
+	( animateBegin
+	, animateEnd )
+where
+import Graphics.Gloss.Internals.Interface.Animate.State
+import Control.Monad
+import Control.Concurrent
+import Data.IORef
+import qualified Graphics.UI.GLUT			as GLUT
+import qualified Graphics.Rendering.OpenGL.GL		as GL
+import Graphics.UI.GLUT					(($=), get)
+
+
+-- | Handles animation timing details.
+--	Call this function at the start of each frame.
+animateBegin :: IORef State -> IO ()
+animateBegin stateRef
+ = do
+	-- write the current time into the display state
+	displayTime		<- get GLUT.elapsedTime
+	displayTimeLast		<- stateRef `getsIORef` stateDisplayTime
+	let displayTimeElapsed	= displayTime - displayTimeLast
+
+	stateRef `modifyIORef` \s -> s 
+		{ stateDisplayTime	= displayTime 
+		, stateDisplayTimeLast	= displayTimeLast }
+
+{-	putStr 	$  "  displayTime        = " ++ show displayTime 		++ "\n"
+	 	++ "  displayTimeLast    = " ++ show displayTimeLast 		++ "\n"
+		++ "  displayTimeElapsed = " ++ show displayTimeElapsed 	++ "\n"
+-}
+
+	-- increment the animation time
+	animate			<- stateRef `getsIORef` stateAnimate
+	animateTime		<- stateRef `getsIORef` stateAnimateTime
+	animateStart		<- stateRef `getsIORef` stateAnimateStart
+	
+	when (animate && not animateStart)
+	 $ do	stateRef `modifyIORef` \s -> s
+			{ stateAnimateTime	= animateTime + displayTimeElapsed }
+			
+	when animate
+	 $ do	stateRef `modifyIORef` \s -> s
+	 		{ stateAnimateStart	= False }
+
+
+-- | Handles animation timing details.
+--	Call this function at the end of each frame.
+animateEnd :: IORef State -> IO ()
+animateEnd stateRef
+ = do
+	-- timing gate, limits the maximum frame frequency (FPS)
+	timeClamp	<- stateRef `getsIORef` stateDisplayTimeClamp
+
+	gateTimeStart	<- get GLUT.elapsedTime				-- the start of this gate
+	gateTimeEnd	<- stateRef `getsIORef` stateGateTimeEnd	-- end of the previous gate
+	let gateTimeElapsed	
+			= gateTimeStart - gateTimeEnd
+	
+	when (gateTimeElapsed < timeClamp)
+	 $ do	threadDelay ((timeClamp - gateTimeElapsed) * 1000)
+
+	gateTimeFinal	<- get GLUT.elapsedTime
+
+	stateRef `modifyIORef` \s -> s 
+		{ stateGateTimeEnd	= gateTimeFinal 
+		, stateGateTimeElapsed	= gateTimeElapsed }
+
+
+getsIORef ref fun
+ = liftM fun $ readIORef ref
diff --git a/Graphics/Gloss/Internals/Interface/Callback.hs b/Graphics/Gloss/Internals/Interface/Callback.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Callback.hs
@@ -0,0 +1,14 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | Event callbacks.
+module Graphics.Gloss.Internals.Interface.Callback where
+
+import qualified Graphics.UI.GLUT	as GLUT
+
+-- | Holds callback functions.
+data Callback
+	= Display	GLUT.DisplayCallback
+	| KeyMouse	GLUT.KeyboardMouseCallback
+	| Idle		GLUT.IdleCallback
+	| Motion	GLUT.MotionCallback	
+	| Reshape	GLUT.ReshapeCallback
diff --git a/Graphics/Gloss/Internals/Interface/Common/Exit.hs b/Graphics/Gloss/Internals/Interface/Common/Exit.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Common/Exit.hs
@@ -0,0 +1,30 @@
+{-# OPTIONS_HADDOCK hide #-}
+{-# LANGUAGE PatternGuards #-}
+
+-- | Callback for exiting the program.
+module Graphics.Gloss.Internals.Interface.Common.Exit
+	(callback_exit)
+where
+import	Graphics.Gloss.Internals.Interface.Callback
+import	qualified Graphics.UI.GLUT		as GLUT
+import	qualified System.Exit			as System
+
+callback_exit stateRef
+ =	KeyMouse (keyMouse_exit stateRef)
+
+keyMouse_exit
+	stateRef
+	key keyState keyMods
+	pos
+
+	-- exit
+	| key		== GLUT.Char '\27'
+	, keyState	== GLUT.Down
+	= do
+		-- non-freeglut doesn't like this
+		-- GLUT.leaveMainLoop
+		
+		System.exitWith System.ExitSuccess
+
+	| otherwise
+	= return ()
diff --git a/Graphics/Gloss/Internals/Interface/Debug.hs b/Graphics/Gloss/Internals/Interface/Debug.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Debug.hs
@@ -0,0 +1,105 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | Implements functions to dump portions of the GLUT and OpenGL state to stdout. 
+--	Used for debugging.
+module Graphics.Gloss.Internals.Interface.Debug
+	( dumpGlutState
+	, dumpFramebufferState
+	, dumpFragmentState )
+where
+
+import qualified Graphics.Rendering.OpenGL.GL	as GL
+import qualified Graphics.UI.GLUT		as GLUT
+import Graphics.UI.GLUT			(($=), get)
+
+
+-- | Dump the internal state of GLUT
+dumpGlutState :: IO ()
+dumpGlutState 
+ = do
+	wbw		<- get GLUT.windowBorderWidth
+ 	whh		<- get GLUT.windowHeaderHeight
+	rgba		<- get GLUT.rgba
+
+	rgbaBD		<- get GLUT.rgbaBufferDepths
+	colorBD		<- get GLUT.colorBufferDepth
+	depthBD		<- get GLUT.depthBufferDepth
+	accumBD		<- get GLUT.accumBufferDepths
+	stencilBD	<- get GLUT.stencilBufferDepth
+
+	doubleBuffered	<- get GLUT.doubleBuffered
+
+	colorMask	<- get GLUT.colorMask
+	depthMask	<- get GLUT.depthMask
+	
+	putStr	$  "* dumpGlutState\n"
+		++ "  windowBorderWidth  = " ++ show wbw		++ "\n"
+		++ "  windowHeaderHeight = " ++ show whh		++ "\n"
+		++ "  rgba               = " ++ show rgba		++ "\n"
+		++ "  depth      rgba    = " ++ show rgbaBD		++ "\n"
+		++ "             color   = " ++ show colorBD		++ "\n"
+		++ "             depth   = " ++ show depthBD		++ "\n"
+		++ "             accum   = " ++ show accumBD		++ "\n"
+		++ "             stencil = " ++ show stencilBD		++ "\n"
+		++ "  doubleBuffered     = " ++ show doubleBuffered	++ "\n"
+		++ "  mask         color = " ++ show colorMask		++ "\n"
+		++ "               depth = " ++ show depthMask		++ "\n"
+		++ "\n"
+		
+		
+-- | Dump internal state of the OpenGL framebuffer
+dumpFramebufferState :: IO ()
+dumpFramebufferState
+ = do
+ 	auxBuffers	<- get GL.auxBuffers
+	doubleBuffer	<- get GL.doubleBuffer
+	drawBuffer	<- get GL.drawBuffer
+
+	rgbaBits	<- get GL.rgbaBits
+	stencilBits	<- get GL.stencilBits
+	depthBits	<- get GL.depthBits
+	accumBits	<- get GL.accumBits
+	
+	clearColor	<- get GL.clearColor
+	clearStencil	<- get GL.clearStencil
+	clearDepth	<- get GL.clearDepth
+	clearAccum	<- get GL.clearAccum
+	
+	colorMask	<- get GL.colorMask
+	stencilMask	<- get GL.stencilMask
+	depthMask	<- get GL.depthMask
+	
+	putStr	$  "* dumpFramebufferState\n"
+		++ "  auxBuffers         = " ++ show auxBuffers		++ "\n"
+		++ "  doubleBuffer       = " ++ show doubleBuffer	++ "\n"
+		++ "  drawBuffer         = " ++ show drawBuffer		++ "\n"
+		++ "\n"
+		++ "  bits       rgba    = " ++ show rgbaBits		++ "\n"
+		++ "             stencil = " ++ show stencilBits	++ "\n"
+		++ "             depth   = " ++ show depthBits		++ "\n"
+		++ "             accum   = " ++ show accumBits		++ "\n"
+		++ "\n"
+		++ "  clear      color   = " ++ show clearColor		++ "\n"
+		++ "             stencil = " ++ show clearStencil	++ "\n"
+		++ "             depth   = " ++ show clearDepth		++ "\n"
+		++ "             accum   = " ++ show clearAccum		++ "\n"
+		++ "\n"
+		++ "  mask       color   = " ++ show colorMask		++ "\n"
+		++ "             stencil = " ++ show stencilMask	++ "\n"
+		++ "             depth   = " ++ show depthMask		++ "\n"
+		++ "\n"
+		
+
+-- | Dump internal state of the fragment renderer.
+dumpFragmentState :: IO ()
+dumpFragmentState
+ = do
+ 	blend		<- get GL.blend
+	blendEquation	<- get GL.blendEquation
+	blendFunc	<- get GL.blendFunc
+	
+	putStr	$  "* dumpFragmentState\n"
+		++ "  blend              = " ++ show blend		++ "\n"
+		++ "  blend equation     = " ++ show blendEquation	++ "\n"
+		++ "  blend func         = " ++ show blendFunc		++ "\n"
+		++ "\n"
diff --git a/Graphics/Gloss/Internals/Interface/Display.hs b/Graphics/Gloss/Internals/Interface/Display.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Display.hs
@@ -0,0 +1,74 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Display
+	(displayInWindow)
+where	
+import Graphics.Gloss.Color
+import Graphics.Gloss.Picture
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Internals.Render.Picture
+import Graphics.Gloss.Internals.Render.ViewPort
+import Graphics.Gloss.Internals.Interface.Window
+import Graphics.Gloss.Internals.Interface.Common.Exit
+import Graphics.Gloss.Internals.Interface.ViewPort.KeyMouse
+import Graphics.Gloss.Internals.Interface.ViewPort.Motion
+import Graphics.Gloss.Internals.Interface.ViewPort.Reshape
+import qualified Graphics.Gloss.Internals.Render.Options			as RO
+import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
+import qualified Graphics.Gloss.Internals.Interface.Callback			as Callback
+
+import Data.IORef
+import Control.Concurrent
+
+
+-- | Open a new window and display the given picture.
+--
+--   Use the following commands once the window is open:
+--
+-- 	* Quit - esc-key.
+--
+--	* Move Viewport - left-click drag, arrow keys.
+--
+--	* Rotate Viewport - right-click drag, control-left-click drag, or home\/end-keys.
+--
+--	* Zoom Viewport - mouse wheel, or page up\/down-keys.
+--
+displayInWindow
+	:: String	-- ^ Name of the window.
+	-> (Int, Int)	-- ^ Initial size of the window, in pixels.
+	-> (Int, Int)	-- ^ Initial position of the window, in pixels.
+	-> Color	-- ^ Background color.
+	-> Picture	-- ^ The picture to draw.
+	-> IO ()
+
+displayInWindow name size pos background picture
+ =  do
+	viewSR		<- newIORef viewPortInit
+	viewControlSR	<- newIORef VPC.stateInit
+	renderSR	<- newIORef RO.optionsInit
+	
+	let renderFun = do
+		view	<- readIORef viewSR
+		options	<- readIORef renderSR
+	 	withViewPort
+	 		view
+			(renderPicture options view picture)
+
+	let callbacks
+	     =	[ Callback.Display renderFun 
+
+		-- Delay the thread for a bit to give the runtime
+		--	a chance to switch back to the OS.
+		, Callback.Idle	   (threadDelay 1000)
+
+		-- Escape exits the program
+		, callback_exit () 
+		
+		-- Viewport control with mouse
+		, callback_viewPort_keyMouse viewSR viewControlSR 
+		, callback_viewPort_motion   viewSR viewControlSR 
+		, callback_viewPort_reshape ]
+
+	createWindow name size pos background callbacks
+
+
diff --git a/Graphics/Gloss/Internals/Interface/Simulate.hs b/Graphics/Gloss/Internals/Interface/Simulate.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Simulate.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE ExplicitForAll #-}
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Simulate
+	(simulateInWindow)
+where
+import Graphics.Gloss.Color
+import Graphics.Gloss.Picture
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Internals.Render.Picture
+import Graphics.Gloss.Internals.Render.ViewPort
+import Graphics.Gloss.Internals.Interface.Window
+import Graphics.Gloss.Internals.Interface.Common.Exit
+import Graphics.Gloss.Internals.Interface.ViewPort.KeyMouse
+import Graphics.Gloss.Internals.Interface.ViewPort.Motion
+import Graphics.Gloss.Internals.Interface.ViewPort.Reshape
+import Graphics.Gloss.Internals.Interface.Animate.Timing
+import Graphics.Gloss.Internals.Interface.Simulate.Idle
+import qualified Graphics.Gloss.Internals.Interface.Callback			as Callback
+import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
+import qualified Graphics.Gloss.Internals.Interface.Simulate.State		as SM
+import qualified Graphics.Gloss.Internals.Interface.Animate.State		as AN
+import qualified Graphics.Gloss.Internals.Render.Options			as RO
+import qualified Graphics.UI.GLUT						as GLUT
+import Data.IORef
+import System.Mem
+
+-- | Run a finite-time-step simulation in a window. You decide how the world is represented,
+--	how to convert the world to a picture, and how to advance the world for each unit of time. 
+--	This function does the rest.
+--
+--   Once the window is open you can use the same commands as with @displayInWindow@.
+--
+simulateInWindow 
+	:: forall world
+	.  String			-- ^ Name of the window.
+	-> (Int, Int)			-- ^ Initial size of the window, in pixels.
+	-> (Int, Int)			-- ^ Initial position of the window, in pixels.
+	-> Color			-- ^ Background color.
+	-> Int				-- ^ Number of simulation steps to take for each second of real time.
+	-> world 			-- ^ The initial world.
+	-> (world -> Picture)	 	-- ^ A function to convert the world a picture.
+	-> (ViewPort -> Float -> world -> world) -- ^ A function to step the world one iteration. It is passed the 
+						 --	current viewport and the amount of time for this simulation
+						 --     step (in seconds).
+	-> IO ()
+
+simulateInWindow
+	windowName
+	windowSize
+	windowPos
+	backgroundColor
+	simResolution
+	worldStart
+	worldToPicture
+	worldAdvance
+ = do
+	let singleStepTime	= 1
+
+	-- make the simulation state
+	stateSR		<- newIORef $ SM.stateInit simResolution
+
+	-- make a reference to the initial world
+	worldSR		<- newIORef worldStart
+
+	-- make the initial GL view and render states
+	viewSR		<- newIORef viewPortInit
+	viewControlSR	<- newIORef VPC.stateInit
+	renderSR	<- newIORef RO.optionsInit
+	animateSR	<- newIORef AN.stateInit
+
+	let displayFun
+	     = do
+		-- convert the world to a picture
+		world		<- readIORef worldSR
+		let picture	= worldToPicture world
+	
+		-- display the picture in the current view
+		renderS		<- readIORef renderSR
+		viewS		<- readIORef viewSR
+
+		-- render the frame
+		withViewPort 
+			viewS
+	 	 	(renderPicture renderS viewS picture)
+ 
+		-- perform garbage collection
+		performGC
+
+	let callbacks
+	     = 	[ Callback.Display	(animateBegin animateSR)
+		, Callback.Display 	displayFun
+		, Callback.Display	(animateEnd   animateSR)
+		, Callback.Idle		(callback_simulate_idle 
+						stateSR animateSR viewSR 
+						worldSR worldStart worldAdvance
+						singleStepTime)
+		, callback_exit () 
+		, callback_viewPort_keyMouse viewSR viewControlSR 
+		, callback_viewPort_motion   viewSR viewControlSR 
+		, callback_viewPort_reshape ]
+
+	createWindow windowName windowSize windowPos backgroundColor callbacks
diff --git a/Graphics/Gloss/Internals/Interface/Simulate/Idle.hs b/Graphics/Gloss/Internals/Interface/Simulate/Idle.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Simulate/Idle.hs
@@ -0,0 +1,149 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Simulate.Idle
+	( callback_simulate_idle )
+where
+import Graphics.Gloss.ViewPort
+import qualified Graphics.Gloss.Internals.Interface.Animate.State	as AN
+import qualified Graphics.Gloss.Internals.Interface.Simulate.State	as SM
+import qualified Graphics.UI.GLUT					as GLUT
+import Graphics.UI.GLUT							(($=), get)
+import Data.IORef
+import Control.Monad
+
+
+-- | The graphics library calls back on this function when it's finished drawing
+--	and it's time to do some computation.
+callback_simulate_idle
+	:: IORef SM.State				-- ^ the simulation state
+	-> IORef AN.State				-- ^ the animation statea
+	-> IORef ViewPort				-- ^ the viewport state
+	-> IORef world					-- ^ the current world
+	-> world					-- ^ the initial world
+	-> (ViewPort -> Float -> world -> world) 	-- ^ fn to advance the world
+	-> Float					-- ^ how much time to advance world by 
+							--	in single step mode
+	-> IO ()
+	
+callback_simulate_idle simSR animateSR viewSR worldSR worldStart worldAdvance singleStepTime
+ = {-# SCC "callbackIdle" #-}
+   do	simS		<- readIORef simSR
+	let result
+		| SM.stateReset simS
+		= simulate_reset simSR worldSR worldStart
+
+		| SM.stateRun   simS
+		= simulate_run   simSR animateSR viewSR worldSR worldAdvance
+		
+		| SM.stateStep  simS
+		= simulate_step  simSR viewSR worldSR worldAdvance singleStepTime
+		
+		| otherwise
+		= return ()
+		
+	result
+ 
+
+-- reset the world to 
+simulate_reset simSR worldSR worldStart
+ = do	writeIORef worldSR worldStart
+
+ 	simSR `modifyIORef` \c -> c 	
+		{ SM.stateReset		= False 
+	 	, SM.stateIteration	= 0 
+		, SM.stateSimTime	= 0 }
+	 
+	GLUT.postRedisplay Nothing
+	 
+ 
+-- take the number of steps specified by controlWarp
+simulate_run 
+	:: IORef SM.State
+	-> IORef AN.State
+	-> IORef ViewPort
+	-> IORef world
+	-> (ViewPort -> Float -> world -> world)
+	-> IO ()
+	
+simulate_run simSR animateSR viewSR worldSR worldAdvance
+ = do	
+	simS		<- readIORef simSR
+	viewS		<- readIORef viewSR
+	worldS		<- readIORef worldSR
+
+	-- get the elapsed time since the start simulation (wall clock)
+ 	elapsedTime_msec	<- get GLUT.elapsedTime
+	let elapsedTime		= fromIntegral elapsedTime_msec / 1000
+
+	-- get how far along the simulation is
+	simTime			<- simSR `getsIORef` SM.stateSimTime
+ 
+ 	-- we want to simulate this much extra time to bring the simulation
+	--	up to the wall clock.
+	let thisTime	= elapsedTime - simTime
+	 
+	-- work out how many steps of simulation this equals
+	resolution	<- simSR `getsIORef` SM.stateResolution
+	let timePerStep	= 1 / fromIntegral resolution
+	let thisSteps_	= truncate $ fromIntegral resolution * thisTime
+	let thisSteps	= if thisSteps_ < 0 then 0 else thisSteps_
+
+	let newSimTime	= simTime + fromIntegral thisSteps * timePerStep
+	 
+{-	putStr	$  "elapsed time    = " ++ show elapsedTime 	++ "\n"
+		++ "sim time        = " ++ show simTime		++ "\n"
+		++ "this time       = " ++ show thisTime	++ "\n"
+		++ "this steps      = " ++ show thisSteps	++ "\n"
+		++ "new sim time    = " ++ show newSimTime	++ "\n"
+		++ "taking          = " ++ show thisSteps	++ "\n\n"
+-}
+ 	-- work out the final step number for this display cycle
+	let nStart	= SM.stateIteration simS
+	let nFinal 	= nStart + thisSteps
+
+	-- keep advancing the world until we get to the final iteration number
+	let (_, world')	= 
+		until 	(\(n, w) 	-> n >= nFinal)
+			(\(n, w)	-> (n+1, worldAdvance viewS timePerStep w))
+			(nStart, worldS)
+	
+	-- write the world back into its IORef
+	writeIORef worldSR world'
+
+	-- update the control state
+	simSR `modifyIORef` \c -> c
+		{ SM.stateIteration	= nFinal
+		, SM.stateSimTime	= newSimTime 
+		, SM.stateStepsPerFrame	= fromIntegral thisSteps }
+	
+	-- tell glut we want to draw the window after returning
+	GLUT.postRedisplay Nothing
+
+
+-- take a single step
+simulate_step 
+	:: IORef SM.State
+	-> IORef ViewPort
+	-> IORef world
+	-> (ViewPort -> Float -> world -> world) 
+	-> Float
+	-> IO ()
+
+simulate_step simSR viewSR worldSR worldAdvance singleStepTime
+ = do
+	simS		<- readIORef simSR
+	viewS		<- readIORef viewSR
+	
+ 	world		<- readIORef worldSR
+	let world'	= worldAdvance viewS singleStepTime world
+	
+	writeIORef worldSR world'
+	simSR `modifyIORef` \c -> c 	
+		{ SM.stateIteration 	= SM.stateIteration c + 1 
+	 	, SM.stateStep		= False }
+	 
+	GLUT.postRedisplay Nothing
+
+
+getsIORef ref fun
+ = liftM fun $ readIORef ref
diff --git a/Graphics/Gloss/Internals/Interface/Simulate/State.hs b/Graphics/Gloss/Internals/Interface/Simulate/State.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Simulate/State.hs
@@ -0,0 +1,44 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.Simulate.State
+	( State (..)
+	, stateInit )
+where
+
+-- | Simulation state
+data State	
+ = 	State
+	{ -- | The iteration number we're up to.
+	  stateIteration	:: Integer
+
+	-- | Whether the animation is free-running (or single step)
+	, stateRun		:: Bool
+
+	-- | Signals to callbackIdle to take a single step of the automation.
+	, stateStep		:: Bool
+
+	-- | Signals to callbackIdle to roll-back to the initial world.
+	, stateReset		:: Bool
+		
+	-- | How many simulation setps to take for each second of real time
+	, stateResolution	:: Int 
+	
+	-- | How many seconds worth of simulation we've done so far
+	, stateSimTime		:: Float
+	
+	-- | Record how many steps we've been taking per frame
+	, stateStepsPerFrame 	:: Int  }
+	
+
+-- | Initial control state
+stateInit resolution
+ 	= State
+ 	{ stateIteration		= 0
+	, stateRun			= True
+	, stateStep			= False
+	, stateReset			= False
+	, stateResolution		= resolution 
+	, stateSimTime			= 0 
+	, stateStepsPerFrame		= 0 }
+	
+	
diff --git a/Graphics/Gloss/Internals/Interface/ViewPort/Command.hs b/Graphics/Gloss/Internals/Interface/ViewPort/Command.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/ViewPort/Command.hs
@@ -0,0 +1,101 @@
+{-# OPTIONS_HADDOCK hide #-}
+{-# LANGUAGE PatternGuards #-}
+
+module Graphics.Gloss.Internals.Interface.ViewPort.Command
+	( Command (..)
+	, defaultCommandConfig
+	, isCommand )
+where
+import Data.Map					(Map)
+import qualified Graphics.UI.GLUT		as GLUT
+import qualified Data.Map			as Map
+
+-- | The commands suported by the view controller
+data Command
+	= CRestore
+
+	| CTranslate
+	| CRotate
+
+	-- bump zoom
+	| CBumpZoomOut
+	| CBumpZoomIn
+
+	-- bump translate
+	| CBumpLeft
+	| CBumpRight
+	| CBumpUp
+	| CBumpDown
+
+	-- bump rotate
+	| CBumpClockwise
+	| CBumpCClockwise
+	deriving (Show, Eq, Ord)
+
+
+-- | The default commands
+defaultCommandConfig
+ =	[ (CRestore, 	
+		[ (GLUT.Char 'r', 			Nothing) ])
+
+	, (CTranslate,
+		[ ( GLUT.MouseButton GLUT.LeftButton
+		  , Just (GLUT.Modifiers { GLUT.shift = GLUT.Up, GLUT.ctrl = GLUT.Up, GLUT.alt = GLUT.Up }))
+		])
+	
+	, (CRotate,
+		[ ( GLUT.MouseButton GLUT.RightButton
+		  , Nothing)
+		, ( GLUT.MouseButton GLUT.LeftButton
+		  , Just (GLUT.Modifiers { GLUT.shift = GLUT.Up, GLUT.ctrl = GLUT.Down, GLUT.alt = GLUT.Up }))
+	 	])
+	
+	-- bump zoom
+	, (CBumpZoomOut,	
+		[ (GLUT.MouseButton GLUT.WheelDown,	Nothing)
+		, (GLUT.SpecialKey  GLUT.KeyPageDown,	Nothing) ])
+
+	, (CBumpZoomIn,
+		[ (GLUT.MouseButton GLUT.WheelUp, 	Nothing)
+		, (GLUT.SpecialKey  GLUT.KeyPageUp,	Nothing)] )
+	
+	-- bump translate
+	, (CBumpLeft,
+		[ (GLUT.SpecialKey  GLUT.KeyLeft,	Nothing) ])
+
+	, (CBumpRight,
+		[ (GLUT.SpecialKey  GLUT.KeyRight,	Nothing) ])
+
+	, (CBumpUp,
+		[ (GLUT.SpecialKey  GLUT.KeyUp,		Nothing) ])
+
+	, (CBumpDown,
+		[ (GLUT.SpecialKey  GLUT.KeyDown,	Nothing) ])
+
+	-- bump rotate
+	, (CBumpClockwise,
+		[ (GLUT.SpecialKey  GLUT.KeyHome,	Nothing) ])
+	
+	, (CBumpCClockwise,
+		[ (GLUT.SpecialKey  GLUT.KeyEnd,	Nothing) ])
+
+	]
+
+
+isCommand commands c key keyMods
+	| Just csMatch		<- Map.lookup c commands
+	= or $ map (isCommand2 c key keyMods) csMatch 
+
+	| otherwise
+	= False
+
+isCommand2 c key keyMods cMatch
+	| (keyC, mModsC)	<- cMatch
+	, keyC == key
+	, case mModsC of
+		Nothing		-> True
+		Just modsC 	-> modsC == keyMods
+	= True
+	
+	| otherwise
+	= False
diff --git a/Graphics/Gloss/Internals/Interface/ViewPort/ControlState.hs b/Graphics/Gloss/Internals/Interface/ViewPort/ControlState.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/ViewPort/ControlState.hs
@@ -0,0 +1,46 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.ViewPort.ControlState
+	( State (..)
+	, stateInit )
+where
+import Graphics.Gloss.Internals.Interface.ViewPort.Command
+import qualified Graphics.UI.GLUT		as GLUT
+import qualified Data.Map			as Map
+import Data.Map					(Map)
+
+-- ViewControl State ------------------------------------------------------------------------------
+-- | State for controlling the viewport.
+--	These are used by the viewport control component.
+data State
+	= State {
+	-- | The command list for the viewport controller.
+	--	These can be safely overwridden at any time by deleting / adding entries to the list.
+	--	Entries at the front of the list take precedence.
+	  stateCommands		:: Map Command [(GLUT.Key, Maybe GLUT.Modifiers)]
+
+	-- | How much to scale the world by for each step of the mouse wheel.
+	, stateScaleStep	:: Float	
+							
+	-- | How many degrees to rotate the world by for each pixel of x motion.
+	, stateRotateFactor	:: Float
+
+	-- | During viewport translation,
+	--	where the mouse was clicked on the window.
+	, stateTranslateMark	:: Maybe (Int, Int)	
+
+	-- | During viewport rotation,	
+	--	where the mouse was clicked on the window
+	, stateRotateMark	:: Maybe (Int, Int)
+	}
+
+
+-- | The initial view state.
+stateInit :: State
+stateInit
+	= State
+	{ stateCommands		= Map.fromList defaultCommandConfig
+	, stateScaleStep	= 0.85
+	, stateRotateFactor	= 0.6
+	, stateTranslateMark	= Nothing
+	, stateRotateMark	= Nothing }
diff --git a/Graphics/Gloss/Internals/Interface/ViewPort/KeyMouse.hs b/Graphics/Gloss/Internals/Interface/ViewPort/KeyMouse.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/ViewPort/KeyMouse.hs
@@ -0,0 +1,181 @@
+{-# OPTIONS_HADDOCK hide #-}
+{-# LANGUAGE PatternGuards #-}
+
+module Graphics.Gloss.Internals.Interface.ViewPort.KeyMouse
+	(callback_viewPort_keyMouse)
+where
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Geometry.Angle
+import Graphics.Gloss.Geometry.Vector
+import Graphics.Gloss.Internals.Interface.ViewPort.Command
+import Graphics.Gloss.Internals.Interface.Callback
+import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
+import qualified Graphics.UI.GLUT						as GLUT
+import qualified Graphics.Rendering.OpenGL.GL					as GL
+import Data.IORef
+import Control.Monad
+
+
+-- | Callback to handle keyboard and mouse button events
+--	for controlling the viewport.
+callback_viewPort_keyMouse 
+	:: IORef ViewPort 	-- ^ ref to ViewPort state
+	-> IORef VPC.State 	-- ^ ref to ViewPort Control state
+	-> Callback
+
+callback_viewPort_keyMouse portRef controlRef 
+ 	= KeyMouse (viewPort_keyMouse portRef controlRef)
+
+
+viewPort_keyMouse portRef controlRef key keyState keyMods pos
+ = do	commands	<- controlRef `getsIORef` VPC.stateCommands 
+
+{-	putStr 	$  "keyMouse key      = " ++ show key 		++ "\n"
+		++ "keyMouse keyState = " ++ show keyState	++ "\n"
+		++ "keyMouse keyMods  = " ++ show keyMods 	++ "\n"
+-}
+	viewPort_keyMouse2 commands portRef controlRef key keyState keyMods pos
+	
+viewPort_keyMouse2
+	commands portRef controlRef
+	key keyState keyMods
+	pos
+
+	-- restore viewport
+	| isCommand commands CRestore key keyMods
+	, keyState	== GLUT.Down
+	= do	portRef `modifyIORef` \s -> s 
+			{ viewPortScale		= 1
+			, viewPortTranslate	= (0, 0) 
+			, viewPortRotate	= 0 }
+		GLUT.postRedisplay Nothing
+
+	-- zoom ----------------------------------------
+	-- zoom out
+	| isCommand commands CBumpZoomOut key keyMods
+	, keyState	== GLUT.Down
+	= 	controlZoomOut portRef controlRef
+
+	-- zoom in
+	| isCommand commands CBumpZoomIn key keyMods
+	, keyState	== GLUT.Down
+	= 	controlZoomIn portRef controlRef
+	
+	-- bump -------------------------------------
+	-- bump left
+	| isCommand commands CBumpLeft key keyMods
+	, keyState	== GLUT.Down
+	= 	motionBump portRef controlRef (20, 0)
+
+	-- bump right
+	| isCommand commands CBumpRight key keyMods
+	, keyState	== GLUT.Down
+	= 	motionBump portRef controlRef (-20, 0)
+
+	-- bump up
+	| isCommand commands CBumpUp key keyMods
+	, keyState	== GLUT.Down
+	= 	motionBump portRef controlRef (0, 20)
+
+	-- bump down
+	| isCommand commands CBumpDown key keyMods
+	, keyState	== GLUT.Down
+	= 	motionBump portRef controlRef (0, -20)
+
+	-- bump clockwise
+	| isCommand commands CBumpClockwise key keyMods
+	, keyState	== GLUT.Down
+	= do	portRef `modifyIORef` \s -> s {
+			viewPortRotate
+				= (\r -> r + 5)
+				$ viewPortRotate s }
+		GLUT.postRedisplay Nothing	
+
+	-- bump anti-clockwise
+	| isCommand commands CBumpCClockwise key keyMods
+	, keyState	== GLUT.Down
+	= do	portRef `modifyIORef` \s -> s {
+			viewPortRotate
+				= (\r -> r - 5)
+				$ viewPortRotate s }
+		GLUT.postRedisplay Nothing
+		
+	-- translation --------------------------------------
+	-- start
+	| isCommand commands CTranslate key keyMods
+	, keyState	== GLUT.Down
+	= do	let GL.Position posX posY	= pos
+		controlRef `modifyIORef` \s -> s { 
+			VPC.stateTranslateMark 
+		 		= Just (  fromIntegral posX
+				  	, fromIntegral posY) }
+		GLUT.postRedisplay Nothing
+
+	-- end
+	| isCommand commands CTranslate key keyMods
+	, keyState	== GLUT.Up
+	= do	controlRef `modifyIORef` \s -> s { 
+		 	VPC.stateTranslateMark = Nothing }
+		GLUT.postRedisplay Nothing
+
+	-- rotation  ---------------------------------------
+	-- start
+	| isCommand commands CRotate key keyMods
+	, keyState	== GLUT.Down
+	= do	let GL.Position posX posY	= pos
+		controlRef `modifyIORef` \s -> s { 
+			VPC.stateRotateMark 
+		 		= Just (  fromIntegral posX
+				  	, fromIntegral posY) }
+		GLUT.postRedisplay Nothing
+
+	-- end
+	| isCommand commands CRotate key keyMods
+	, keyState	== GLUT.Up
+	= do	controlRef `modifyIORef` \s -> s { 
+		 	VPC.stateRotateMark = Nothing }
+		GLUT.postRedisplay Nothing
+
+	-- carry on
+	| otherwise
+	= return ()
+
+
+controlZoomIn portRef controlRef
+ = do	scaleStep	<- controlRef `getsIORef` VPC.stateScaleStep
+	portRef `modifyIORef` \s -> s { 
+	 	viewPortScale = viewPortScale s * scaleStep }
+	GLUT.postRedisplay Nothing
+
+
+controlZoomOut portRef controlRef
+ = do	scaleStep	<- controlRef `getsIORef` VPC.stateScaleStep 
+	portRef `modifyIORef` \s -> s {
+	 	viewPortScale = viewPortScale s / scaleStep }
+	GLUT.postRedisplay Nothing
+
+
+motionBump
+	portRef controlRef
+	(bumpX, bumpY)
+ = do
+	(transX, transY)
+		<- portRef `getsIORef` viewPortTranslate
+
+	s	<- portRef `getsIORef` viewPortScale
+	r	<- portRef `getsIORef` viewPortRotate
+
+	let offset	= (bumpX / s, bumpY / s)
+
+	let (oX, oY)	= rotateV (degToRad r) offset
+
+	portRef `modifyIORef` \s -> s 
+		{ viewPortTranslate	
+		   = 	( transX - oX
+		 	, transY + oY) }
+			
+	GLUT.postRedisplay Nothing
+ 
+
+getsIORef ref fun
+ = liftM fun $ readIORef ref
diff --git a/Graphics/Gloss/Internals/Interface/ViewPort/Motion.hs b/Graphics/Gloss/Internals/Interface/ViewPort/Motion.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/ViewPort/Motion.hs
@@ -0,0 +1,104 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.ViewPort.Motion
+	(callback_viewPort_motion)
+where
+import Graphics.Gloss.ViewPort
+import Graphics.Gloss.Geometry.Angle
+import Graphics.Gloss.Geometry.Vector
+import Graphics.Gloss.Internals.Interface.Callback
+import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
+import qualified Graphics.UI.GLUT						as GLUT
+import qualified Graphics.Rendering.OpenGL.GL					as GL
+import Control.Monad	
+import Data.IORef
+
+
+-- | Callback to handle keyboard and mouse button events
+--	for controlling the viewport.
+callback_viewPort_motion 
+	:: IORef ViewPort 	-- ^ ref to ViewPort state
+	-> IORef VPC.State 	-- ^ ref to ViewPort Control state
+	-> Callback
+
+callback_viewPort_motion portRef controlRef 
+ 	= Motion (viewPort_motion portRef controlRef)
+
+viewPort_motion
+	portRef controlRef
+	pos
+ = do
+--	putStr $ "motion pos = " ++ show pos ++ "\n"
+
+	translateMark	<- controlRef `getsIORef` VPC.stateTranslateMark
+	rotateMark	<- controlRef `getsIORef` VPC.stateRotateMark
+
+	(case translateMark of
+	 Nothing		-> return ()
+	 Just (markX, markY)	
+	  -> motionTranslate
+	  	portRef controlRef 
+		(fromIntegral markX, fromIntegral markY) 
+		pos )
+
+
+	(case rotateMark of
+	 Nothing		-> return ()
+	 Just (markX, markY)
+	  -> motionRotate
+	  	portRef controlRef
+		(fromIntegral markX, fromIntegral markY) 
+		pos )
+
+
+motionTranslate 
+	portRef controlRef
+	(markX, markY)
+	(GL.Position posX posY)
+ = do
+	(transX, transY)
+		<- portRef `getsIORef` viewPortTranslate
+
+	s	<- portRef `getsIORef` viewPortScale
+	r	<- portRef `getsIORef` viewPortRotate
+
+	let dX		= fromIntegral $ markX - posX
+	let dY		= fromIntegral $ markY - posY
+
+	let offset	= (dX / s, dY / s)
+
+	let (oX, oY)	= rotateV (degToRad r) offset
+
+	portRef `modifyIORef` \s -> s 
+		{ viewPortTranslate	
+		   = 	( transX - oX
+		 	, transY + oY) }
+		
+	controlRef `modifyIORef` \s -> s
+		{ VPC.stateTranslateMark
+		   =	Just (fromIntegral posX, fromIntegral posY) }
+
+	GLUT.postRedisplay Nothing
+
+
+motionRotate 
+	portRef controlRef
+	(markX, markY)
+	(GL.Position posX posY)
+ = do
+ 	rotate		<- portRef    `getsIORef` viewPortRotate
+	rotateFactor	<- controlRef `getsIORef` VPC.stateRotateFactor
+	
+	portRef `modifyIORef` \s -> s 
+		{ viewPortRotate
+		   = 	rotate + rotateFactor * fromIntegral (posX - markX) }
+		
+	controlRef `modifyIORef` \s -> s
+		{ VPC.stateRotateMark
+		   = 	Just (fromIntegral posX, fromIntegral posY) }
+	
+	GLUT.postRedisplay Nothing
+
+
+getsIORef ref fun
+ = liftM fun $ readIORef ref
diff --git a/Graphics/Gloss/Internals/Interface/ViewPort/Reshape.hs b/Graphics/Gloss/Internals/Interface/ViewPort/Reshape.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/ViewPort/Reshape.hs
@@ -0,0 +1,26 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module Graphics.Gloss.Internals.Interface.ViewPort.Reshape
+	(callback_viewPort_reshape)
+where
+import Graphics.Gloss.Internals.Interface.Callback
+import Graphics.UI.GLUT					(($=), get)
+import qualified Graphics.UI.GLUT			as GLUT
+import qualified Graphics.Rendering.OpenGL.GL		as GL
+
+
+-- | Callback to handle keyboard and mouse button events
+--	for controlling the viewport.
+callback_viewPort_reshape :: Callback
+
+callback_viewPort_reshape
+ 	= Reshape (viewPort_reshape)
+
+viewPort_reshape size
+ = do
+	-- Setup the viewport
+	--	This controls what part of the window openGL renders to.
+	--	We'll use the whole window.
+	--
+ 	GL.viewport 	$= (GL.Position 0 0, size)
+	GLUT.postRedisplay Nothing
diff --git a/Graphics/Gloss/Internals/Interface/Window.hs b/Graphics/Gloss/Internals/Interface/Window.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Interface/Window.hs
@@ -0,0 +1,161 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | 	The main display function.
+module	Graphics.Gloss.Internals.Interface.Window
+	( createWindow )
+where
+
+import Graphics.Gloss.Color
+import Graphics.Gloss.Internals.Color
+import Graphics.Gloss.Internals.Interface.Debug
+import Graphics.Gloss.Internals.Interface.Callback		(Callback)
+import qualified Graphics.Gloss.Internals.Interface.Callback	as Callback
+
+import Graphics.UI.GLUT					(($=), get)
+import qualified Graphics.Rendering.OpenGL.GL		as GL
+import qualified Graphics.UI.GLUT			as GLUT
+
+import Control.Monad
+
+-- | Open a window and use the supplied callbacks to handle window events.
+createWindow	
+	:: String 		-- ^ Name of the window.
+	-> (Int, Int) 		-- ^ Initial size of the window, in pixels.
+	-> (Int, Int)		-- ^ Initial position of the window, in pixels relative to 
+				--	the top left corner of the screen.
+	-> Color		-- ^ Color to use when clearing.
+	-> [Callback]		-- ^ Callbacks to use
+	-> IO ()
+
+createWindow
+	windowName
+	size@(sizeX, sizeY) 
+	pos @(posX,  posY)
+	clearColor
+	callbacks
+ = do
+	-- Turn this on to spew debugging info to stdout
+	let debug	= False
+
+	-- Initialize GLUT
+ 	(progName, args)	<- GLUT.getArgsAndInitialize
+	glutVersion		<- get GLUT.glutVersion
+
+	when debug
+	 $ do 	putStr	$ "* displayInWindow\n"
+	 	putStr	$ "  glutVersion        = " ++ show glutVersion		++ "\n"
+
+	-- Setup and create a new window.
+	--	Be sure to set initialWindow{Position,Size} before calling
+	--	createWindow. If we don't do this we get wierd half-created
+	--	windows some of the time.
+	--
+	GLUT.initialWindowPosition	
+	 $= 	GL.Position		
+	 		(fromIntegral posX)
+			(fromIntegral posY)
+
+	GLUT.initialWindowSize	
+	 $= 	GL.Size 
+			(fromIntegral sizeX) 
+			(fromIntegral sizeY)
+
+	GLUT.initialDisplayMode
+	 $= 	[ GLUT.RGBMode
+		, GLUT.DoubleBuffered]
+
+	-- See if our requested display mode is possible
+	displayMode		<- get GLUT.initialDisplayMode
+	displayModePossible	<- get GLUT.displayModePossible
+	when debug
+	 $ do	putStr	$  "  displayMode        = " ++ show displayMode ++ "\n"
+	 		++ "       possible      = " ++ show displayModePossible ++ "\n"
+			++ "\n"
+		
+	-- Here we go!
+	when debug
+	 $ do	putStr	$ "* creating window\n\n"
+
+	GLUT.createWindow windowName
+	GLUT.windowSize	
+	 $= 	GL.Size 
+			(fromIntegral sizeX)
+			(fromIntegral sizeY)
+	
+	-- Setup callbacks
+	GLUT.displayCallback		$= callbackDisplay clearColor callbacks
+	GLUT.reshapeCallback		$= Just (callbackReshape  	callbacks)
+	GLUT.keyboardMouseCallback	$= Just (callbackKeyMouse 	callbacks)
+	GLUT.motionCallback		$= Just (callbackMotion   	callbacks)
+	GLUT.idleCallback		$= Just (callbackIdle 		callbacks)
+
+	--  Switch some things.
+	--  auto repeat interferes with key up / key down checks.
+	--	BUGS: this doesn't seem to work?
+	GLUT.perWindowKeyRepeat		$= GLUT.PerWindowKeyRepeatOff	
+
+	-- we don't need the depth buffer for 2d.
+	GL.depthFunc	$= Just GL.Always
+
+	-- always clear the buffer to white
+	GL.clearColor	$= glColor4OfColor clearColor
+
+	-- Dump some debugging info
+	when debug
+	 $ do	dumpGlutState
+	 	dumpFramebufferState
+		dumpFragmentState
+
+	---------------
+	-- Call the GLUT mainloop. 
+	--	This function will return when something calls GLUT.leaveMainLoop
+	--
+	--	We can ask for this in freeglut, but it doesn't seem to work :(.
+	--	GLUT.actionOnWindowClose	$= GLUT.MainLoopReturns
+	when debug
+	 $ do	putStr	$ "* entering mainloop..\n"
+	
+	GLUT.mainLoop
+
+	when debug
+	 $	putStr	$ "* all done\n"
+	 
+	return ()
+
+
+callbackDisplay clearColor callbacks
+ = do
+	-- clear the display
+	GL.clear [GL.ColorBuffer, GL.DepthBuffer]
+	GL.color $ GL.Color4 0 0 0 (1 :: GL.GLfloat)
+
+	-- get the display callbacks from the chain
+	let funs	= [f	| (Callback.Display f) <- callbacks]
+	sequence_ funs
+
+	-- swap front and back buffers
+	GLUT.swapBuffers
+	GLUT.reportErrors 
+ 	return ()
+
+
+callbackReshape callbacks size
+ 	= sequence_
+	$ map 	(\f -> f size)
+		[f | Callback.Reshape f 	<- callbacks]
+
+callbackKeyMouse callbacks key keystate modifiers pos
+ 	= sequence_ 
+	$ map 	(\f -> f key keystate modifiers pos) 
+		[f | Callback.KeyMouse f 	<- callbacks]
+
+callbackMotion callbacks pos
+ 	= sequence_
+	$ map	(\f -> f pos)
+		[f | Callback.Motion f 		<- callbacks]
+
+callbackIdle callbacks
+ 	= sequence_
+	$ [f | Callback.Idle f 			<- callbacks]
+	
+	
diff --git a/Graphics/Gloss/Internals/Render/Circle.hs b/Graphics/Gloss/Internals/Render/Circle.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Render/Circle.hs
@@ -0,0 +1,89 @@
+{-# OPTIONS -fglasgow-exts #-}
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | Fast(ish) rendering of circles.
+module Graphics.Gloss.Internals.Render.Circle  where
+
+import 	Graphics.Gloss.Internals.Render.Common
+import	qualified Graphics.Rendering.OpenGL.GL		as GL
+import	GHC.Exts
+import	GHC.Prim
+
+
+-- | Render a circle with the given thickness
+renderCircle :: Float -> Float -> Float -> Float -> Float -> IO ()
+renderCircle posX posY scaleFactor radius thickness
+ 	| radScreen	<- scaleFactor * radius
+	, steps		<- circleSteps (2 * radScreen)
+	= if thickness == 0 
+		then renderCircleLine posX posY steps radius
+		else renderCircleStrip posX posY steps radius thickness
+
+
+-- | Decide how many line segments to use to render the circle
+circleSteps :: Float -> Int
+circleSteps sDiam
+	| sDiam < 1	= 1
+	| sDiam < 2	= 4
+	| sDiam < 10	= 8
+	| sDiam < 20	= 16
+	| sDiam < 30	= 32
+	| otherwise	= 40
+
+
+-- | Render a circle with as a line.
+renderCircleLine :: Float -> Float -> Int -> Float -> IO ()
+renderCircleLine (F# posX) (F# posY) steps (F# rad)
+ = let 	n		= fromIntegral steps
+ 	!(F# tStep)	= (2 * pi) / n
+	!(F# tStop)	= (2 * pi)
+
+   in	GL.renderPrimitive GL.LineLoop
+   		$ renderCircleLine_step posX posY tStep tStop rad 0.0#
+
+renderCircleLine_step :: Float# -> Float# -> Float# -> Float# -> Float# -> Float# -> IO ()
+renderCircleLine_step posX posY tStep tStop rad tt
+	| tt `geFloat#` tStop
+	= return ()
+	
+	| otherwise
+	= do	GL.vertex 
+			$ GL.Vertex2 
+				(gf $ F# (posX `plusFloat#` (rad `timesFloat#` (cosFloat# tt))))
+				(gf $ F# (posY `plusFloat#` (rad `timesFloat#` (sinFloat# tt))))
+
+		renderCircleLine_step posX posY tStep tStop rad (tt `plusFloat#` tStep)
+ 
+
+-- | Render a circle with a given thickness as a triangle strip
+renderCircleStrip :: Float -> Float -> Int -> Float -> Float -> IO ()
+renderCircleStrip (F# posX) (F# posY) steps r width
+ = let	n		= fromIntegral steps
+	!(F# tStep)	= (2 * pi) / n
+	!(F# tStop)	= (2 * pi) + (F# tStep) / 2
+	!(F# r1)	= r - width / 2
+	!(F# r2)	= r + width / 2
+
+   in	GL.renderPrimitive GL.TriangleStrip
+   		$ renderCircleStrip_step posX posY tStep tStop r1 0.0# r2 (tStep `divideFloat#` 2.0#)
+   
+renderCircleStrip_step 
+	:: Float# -> Float# 
+	-> Float# -> Float# 
+	-> Float# -> Float# -> Float# -> Float# -> IO ()
+
+renderCircleStrip_step posX posY tStep tStop r1 t1 r2 t2
+	| t1 `geFloat#` tStop
+	= return ()
+	
+	| otherwise
+	= do	GL.vertex $ GL.Vertex2 
+				(gf $ F# (posX `plusFloat#` (r1 `timesFloat#` (cosFloat# t1)))) 
+				(gf $ F# (posY `plusFloat#` (r1 `timesFloat#` (sinFloat# t1))))
+
+		GL.vertex $ GL.Vertex2 
+				(gf $ F# (posX `plusFloat#` (r2 `timesFloat#` (cosFloat# t2))))
+				(gf $ F# (posY `plusFloat#` (r2 `timesFloat#` (sinFloat# t2))))
+		
+		renderCircleStrip_step posX posY tStep tStop r1 (t1 `plusFloat#` tStep) r2 (t2 `plusFloat#` tStep)
+	
diff --git a/Graphics/Gloss/Internals/Render/Common.hs b/Graphics/Gloss/Internals/Render/Common.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Render/Common.hs
@@ -0,0 +1,16 @@
+{-# OPTIONS_HADDOCK hide #-}
+module Graphics.Gloss.Internals.Render.Common where
+
+import qualified Graphics.Rendering.OpenGL.GL	as GL
+import Unsafe.Coerce
+
+-- | The OpenGL library doesn't seem to provide a nice way convert
+--	a Float to a GLfloat, even though they're the same thing
+--	under the covers.  
+--
+--  Using realToFrac is too slow, as it doesn't get fused in at
+--	least GHC 6.12.1
+--
+gf :: Float -> GL.GLfloat
+{-# INLINE gf #-}
+gf x = unsafeCoerce x
diff --git a/Graphics/Gloss/Internals/Render/Options.hs b/Graphics/Gloss/Internals/Render/Options.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Render/Options.hs
@@ -0,0 +1,34 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+-- | Rendering options
+module Graphics.Gloss.Internals.Render.Options 
+	( Options (..)
+	, optionsInit )
+where
+
+-- | Render options settings
+data Options
+	= Options
+	{ -- | Whether to use color
+	  optionsColor		:: Bool
+
+	  -- | Whether to force wireframe mode only
+	, optionsWireframe	:: Bool
+
+	  -- | Whether to use alpha blending
+	, optionsBlendAlpha	:: Bool
+
+	  -- | Whether to use line smoothing
+	, optionsLineSmooth	:: Bool
+	}
+	
+
+-- | Default render options
+optionsInit
+	= Options
+	{ optionsColor		= True
+	, optionsWireframe	= False
+	, optionsBlendAlpha	= True
+	, optionsLineSmooth	= False }
+	
+
diff --git a/Graphics/Gloss/Internals/Render/Picture.hs b/Graphics/Gloss/Internals/Render/Picture.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Render/Picture.hs
@@ -0,0 +1,175 @@
+{-# OPTIONS -fwarn-incomplete-patterns #-}
+{-# OPTIONS_HADDOCK hide #-}
+{-# LANGUAGE ImplicitParams, ScopedTypeVariables #-}
+
+module Graphics.Gloss.Internals.Render.Picture
+	( renderPicture )
+where
+import	Graphics.Gloss.Picture
+import	Graphics.Gloss.Color
+import	Graphics.Gloss.ViewPort
+import	Graphics.Gloss.Internals.Render.Options
+import	Graphics.Gloss.Internals.Render.Common
+import	Graphics.Gloss.Internals.Render.Circle
+import	Graphics.UI.GLUT						(($=), get)
+import  qualified Graphics.Rendering.OpenGL.GLU.Matrix 			as GLU
+import	qualified Graphics.Rendering.OpenGL.GL				as GL
+import	qualified Graphics.UI.GLUT					as GLUT
+
+import 	Data.IORef
+import	Control.Monad
+
+-- ^ Render a picture using the given render options and viewport.
+renderPicture
+	:: Options 		-- ^ The render options to use
+	-> ViewPort		-- ^ The current viewport.
+	-> Picture 		-- ^ The picture to render.
+	-> IO ()
+
+renderPicture
+	renderS
+	viewS
+	picture
+ = do
+	-- This GL state doesn't change during rendering, 
+	--	so we can just read it once here
+	(matProj_  :: GL.GLmatrix GL.GLdouble)	
+			<- get $ GL.matrix (Just $ GL.Projection)
+	viewport_  	<- get $ GL.viewport
+	windowSize_	<- get GLUT.windowSize
+
+	-- 
+	let ?modeWireframe	= optionsWireframe renderS
+	    ?modeColor		= optionsColor     renderS
+	    ?scale		= viewPortScale    viewS
+	    ?matProj		= matProj_
+	    ?viewport		= viewport_
+	    ?windowSize		= windowSize_
+	
+	-- setup render state for world
+	setLineSmooth	(optionsLineSmooth renderS)
+	setBlendAlpha	(optionsBlendAlpha renderS)
+	
+	drawPicture picture
+	  
+drawPicture picture
+ = {-# SCC "drawComponent" #-}
+   case picture of
+
+	-- nothin'
+	Blank
+	 -> 	return ()
+
+	-- line
+ 	Line path	
+	 -> GL.renderPrimitive GL.LineStrip 
+		$ vertexPFs path
+
+
+	-- polygon (where?)
+	Polygon path
+	 | ?modeWireframe
+	 -> GL.renderPrimitive GL.LineLoop
+	 	$ vertexPFs path
+		
+	 | otherwise
+	 -> GL.renderPrimitive GL.Polygon
+	 	$ vertexPFs path
+
+	-- circle
+	Circle radius
+	 ->  renderCircle 0 0 ?scale radius 0
+	
+	ThickCircle radius thickness
+	 ->  renderCircle 0 0 ?scale radius thickness
+	
+	-- stroke text
+	-- 	text looks wierd when we've got blend on,
+	--	so disable it during the renderString call.
+	Text str 
+	 -> do
+	 	GL.blend	$= GL.Disabled
+		GLUT.renderString GLUT.Roman str
+		GL.blend	$= GL.Enabled
+
+	-- colors with float components.
+	Color color p
+	 |  ?modeColor
+	 ->  {-# SCC "draw.color" #-}
+   	     do
+		oldColor 	 <- get GL.currentColor
+
+		let (r, g, b, a) = rgbaOfColor color
+
+		GL.currentColor	
+			$= GL.Color4 (gf r) (gf g) (gf b) (gf a)
+
+		drawPicture p
+
+		GL.currentColor	$= oldColor		
+
+	 |  otherwise
+	 -> 	drawPicture p
+
+
+	-- ease up on GL.preservingMatrix
+	--	This is an important optimisation for the Eden example,
+	--	as it draws lots of translated circles.
+	Translate posX posY (Circle radius)
+	 -> renderCircle posX posY ?scale radius 0
+
+	Translate posX posY (ThickCircle radius thickness)
+	 -> renderCircle posX posY ?scale radius thickness
+
+	Translate tx ty (Rotate deg p)
+	 -> GL.preservingMatrix
+	     $ do	GL.translate (GL.Vector3 (gf tx) (gf ty) 0)
+			GL.rotate (gf deg) (GL.Vector3 0 0 (-1))
+			drawPicture p
+
+	-----
+	Translate tx ty	p
+	 -> GL.preservingMatrix
+	     $ do	GL.translate (GL.Vector3 (gf tx) (gf ty) 0)
+			drawPicture p
+
+	Rotate deg p
+	 -> GL.preservingMatrix
+	     $ do	GL.rotate (gf deg) (GL.Vector3 0 0 (-1))
+			drawPicture p
+
+	Scale sx sy p
+	 -> GL.preservingMatrix
+	     $ do	GL.scale (gf sx) (gf sy) 1
+			drawPicture p
+			
+	Pictures ps
+	 -> mapM_ drawPicture ps
+	
+
+-- Utils ------------------------------------------------------------------------------------------
+-- | Turn alpha blending on or off
+setBlendAlpha state
+ 	| state	
+ 	= do	GL.blend	$= GL.Enabled
+		GL.blendFunc	$= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
+
+	| otherwise
+ 	= do	GL.blend	$= GL.Disabled
+		GL.blendFunc	$= (GL.One, GL.Zero) 	
+
+-- | Turn line smoothing on or off
+setLineSmooth state
+	| state		= GL.lineSmooth	$= GL.Enabled
+	| otherwise	= GL.lineSmooth $= GL.Disabled
+
+
+vertexPFs ::	[(Float, Float)] -> IO ()
+{-# INLINE vertexPFs #-}
+vertexPFs []	= return ()
+vertexPFs ((x, y) : rest)
+ = do	GL.vertex $ GL.Vertex2 (gf x) (gf y)
+ 	vertexPFs rest
+
+
+
diff --git a/Graphics/Gloss/Internals/Render/ViewPort.hs b/Graphics/Gloss/Internals/Render/ViewPort.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Internals/Render/ViewPort.hs
@@ -0,0 +1,54 @@
+{-# OPTIONS_HADDOCK hide #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- | Handling the current viewport during rendering.
+module Graphics.Gloss.Internals.Render.ViewPort
+	( withViewPort )
+where
+import	Graphics.Gloss.ViewPort
+import	Graphics.Rendering.OpenGL					(GLfloat)
+import 	Graphics.UI.GLUT						(($=), get)
+import	qualified Graphics.UI.GLUT					as GLUT
+import	qualified Graphics.Rendering.OpenGL.GL				as GL
+
+
+-- | Perform a rendering action whilst using the given viewport
+withViewPort
+	:: ViewPort 		-- ^ The viewport to use.
+	-> IO () 		-- ^ The rendering action to perform.
+	-> IO ()
+
+withViewPort port action
+ = do
+ 	GL.matrixMode	$= GL.Projection
+	GL.preservingMatrix
+	 $ do
+		-- setup the co-ordinate system
+	 	GL.loadIdentity
+		size@(GL.Size sizeX sizeY) 
+				<- get GLUT.windowSize
+		let (sx, sy)	= (fromIntegral sizeX / 2, fromIntegral sizeY / 2)
+
+		GL.ortho (-sx) sx (-sy) sy 0 (-100)
+	
+		-- draw the world
+		GL.matrixMode 	$= GL.Modelview 0
+		GL.preservingMatrix
+		 $ do
+			GL.loadIdentity
+			let rotate :: GLfloat	= realToFrac $ viewPortRotate port
+			let transX :: GLfloat	= realToFrac $ fst $ viewPortTranslate port
+			let transY :: GLfloat   = realToFrac $ snd $ viewPortTranslate port
+		 	let scale  :: GLfloat	= realToFrac $ viewPortScale port
+
+			-- apply the global view transforms
+			GL.scale     scale  scale  1
+			GL.rotate    rotate (GL.Vector3 0 0 1)
+			GL.translate (GL.Vector3 transX transY 0)
+
+			-- call the client render action
+			action 
+
+		GL.matrixMode	$= GL.Projection
+	
+	GL.matrixMode	$= GL.Modelview 0
diff --git a/Graphics/Gloss/Picture.hs b/Graphics/Gloss/Picture.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Picture.hs
@@ -0,0 +1,62 @@
+
+-- | Data types for representing pictures.
+module Graphics.Gloss.Picture
+	( Point
+	, Vector
+	, Path
+	, Picture(..))
+where
+
+import Graphics.Gloss.Color
+
+-- | A point on the x-y plane.
+type Point	= (Float, Float)			
+
+-- | A vector can be treated as a point, and vis-versa.
+type Vector	= Point
+
+-- | A path through the x-y plane.
+type Path	= [Point]				
+
+-- | A 2D picture.
+data Picture
+	-- Primitives -------------------------------------
+
+	-- | A blank picture, with nothing in it.
+	= Blank
+
+	-- | A polygon filled with a solid color.
+	| Polygon 	Path
+	
+	-- | A line along an arbitrary path.
+	| Line		Path
+
+	-- | A circle with the given radius.
+	| Circle	Float
+
+	-- | A circle with the given thickness and radius. If the thickness is 0 then this is equivalent to `Circle`.
+	| ThickCircle	Float		Float
+
+	-- | Some text to draw with a vector font.
+	| Text		String
+
+	-- Color ------------------------------------------
+	-- | A picture drawn with this color.
+	| Color		Color  		Picture
+
+	-- Transforms -------------------------------------
+	-- | A picture translated by the given x and y coordinates.
+	| Translate	Float Float	Picture
+
+	-- | A picture rotated by the given angle (in degrees).
+	| Rotate	Float		Picture
+
+	-- | A picture scaled by the given x and y factors.
+	| Scale		Float	Float	Picture
+
+	-- More Pictures ----------------------------------
+
+	-- | A picture consisting of several others.
+	| Pictures	[Picture]
+	deriving (Show, Eq)
+
diff --git a/Graphics/Gloss/Shapes.hs b/Graphics/Gloss/Shapes.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/Shapes.hs
@@ -0,0 +1,77 @@
+
+-- | Functions for drawing shapes that aren't constructors of the `Picture` data type.
+module Graphics.Gloss.Shapes
+	( lineLoop
+	, rectangleWire, 	rectangleSolid, 	rectanglePath
+	, rectangleUpperWire, 	rectangleUpperSolid,	rectangleUpperPath )
+where
+import Graphics.Gloss.Picture
+
+-- | A closed loop along this path.
+lineLoop :: Path -> Picture
+lineLoop []	= Line []
+lineLoop (x:xs)	= Line ((x:xs) ++ [x])
+
+
+-- Rectangles -------------------------------------------------------------------------------------
+-- | A wireframe rectangle centered about the origin.
+rectangleWire 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Picture
+rectangleWire sizeX sizeY
+	= lineLoop $ rectanglePath sizeX sizeY
+
+
+-- | A solid rectangle centered about the origin.
+rectangleSolid 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Picture
+
+rectangleSolid sizeX sizeY
+	= Polygon $ rectanglePath sizeX sizeY
+
+
+-- | A path representing a rectangle centered about the origin.
+rectanglePath 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Path
+
+rectanglePath sizeX sizeY			
+ = let	sx	= sizeX / 2
+	sy	= sizeY / 2
+   in	[(-sx, -sy), (-sx, sy), (sx, sy), (sx, -sy)]
+
+
+-- | A wireframe rectangle in the y > 0 half of the x-y plane.
+rectangleUpperWire 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Picture
+
+rectangleUpperWire sizeX sizeY
+	= lineLoop $ rectangleUpperPath sizeX sizeY
+
+
+-- | A sold rectangle in the y > 0 half of the x-y plane.
+rectangleUpperSolid 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Picture
+
+rectangleUpperSolid sizeX sizeY
+	= Polygon  $ rectangleUpperPath sizeX sizeY
+
+
+-- | A path representing a rectangle in the y > 0 half of the x-y plane.
+rectangleUpperPath 
+	:: Float 	-- ^ width
+	-> Float 	-- ^ height
+	-> Path
+
+rectangleUpperPath sizeX sy
+ = let 	sx	= sizeX / 2
+   in  	[(-sx, 0), (-sx, sy), (sx, sy), (sx, 0)]
+
diff --git a/Graphics/Gloss/ViewPort.hs b/Graphics/Gloss/ViewPort.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Gloss/ViewPort.hs
@@ -0,0 +1,29 @@
+
+-- | The 'ViewPort' represents the global transformation applied to the displayed picture.
+--	When the user pans, zooms, or rotates the display then this changes the 'ViewPort'.
+module Graphics.Gloss.ViewPort
+	( ViewPort(..)
+	, viewPortInit )
+where
+	
+data ViewPort
+	= ViewPort { 
+	-- | Global translation.
+	  viewPortTranslate	:: (Float, Float)
+
+	-- | Global rotation (in degrees).
+	, viewPortRotate	:: Float		
+
+	-- | Global scaling (of both x and y coordinates).
+	, viewPortScale		:: Float		
+	}
+	
+	
+-- | The initial state of the viewport.
+viewPortInit :: ViewPort
+viewPortInit
+	= ViewPort
+	{ viewPortTranslate	= (0, 0) 
+	, viewPortRotate	= 0
+	, viewPortScale		= 1 
+	}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2010 Benjamin Lippmeier 
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ condition:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
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/gloss.cabal b/gloss.cabal
new file mode 100644
--- /dev/null
+++ b/gloss.cabal
@@ -0,0 +1,63 @@
+Name:                gloss
+Version:             1.0.0.0
+License:             MIT
+License-file:        LICENSE
+Author:              Ben Lippmeier
+Maintainer:          gloss@ouroborus.net
+Build-Type:          Simple
+Cabal-Version:       >=1.8
+Stability:           provisional
+Category:            Graphics
+Description:
+	Gloss hides the pain of drawing simple vector graphics behind a nice data type and
+	a few display functions. Gloss uses OpenGL and GLUT under the hood, but you won't
+	have to worry about any of that. Get something cool on the screen in under 10 minutes.
+
+Synopsis:            Painless 2D vector graphics, animations and simulations.
+
+Library
+  Build-Depends: 
+           base       >= 3 && < 5,
+           ghc-prim   >= 0.2,
+           containers >= 0.3,
+           OpenGL     >= 2.0,
+           GLUT       >= 2.0
+
+  ghc-options:    -O2
+
+  Exposed-modules:
+           Graphics.Gloss
+           Graphics.Gloss.Color
+           Graphics.Gloss.Geometry
+           Graphics.Gloss.Geometry.Angle
+           Graphics.Gloss.Geometry.Line
+           Graphics.Gloss.Geometry.Vector
+           Graphics.Gloss.Picture
+           Graphics.Gloss.Shapes
+           Graphics.Gloss.ViewPort
+
+  Other-modules:
+           Graphics.Gloss.Internals.Color
+           Graphics.Gloss.Internals.Interface.Animate
+           Graphics.Gloss.Internals.Interface.Animate.State
+           Graphics.Gloss.Internals.Interface.Animate.Timing
+           Graphics.Gloss.Internals.Interface.Callback
+           Graphics.Gloss.Internals.Interface.Common.Exit
+           Graphics.Gloss.Internals.Interface.Debug
+           Graphics.Gloss.Internals.Interface.Display
+           Graphics.Gloss.Internals.Interface.Simulate
+           Graphics.Gloss.Internals.Interface.Simulate.Idle
+           Graphics.Gloss.Internals.Interface.Simulate.State
+           Graphics.Gloss.Internals.Interface.ViewPort.Command
+           Graphics.Gloss.Internals.Interface.ViewPort.ControlState
+           Graphics.Gloss.Internals.Interface.ViewPort.KeyMouse
+           Graphics.Gloss.Internals.Interface.ViewPort.Motion
+           Graphics.Gloss.Internals.Interface.ViewPort.Reshape
+           Graphics.Gloss.Internals.Interface.Window
+           Graphics.Gloss.Internals.Render.Circle
+           Graphics.Gloss.Internals.Render.Common
+           Graphics.Gloss.Internals.Render.Options
+           Graphics.Gloss.Internals.Render.Picture
+           Graphics.Gloss.Internals.Render.ViewPort
+
+
