diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for miso-action-logger
+
+## 0.1.0.0 -- 2019-06-24
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2019, Sviat Chumakov
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Sviat Chumakov nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/miso-action-logger.cabal b/miso-action-logger.cabal
new file mode 100644
--- /dev/null
+++ b/miso-action-logger.cabal
@@ -0,0 +1,34 @@
+cabal-version:       2.4
+name:                miso-action-logger
+version:             0.1.0.0
+synopsis:            Miso state transition logger
+description:         State transition logger for Miso heavily inspired by Redux-Logger.
+homepage:            https://github.com/Lermex/miso-action-logger
+bug-reports:         https://github.com/Lermex/miso-action-logger/issues
+license:             BSD-3-Clause
+license-file:        LICENSE
+author:              Sviat Chumakov
+maintainer:          svchumakov@gmail.com
+copyright:           Copyright (c) 2019 Sviat Chumakov
+category:            Web
+extra-source-files:  CHANGELOG.md
+
+library
+  exposed-modules:
+    MisoActionLogger
+    MisoActionLogger.FFI
+  -- other-modules:
+  -- other-extensions:
+  build-depends:
+      aeson
+    , base < 5
+    , ghcjs-base
+    , miso
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+  ghc-options:
+    -Wall
+
+source-repository head
+   type: git
+   location: https://github.com/Lermex/miso-action-logger.git
diff --git a/src/MisoActionLogger.hs b/src/MisoActionLogger.hs
new file mode 100644
--- /dev/null
+++ b/src/MisoActionLogger.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  MisoActionLogger
+-- Copyright   :  (C) 2019 Sviat Chumakov
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  Sviat Chumakov <svchumakov@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+----------------------------------------------------------------------------
+module MisoActionLogger
+  ( mkActionLogger
+  , defaultActionLogger
+  , defaultGroupFormat
+  , defaultStateFormat
+  , defaultActionFormat
+  , ActionLoggerOptions
+  ) where
+
+import           Data.Aeson
+import           Miso (Effect(..))
+import           Miso.String hiding (head, words)
+import           GHCJS.Types
+import           GHCJS.Marshal
+import           GHCJS.Marshal.Pure
+
+import           MisoActionLogger.FFI
+
+-- | Configuration for mkActionLogger.
+data ActionLoggerOptions action model = ActionLoggerOptions
+  { groupFormat         :: action -> IO JSVal
+   -- ^ Function to format the log group title
+  , previousStateFormat :: model  -> IO JSVal
+   -- ^ Function to format the previous state
+  , actionFormat        :: action -> IO JSVal
+   -- ^ Function to format the action
+  , nextStateFormat     :: model  -> IO JSVal
+   -- ^ Function to format the next state
+  }
+
+-- | Create an action logger with custom settings.
+-- Returns a logger that wraps around your 'update' function when you construct a Miso app.
+mkActionLogger
+  :: (Show action, ToJSON model)
+  => ActionLoggerOptions action model
+  -> (action -> model -> Effect action model)
+  -> action -> model -> Effect action model
+mkActionLogger ActionLoggerOptions{..} update action oldModel = Effect newModel (logSub : subs)
+    where
+      Effect newModel subs = update action oldModel
+      logSub _ = do
+         groupVal  <- groupFormat action
+         oldVal    <- previousStateFormat oldModel
+         actionVal <- actionFormat action
+         newVal    <- nextStateFormat newModel
+
+         consoleGroupCollapsed groupVal
+         consoleLog oldVal
+         consoleLog actionVal
+         consoleLog newVal
+         consoleGroupEnd
+
+-- | Action logger with default settings.
+-- Wraps around your 'update' function when you construct a Miso app.
+defaultActionLogger
+  :: (Show action, ToJSON model)
+  => (action -> model -> Effect action model)
+  -> action -> model -> Effect action model
+defaultActionLogger = mkActionLogger ActionLoggerOptions
+  { groupFormat = defaultGroupFormat
+  , previousStateFormat = defaultStateFormat defaultPreviousStateLabel defaultPreviousStateStyle
+  , actionFormat = defaultActionFormat
+  , nextStateFormat = defaultStateFormat defaultNextStateLabel defaultNextStateStyle
+  }
+
+defaultPreviousStateLabel :: MisoString
+defaultPreviousStateLabel = "%cprev state %c"
+
+defaultNextStateLabel :: MisoString
+defaultNextStateLabel = "%cnext state %c"
+
+defaultPreviousStateStyle :: MisoString
+defaultPreviousStateStyle = "color: #9E9E9E; font-weight: bold;"
+
+defaultNextStateStyle :: MisoString
+defaultNextStateStyle = "color: #4CAF50; font-weight: bold;"
+
+defaultGroupFormat :: Show action => action -> IO JSVal
+defaultGroupFormat action =
+  toJSVal
+    [ "%caction %c" <> ((ms . head . words . show) action)
+    , "color: gray; font-weight: lighter;"
+    , ""
+    ]
+
+defaultStateFormat :: ToJSON model => MisoString -> MisoString -> model -> IO JSVal
+defaultStateFormat label style model = do
+  modelVal <- toJSVal (toJSON model) 
+  toJSVal
+    [ pToJSVal label
+    , pToJSVal style
+    , pToJSVal ("" :: MisoString)
+    , modelVal
+    ]
+
+defaultActionFormat :: Show action => action -> IO JSVal
+defaultActionFormat action =
+  toJSVal
+    [ pToJSVal ("%caction %c" :: MisoString)
+    , pToJSVal ("color: #03A9F4; font-weight: bold;" :: MisoString)
+    , pToJSVal ("" :: MisoString)
+    , pToJSVal $ show action
+    ]
diff --git a/src/MisoActionLogger/FFI.hs b/src/MisoActionLogger/FFI.hs
new file mode 100644
--- /dev/null
+++ b/src/MisoActionLogger/FFI.hs
@@ -0,0 +1,44 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  MisoActionLogger.FFI
+-- Copyright   :  (C) 2019 Sviat Chumakov
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  Sviat Chumakov <svchumakov@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+----------------------------------------------------------------------------
+module MisoActionLogger.FFI where
+
+import         GHCJS.Types
+ 
+-- | Creates a new inline group in the browser console.
+-- This indents following console messages by an additional level,
+-- until 'consoleGroupEnd' is called.
+foreign import javascript unsafe "console.group.apply(console, $1);"
+    consoleGroup 
+      :: JSVal  -- ^ a JS array of arguments to print. 
+                -- Each one can be either a string to print, a string with CSS styles,
+                -- or an Object that will be inspectable in the console.
+      -> IO ()
+
+-- | Creates a new inline group in the browser console. Unlike 'consoleGroup', however,
+-- the new group is created collapsed. The user will need to use the disclosure button
+-- next to it to expand it, revealing the entries created in the group.
+foreign import javascript unsafe "console.groupCollapsed.apply(console, $1);"
+    consoleGroupCollapsed
+      :: JSVal  -- ^ a JS array of arguments to print. 
+                -- Each one can be either a string to print, a string with CSS styles,
+                -- or an Object that will be inspectable in the console.
+      -> IO ()
+
+-- | Exits the current inline group in the browser console. 
+foreign import javascript unsafe "console.groupEnd();"
+    consoleGroupEnd :: IO ()
+
+-- | Prints to the browser console.
+foreign import javascript unsafe "console.log.apply(console, $1);"
+    consoleLog
+      :: JSVal  -- ^ a JS array of arguments to print. 
+                -- Each one can be either a string to print, a string with CSS styles,
+                -- or an Object that will be inspectable in the console.
+      -> IO ()
