diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Gushcha Anton (c) 2015-2016
+
+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  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/gore-and-ash-demo.cabal b/gore-and-ash-demo.cabal
new file mode 100644
--- /dev/null
+++ b/gore-and-ash-demo.cabal
@@ -0,0 +1,136 @@
+name:                gore-and-ash-demo
+version:             1.0.0.0
+synopsis:            Demonstration game for Gore&Ash game engine
+description:         Please see README.md
+homepage:            https://github.com/Teaspot-Studio/gore-and-ash-demo
+license:             BSD3
+license-file:        LICENSE
+author:              Anton Gushcha
+maintainer:          ncrashed@gmail.com
+copyright:           2015-2016 Anton Gushcha
+category:            Game
+build-type:          Simple
+cabal-version:       >=1.10
+
+executable gore-and-ash-demo-client
+  hs-source-dirs:      src/client
+                       src/shared
+  main-is:             Main.hs
+  default-language:    Haskell2010
+  
+  other-modules:       
+                       Consts
+                       FPS
+                       Game
+                       Game.Bullet
+                       Game.Bullet.Data
+                       Game.Bullet.Shared
+                       Game.Camera
+                       Game.Core
+                       Game.Data
+                       Game.Player
+                       Game.Player.Data
+                       Game.Player.Shared
+                       Game.Shared
+                       Graphics.Bullet
+                       Graphics.Square
+                       
+  build-depends:       base >= 4.7 && < 5
+                     , bytestring >= 0.10.6.0
+                     , cereal >= 0.4.1.1
+                     , containers >= 0.5.6.2
+                     , deepseq >= 1.4
+                     , exception-transformers >= 0.4
+                     , exceptions >= 0.8.0.2
+                     , GLFW-b >= 1.4.7.3
+                     , gore-and-ash >= 1.1.0.0
+                     , gore-and-ash-actor >= 1.1.0.0
+                     , gore-and-ash-logging >= 1.1.0.0
+                     , gore-and-ash-network >= 1.1.0.0
+                     , gore-and-ash-sdl >= 1.1.0.0
+                     , gore-and-ash-sync >= 1.1.0.0
+                     , hashable >= 1.2.3.3
+                     , lens >= 4.12.3
+                     , linear >= 1.19
+                     , network >= 2.6.2.1
+                     , OpenGL >= 3.0.0.0
+                     , sdl2 >= 2.1.1 
+                     , text >= 1.2.1
+                     , text-show >= 2
+                     , transformers >= 0.4.2
+                     , unordered-containers >= 0.2.5.1
+                     , vector >= 0.11.0.0
+
+  default-extensions:  
+                       Arrows
+                       DataKinds
+                       DeriveGeneric
+                       FlexibleContexts
+                       FlexibleInstances
+                       GeneralizedNewtypeDeriving
+                       MultiParamTypeClasses
+                       OverloadedStrings
+                       RankNTypes
+                       RecordWildCards
+                       TypeFamilies
+                       
+
+  ghc-options: -Wall -threaded
+
+executable gore-and-ash-demo-server
+  hs-source-dirs:      src/server
+                       src/shared
+  main-is:             Main.hs
+  default-language:    Haskell2010
+  
+  other-modules:       
+                       FPS
+                       Game
+                       Game.Bullet
+                       Game.Bullet.Data
+                       Game.Bullet.Shared
+                       Game.Core
+                       Game.Data
+                       Game.Player
+                       Game.Player.Data
+                       Game.Player.Shared
+                       Game.Shared
+                       
+  build-depends:       base >= 4.7 && < 5
+                     , bytestring >= 0.10.6.0
+                     , cereal >= 0.4.1.1
+                     , containers >= 0.5.6.2
+                     , deepseq >= 1.4
+                     , exception-transformers >= 0.4
+                     , exceptions >= 0.8.0.2                     
+                     , gore-and-ash >= 1.1.0.0
+                     , gore-and-ash-actor >= 1.1.0.0
+                     , gore-and-ash-logging >= 1.1.0.0
+                     , gore-and-ash-network >= 1.1.0.0
+                     , gore-and-ash-sync >= 1.1.0.0
+                     , hashable >= 1.2.3.3
+                     , lens >= 4.12.3
+                     , linear >= 1.19
+                     , network >= 2.6.2.1
+                     , text >= 1.2.1
+                     , text-show >= 2
+                     , time >= 1.5.0.1
+                     , transformers >= 0.4.2
+                     , unordered-containers >= 0.2.5.1
+                     
+  default-extensions:  
+                       Arrows
+                       DataKinds
+                       DeriveGeneric
+                       FlexibleContexts
+                       FlexibleInstances
+                       GeneralizedNewtypeDeriving
+                       MultiParamTypeClasses
+                       OverloadedStrings
+                       RankNTypes
+                       RecordWildCards
+                       ScopedTypeVariables
+                       TupleSections
+                       TypeFamilies
+                       
+  ghc-options: -Wall -threaded
diff --git a/src/client/Consts.hs b/src/client/Consts.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Consts.hs
@@ -0,0 +1,6 @@
+module Consts where
+
+import Data.Text 
+
+mainWindowName :: Text
+mainWindowName = "mainWindow"
diff --git a/src/client/Game.hs b/src/client/Game.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game.hs
@@ -0,0 +1,124 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game(
+    mainWire
+  , Player(..)
+  , Camera(..)
+  , Game(..)
+  , AppMonad
+  ) where
+
+import Control.Wire
+import Control.Wire.Unsafe.Event (event)
+import Data.Text (pack)
+import Prelude hiding (id, (.))
+import qualified Data.HashMap.Strict as H 
+import qualified Data.Sequence as S 
+
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor 
+import Game.GoreAndAsh.Logging
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.SDL
+import Game.GoreAndAsh.Sync 
+
+import Consts
+import Game.Bullet 
+import Game.Camera 
+import Game.Core
+import Game.Data
+import Game.Player
+import Game.Shared
+
+-- | Entry point of the game, controls global game stages
+mainWire :: AppWire a (Maybe Game)
+mainWire = waitConnection
+  where
+    -- | Game stage before connection established
+    waitConnection = dSwitch $ proc _ -> do 
+      e <- mapE seqLeftHead . peersConnected -< ()
+      traceEvent (const "Connected to server") -< e
+      returnA -< (Nothing, waitPlayerId <$> e) 
+
+    -- | Helper to get left most element from sequence or die
+    seqLeftHead s = case S.viewl s of 
+      S.EmptyL -> error "seqLeftHead: empty sequence"
+      (h S.:< _) -> h 
+
+    -- | After connection succeded, get important data to begin game
+    waitPlayerId peer = switch $ proc _ -> do 
+      -- Send request for player id
+      emsg <- now -< PlayerRequestId
+      peerSendIndexed peer (ChannelID 0) globalGameId ReliableMessage -< emsg
+      traceEvent (const "Waiting for player id") -< emsg
+      
+      -- Waiting for respond with player id
+      e <- mapE seqLeftHead . filterMsgs isPlayerResponseId . peerIndexedMessages peer (ChannelID 0) globalGameId -< () 
+      traceEvent (\(PlayerResponseId i _ _) -> "Got player id: " <> pack (show i)) -< e
+      
+      -- When recieved switch to next stage
+      let nextWire = (\(PlayerResponseId i bulletsColId playersColId) -> untilDisconnected peer (PlayerId i) (fromCounter bulletsColId) (fromCounter playersColId)) <$> e
+      returnA -< (Nothing, nextWire)
+
+    -- | Main game stage, actual playing
+    untilDisconnected peer pid bulletsColId playersColId = switch $ proc _ -> do 
+      e <- peerDisconnected peer -< ()
+      traceEvent (const "Disconnected from server") -< e
+      g <- runActor' (playGame pid peer bulletsColId playersColId) -< ()
+      returnA -< (g, const disconnected <$> e)
+
+    -- | Final stage, we are disconnected
+    disconnected = pure Nothing
+
+-- | Controller of main game stage when actual playing is happen
+playGame :: PlayerId -> Peer -> RemActorCollId -> RemActorCollId -> AppActor GameId a (Maybe Game)
+playGame pid peer bulletsColId playersColId = makeFixedActor globalGameId $ stateWire Nothing $ proc (_, mg) -> do 
+  c <- runActor' $ cameraWire initialCamera -< ()
+  ex <- exitCheck -< ()
+  (ps, bs) <- case mg of 
+    Nothing -> returnA -< (H.empty, H.empty)
+    Just g -> do 
+      ps <- processPlayers playersColId -< g
+      bs <- processBullets bulletsColId -< g
+      returnA -< (ps, bs)
+
+  forceNF -< Just $! case mg of 
+    Nothing -> Game {
+        gameId = globalGameId
+      , gamePlayer = H.lookup pid ps
+      , gameCamera = c
+      , gamePlayers = ps
+      , gameBullets = bs
+      , gameExit = ex
+      }
+    Just g -> g {
+        gamePlayer = H.lookup pid ps
+      , gameCamera = c
+      , gamePlayers = ps
+      , gameBullets = bs
+      , gameExit = ex
+      }
+  where
+  -- | Check if user or system wants us to die
+  exitCheck = proc _ -> do 
+    e <- windowClosed mainWindowName -< ()
+    q <- liftGameMonad sdlQuitEventM -< ()
+    returnA -< event False (const True) e || q
+
+  -- | Maker of startup camera
+  initialCamera i = Camera i 0 0.1
+
+  -- | Handles spawing/despawing of other players
+  processPlayers :: RemActorCollId -> AppWire Game PlayerMap
+  processPlayers cid = proc g -> do
+    ps <- runActor' $ remoteActorCollectionClient cid peer makePlayerActor -< gameCamera g
+    returnA -< mapFromSeq $ fmap playerId ps `S.zip` ps
+    where
+      makePlayerActor i = if i == pid 
+        then playerActor peer pid
+        else remotePlayerActor peer i
+
+  -- | Handles spawing/despawing of bullets
+  processBullets :: RemActorCollId -> AppWire Game BulletMap
+  processBullets cid = proc g -> do 
+    bs <- runActor' $ remoteActorCollectionClient cid peer (bulletActor peer) -< g
+    returnA -< mapFromSeq $ fmap bulletId bs `S.zip` bs
diff --git a/src/client/Game/Bullet.hs b/src/client/Game/Bullet.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Bullet.hs
@@ -0,0 +1,45 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game.Bullet(
+    module ReExport
+  , bulletActor
+  ) where
+
+import Control.Wire 
+import Prelude hiding (id, (.))
+
+import Game.Bullet.Data as ReExport
+import Game.Core 
+import Game.Data 
+
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Sync 
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Network 
+
+import Graphics.Bullet
+
+instance RemoteActor BulletId Bullet where
+  type RemoteActorState BulletId = Bullet
+  type RemoteActorId Bullet = BulletId
+
+bulletActor :: Peer -> BulletId -> AppActor BulletId Game Bullet 
+bulletActor peer i = makeFixedActor i $ stateWire initalBullet mainController
+  where
+  initalBullet = Bullet {
+      bulletId = i
+    , bulletPos = 0
+    , bulletVel = 0
+    , bulletOwner = fromCounter (-1)
+    }
+
+  mainController :: AppWire (Game, Bullet) Bullet
+  mainController = proc (g, b) -> do
+    liftGameMonad3 renderBullet -< (bulletPos b, bulletVel b, gameCamera g)
+    forceNF . clientSync bulletSync peer i -< b
+
+  bulletSync :: FullSync AppMonad BulletId Bullet
+  bulletSync = Bullet 
+    <$> pure i 
+    <*> serverSide 0 bulletPos 
+    <*> serverSide 1 bulletVel 
+    <*> serverSide 2 bulletOwner
diff --git a/src/client/Game/Bullet/Data.hs b/src/client/Game/Bullet/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Bullet/Data.hs
@@ -0,0 +1,43 @@
+module Game.Bullet.Data(
+    BulletId(..)
+  , Bullet(..)
+  , BulletMessage(..)
+  , BulletNetMessage
+  ) where
+
+import Control.DeepSeq
+import Data.Hashable
+import Data.Typeable 
+import GHC.Generics (Generic)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Sync
+
+import Game.Player.Data 
+import Game.Bullet.Shared
+
+data Bullet = Bullet {
+  bulletId :: !BulletId
+, bulletPos :: !(V2 Double)
+, bulletVel :: !(V2 Double)
+, bulletOwner :: !PlayerId
+} deriving (Generic)
+
+instance NFData Bullet 
+
+newtype BulletId = BulletId { unBulletId :: Int } deriving (Eq, Show, Generic) 
+instance NFData BulletId 
+instance Hashable BulletId 
+
+data BulletMessage = BulletMessageStub deriving (Typeable, Generic)
+instance NFData BulletMessage 
+
+instance ActorMessage BulletId where
+  type ActorMessageType BulletId = BulletMessage
+  toCounter = unBulletId
+  fromCounter = BulletId
+  
+instance NetworkMessage BulletId where 
+  type NetworkMessageType BulletId = BulletNetMessage
diff --git a/src/client/Game/Camera.hs b/src/client/Game/Camera.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Camera.hs
@@ -0,0 +1,80 @@
+module Game.Camera(
+    Camera(..)
+  , CameraId(..)
+  , cameraWire
+  , cameraMatrix
+  , cameraToWorld
+  , cameraFromWorld
+  ) where
+
+import Control.DeepSeq
+import Control.Lens 
+import Control.Wire
+import Control.Wire.Unsafe.Event
+import GHC.Generics (Generic)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.Core
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.SDL
+
+data Camera = Camera {
+  cameraId :: !CameraId
+, cameraPos :: !(V2 Double)
+, cameraZoom :: !Double
+} deriving (Generic)
+
+instance NFData Camera 
+
+newtype CameraId = CameraId { unCameraId :: Int } deriving (Eq, Show, Generic)
+instance NFData CameraId 
+
+data CameraMessage
+
+instance ActorMessage CameraId where
+  type ActorMessageType CameraId = CameraMessage
+  toCounter = unCameraId
+  fromCounter = CameraId
+
+cameraWire :: (CameraId -> Camera) -> AppActor CameraId a Camera 
+cameraWire initialCamera = makeActor $ \i -> stateWire (initialCamera i) $ proc (_, c) -> do 
+  forceNF
+    . moveCamera (V2 0 (-cameraSpeed)) ScancodeS 
+    . moveCamera (V2 0 cameraSpeed) ScancodeW 
+    . moveCamera (V2 cameraSpeed 0) ScancodeD
+    . moveCamera (V2 (-cameraSpeed) 0) ScancodeA
+    . zoomCamera 0.1 -< c
+  where 
+    cameraSpeed :: Double 
+    cameraSpeed = 0.1
+
+    moveCamera :: V2 Double -> Scancode -> AppWire Camera Camera
+    moveCamera dv k = proc c -> do 
+      e <- keyPressing k -< ()
+      let newCam = c {
+            cameraPos = cameraPos c + dv 
+          }
+      returnA -< event c (const newCam) e
+
+    zoomCamera :: Double -> AppWire Camera Camera 
+    zoomCamera z = proc c -> do 
+      e <- mouseScrollY -< ()
+      let newCam k = c {
+            cameraZoom = min 3 $ max 0.01 $ cameraZoom c + 0.2 * z * k
+          }
+      returnA -< event c (newCam . fromIntegral) e 
+
+-- | Calculate transformation matrix for camera
+cameraMatrix :: Camera -> M33 Double
+cameraMatrix Camera{..} = translate2D (V2 (-cameraPos^._x) (-cameraPos^._y))
+  !*! scale2D (V2 (-cameraZoom) (-cameraZoom))
+
+-- | Transform camera local coords to world
+cameraToWorld :: Camera -> V2 Double -> V2 Double
+cameraToWorld c v = inv33 (cameraMatrix c) `applyTransform2D` v
+
+-- | Transform world coords to camera coords
+cameraFromWorld :: Camera -> V2 Double -> V2 Double 
+cameraFromWorld c v = cameraMatrix c `applyTransform2D` v
diff --git a/src/client/Game/Core.hs b/src/client/Game/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Core.hs
@@ -0,0 +1,58 @@
+module Game.Core(
+    AppMonad(..)
+  , AppWire
+  , AppActor
+  ) where
+
+import Control.DeepSeq
+import Control.Monad.Catch
+import Control.Monad.Fix
+import Control.Monad.IO.Class
+import Control.Wire
+import Data.Proxy 
+import Game.GoreAndAsh
+import GHC.Generics (Generic)
+import Prelude hiding (id, (.))
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Logging
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.SDL 
+import Game.GoreAndAsh.Sync 
+
+-- | Application monad is monad stack build from given list of modules over base monad (IO)
+type AppStack = ModuleStack [LoggingT, ActorT, NetworkT, SyncT, SDLT] IO
+newtype AppState = AppState (ModuleState AppStack)
+  deriving (Generic)
+
+instance NFData AppState 
+
+-- | Wrapper around type family
+newtype AppMonad a = AppMonad (AppStack a)
+  deriving (Functor, Applicative, Monad, MonadFix, MonadIO, LoggingMonad, NetworkMonad, ActorMonad, MonadCatch, MonadThrow, MonadSDL)
+
+-- | Current GHC (7.10.3) isn't able to derive this
+instance SyncMonad AppMonad where 
+  getSyncIdM = AppMonad . getSyncIdM
+  getSyncTypeRepM = AppMonad . getSyncTypeRepM
+  registerSyncIdM = AppMonad . registerSyncIdM
+  addSyncTypeRepM a b = AppMonad $ addSyncTypeRepM a b
+  syncScheduleMessageM peer ch i mt msg  = AppMonad $ syncScheduleMessageM peer ch i mt msg
+  syncSetLoggingM = AppMonad . syncSetLoggingM
+  syncSetRoleM = AppMonad . syncSetRoleM
+  syncGetRoleM = AppMonad syncGetRoleM
+  syncRequestIdM a b = AppMonad $ syncRequestIdM a b 
+  
+instance GameModule AppMonad AppState where 
+  type ModuleState AppMonad = AppState
+  runModule (AppMonad m) (AppState s) = do 
+    (a, s') <- runModule m s 
+    return (a, AppState s')
+  newModuleState = AppState <$> newModuleState
+  withModule _ = withModule (Proxy :: Proxy AppStack)
+  cleanupModule (AppState s) = cleanupModule s 
+
+-- | Arrow that is build over the monad stack
+type AppWire a b = GameWire AppMonad a b
+-- | App actor that is monadic action to create indexed wire
+type AppActor i a b = GameActor AppMonad i a b 
diff --git a/src/client/Game/Data.hs b/src/client/Game/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Data.hs
@@ -0,0 +1,42 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game.Data(
+    BulletMap
+  , PlayerMap
+  , Game(..)
+  ) where
+
+import Control.DeepSeq
+import Game.Shared
+import GHC.Generics
+import qualified Data.HashMap.Strict as H 
+
+import Game.Bullet.Data
+import Game.Camera 
+import Game.Player.Data 
+
+import Game.GoreAndAsh.Actor 
+import Game.GoreAndAsh.Sync 
+
+type BulletMap = H.HashMap BulletId Bullet
+type PlayerMap = H.HashMap PlayerId Player 
+
+data Game = Game {
+  gameId :: !GameId
+, gamePlayer :: !(Maybe Player)
+, gameCamera :: !Camera
+, gamePlayers :: !PlayerMap
+, gameBullets :: !BulletMap
+, gameExit :: !Bool
+} deriving (Generic)
+
+instance NFData Game 
+
+data GameMessage 
+
+instance ActorMessage GameId where
+  type ActorMessageType GameId = GameMessage 
+  toCounter = unGameId
+  fromCounter = GameId
+
+instance NetworkMessage GameId where 
+  type NetworkMessageType GameId = GameNetMessage
diff --git a/src/client/Game/Player.hs b/src/client/Game/Player.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Player.hs
@@ -0,0 +1,95 @@
+module Game.Player(
+    module ReExport
+  , playerActor
+  , remotePlayerActor
+  ) where
+
+import Control.Wire
+import Control.Wire.Unsafe.Event
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.Core
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.SDL 
+import Game.GoreAndAsh.Sync
+
+import Game.Camera 
+import Game.Player.Data as ReExport
+import Graphics.Square
+
+playerActor :: Peer -> PlayerId -> AppActor PlayerId Camera Player 
+playerActor peer i = makeFixedActor i $ stateWire initialPlayer $ proc (c, p) -> do 
+  processFire -< (c, p)
+  liftGameMonad4 renderSquare -< (playerSize p, playerPos p, playerColor p, c)
+  forceNF . clientSync playerSync peer i . controlPlayer -< p
+  where
+    initialPlayer = Player {
+        playerId = i 
+      , playerPos = 0
+      , playerColor = V3 1 0 0
+      , playerRot = 0
+      , playerSpeed = 0.5
+      , playerSize = 1
+      }
+      
+    controlPlayer :: AppWire Player Player
+    controlPlayer = 
+        movePlayer (V2 (-1) 0) ScancodeRight
+      . movePlayer (V2 1 0) ScancodeLeft
+      . movePlayer (V2 0 1) ScancodeDown
+      . movePlayer (V2 0 (-1)) ScancodeUp
+
+    movePlayer :: V2 Double -> Scancode -> AppWire Player Player
+    movePlayer dv k = proc p -> do 
+      e <- keyPressing k -< ()
+      dt <- deltaTime -< ()
+      let newPlayer = p {
+            playerPos = playerPos p + dv * v2 (dt * playerSpeed p)
+          }
+          v2 a = V2 a a
+      returnA -< event p (const newPlayer) e
+
+    processFire :: AppWire (Camera, Player) ()
+    processFire = proc (c, p) -> do 
+      e <- mouseClick ButtonLeft -< ()
+      let wpos = cameraToWorld c <$> e
+      let edir = (\v -> normalize $ v - playerPos p) <$> wpos 
+      let emsg = NetMsgPlayerFire <$> edir
+      peerSendIndexed peer (ChannelID 0) i ReliableMessage -< emsg
+      returnA -< ()
+
+    playerSync :: FullSync AppMonad PlayerId Player 
+    playerSync = Player 
+      <$> pure i 
+      <*> clientSide peer 0 playerPos
+      <*> clientSide peer 1 playerColor
+      <*> clientSide peer 2 playerRot
+      <*> clientSide peer 3 playerSpeed
+      <*> clientSide peer 4 playerSize
+
+-- | Actor for updating local state of remote player on server
+remotePlayerActor :: Peer -> PlayerId -> AppActor PlayerId Camera Player
+remotePlayerActor peer i = makeFixedActor i $ stateWire initPlayer $ proc (c, p) -> do 
+    liftGameMonad4 renderSquare -< (playerSize p, playerPos p, playerColor p, c)
+    forceNF . clientSync playerSync peer i -< p
+    where
+    initPlayer = Player {
+        playerId = i 
+      , playerPos = 0 
+      , playerColor = 0
+      , playerRot = 0
+      , playerSpeed = 0
+      , playerSize = 1
+      }
+
+    playerSync :: FullSync AppMonad PlayerId Player 
+    playerSync = Player 
+      <$> pure i 
+      <*> serverSide 0 playerPos
+      <*> serverSide 1 playerColor
+      <*> serverSide 2 playerRot
+      <*> serverSide 3 playerSpeed
+      <*> serverSide 4 playerSize
diff --git a/src/client/Game/Player/Data.hs b/src/client/Game/Player/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Game/Player/Data.hs
@@ -0,0 +1,50 @@
+module Game.Player.Data(
+    Player(..)
+  , PlayerId(..)
+  , PlayerMessage(..)
+  , PlayerNetMessage(..)
+  ) where
+
+import Control.DeepSeq
+import Data.Hashable
+import Data.Serialize
+import Data.Typeable
+import GHC.Generics (Generic)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Sync
+
+import Game.Player.Shared
+
+data Player = Player {
+  playerId :: !PlayerId
+, playerPos :: !(V2 Double)
+, playerColor :: !(V3 Double) 
+, playerRot :: !Double
+, playerSpeed :: !Double
+, playerSize :: !Double
+} deriving (Generic, Show)
+
+instance NFData Player 
+
+newtype PlayerId = PlayerId { unPlayerId :: Int } deriving (Eq, Show, Generic)
+instance NFData PlayerId 
+instance Serialize PlayerId 
+instance Hashable PlayerId 
+
+data PlayerMessage = PlayerMessageStub deriving (Typeable, Generic)
+instance NFData PlayerMessage 
+
+instance ActorMessage PlayerId where
+  type ActorMessageType PlayerId = PlayerMessage
+  toCounter = unPlayerId
+  fromCounter = PlayerId
+
+instance NetworkMessage PlayerId where 
+  type NetworkMessageType PlayerId = PlayerNetMessage
+
+instance RemoteActor PlayerId Player where
+  type RemoteActorState PlayerId = Player
+  type RemoteActorId Player = PlayerId
diff --git a/src/client/Graphics/Bullet.hs b/src/client/Graphics/Bullet.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Graphics/Bullet.hs
@@ -0,0 +1,31 @@
+module Graphics.Bullet(
+    renderBullet
+  ) where
+
+import Consts
+import Game.Camera 
+import Game.GoreAndAsh
+import Game.GoreAndAsh.SDL 
+import Linear
+import Linear.Affine
+import SDL 
+
+-- | Function of rendering player
+renderBullet :: MonadSDL m => V2 Double -> V2 Double -> Camera -> GameMonadT m ()
+renderBullet pos vel c = do  
+  mwr <- sdlGetWindowM mainWindowName
+  case mwr of 
+    Nothing -> return ()
+    Just (w, r) -> do 
+      wsize <- fmap (fmap fromIntegral) . get $ windowSize w
+      rendererDrawColor r $= V4 0 0 0 255
+      drawLine r (apply wsize startPoint) (apply wsize endPoint)
+  where
+    velScaleFactor = 0.04
+    startPoint = negate (velScaleFactor * 0.5 * vel)
+    endPoint = velScaleFactor * 0.5 * vel
+
+    apply wsize = P . fmap round . applyTransform2D (modelMtx wsize)
+
+    modelMtx :: V2 Double -> M33 Double 
+    modelMtx wsize = viewportTransform2D 0 wsize !*! cameraMatrix c !*! translate2D pos
diff --git a/src/client/Graphics/Square.hs b/src/client/Graphics/Square.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Graphics/Square.hs
@@ -0,0 +1,36 @@
+module Graphics.Square(
+    renderSquare
+  ) where
+
+import Consts
+import Data.Word
+import Foreign.C.Types
+import Game.Camera 
+import Game.GoreAndAsh
+import Game.GoreAndAsh.SDL 
+import Linear
+import Linear.Affine
+import SDL 
+
+-- | Function of rendering player
+renderSquare :: MonadSDL m => Double -> V2 Double -> V3 Double -> Camera -> GameMonadT m ()
+renderSquare size pos col c = do  
+  mwr <- sdlGetWindowM mainWindowName
+  case mwr of 
+    Nothing -> return ()
+    Just (w, r) -> do 
+      wsize <- fmap (fmap fromIntegral) . get $ windowSize w
+      rendererDrawColor r $= transColor col 
+      fillRect r $ Just $ transformedSquare wsize
+  where
+    transColor :: V3 Double -> V4 Word8
+    transColor (V3 r g b) = V4 (round $ r * 255) (round $ g * 255) (round $ b * 255) 255
+
+    modelMtx :: V2 Double -> M33 Double 
+    modelMtx wsize = viewportTransform2D 0 wsize !*! cameraMatrix c !*! translate2D pos
+
+    transformedSquare :: V2 Double -> Rectangle CInt
+    transformedSquare wsize = Rectangle (P topleft) (botright - topleft) 
+      where
+      topleft = fmap round . applyTransform2D (modelMtx wsize) $ V2 (-size/2) (-size/2)
+      botright = fmap round . applyTransform2D (modelMtx wsize) $ V2 (size/2) (size/2)
diff --git a/src/client/Main.hs b/src/client/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/client/Main.hs
@@ -0,0 +1,87 @@
+module Main where  
+
+import Consts
+import Control.DeepSeq 
+import Control.Monad (join)
+import Control.Monad.IO.Class
+import Data.Maybe (fromMaybe)
+import Data.Proxy 
+import FPS
+import Game 
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.SDL
+import Game.GoreAndAsh.Sync
+import Network.BSD (getHostByName, hostAddress)
+import Network.Socket (SockAddr(..))
+import System.Environment
+import Text.Read 
+
+import Linear (V4(..))
+
+gameFPS :: Int 
+gameFPS = 60 
+
+parseArgs :: IO (String, Int)
+parseArgs = do 
+  args <- getArgs 
+  case args of 
+    [h, p] -> case readMaybe p of 
+      Nothing -> fail "Failed to parse port"
+      Just pint -> return (h, pint)
+    _ -> fail "Misuse of arguments: gore-and-ash-client HOST PORT"
+
+
+main :: IO ()
+main = withModule (Proxy :: Proxy AppMonad) $ do
+  gs <- newGameState mainWire
+  (host, port) <- liftIO parseArgs
+  fps <- makeFPSBounder 60
+  firstLoop fps host port gs 
+  where 
+    -- | Resolve given hostname and port
+    getAddr s p = do
+      he <- getHostByName s
+      return $ SockAddrInet p $ hostAddress he
+
+    firstLoop fps host port gs = do 
+      (_, gs') <- stepGame gs $ do 
+        networkSetDetailedLoggingM False
+        syncSetLoggingM False
+        syncSetRoleM SyncSlave
+        networkBind Nothing 1 2 0 0
+        addr <- liftIO $ getAddr host (fromIntegral port)
+        _ <- networkConnect addr 2 0
+        _ <- sdlCreateWindowM mainWindowName "Gore&Ash Client" defaultWindow defaultRenderer
+        sdlSetBackColor mainWindowName $ V4 200 200 200 255
+      gameLoop fps gs'
+
+    gameLoop fps gs = do
+      waitFPSBound fps 
+      (mg, gs') <- stepGame gs (return ())
+      mg `deepseq` if fromMaybe False $ gameExit <$> join mg
+        then cleanupGameState gs'
+        else gameLoop fps gs'
+
+{-
+main :: IO ()
+main = do
+  initializeAll
+  window <- createWindow "My SDL Application" defaultWindow
+  renderer <- createRenderer window (-1) defaultRenderer
+  appLoop renderer
+
+appLoop :: Renderer -> IO ()
+appLoop renderer = do
+  events <- pollEvents
+  let eventIsQPress event =
+        case eventPayload event of
+          KeyboardEvent keyboardEvent ->
+            keyboardEventKeyMotion keyboardEvent == Pressed &&
+            keysymKeycode (keyboardEventKeysym keyboardEvent) == KeycodeQ
+          _ -> False
+      qPressed = not (null (filter eventIsQPress events))
+  rendererDrawColor renderer $= V4 0 0 255 255
+  clear renderer
+  present renderer
+  unless qPressed (appLoop renderer) -}
diff --git a/src/server/Game.hs b/src/server/Game.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game.hs
@@ -0,0 +1,105 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game(
+    mainWire
+  , Game(..)
+  ) where
+
+import Control.Wire
+import Data.Maybe 
+import Data.Text (pack)
+import Linear
+import Prelude hiding (id, (.))
+import qualified Data.HashMap.Strict as H 
+import qualified Data.Sequence as S 
+
+import Game.Bullet 
+import Game.Core
+import Game.Data
+import Game.Player
+import Game.Shared
+
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor 
+import Game.GoreAndAsh.Logging
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.Sync 
+
+-- | Wire that returns next player color
+playerColors :: AppWire (Event a) (V3 Double)
+playerColors = dDispense [
+    V3 1 0 0
+  , V3 0 1 0
+  , V3 0 0 1
+  , V3 1 1 0
+  , V3 1 0 1
+  , V3 0 1 1
+  ]
+
+mainWire :: AppActor GameId a Game
+mainWire = makeFixedActor globalGameId $ stateWire initGame $ proc (_, g) -> do 
+  forceNF . processBullets . processPlayers -< g
+  where 
+    -- | Game at start of the simulation
+    initGame = Game {
+        gameId = globalGameId
+      , gamePlayers = H.empty
+      , gamePlayerPeers = H.empty
+      , gameBullets = H.empty
+      , gameBulletColId = fromCounter (-1)
+      , gamePlayerColId = fromCounter (-1)
+      }
+
+    -- | Handles process of players connection and disconnections
+    processPlayers :: AppWire Game Game
+    processPlayers = proc g -> do 
+      conEvent <- peersConnected -< ()
+      col <- playerColors -< conEvent
+      let addEvent = fmap (spawnPlayer col) <$> conEvent
+
+      disEvent <- peersDisconnected -< ()
+      remEvent <- filterJustLE -< fmap (despawnPlayer g) <$> disEvent
+
+      traceEvent (const "New player connected") -< addEvent -- Player id is not ready yet :(
+      traceEvent (\i -> "Player " <> (pack . show) i <> " disconnected") -< remEvent
+
+      (ps, i) <- runActor $ remoteActorCollectionServer S.empty -< (g, addEvent, remEvent)
+      returnA -< g {
+          gamePlayers = mapFromSeq $ fmap playerId  ps `S.zip` ps
+        , gamePlayerPeers = mapFromSeq $ fmap playerPeer ps `S.zip` fmap playerId ps
+        , gamePlayerColId = i
+        }
+
+    -- | Spawns new player from peer (creates new arrow)
+    spawnPlayer :: V3 Double -> Peer -> AppActor PlayerId Game Player
+    spawnPlayer c p = playerActor $ \i -> Player {
+        playerId = i
+      , playerPos = 0
+      , playerColor = c
+      , playerRot = 0
+      , playerPeer = p
+      , playerSpeed = 15
+      , playerSize = 1
+      }
+
+    -- | Detects player id by peer for despawning
+    despawnPlayer :: Game -> Peer -> Maybe PlayerId
+    despawnPlayer Game{..} p = H.lookup p gamePlayerPeers
+
+    -- | Handle bullets actors
+    processBullets :: AppWire Game Game 
+    processBullets = proc g -> do 
+      addEvent <- mapE (fmap (bulletActor . newBullet)) . actorMessages globalGameId isGameSpawnBullet -< ()
+      remEvent <- mapE (fmap $ \(GameDeleteBullet i) -> i) . actorMessages globalGameId isGameDeleteBullet -< ()
+      (bs, i) <- runActor $ remoteActorCollectionServer S.empty -< (g, addEvent, remEvent)
+      returnA -< g {
+          gameBullets = mapFromSeq $ fmap bulletId bs `S.zip` bs
+        , gameBulletColId = i
+        }
+      where
+        newBullet (GameSpawnBullet pos vel owner) i = Bullet {
+            bulletId = i 
+          , bulletPos = pos
+          , bulletVel = vel
+          , bulletOwner = owner
+          }
+        newBullet _ _ = error "newBullet: wrong message"
diff --git a/src/server/Game/Bullet.hs b/src/server/Game/Bullet.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Bullet.hs
@@ -0,0 +1,72 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game.Bullet(
+    module ReExport
+  , bulletActor
+  ) where
+
+import Control.Wire 
+import Data.Serialize
+import Data.Word 
+import Linear 
+import Prelude hiding (id, (.))
+import qualified Data.HashMap.Strict as H
+
+import Game.Bullet.Data as ReExport
+import Game.Core 
+import Game.Data 
+import Game.Player.Data
+import Game.Shared 
+
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor 
+import Game.GoreAndAsh.Sync 
+
+instance RemoteActor BulletId Bullet where
+  type RemoteActorState BulletId = Bullet
+  type RemoteActorId Bullet = BulletId
+
+bulletActor :: (BulletId -> Bullet) -> AppActor BulletId Game Bullet 
+bulletActor initalBullet = makeActor $ \i -> stateWire (initalBullet i) $ mainController i
+  where
+
+  mainController :: BulletId -> AppWire (Game, Bullet) Bullet
+  mainController i = proc (g, b) -> do
+    forceNF . serverSync bulletSync i . processBullet -< (b, g)
+    where
+
+    -- | Actual bullet logic
+    processBullet :: AppWire (Bullet, Game) Bullet 
+    processBullet = proc (b, g) -> do 
+      actorSend globalGameId . at bulletLifespan -< GameDeleteBullet i
+      playersShot -< (b, gamePlayers g)
+      dt <- deltaTime -< ()
+      let newPos = bulletPos b + V2 dt dt * bulletVel b 
+      returnA -< b {
+          bulletPos = newPos
+        } 
+      where 
+      -- | Test all players was shot
+      playersShot :: AppWire (Bullet, PlayerMap) ()
+      playersShot = liftGameMonad2 $ \b ps -> mapM_ (playerShot b) . H.elems $! ps 
+
+      -- | Test single player was shot
+      playerShot :: Bullet -> Player -> GameMonadT AppMonad ()
+      playerShot b p = do 
+        let V2 px py = playerPos p 
+            V2 bx by = bulletPos b
+            cond = abs (px - bx) <= playerSize p && abs (py - by) <= playerSize p
+        if cond then do 
+            actorSendM globalGameId . GameDeleteBullet $! i
+            actorSendM (playerId p) . PlayerShotMessage . bulletOwner $! b
+          else return ()
+
+    bulletSync :: FullSync AppMonad BulletId Bullet
+    bulletSync = Bullet 
+      <$> pure i 
+      <*> fsync 0 bulletPos 
+      <*> fsync 1 bulletVel 
+      <*> fsync 2 bulletOwner
+      where
+        fsync :: (Eq a, Serialize a) 
+          => Word64 -> (Bullet -> a) -> Sync AppMonad BulletId Bullet a
+        fsync fi f = condSync (fieldChanges f &> periodic 4 . arr f) f $ serverSide fi f 
diff --git a/src/server/Game/Bullet/Data.hs b/src/server/Game/Bullet/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Bullet/Data.hs
@@ -0,0 +1,55 @@
+module Game.Bullet.Data(
+    BulletId(..)
+  , Bullet(..)
+  , BulletMessage(..)
+  , BulletNetMessage
+  , bulletSpeed
+  , bulletLifespan
+  ) where
+
+import Control.DeepSeq
+import Data.Hashable
+import Data.Time.Clock (NominalDiffTime)
+import Data.Typeable 
+import GHC.Generics (Generic)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Sync
+
+import Game.Player.Data 
+import Game.Bullet.Shared 
+
+data Bullet = Bullet {
+  bulletId :: !BulletId
+, bulletPos :: !(V2 Double)
+, bulletVel :: !(V2 Double)
+, bulletOwner :: !PlayerId
+} deriving (Generic)
+
+instance NFData Bullet 
+
+newtype BulletId = BulletId { unBulletId :: Int } deriving (Eq, Show, Generic) 
+instance NFData BulletId 
+instance Hashable BulletId 
+
+data BulletMessage = BulletMessageStub deriving (Typeable, Generic)
+instance NFData BulletMessage 
+
+instance ActorMessage BulletId where
+  type ActorMessageType BulletId = BulletMessage
+  toCounter = unBulletId
+  fromCounter = BulletId
+  
+instance NetworkMessage BulletId where 
+  type NetworkMessageType BulletId = BulletNetMessage
+
+instance ElementWithId Bullet BulletId where
+    elementId = bulletId
+
+bulletSpeed :: Double 
+bulletSpeed = 20
+
+bulletLifespan :: NominalDiffTime 
+bulletLifespan = 5
diff --git a/src/server/Game/Core.hs b/src/server/Game/Core.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Core.hs
@@ -0,0 +1,57 @@
+module Game.Core(
+    AppMonad
+  , AppWire
+  , AppActor
+  ) where
+
+import Control.DeepSeq
+import Control.Monad.Catch
+import Control.Monad.Fix 
+import Control.Monad.IO.Class
+import Control.Wire
+import Data.Proxy
+import Game.GoreAndAsh
+import GHC.Generics (Generic)
+import Prelude hiding (id, (.))
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Logging
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.Sync
+
+-- | Application monad is monad stack build from given list of modules over base monad (IO)
+type AppStack = ModuleStack [LoggingT, ActorT, NetworkT, SyncT] IO
+newtype AppState = AppState (ModuleState AppStack)
+  deriving (Generic)
+
+instance NFData AppState 
+
+-- | Wrapper around type family
+newtype AppMonad a = AppMonad (AppStack a)
+  deriving (Functor, Applicative, Monad, MonadFix, MonadIO, LoggingMonad, NetworkMonad, ActorMonad, MonadThrow, MonadCatch)
+
+-- | Current GHC (7.10.3) isn't able to derive this
+instance SyncMonad AppMonad where 
+  getSyncIdM = AppMonad . getSyncIdM
+  getSyncTypeRepM = AppMonad . getSyncTypeRepM
+  registerSyncIdM = AppMonad . registerSyncIdM
+  addSyncTypeRepM a b = AppMonad $ addSyncTypeRepM a b
+  syncScheduleMessageM peer ch i mt msg  = AppMonad $ syncScheduleMessageM peer ch i mt msg
+  syncSetLoggingM = AppMonad . syncSetLoggingM
+  syncSetRoleM = AppMonad . syncSetRoleM
+  syncGetRoleM = AppMonad syncGetRoleM
+  syncRequestIdM a b = AppMonad $ syncRequestIdM a b 
+  
+instance GameModule AppMonad AppState where 
+  type ModuleState AppMonad = AppState
+  runModule (AppMonad m) (AppState s) = do 
+    (a, s') <- runModule m s 
+    return (a, AppState s')
+  newModuleState = AppState <$> newModuleState
+  withModule _ = withModule (Proxy :: Proxy AppStack)
+  cleanupModule (AppState s) = cleanupModule s 
+
+-- | Arrow that is build over the monad stack
+type AppWire a b = GameWire AppMonad a b
+-- | Action that makes indexed app wire
+type AppActor i a b = GameActor AppMonad i a b
diff --git a/src/server/Game/Data.hs b/src/server/Game/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Data.hs
@@ -0,0 +1,68 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Game.Data(
+    Game(..)
+  , GameMessage(..)
+  , PlayerMap
+  , PlayerPeerMap
+  , BulletsMap
+  -- | Helpers
+  , isGameSpawnBullet
+  , isGameDeleteBullet
+  ) where
+
+import Control.DeepSeq
+import GHC.Generics (Generic)
+import Prelude hiding (id, (.))
+import qualified Data.HashMap.Strict as H 
+import Linear 
+
+import Game.Bullet.Data
+import Game.Player.Data
+import Game.Shared
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.Sync 
+
+type PlayerMap = H.HashMap PlayerId Player
+type PlayerPeerMap = H.HashMap Peer PlayerId 
+type BulletsMap = H.HashMap BulletId Bullet 
+
+-- | Server local messages to game actor
+data GameMessage = 
+    -- | Spawn bullet at given pos with given velocity and owner
+    GameSpawnBullet !(V2 Double) !(V2 Double) !PlayerId 
+    -- | Deletes bullet with specified id
+  | GameDeleteBullet !BulletId
+  deriving (Generic, Show)
+
+instance ActorMessage GameId where
+  type ActorMessageType GameId = GameMessage 
+  toCounter = unGameId
+  fromCounter = GameId
+
+instance NetworkMessage GameId where 
+  type NetworkMessageType GameId = GameNetMessage
+
+data Game = Game {
+  gameId :: !GameId
+, gamePlayers :: !PlayerMap
+, gamePlayerPeers :: !PlayerPeerMap
+, gameBullets :: !BulletsMap
+, gameBulletColId :: !RemActorCollId 
+, gamePlayerColId :: !RemActorCollId
+} deriving (Generic)
+
+instance NFData Game 
+
+-- | Detect specific message
+isGameSpawnBullet :: GameMessage -> Bool
+isGameSpawnBullet m = case m of 
+  GameSpawnBullet _ _ _ -> True
+  _ -> False
+
+-- | Detect specific message
+isGameDeleteBullet :: GameMessage -> Bool
+isGameDeleteBullet m = case m of 
+  GameDeleteBullet _ -> True
+  _ -> False
diff --git a/src/server/Game/Player.hs b/src/server/Game/Player.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Player.hs
@@ -0,0 +1,77 @@
+module Game.Player(
+    Player(..)
+  , PlayerId(..)
+  , PlayerMessage
+  , playerActor
+  ) where
+
+import Control.Wire
+import Control.Wire.Unsafe.Event (event)
+import Data.Text (pack)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.Bullet.Data
+import Game.Core
+import Game.Data
+import Game.Player.Data
+import Game.Shared
+
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Logging
+import Game.GoreAndAsh.Network 
+import Game.GoreAndAsh.Sync
+
+playerActor :: (PlayerId -> Player) -> AppActor PlayerId Game Player 
+playerActor initialPlayer = makeActor $ \i -> stateWire (initialPlayer i) $ mainController i
+  where
+  mainController i = proc (g, p) -> do
+    p2 <- peerProcessIndexedM peer (ChannelID 0) i netProcess -< p
+    (_, p3) <- peerProcessIndexedM peer (ChannelID 0) globalGameId globalNetProcess -< (g, p2)
+    forceNF . serverSync playerSync i . playerShot -< p3
+    where
+    -- | Shortcut for peer
+    peer = playerPeer $ initialPlayer i
+
+    -- | Handle when player is shot
+    playerShot :: AppWire Player Player
+    playerShot = proc p -> do 
+      emsg <- actorMessages i isPlayerShotMessage -< ()
+      let newPlayer = p {
+          playerPos = 0
+        }
+      returnA -< event p (const newPlayer) emsg
+
+    -- | Process player specific net messages
+    netProcess :: Player -> PlayerNetMessage -> GameMonadT AppMonad Player 
+    netProcess p msg = case msg of 
+      NetMsgPlayerFire v -> do 
+        let d = normalize v 
+            v2 a = V2 a a
+            pos = playerPos p + d * v2 (playerSize p * 1.5)
+            vel = d * v2 bulletSpeed
+        putMsgLnM $ "Fire bullet at " <> pack (show pos) <> " with velocity " <> pack (show vel)
+        actorSendM globalGameId $ GameSpawnBullet pos vel $ playerId p
+        return p 
+
+    -- | Process global net messages from given peer (player)
+    globalNetProcess :: (Game, Player) -> GameNetMessage -> GameMonadT AppMonad (Game, Player)
+    globalNetProcess (g, p) msg = case msg of 
+      PlayerRequestId -> do
+        peerSendIndexedM peer (ChannelID 0) globalGameId ReliableMessage $ 
+          PlayerResponseId (toCounter i) (toCounter $ gameBulletColId g) (toCounter $ gamePlayerColId g)
+        return (g, p)
+      _ -> do 
+        putMsgLnM $ pack $ show msg
+        return (g, p) 
+
+    playerSync :: FullSync AppMonad PlayerId Player 
+    playerSync = Player 
+      <$> pure i 
+      <*> clientSide peer 0 playerPos
+      <*> clientSide peer 1 playerColor
+      <*> clientSide peer 2 playerRot
+      <*> clientSide peer 3 playerSpeed
+      <*> clientSide peer 4 playerSize
+      <*> pure peer
diff --git a/src/server/Game/Player/Data.hs b/src/server/Game/Player/Data.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Game/Player/Data.hs
@@ -0,0 +1,63 @@
+module Game.Player.Data(
+    Player(..)
+  , PlayerId(..)
+  , PlayerMessage(..)
+  , PlayerNetMessage(..)
+  , isPlayerShotMessage
+  ) where
+
+import Control.DeepSeq
+import Data.Hashable
+import Data.Typeable 
+import Data.Serialize
+import GHC.Generics (Generic)
+import Linear
+import Prelude hiding (id, (.))
+
+import Game.Player.Shared
+
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Network 
+import Game.GoreAndAsh.Sync
+
+data Player = Player {
+  playerId :: !PlayerId
+, playerPos :: !(V2 Double)
+, playerColor :: !(V3 Double) 
+, playerRot :: !Double 
+, playerSpeed :: !Double 
+, playerSize :: !Double
+, playerPeer :: !Peer
+} deriving (Generic)
+
+instance NFData Player 
+
+newtype PlayerId = PlayerId { unPlayerId :: Int } deriving (Eq, Show, Generic) 
+instance NFData PlayerId 
+instance Hashable PlayerId 
+instance Serialize PlayerId
+
+data PlayerMessage =
+    -- | The player was shot by specified player
+    PlayerShotMessage !PlayerId 
+  deriving (Typeable, Generic)
+
+instance NFData PlayerMessage 
+
+instance ActorMessage PlayerId where
+  type ActorMessageType PlayerId = PlayerMessage
+  toCounter = unPlayerId
+  fromCounter = PlayerId
+  
+instance NetworkMessage PlayerId where 
+  type NetworkMessageType PlayerId = PlayerNetMessage
+
+instance RemoteActor PlayerId Player where
+  type RemoteActorState PlayerId = Player
+  type RemoteActorId Player = PlayerId
+  
+-- | Check specific type of message
+isPlayerShotMessage :: PlayerMessage -> Bool
+isPlayerShotMessage m = case m of 
+  PlayerShotMessage _ -> True
+--  _ -> False
diff --git a/src/server/Main.hs b/src/server/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/server/Main.hs
@@ -0,0 +1,76 @@
+module Main where 
+
+import Control.Exception
+import Control.Monad.IO.Class
+import Data.Proxy 
+import Game 
+import Game.Core
+import Game.GoreAndAsh
+import Game.GoreAndAsh.Actor
+import Game.GoreAndAsh.Network
+import Game.GoreAndAsh.Sync
+import Network.BSD (getHostByName, hostAddress)
+import Network.Socket (SockAddr(..))
+import System.Exit
+import Data.IORef 
+import System.Environment
+import Text.Read 
+
+import FPS 
+
+simulationFPS :: Int 
+simulationFPS = 60 
+
+parseArgs :: IO (String, Int)
+parseArgs = do 
+  args <- getArgs 
+  case args of 
+    [h, p] -> case readMaybe p of 
+      Nothing -> fail "Failed to parse port"
+      Just pint -> return (h, pint)
+    _ -> fail "Misuse of arguments: gore-and-ash-server HOST PORT"
+
+main :: IO ()
+main = withModule (Proxy :: Proxy AppMonad) $ do
+  gs <- newGameState $ runActor' mainWire
+  gsRef <- newIORef gs
+  (host, port) <- liftIO parseArgs
+  fps <- makeFPSBounder simulationFPS
+  firstStep fps host port gs gsRef `onCtrlC` exitHandler gsRef
+  where
+    -- | What to do on emergency exit
+    exitHandler gsRef = do 
+      gs <- readIORef gsRef 
+      cleanupGameState gs
+      exitSuccess
+
+    -- | Resolve given hostname and port
+    getAddr s p = do
+      he <- getHostByName s
+      return $ SockAddrInet p $ hostAddress he
+
+    -- | Initialization step
+    firstStep fps host port gs gsRef = do 
+      (_, gs') <- stepGame gs $ do 
+        networkSetDetailedLoggingM False
+        syncSetLoggingM True
+        syncSetRoleM SyncMaster
+        addr <- liftIO $ getAddr host (fromIntegral port)
+        networkBind (Just addr) 100 2 0 0
+      writeIORef gsRef gs'
+      gameLoop fps gs' gsRef
+
+    -- | Normal game loop
+    gameLoop fps gs gsRef = do 
+      waitFPSBound fps
+      (_, gs') <- stepGame gs (return ())
+      writeIORef gsRef gs'
+      gameLoop fps gs' gsRef
+
+-- | Executes given handler on Ctrl-C pressing
+onCtrlC :: IO a -> IO () -> IO a
+p `onCtrlC` q = catchJust isUserInterrupt p (const $ q >> p `onCtrlC` q)
+  where
+    isUserInterrupt :: AsyncException -> Maybe ()
+    isUserInterrupt UserInterrupt = Just ()
+    isUserInterrupt _             = Nothing
diff --git a/src/shared/FPS.hs b/src/shared/FPS.hs
new file mode 100644
--- /dev/null
+++ b/src/shared/FPS.hs
@@ -0,0 +1,27 @@
+module FPS(
+    makeFPSBounder
+  , waitFPSBound
+  ) where
+
+import GHC.Event
+import Control.Concurrent
+import Control.Monad 
+
+type FPSBound = MVar ()
+
+-- | Creates mvar that fills periodically with given fps
+makeFPSBounder :: Int -> IO FPSBound
+makeFPSBounder fps = do
+  v <- newEmptyMVar 
+  tm <- getSystemTimerManager
+  let t = ceiling ((1000000 :: Double) / fromIntegral fps)
+  callback v tm t
+  return v
+  where
+    callback v tm t = do 
+      putMVar v ()
+      void $ registerTimeout tm t $ callback v tm t
+
+-- | Wait until next FPS value is reached when the function unblocks
+waitFPSBound :: FPSBound -> IO ()
+waitFPSBound = takeMVar 
diff --git a/src/shared/Game/Bullet/Shared.hs b/src/shared/Game/Bullet/Shared.hs
new file mode 100644
--- /dev/null
+++ b/src/shared/Game/Bullet/Shared.hs
@@ -0,0 +1,5 @@
+module Game.Bullet.Shared(
+    BulletNetMessage
+  ) where
+
+data BulletNetMessage
diff --git a/src/shared/Game/Player/Shared.hs b/src/shared/Game/Player/Shared.hs
new file mode 100644
--- /dev/null
+++ b/src/shared/Game/Player/Shared.hs
@@ -0,0 +1,15 @@
+module Game.Player.Shared(
+    PlayerNetMessage(..)
+  ) where
+
+import Control.DeepSeq
+import Data.Serialize 
+import GHC.Generics (Generic)
+import Linear 
+
+data PlayerNetMessage = 
+    NetMsgPlayerFire !(V2 Double)
+  deriving (Generic, Show)
+
+instance NFData PlayerNetMessage
+instance Serialize PlayerNetMessage
diff --git a/src/shared/Game/Shared.hs b/src/shared/Game/Shared.hs
new file mode 100644
--- /dev/null
+++ b/src/shared/Game/Shared.hs
@@ -0,0 +1,49 @@
+module Game.Shared(
+    GameId(..)
+  , GameNetMessage(..)
+  , globalGameId
+  , isPlayerRequestId
+  , isPlayerResponseId
+  -- | Helpers
+  , mapFromSeq
+  ) where
+
+import Control.DeepSeq
+import Data.Hashable 
+import Data.Serialize
+import GHC.Generics
+import qualified Data.Foldable as F 
+import qualified Data.HashMap.Strict as H 
+import qualified Data.Sequence as S 
+
+-- | Fake id for game global space
+newtype GameId = GameId { unGameId :: Int } deriving (Eq, Generic)
+
+instance NFData GameId 
+
+-- | Statically known game id
+globalGameId :: GameId 
+globalGameId = GameId 0 
+
+-- | Generic messages that are not binded to specific actor
+data GameNetMessage =
+    PlayerRequestId
+  | PlayerResponseId !Int !Int !Int -- ^ Id of player and bullets, players collections
+  deriving (Generic, Show)
+
+instance NFData GameNetMessage
+instance Serialize GameNetMessage
+
+isPlayerRequestId :: GameNetMessage -> Bool 
+isPlayerRequestId m = case m of 
+  PlayerRequestId -> True 
+  _ -> False
+
+isPlayerResponseId :: GameNetMessage -> Bool 
+isPlayerResponseId m = case m of 
+  PlayerResponseId _ _ _ -> True 
+  _ -> False
+
+-- | Construct HashMap from sequence
+mapFromSeq :: (Hashable i, Eq i) => S.Seq (i, a) -> H.HashMap i a 
+mapFromSeq = F.foldl' (\acc (i, a) -> H.insert i a acc) H.empty
