diff --git a/butterflies.cabal b/butterflies.cabal
--- a/butterflies.cabal
+++ b/butterflies.cabal
@@ -1,13 +1,13 @@
 name:                butterflies
-version:             0.3.0.1
+version:             0.3.0.2
 synopsis:            butterfly tilings
 description:         various tilings with butterflies (after M C Escher 1950)
-homepage:            http://code.mathr.co.uk/butterflies
+homepage:            https://code.mathr.co.uk/butterflies
 license:             GPL-3
 license-file:        LICENSE
 author:              Claude Heiland-Allen
 maintainer:          claude@mathr.co.uk
-copyright:           (C) 2013,2015  Claude Heiland-Allen <claude@mathr.co.uk>
+copyright:           (C) 2013,2018  Claude Heiland-Allen <claude@mathr.co.uk>
 category:            Graphics
 build-type:          Simple
 cabal-version:       >=1.8
@@ -27,7 +27,7 @@
     Geometry.Hyperbolic.TwoD.HalfSpace
     Geometry.Utils
   build-depends:
-    base ==4.8.*
+    base >=4.6 && <4.13
 
 executable butterflies-flat
   hs-source-dirs:      flat
@@ -35,21 +35,20 @@
   other-modules:
     Paths_butterflies
   build-depends:
-    base ==4.8.*,
-    bytestring ==0.10.*,
-    OpenGLRaw ==2.6.*,
-    OpenGLRaw21 ==2.0.*,
-    GLUT ==2.7.*,
-    gl-capture ==0.1.*,
-    repa ==3.4.*,
-    repa-devil ==0.3.*,
-    butterflies ==0.3.0.1
+    base,
+    bytestring >=0.10 && <0.11,
+    OpenGLRaw >=3.3 && <3.4,
+    GLUT >=2.7 && <2.8,
+    gl-capture >=0.1 && <0.2,
+    repa >=3.4 && <3.5,
+    repa-devil >=0.3 && <0.4,
+    butterflies
 
 source-repository head
-  type:     git
-  location: http://code.mathr.co.uk/butterflies.git
+  type:                git
+  location:            https://code.mathr.co.uk/butterflies.git
 
 source-repository this
-  type:     git
-  location: http://code.mathr.co.uk/butterflies.git
-  tag:      v0.3.0.1
+  type:                git
+  location:            https://code.mathr.co.uk/butterflies.git
+  tag:                 v0.3.0.2
diff --git a/flat/Main.hs b/flat/Main.hs
--- a/flat/Main.hs
+++ b/flat/Main.hs
@@ -8,9 +8,7 @@
 import Foreign.ForeignPtr (withForeignPtr)
 import System.Exit (exitSuccess)
 
-import Graphics.Rendering.OpenGL.Raw.Core21
-import Graphics.Rendering.OpenGL.Raw.ARB.ShaderObjects (glUniformMatrix4fvARB)
-import Graphics.Rendering.OpenGL.Raw.ARB.FramebufferObjectCore (glGenerateMipmap)
+import Graphics.GL
 import Graphics.Rendering.OpenGL.Capture (capturePPM)
 import Graphics.UI.GLUT (getArgsAndInitialize, createWindow, displayCallback, ($=), swapBuffers, reportErrors, mainLoop)
 import qualified Data.ByteString as BS
@@ -120,16 +118,16 @@
   allocaBytes bytes $ \p -> do
     glPoke swarm p
     vbo <- with 0 $ \q -> glGenBuffers 1 q >> peek q
-    glBindBuffer gl_ARRAY_BUFFER vbo
-    glBufferData gl_ARRAY_BUFFER (fromIntegral bytes) p gl_STATIC_DRAW
+    glBindBuffer GL_ARRAY_BUFFER vbo
+    glBufferData GL_ARRAY_BUFFER (fromIntegral bytes) p GL_STATIC_DRAW
     att <- withCString "p0" $ glGetAttribLocation program
-    glVertexAttribPointer (fromIntegral att) 2 gl_FLOAT (fromIntegral gl_FALSE) stride (plusPtr nullPtr 0)
+    glVertexAttribPointer (fromIntegral att) 2 GL_FLOAT (fromIntegral GL_FALSE) stride (plusPtr nullPtr 0)
     glEnableVertexAttribArray (fromIntegral att)
     att <- withCString "t0" $ glGetAttribLocation program
-    glVertexAttribPointer (fromIntegral att) 2 gl_FLOAT (fromIntegral gl_FALSE) stride (plusPtr nullPtr (2 * 4))
+    glVertexAttribPointer (fromIntegral att) 2 GL_FLOAT (fromIntegral GL_FALSE) stride (plusPtr nullPtr (2 * 4))
     glEnableVertexAttribArray (fromIntegral att)
     att <- withCString "c0" $ glGetAttribLocation program
-    glVertexAttribPointer (fromIntegral att) 3 gl_FLOAT (fromIntegral gl_FALSE) stride (plusPtr nullPtr (4 * 4))
+    glVertexAttribPointer (fromIntegral att) 3 GL_FLOAT (fromIntegral GL_FALSE) stride (plusPtr nullPtr (4 * 4))
     glEnableVertexAttribArray (fromIntegral att)
   let s = 10
       l = -s
@@ -144,15 +142,15 @@
               , 0, 0, 0, 1 ]
   withArray ortho $ \p -> do
     loc <- withCString "mvp" $ glGetUniformLocation program
-    glUniformMatrix4fvARB loc 1 (fromIntegral gl_FALSE) p
+    glUniformMatrix4fv loc 1 (fromIntegral GL_FALSE) p
   loc <- withCString "tex" $ glGetUniformLocation program
   glUniform1i loc 0
   loc <- withCString "pal" $ glGetUniformLocation program
   glUniform1i loc 1
   glClearColor 0.5 0.5 0.5 1
   displayCallback $= do
