diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
 # Revision history for rhine-gloss
 
+## 1.3
+
+* Dropped `dunai` dependency in favour of state automata.
+  See [the versions readme](./versions.md) for details.
+* Support GHC 9.6 and 9.8
+
 ## 1.1
 
 * dunai-0.11 compatibility
diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE TypeFamilies #-}
 
 -- | Example application for the @gloss@ wrapper.
diff --git a/rhine-gloss.cabal b/rhine-gloss.cabal
--- a/rhine-gloss.cabal
+++ b/rhine-gloss.cabal
@@ -1,33 +1,32 @@
 -- Initial rhine-gloss.cabal generated by cabal init.  For further
 -- documentation, see http://haskell.org/cabal/users-guide/
-
-name:                rhine-gloss
-version:             1.2
-synopsis:            Gloss backend for Rhine
+name: rhine-gloss
+version: 1.3
+synopsis: Gloss backend for Rhine
 description:
   This package provides a simple wrapper for the `gloss` library,
   or rather the function `Graphics.Gloss.play`,
   enabling you to write `gloss` applications as signal functions.
-license:             BSD3
-license-file:        LICENSE
-author:              Manuel Bärenz
-maintainer:          programming@manuelbaerenz.de
+
+license: BSD3
+license-file: LICENSE
+author: Manuel Bärenz
+maintainer: programming@manuelbaerenz.de
 -- copyright:
-category:            FRP
-build-type:          Simple
-extra-source-files:  ChangeLog.md
-extra-doc-files:     README.md
-cabal-version:       2.0
+category: FRP
+build-type: Simple
+extra-source-files: ChangeLog.md
+extra-doc-files: README.md
+cabal-version: 2.0
 
 source-repository head
-  type:     git
+  type: git
   location: https://github.com/turion/rhine.git
 
 source-repository this
-  type:     git
+  type: git
   location: https://github.com/turion/rhine.git
-  tag:      v1.1
-
+  tag: v1.3
 
 library
   exposed-modules:
@@ -36,28 +35,39 @@
     FRP.Rhine.Gloss.IO
     FRP.Rhine.Gloss.Pure
     FRP.Rhine.Gloss.Pure.Combined
-  build-depends:       base         >= 4.14 && < 4.18
-                     , transformers >= 0.5
-                     , rhine        == 1.2
-                     , dunai        ^>= 0.11
-                     , gloss        >= 1.12
-                     , mmorph       >= 1.1
-                     , monad-schedule >= 0.1
-  hs-source-dirs:      src
-  default-language:    Haskell2010
-  default-extensions:
-      TypeOperators
-  ghc-options:         -W
+
+  build-depends:
+    automaton,
+    base >=4.14 && <4.20,
+    gloss >=1.12,
+    mmorph >=1.1,
+    monad-schedule >=0.1,
+    rhine ==1.3,
+    transformers >=0.5
+
+  hs-source-dirs: src
+  default-language: Haskell2010
+  default-extensions: TypeOperators
+  ghc-options: -W
+
   if flag(dev)
     ghc-options: -Werror
 
 executable rhine-gloss-gears
-  main-is:             Main.hs
-  ghc-options:         -threaded
-  build-depends:       base         >= 4.14 && < 4.18
-                     , rhine-gloss
-  default-language:    Haskell2010
-  ghc-options:         -W -threaded -rtsopts -with-rtsopts=-N
+  main-is: Main.hs
+  ghc-options: -threaded
+  build-depends:
+    base >=4.14 && <4.20,
+    rhine-gloss
+
+  default-language: Haskell2010
+  default-extensions: TypeOperators
+  ghc-options:
+    -W
+    -threaded
+    -rtsopts
+    -with-rtsopts=-N
+
   if flag(dev)
     ghc-options: -Werror
 
diff --git a/src/FRP/Rhine/Gloss.hs b/src/FRP/Rhine/Gloss.hs
--- a/src/FRP/Rhine/Gloss.hs
+++ b/src/FRP/Rhine/Gloss.hs
@@ -17,7 +17,6 @@
 import FRP.Rhine as X
 
 -- rhine-gloss
-
 import FRP.Rhine.Gloss.Common as X
 import FRP.Rhine.Gloss.IO as X
 import FRP.Rhine.Gloss.Pure as X
diff --git a/src/FRP/Rhine/Gloss/Pure.hs b/src/FRP/Rhine/Gloss/Pure.hs
--- a/src/FRP/Rhine/Gloss/Pure.hs
+++ b/src/FRP/Rhine/Gloss/Pure.hs
@@ -30,16 +30,16 @@
 import Control.Monad.Trans.Reader
 import Control.Monad.Trans.Writer.Strict
 
--- dunai
-import Control.Monad.Trans.MSF (performOnFirstSample)
-import qualified Control.Monad.Trans.MSF.Reader as MSFReader
-import qualified Control.Monad.Trans.MSF.Writer as MSFWriter
-import Data.MonadicStreamFunction.InternalCore
-
 -- monad-schedule
 import Control.Monad.Schedule.Class
 import Control.Monad.Schedule.Yield
 
+-- automaton
+import Data.Automaton.Trans.Except (performOnFirstSample)
+import qualified Data.Automaton.Trans.Reader as AutomatonReader
+import qualified Data.Automaton.Trans.Writer as AutomatonWriter
+import Data.Stream.Result (Result (..))
+
 -- rhine
 import FRP.Rhine
 
@@ -114,7 +114,7 @@
   IO ()
 flowGlossClSF settings clsf = flowGloss settings $ clsf >-> arrMCl paintAll @@ GlossClock
 
-type WorldMSF = MSF Identity ((Float, Maybe Event), ()) (Picture, Maybe ())
+type WorldAutomaton = Automaton Identity ((Float, Maybe Event), ()) (Picture, Maybe ())
 
 -- | The main function that will start the @gloss@ backend and run the 'Rhine'
 flowGloss ::
@@ -123,12 +123,12 @@
   Rhine GlossM cl () () ->
   IO ()
 flowGloss GlossSettings {..} rhine =
-  play display backgroundColor stepsPerSecond (worldMSF, Blank) getPic handleEvent simStep
+  play display backgroundColor stepsPerSecond (worldAutomaton, Blank) getPic handleEvent simStep
   where
-    worldMSF :: WorldMSF
-    worldMSF = MSFWriter.runWriterS $ MSFReader.runReaderS $ morphS (runYieldT . unGlossM) $ performOnFirstSample $ eraseClock rhine
-    stepWith :: (Float, Maybe Event) -> (WorldMSF, Picture) -> (WorldMSF, Picture)
-    stepWith (diff, eventMaybe) (msf, _) = let ((picture, _), msf') = runIdentity $ unMSF msf ((diff, eventMaybe), ()) in (msf', picture)
+    worldAutomaton :: WorldAutomaton
+    worldAutomaton = AutomatonWriter.runWriterS $ AutomatonReader.runReaderS $ hoistS (runYieldT . unGlossM) $ performOnFirstSample $ eraseClock rhine
+    stepWith :: (Float, Maybe Event) -> (WorldAutomaton, Picture) -> (WorldAutomaton, Picture)
+    stepWith (diff, eventMaybe) (automaton, _) = let Result automaton' (picture, _) = runIdentity $ stepAutomaton automaton ((diff, eventMaybe), ()) in (automaton', picture)
     getPic (_, pic) = pic
     handleEvent event = stepWith (0, Just event)
     simStep diff = stepWith (diff, Nothing)
