diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # h-raylib changelog
 
+## Version 4.6.0.5
+_29 June, 2023_
+
+\[[#22](https://github.com/Anut-py/h-raylib/pull/22)\]
+
+- Allowed `base-4.18` to support GHC 9.4 and higher
+
+\[[#23](https://github.com/Anut-py/h-raylib/pull/23)\]
+
+- Added helper functions in `Raylib.Util` as an alternative to the `begin*` and `end*` functions
+
 ## Version 4.6.0.4
 _16 June, 2023_
 
diff --git a/examples/basic-audio/src/Main.hs b/examples/basic-audio/src/Main.hs
--- a/examples/basic-audio/src/Main.hs
+++ b/examples/basic-audio/src/Main.hs
@@ -3,10 +3,10 @@
 module Main where
 
 import Control.Monad (unless, void)
-import Raylib.Core (beginDrawing, changeDirectory, clearBackground, closeWindow, endDrawing, getApplicationDirectory, initWindow, setTargetFPS)
+import Raylib.Core (changeDirectory, clearBackground, getApplicationDirectory)
 import Raylib.Core.Audio (closeAudioDevice, initAudioDevice, loadMusicStream, playMusicStream, updateMusicStream)
 import Raylib.Core.Text (drawText)
-import Raylib.Util (inGHCi, whileWindowOpen0)
+import Raylib.Util (drawing, inGHCi, whileWindowOpen0, withWindow)
 import Raylib.Util.Colors (lightGray, rayWhite)
 
 musicPath :: String
@@ -14,26 +14,26 @@
 
 main :: IO ()
 main = do
-  window <- initWindow 650 400 "raylib [audio] example - basic audio"
-  initAudioDevice
-
-  setTargetFPS 60
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  music <- loadMusicStream musicPath window
-  playMusicStream music
-
-  whileWindowOpen0
-    ( do
-        beginDrawing
-
-        clearBackground rayWhite
-        drawText "You should hear music playing!" 20 20 20 lightGray
+  withWindow
+    650
+    400
+    "raylib [audio] example - basic audio"
+    60
+    ( \window -> do
+        initAudioDevice
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        endDrawing
+        music <- loadMusicStream musicPath window
+        playMusicStream music
 
-        updateMusicStream music
+        whileWindowOpen0
+          ( drawing
+              ( do
+                  clearBackground rayWhite
+                  drawText "You should hear music playing!" 20 20 20 lightGray
+              )
+              >> updateMusicStream music
+          )
+          
+        closeAudioDevice window
     )
-
-  closeAudioDevice window
-  closeWindow window
diff --git a/examples/basic-images/src/Main.hs b/examples/basic-images/src/Main.hs
--- a/examples/basic-images/src/Main.hs
+++ b/examples/basic-images/src/Main.hs
@@ -3,16 +3,9 @@
 
 import Control.Monad (unless, void)
 import Raylib.Core
-  ( beginDrawing,
-    beginTextureMode,
-    changeDirectory,
+  ( changeDirectory,
     clearBackground,
-    closeWindow,
-    endDrawing,
-    endTextureMode,
     getApplicationDirectory,
-    initWindow,
-    setTargetFPS,
   )
 import Raylib.Core.Text (drawText)
 import Raylib.Core.Textures
@@ -24,7 +17,7 @@
     loadTextureFromImage,
   )
 import Raylib.Types (Rectangle (Rectangle), RenderTexture (renderTexture'texture), Vector2 (Vector2))
-import Raylib.Util (inGHCi, whileWindowOpen0)
+import Raylib.Util (drawing, inGHCi, textureMode, whileWindowOpen0, withWindow)
 import Raylib.Util.Colors (black, lightGray, orange, white)
 
 logoPath :: String
@@ -32,31 +25,32 @@
 
 main :: IO ()
 main = do
-  window <- initWindow 600 450 "raylib [textures] example - basic images"
-  setTargetFPS 60
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  texture <- genImagePerlinNoise 600 450 20 20 2 >>= (`loadTextureFromImage` window)
-  logo <- loadImage logoPath >>= (`loadTextureFromImage` window)
-  rt <- loadRenderTexture 200 200 window
-
-  whileWindowOpen0
-    ( do
-        beginDrawing
-
-        beginTextureMode rt
-
-        clearBackground lightGray
-        drawText "This is scaled up" 10 10 20 black
+  withWindow
+    600
+    450
+    "raylib [textures] example - basic images"
+    60
+    ( \window -> do
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        endTextureMode
+        texture <- genImagePerlinNoise 600 450 20 20 2 >>= (`loadTextureFromImage` window)
+        logo <- loadImage logoPath >>= (`loadTextureFromImage` window)
+        rt <- loadRenderTexture 200 200 window
 
-        clearBackground white
-        drawTexture texture 0 0 orange
-        drawTexturePro (renderTexture'texture rt) (Rectangle 0 0 200 (-200)) (Rectangle 50 50 300 300) (Vector2 0 0) 0 white
-        drawTexturePro logo (Rectangle 0 0 256 256) (Rectangle 375 50 175 175) (Vector2 0 0) 0 white
+        whileWindowOpen0
+          ( drawing
+              ( do
+                  textureMode
+                    rt
+                    ( do
+                        clearBackground lightGray
+                        drawText "This is scaled up" 10 10 20 black
+                    )
 
-        endDrawing
+                  clearBackground white
+                  drawTexture texture 0 0 orange
+                  drawTexturePro (renderTexture'texture rt) (Rectangle 0 0 200 (-200)) (Rectangle 50 50 300 300) (Vector2 0 0) 0 white
+                  drawTexturePro logo (Rectangle 0 0 256 256) (Rectangle 375 50 175 175) (Vector2 0 0) 0 white
+              )
+          )
     )
-
-  closeWindow window
diff --git a/examples/basic-models/src/Main.hs b/examples/basic-models/src/Main.hs
--- a/examples/basic-models/src/Main.hs
+++ b/examples/basic-models/src/Main.hs
@@ -3,11 +3,11 @@
 module Main where
 
 import Control.Monad (unless, void)
-import Raylib.Core (beginDrawing, beginMode3D, changeDirectory, clearBackground, closeWindow, disableCursor, endDrawing, endMode3D, getApplicationDirectory, initWindow, setTargetFPS)
+import Raylib.Core (changeDirectory, clearBackground, disableCursor, getApplicationDirectory)
 import Raylib.Core.Camera (updateCamera)
 import Raylib.Core.Models (drawGrid, drawModel, genMeshCube, loadModel, loadModelFromMesh)
 import Raylib.Types (Camera3D (Camera3D), CameraMode (CameraModeFirstPerson), CameraProjection (CameraPerspective), Vector3 (Vector3))
-import Raylib.Util (inGHCi, whileWindowOpen_)
+import Raylib.Util (drawing, inGHCi, mode3D, whileWindowOpen_, withWindow)
 import Raylib.Util.Colors (orange, white)
 
 modelPath :: String
@@ -15,34 +15,35 @@
 
 main :: IO ()
 main = do
-  window <- initWindow 650 400 "raylib [models] example - basic models"
-  setTargetFPS 60
-  disableCursor
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  mesh <- genMeshCube 2 3 4 window
-  cubeModel <- loadModelFromMesh mesh window
-  customModel <- loadModel modelPath window
-
-  let camera = Camera3D (Vector3 3 2 3) (Vector3 0 0 0) (Vector3 0 1 0) 70 CameraPerspective
-
-  whileWindowOpen_
-    ( \c -> do
-        beginDrawing
-
-        clearBackground white
-        beginMode3D c
-
-        drawGrid 20 2.0
-        drawModel cubeModel (Vector3 0 1.5 0) 1 orange
-        drawModel customModel (Vector3 (-5) 1 0) 1 white
+  withWindow
+    650
+    400
+    "raylib [models] example - basic models"
+    60
+    ( \window -> do
+        disableCursor
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        endMode3D
+        mesh <- genMeshCube 2 3 4 window
+        cubeModel <- loadModelFromMesh mesh window
+        customModel <- loadModel modelPath window
 
-        endDrawing
+        let camera = Camera3D (Vector3 3 2 3) (Vector3 0 0 0) (Vector3 0 1 0) 70 CameraPerspective
 
-        updateCamera c CameraModeFirstPerson
+        whileWindowOpen_
+          ( \c -> do
+              drawing
+                ( do
+                    clearBackground white
+                    mode3D
+                      c
+                      ( do
+                          drawGrid 20 2.0
+                          drawModel cubeModel (Vector3 0 1.5 0) 1 orange
+                          drawModel customModel (Vector3 (-5) 1 0) 1 white
+                      )
+                )
+              updateCamera c CameraModeFirstPerson
+          )
+          camera
     )
-    camera
-
-  closeWindow window
diff --git a/examples/basic-rlgl/src/Main.hs b/examples/basic-rlgl/src/Main.hs
--- a/examples/basic-rlgl/src/Main.hs
+++ b/examples/basic-rlgl/src/Main.hs
@@ -2,11 +2,11 @@
 module Main where
 
 import Control.Monad (unless, void)
-import Raylib.Core (beginDrawing, beginMode3D, changeDirectory, clearBackground, closeWindow, endDrawing, endMode3D, getApplicationDirectory, initWindow, setTargetFPS)
+import Raylib.Core (changeDirectory, clearBackground, closeWindow, getApplicationDirectory)
 import Raylib.Core.Models (drawGrid)
 import Raylib.Core.Textures (loadTexture)
 import Raylib.Types (Camera3D (Camera3D), CameraProjection (CameraPerspective), Color (Color), RLDrawMode (RLQuads), Rectangle (Rectangle), Texture (texture'height, texture'id, texture'width), Vector3 (Vector3))
-import Raylib.Util (inGHCi, whileWindowOpen0)
+import Raylib.Util (drawing, inGHCi, mode3D, whileWindowOpen0, withWindow)
 import Raylib.Util.Colors (rayWhite, white)
 import Raylib.Util.RLGL (rlBegin, rlColor4ub, rlEnd, rlNormal3f, rlPopMatrix, rlPushMatrix, rlRotatef, rlScalef, rlSetTexture, rlTexCoord2f, rlTranslatef, rlVertex3f)
 import Prelude hiding (length)
@@ -16,38 +16,41 @@
 
 main :: IO ()
 main = do
-  window <- initWindow 650 400 "raylib [rlgl] example - basic rlgl"
-  setTargetFPS 60
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  let camera = Camera3D (Vector3 0 10 10) (Vector3 0 0 0) (Vector3 0 1 0) 45 CameraPerspective
-
-  texture <- loadTexture texturePath window
-
-  whileWindowOpen0
-    ( do
-        beginDrawing
-        clearBackground rayWhite
+  withWindow
+    650
+    400
+    "raylib [rlgl] example - basic rlgl"
+    60
+    ( \window -> do
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        beginMode3D camera
+        let camera = Camera3D (Vector3 0 10 10) (Vector3 0 0 0) (Vector3 0 1 0) 45 CameraPerspective
 
-        drawCubeTexture texture (Vector3 (-2) 2 0) 2 4 2 white
-        drawCubeTextureRec
-          texture
-          (Rectangle 0 (fromIntegral (texture'height texture) / 2.0) (fromIntegral (texture'width texture) / 2.0) (fromIntegral (texture'height texture) / 2.0))
-          (Vector3 2 1 0)
-          2
-          2
-          2
-          white
-        drawGrid 10 1
+        texture <- loadTexture texturePath window
 
-        endMode3D
+        whileWindowOpen0
+          ( drawing
+              ( do
+                  clearBackground rayWhite
+                  mode3D
+                    camera
+                    ( do
+                        drawCubeTexture texture (Vector3 (-2) 2 0) 2 4 2 white
+                        drawCubeTextureRec
+                          texture
+                          (Rectangle 0 (fromIntegral (texture'height texture) / 2.0) (fromIntegral (texture'width texture) / 2.0) (fromIntegral (texture'height texture) / 2.0))
+                          (Vector3 2 1 0)
+                          2
+                          2
+                          2
+                          white
+                        drawGrid 10 1
+                    )
+              )
+          )
 
-        endDrawing
+        closeWindow window
     )
-
-  closeWindow window
 
 drawCubeTexture :: Texture -> Vector3 -> Float -> Float -> Float -> Color -> IO ()
 drawCubeTexture texture (Vector3 x y z) width height length (Color r g b a) = do
diff --git a/examples/basic-window/src/Main.hs b/examples/basic-window/src/Main.hs
--- a/examples/basic-window/src/Main.hs
+++ b/examples/basic-window/src/Main.hs
@@ -1,31 +1,24 @@
 {-# OPTIONS -Wall #-}
 module Main where
 
-import Raylib.Core
-  ( beginDrawing,
-    clearBackground,
-    closeWindow,
-    endDrawing,
-    initWindow,
-    setTargetFPS,
-  )
+import Raylib.Core (clearBackground)
 import Raylib.Core.Text (drawText)
-import Raylib.Util (whileWindowOpen0)
+import Raylib.Util (drawing, whileWindowOpen0, withWindow)
 import Raylib.Util.Colors (lightGray, rayWhite)
 
 main :: IO ()
 main = do
-  window <- initWindow 600 450 "raylib [core] example - basic window"
-  setTargetFPS 60
-
-  whileWindowOpen0
-    ( do
-        beginDrawing
-
-        clearBackground rayWhite
-        drawText "Basic raylib window" 30 40 18 lightGray
-
-        endDrawing
+  withWindow
+    600
+    450
+    "raylib [core] example - basic window"
+    60
+    ( \_ -> do
+        whileWindowOpen0
+          ( drawing
+              ( do
+                  clearBackground rayWhite
+                  drawText "Basic raylib window" 30 40 18 lightGray
+              )
+          )
     )
-
-  closeWindow window
diff --git a/examples/camera-ray-collision/src/Main.hs b/examples/camera-ray-collision/src/Main.hs
--- a/examples/camera-ray-collision/src/Main.hs
+++ b/examples/camera-ray-collision/src/Main.hs
@@ -2,23 +2,9 @@
 module Main where
 
 import Control.Monad (when)
-import Raylib.Core
-  ( beginDrawing,
-    beginMode3D,
-    clearBackground,
-    closeWindow,
-    disableCursor,
-    endDrawing,
-    endMode3D,
-    initWindow,
-    setTargetFPS,
-  )
+import Raylib.Core (clearBackground, disableCursor)
 import Raylib.Core.Camera (updateCamera)
-import Raylib.Core.Models
-  ( drawBoundingBox,
-    drawPoint3D,
-    getRayCollisionQuad,
-  )
+import Raylib.Core.Models (drawBoundingBox, drawPoint3D, getRayCollisionQuad)
 import Raylib.Core.Text (drawFPS)
 import Raylib.Types
   ( BoundingBox (BoundingBox),
@@ -28,37 +14,39 @@
     RayCollision (rayCollision'hit, rayCollision'point),
     Vector3 (Vector3),
   )
-import Raylib.Util (cameraDirectionRay, whileWindowOpen_)
+import Raylib.Util (cameraDirectionRay, drawing, mode3D, whileWindowOpen_, withWindow)
 import Raylib.Util.Colors (black, red, white)
 
 main :: IO ()
 main = do
-  window <- initWindow 600 450 "raylib [core] example - camera ray collision"
-  setTargetFPS 60
-  disableCursor
-
-  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
-
-  whileWindowOpen_
-    ( \c -> do
-        beginDrawing
-
-        clearBackground black
-        drawFPS 10 20
-
-        let collision = getRayCollisionQuad (cameraDirectionRay c) (Vector3 0 0 0) (Vector3 0 2 0) (Vector3 0 2 4) (Vector3 0 0 4)
-        let color = if rayCollision'hit collision then red else white
+  withWindow
+    600
+    450
+    "raylib [core] example - camera ray collision"
+    60
+    ( \_ -> do
+        disableCursor
 
-        beginMode3D c
+        let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
 
-        drawBoundingBox (BoundingBox (Vector3 0 0 0) (Vector3 0 2 4)) color
-        when (rayCollision'hit collision) $ drawPoint3D (rayCollision'point collision) red
+        whileWindowOpen_
+          ( \c ->
+              drawing
+                ( do
+                    clearBackground black
+                    drawFPS 10 20
 
-        endMode3D
+                    let collision = getRayCollisionQuad (cameraDirectionRay c) (Vector3 0 0 0) (Vector3 0 2 0) (Vector3 0 2 4) (Vector3 0 0 4)
+                    let color = if rayCollision'hit collision then red else white
 
-        endDrawing
-        updateCamera c CameraModeFirstPerson
+                    mode3D
+                      c
+                      ( do
+                          drawBoundingBox (BoundingBox (Vector3 0 0 0) (Vector3 0 2 4)) color
+                          when (rayCollision'hit collision) $ drawPoint3D (rayCollision'point collision) red
+                      )
+                )
+                >> updateCamera c CameraModeFirstPerson
+          )
+          camera
     )
-    camera
-
-  closeWindow window
diff --git a/examples/custom-font-text/src/Main.hs b/examples/custom-font-text/src/Main.hs
--- a/examples/custom-font-text/src/Main.hs
+++ b/examples/custom-font-text/src/Main.hs
@@ -4,19 +4,14 @@
 import Control.Monad (unless, void)
 import Foreign (fromBool)
 import Raylib.Core
-  ( beginDrawing,
-    changeDirectory,
+  ( changeDirectory,
     clearBackground,
-    closeWindow,
-    endDrawing,
     getApplicationDirectory,
-    initWindow,
     isKeyPressed,
-    setTargetFPS,
   )
 import Raylib.Core.Text (drawText, drawTextEx, loadFont)
 import Raylib.Types (KeyboardKey (KeyDown, KeyUp), Vector2 (Vector2))
-import Raylib.Util (inGHCi, whileWindowOpen_)
+import Raylib.Util (inGHCi, whileWindowOpen_, withWindow, drawing)
 import Raylib.Util.Colors (black, rayWhite)
 
 mainFontPath :: String
@@ -24,27 +19,29 @@
 
 main :: IO ()
 main = do
-  window <- initWindow 800 450 "raylib [text] example - custom font text"
-  setTargetFPS 60
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  mainFont <- loadFont mainFontPath window
-
-  whileWindowOpen_
-    ( \size -> do
-        beginDrawing
-        clearBackground rayWhite
-
-        drawTextEx mainFont "Testing drawTextEx" (Vector2 20.0 12.0) (fromIntegral size) 1.0 black
-        drawText "Press the up and down arrows to change the font size" 20 (size + 15) 24 black
-
-        increaseSize <- isKeyPressed KeyUp
-        decreaseSize <- isKeyPressed KeyDown
+  withWindow
+    800
+    450
+    "raylib [text] example - custom font text"
+    60
+    ( \window -> do
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        endDrawing
+        mainFont <- loadFont mainFontPath window
 
-        return (size + fromBool increaseSize - fromBool decreaseSize)
+        whileWindowOpen_
+          ( \size -> do
+              drawing
+                ( do
+                    clearBackground rayWhite
+  
+                    drawTextEx mainFont "Testing drawTextEx" (Vector2 20.0 12.0) (fromIntegral size) 1.0 black
+                    drawText "Press the up and down arrows to change the font size" 20 (size + 15) 24 black
+                )
+                
+              increaseSize <- isKeyPressed KeyUp
+              decreaseSize <- isKeyPressed KeyDown
+              return (size + fromBool increaseSize - fromBool decreaseSize)
+          )
+          20
     )
-    20
-
-  closeWindow window
diff --git a/examples/first-person-camera/src/Main.hs b/examples/first-person-camera/src/Main.hs
--- a/examples/first-person-camera/src/Main.hs
+++ b/examples/first-person-camera/src/Main.hs
@@ -1,51 +1,43 @@
 {-# OPTIONS -Wall #-}
 module Main where
 
-import Raylib.Core
-  ( beginDrawing,
-    beginMode3D,
-    clearBackground,
-    closeWindow,
-    disableCursor,
-    endDrawing,
-    endMode3D,
-    initWindow,
-    setTargetFPS,
-  )
+import Raylib.Core (clearBackground, disableCursor)
 import Raylib.Core.Camera (updateCamera)
 import Raylib.Core.Models (drawCircle3D, drawCubeWiresV, drawLine3D)
 import Raylib.Core.Text (drawFPS)
 import Raylib.Types (Camera3D (Camera3D), CameraMode (CameraModeFirstPerson), CameraProjection (CameraPerspective), Vector3 (Vector3))
-import Raylib.Util (whileWindowOpen_)
+import Raylib.Util (drawing, mode3D, whileWindowOpen_, withWindow)
 import Raylib.Util.Colors (black, white)
 
 main :: IO ()
 main = do
-  window <- initWindow 600 450 "raylib [core] example - first person camera"
-  setTargetFPS 60
-  disableCursor
-
-  let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
-
-  whileWindowOpen_
-    ( \c -> do
-        beginDrawing
-
-        clearBackground black
-        drawFPS 10 20
-
-        beginMode3D c
+  withWindow
+    600
+    450
+    "raylib [core] example - first person camera"
+    60
+    ( \_ -> do
+        disableCursor
 
-        drawCircle3D (Vector3 2 0 1) 2 (Vector3 0 0 0) 0 white
-        drawLine3D (Vector3 3 (-1) 1) (Vector3 1 1 1) white
-        drawLine3D (Vector3 4 2 2) (Vector3 1 (-1) 1) white
-        drawCubeWiresV (Vector3 (-2) 0 0) (Vector3 1 1 1) white
+        let camera = Camera3D (Vector3 0 0 0) (Vector3 2 0 1) (Vector3 0 1 0) 70 CameraPerspective
 
-        endMode3D
+        whileWindowOpen_
+          ( \c ->
+              drawing
+                ( do
+                    clearBackground black
+                    drawFPS 10 20
 
-        endDrawing
-        updateCamera c CameraModeFirstPerson
+                    mode3D
+                      c
+                      ( do
+                          drawCircle3D (Vector3 2 0 1) 2 (Vector3 0 0 0) 0 white
+                          drawLine3D (Vector3 3 (-1) 1) (Vector3 1 1 1) white
+                          drawLine3D (Vector3 4 2 2) (Vector3 1 (-1) 1) white
+                          drawCubeWiresV (Vector3 (-2) 0 0) (Vector3 1 1 1) white
+                      )
+                )
+                >> updateCamera c CameraModeFirstPerson
+          )
+          camera
     )
-    camera
-
-  closeWindow window
diff --git a/examples/postprocessing-effects/src/Main.hs b/examples/postprocessing-effects/src/Main.hs
--- a/examples/postprocessing-effects/src/Main.hs
+++ b/examples/postprocessing-effects/src/Main.hs
@@ -3,13 +3,13 @@
 module Main where
 
 import Control.Monad (unless, void)
-import Raylib.Core (beginDrawing, beginMode3D, beginShaderMode, beginTextureMode, changeDirectory, clearBackground, closeWindow, endDrawing, endMode3D, endShaderMode, endTextureMode, getApplicationDirectory, initWindow, isKeyPressed, loadShader, setShaderValue, setTargetFPS)
+import Raylib.Core (changeDirectory, clearBackground, getApplicationDirectory, isKeyPressed, loadShader, setShaderValue)
 import Raylib.Core.Camera (updateCamera)
 import Raylib.Core.Models (drawCube, drawGrid, drawSphere)
 import Raylib.Core.Text (drawText)
 import Raylib.Core.Textures (drawTextureRec, loadRenderTexture)
 import Raylib.Types (Camera3D (Camera3D), CameraMode (CameraModeOrbital), CameraProjection (CameraPerspective), KeyboardKey (KeyLeft, KeyRight), Rectangle (Rectangle), RenderTexture (renderTexture'texture), ShaderUniformData (ShaderUniformVec2), Vector2 (Vector2), Vector3 (Vector3))
-import Raylib.Util (inGHCi, whileWindowOpen_)
+import Raylib.Util (inGHCi, mode3D, textureMode, whileWindowOpen_, withWindow, drawing, shaderMode)
 import Raylib.Util.Colors (black, blue, darkBlue, darkGreen, green, maroon, orange, red, white)
 
 assetsPath :: String
@@ -20,82 +20,80 @@
   let width = 1300
       height = 800
 
-  window <- initWindow width height "raylib [shaders] example - postprocessing effects"
-  setTargetFPS 60
-  unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
-
-  let camera = Camera3D (Vector3 3 4 3) (Vector3 0 1 0) (Vector3 0 1 0) 45 CameraPerspective
-
-  rt <- loadRenderTexture width height window
-
-  -- Most of the shaders here are based on the ones at https://github.com/raysan5/raylib/tree/master/examples/shaders/resources/shaders/glsl330
-  defaultShader <- loadShader Nothing Nothing window
-  grayscaleShader <- loadShader Nothing (Just $ assetsPath ++ "grayscale.frag") window
-  blurShader <- loadShader Nothing (Just $ assetsPath ++ "blur.frag") window
-  pixelateShader <- loadShader Nothing (Just $ assetsPath ++ "pixelate.frag") window
-  bloomShader <- loadShader Nothing (Just $ assetsPath ++ "bloom.frag") window
-
-  let shaders = [("None", defaultShader), ("Grayscale", grayscaleShader), ("Blur", blurShader), ("Pixelate", pixelateShader), ("Bloom", bloomShader)]
-
-  setShaderValue blurShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
-  setShaderValue pixelateShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
-  setShaderValue bloomShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
-
-  whileWindowOpen_
-    ( \(c, currentShader) -> do
-        let (shaderName, selectedShader) = shaders !! currentShader
-
-        beginTextureMode rt
-
-        beginMode3D c
+  withWindow
+    width
+    height
+    "raylib [shaders] example - postprocessing effects"
+    60
+    ( \window -> do
+        unless inGHCi (void $ changeDirectory =<< getApplicationDirectory)
 
-        clearBackground white
+        let camera = Camera3D (Vector3 3 4 3) (Vector3 0 1 0) (Vector3 0 1 0) 45 CameraPerspective
 
-        drawGrid 30 1.0
-        drawCube (Vector3 0 1 0) 2.0 2.0 2.0 orange
-        drawSphere (Vector3 0 2 0) 0.5 green
-        drawSphere (Vector3 0 0 0) 0.5 darkGreen
-        drawSphere (Vector3 1 1 0) 0.5 red
-        drawSphere (Vector3 (-1) 1 0) 0.5 maroon
-        drawSphere (Vector3 0 1 1) 0.5 blue
-        drawSphere (Vector3 0 1 (-1)) 0.5 darkBlue
+        rt <- loadRenderTexture width height window
 
-        endMode3D
+        -- Most of the shaders here are based on the ones at https://github.com/raysan5/raylib/tree/master/examples/shaders/resources/shaders/glsl330
+        defaultShader <- loadShader Nothing Nothing window
+        grayscaleShader <- loadShader Nothing (Just $ assetsPath ++ "grayscale.frag") window
+        blurShader <- loadShader Nothing (Just $ assetsPath ++ "blur.frag") window
+        pixelateShader <- loadShader Nothing (Just $ assetsPath ++ "pixelate.frag") window
+        bloomShader <- loadShader Nothing (Just $ assetsPath ++ "bloom.frag") window
 
-        endTextureMode
+        let shaders = [("None", defaultShader), ("Grayscale", grayscaleShader), ("Blur", blurShader), ("Pixelate", pixelateShader), ("Bloom", bloomShader)]
 
-        beginDrawing
+        setShaderValue blurShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
+        setShaderValue pixelateShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
+        setShaderValue bloomShader "renderSize" (ShaderUniformVec2 (Vector2 (fromIntegral width) (fromIntegral height))) window
 
-        clearBackground white
+        whileWindowOpen_
+          ( \(c, currentShader) -> do
+              let (shaderName, selectedShader) = shaders !! currentShader
 
-        beginShaderMode selectedShader
+              textureMode
+                rt
+                ( mode3D
+                    c
+                    ( do
+                        clearBackground white
 
-        drawTextureRec (renderTexture'texture rt) (Rectangle 0 0 (fromIntegral width) (fromIntegral $ - height)) (Vector2 0 0) white
+                        drawGrid 30 1.0
+                        drawCube (Vector3 0 1 0) 2.0 2.0 2.0 orange
+                        drawSphere (Vector3 0 2 0) 0.5 green
+                        drawSphere (Vector3 0 0 0) 0.5 darkGreen
+                        drawSphere (Vector3 1 1 0) 0.5 red
+                        drawSphere (Vector3 (-1) 1 0) 0.5 maroon
+                        drawSphere (Vector3 0 1 1) 0.5 blue
+                        drawSphere (Vector3 0 1 (-1)) 0.5 darkBlue
+                    )
+                )
 
-        endShaderMode
+              drawing
+                ( do
+                    clearBackground white
 
-        drawText "Press the left and right arrow keys to change the effect" 20 20 20 black
-        drawText ("Current effect: " ++ shaderName) 20 50 20 black
+                    shaderMode selectedShader $
+                      drawTextureRec (renderTexture'texture rt) (Rectangle 0 0 (fromIntegral width) (fromIntegral $ - height)) (Vector2 0 0) white
 
-        endDrawing
+                    drawText "Press the left and right arrow keys to change the effect" 20 20 20 black
+                    drawText ("Current effect: " ++ shaderName) 20 50 20 black
+                )
 
-        leftDown <- isKeyPressed KeyLeft
-        rightDown <- isKeyPressed KeyRight
-        let newShaderIdx = clamp (currentShader + change)
-              where
-                total = length shaders
-                clamp x
-                  | x < 0 = total + x
-                  | x >= total = x - total
-                  | otherwise = x
-                change
-                  | leftDown = -1
-                  | rightDown = 1
-                  | otherwise = 0
+              leftDown <- isKeyPressed KeyLeft
+              rightDown <- isKeyPressed KeyRight
+              let newShaderIdx = clamp (currentShader + change)
+                    where
+                      total = length shaders
+                      clamp x
+                        | x < 0 = total + x
+                        | x >= total = x - total
+                        | otherwise = x
+                      change
+                        | leftDown = -1
+                        | rightDown = 1
+                        | otherwise = 0
 
-        newCam <- updateCamera c CameraModeOrbital
-        return (newCam, newShaderIdx)
+              newCam <- updateCamera c CameraModeOrbital
+              return (newCam, newShaderIdx)
+          )
+          (camera, 0)
     )
-    (camera, 0)
-
-  closeWindow window
diff --git a/h-raylib.cabal b/h-raylib.cabal
--- a/h-raylib.cabal
+++ b/h-raylib.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               h-raylib
-version:            4.6.0.4
+version:            4.6.0.5
 synopsis:           Raylib bindings for Haskell
 category:           graphics
 description:
@@ -12,12 +12,12 @@
 author:             Anut
 maintainer:         Anut
 extra-doc-files:
+  CHANGELOG.md
   CONTRIBUTING.md
   README.md
   ROADMAP.md
 
 extra-source-files:
-  CHANGELOG.md
   examples/**/*.frag
   examples/**/*.mtl
   examples/**/*.obj
@@ -30,6 +30,10 @@
   raylib/**/*.h
   raylib/**/*.m
 
+source-repository head
+  type:     git
+  location: git://github.com/Anut-py/h-raylib.git
+
 flag detect-platform
   description:
     Detect platform and automatically add platform-specific configuration
@@ -165,9 +169,10 @@
     Raylib.Native
 
   build-depends:
-    , base        >=4.0   && <4.17.0
-    , containers  >=0.6.0 && <0.6.7.0
-    , lens        >=4.0   && <=5.2.2
+    , base        >=4.0    && <4.19
+    , containers  >=0.6.0  && <0.6.7.0
+    , exceptions  >=0.10.4 && <0.10.8
+    , lens        >=4.0    && <5.2.2.0
 
   hs-source-dirs:   src
   default-language: Haskell2010
diff --git a/src/Raylib/Util.hs b/src/Raylib/Util.hs
--- a/src/Raylib/Util.hs
+++ b/src/Raylib/Util.hs
@@ -1,21 +1,78 @@
 {-# OPTIONS -Wall #-}
 {-# LANGUAGE CPP #-}
 
-module Raylib.Util (WindowResources, cameraDirectionRay, whileWindowOpen, whileWindowOpen_, whileWindowOpen0, setMaterialShader, inGHCi, Freeable (..)) where
+module Raylib.Util
+  ( 
+    -- * Bracket functions
+    withWindow,
+    drawing,
+    mode2D,
+    mode3D,
+    textureMode,
+    shaderMode,
+    blendMode,
+    scissorMode,
+    vrStereoMode,
 
+    -- * Game loop functions
+    whileWindowOpen,
+    whileWindowOpen_,
+    whileWindowOpen0,
+
+    -- * Miscellaneous
+    cameraDirectionRay,
+    setMaterialShader,
+    inGHCi,
+    WindowResources,
+    Freeable (..),
+  )
+where
+
 import Control.Monad (void)
+import Control.Monad.Catch (MonadMask, bracket, bracket_)
 import Control.Monad.IO.Class (MonadIO (liftIO))
-import Raylib.Core (windowShouldClose)
+import Raylib.Core (beginBlendMode, beginDrawing, beginMode2D, beginMode3D, beginScissorMode, beginShaderMode, beginTextureMode, beginVrStereoMode, closeWindow, endBlendMode, endDrawing, endMode2D, endMode3D, endScissorMode, endShaderMode, endTextureMode, endVrStereoMode, initWindow, setTargetFPS, windowShouldClose)
 import Raylib.ForeignUtil (Freeable (..))
 import Raylib.Internal (WindowResources)
 import Raylib.Types
-  ( Camera3D (camera3D'position, camera3D'target),
+  ( BlendMode,
+    Camera2D,
+    Camera3D (camera3D'position, camera3D'target),
     Material (material'shader),
     Model (model'materials),
     Ray (Ray),
+    RenderTexture,
     Shader,
+    VrStereoConfig,
   )
 import Raylib.Util.Math (Vector (vectorNormalize, (|-|)))
+
+withWindow :: (MonadIO m, MonadMask m) => Int -> Int -> String -> Int -> (WindowResources -> m b) -> m b
+withWindow w h title fps = bracket (liftIO $ initWindow w h title <* setTargetFPS fps) (liftIO . closeWindow)
+
+drawing :: (MonadIO m, MonadMask m) => m b -> m b
+drawing = bracket_ (liftIO beginDrawing) (liftIO endDrawing)
+
+mode2D :: (MonadIO m, MonadMask m) => Camera2D -> m b -> m b
+mode2D camera = bracket_ (liftIO (beginMode2D camera)) (liftIO endMode2D)
+
+mode3D :: (MonadIO m, MonadMask m) => Camera3D -> m b -> m b
+mode3D camera = bracket_ (liftIO (beginMode3D camera)) (liftIO endMode3D)
+
+textureMode :: (MonadIO m, MonadMask m) => RenderTexture -> m b -> m b
+textureMode rt = bracket_ (liftIO (beginTextureMode rt)) (liftIO endTextureMode)
+
+shaderMode :: (MonadIO m, MonadMask m) => Shader -> m b -> m b
+shaderMode shader = bracket_ (liftIO (beginShaderMode shader)) (liftIO endShaderMode)
+
+blendMode :: (MonadIO m, MonadMask m) => BlendMode -> m b -> m b
+blendMode bm = bracket_ (liftIO (beginBlendMode bm)) (liftIO endBlendMode)
+
+scissorMode :: (MonadIO m, MonadMask m) => Int -> Int -> Int -> Int -> m b -> m b
+scissorMode x y width height = bracket_ (liftIO (beginScissorMode x y width height)) (liftIO endScissorMode)
+
+vrStereoMode :: (MonadIO m, MonadMask m) => VrStereoConfig -> m b -> m b
+vrStereoMode config = bracket_ (liftIO (beginVrStereoMode config)) (liftIO endVrStereoMode)
 
 -- | Gets the direction of a camera as a ray.
 cameraDirectionRay :: Camera3D -> Ray