-    glClear gl_COLOR_BUFFER_BIT
-    glDrawArrays gl_TRIANGLES 0 (fromIntegral count)
+    glClear GL_COLOR_BUFFER_BIT
+    glDrawArrays GL_TRIANGLES 0 (fromIntegral count)
     swapBuffers
     let ipq = ip * ip + iq * iq + ip * iq
     capturePPM >>= BS.writeFile ("tessellation-" ++ (if ipq < 10 then "0" else "") ++ show ipq ++ "-" ++ show ip ++ "-" ++ show iq ++ ".ppm")
@@ -164,24 +162,24 @@
   RGBA img <- getDataFileName "butterfly.png" >>= runIL . readImage
   withForeignPtr (toForeignPtr img) $ \p -> do
     tex <- with 0 $ \q -> glGenTextures 1 q >> peek q
-    glBindTexture gl_TEXTURE_2D tex
-    glTexImage2D gl_TEXTURE_2D 0 (fromIntegral gl_RGBA) 1024 1024 0 gl_RGBA gl_UNSIGNED_BYTE p
-    glTexParameteri gl_TEXTURE_2D gl_TEXTURE_MIN_FILTER (fromIntegral gl_LINEAR_MIPMAP_LINEAR)
-    glTexParameteri gl_TEXTURE_2D gl_TEXTURE_MAG_FILTER (fromIntegral gl_LINEAR)
-    glGenerateMipmap gl_TEXTURE_2D
-  glActiveTexture gl_TEXTURE1
+    glBindTexture GL_TEXTURE_2D tex
+    glTexImage2D GL_TEXTURE_2D 0 (fromIntegral GL_RGBA) 1024 1024 0 GL_RGBA GL_UNSIGNED_BYTE p
+    glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER (fromIntegral GL_LINEAR_MIPMAP_LINEAR)
+    glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER (fromIntegral GL_LINEAR)
+    glGenerateMipmap GL_TEXTURE_2D
+  glActiveTexture GL_TEXTURE1
   RGBA img <- getDataFileName "palette.png" >>= runIL . readImage
   withForeignPtr (toForeignPtr img) $ \p -> do
     tex <- with 0 $ \q -> glGenTextures 1 q >> peek q
-    glBindTexture gl_TEXTURE_1D tex
-    glTexImage1D gl_TEXTURE_1D 0 (fromIntegral gl_RGBA) 256 0 gl_RGBA gl_UNSIGNED_BYTE p
-    glTexParameteri gl_TEXTURE_1D gl_TEXTURE_MIN_FILTER (fromIntegral gl_NEAREST)
-    glTexParameteri gl_TEXTURE_1D gl_TEXTURE_MAG_FILTER (fromIntegral gl_NEAREST)
+    glBindTexture GL_TEXTURE_1D tex
+    glTexImage1D GL_TEXTURE_1D 0 (fromIntegral GL_RGBA) 256 0 GL_RGBA GL_UNSIGNED_BYTE p
+    glTexParameteri GL_TEXTURE_1D GL_TEXTURE_MIN_FILTER (fromIntegral GL_NEAREST)
+    glTexParameteri GL_TEXTURE_1D GL_TEXTURE_MAG_FILTER (fromIntegral GL_NEAREST)
 
 compileProgram = do
   program <- glCreateProgram
-  compileShader program gl_VERTEX_SHADER vert
-  compileShader program gl_FRAGMENT_SHADER frag
+  compileShader program GL_VERTEX_SHADER vert
+  compileShader program GL_FRAGMENT_SHADER frag
   glLinkProgram program
   debugProgram program
   return program
@@ -197,9 +195,9 @@
 debugProgram program = do
   if program /= 0
     then do
-      linked <- with 0 $ \p -> glGetProgramiv program gl_LINK_STATUS p >> peek p
-      when (linked /= fromIntegral gl_TRUE) $ putStrLn "link failed"
-      len <- with 0 $ \p -> glGetProgramiv program gl_INFO_LOG_LENGTH p >> peek p
+      linked <- with 0 $ \p -> glGetProgramiv program GL_LINK_STATUS p >> peek p
+      when (linked /= fromIntegral GL_TRUE) $ putStrLn "link failed"
+      len <- with 0 $ \p -> glGetProgramiv program GL_INFO_LOG_LENGTH p >> peek p
       when (len > 1) $ do
         allocaBytes (fromIntegral len + 1) $ \p -> glGetProgramInfoLog program len nullPtr p >> pokeByteOff p (fromIntegral len) (0 :: CUChar) >> peekCString p >>= putStrLn
     else putStrLn "no program"
@@ -207,9 +205,9 @@
 debugShader shader = do
   if shader /= 0
     then do
-      compiled <- with 0 $ \p -> glGetShaderiv shader gl_COMPILE_STATUS p >> peek p
-      when (compiled /= fromIntegral gl_TRUE) $ putStrLn "compile failed"
-      len <- with 0 $ \p -> glGetShaderiv shader gl_INFO_LOG_LENGTH p >> peek p
+      compiled <- with 0 $ \p -> glGetShaderiv shader GL_COMPILE_STATUS p >> peek p
+      when (compiled /= fromIntegral GL_TRUE) $ putStrLn "compile failed"
+      len <- with 0 $ \p -> glGetShaderiv shader GL_INFO_LOG_LENGTH p >> peek p
       when (len > 1) $ do
         allocaBytes (fromIntegral len + 1) $ \p -> glGetShaderInfoLog shader len nullPtr p >> pokeByteOff p (fromIntegral len) (0 :: CUChar) >> peekCString p >>= putStrLn
     else putStrLn "no shader"
