diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2018, Francesco Ariis
+
+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 Francesco Ariis 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/changes.txt b/changes.txt
new file mode 100644
--- /dev/null
+++ b/changes.txt
@@ -0,0 +1,5 @@
+0.1.0.0
+-------
+
+- Added basic animation/timer functionality.
+- Released on: Wed 14 Mar 2018 13:36:06 CET
diff --git a/src/Control/Timer/Tick.hs b/src/Control/Timer/Tick.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Timer/Tick.hs
@@ -0,0 +1,166 @@
+--------------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Timer.Tick
+-- Copyright   :  (C) 2018 Francesco Ariis
+-- License     :  BSD3 (see LICENSE file)
+--
+-- Maintainer  :  Francesco Ariis <fa-ml@ariis.it>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- Timers and timed resources (animations, etc.) utilities for tick-based
+-- programs.
+--
+--------------------------------------------------------------------------------
+
+
+module Control.Timer.Tick ( -- * Simple timers
+                            creaTimer,
+                            Timer,
+                            -- * Timed Resources
+                            TimedRes,
+                            creaTimedRes,
+                            Loop(..),
+                            -- * Use
+                            tick,
+                            ticks,
+                            reset,
+                            -- * Query
+                            isLive,
+                            isExpired,
+                            fetch
+                          )
+
+
+       where
+
+-----------
+-- TYPES --
+-----------
+
+-- | A timed resource is a timer which, at any given moment, points to
+-- a specific item (like an animation).
+--
+-- Example:
+--
+-- @
+-- run = creaTimedRes (Times 1) [(2, "a "), (1, "b "), (2, "c ")]
+-- main = count run
+--     where
+--           count t | isExpired t = putStrLn "\nOver!"
+--                   | otherwise   = do putStr (fetch t)
+--                                      count (tick t)
+--    -- λ> main
+--    -- a a b c c
+--    -- Over!
+-- @
+data TimedRes a = TimedRes { -- init
+                             tSteps    :: [TimerStep a],
+                             tLoop     :: Loop,
+                             tOrigLoop :: Loop,
+
+                             -- convenience
+                             tMaxTicks :: Integer,
+
+                             --  curr
+                             tCurrTick :: Integer,
+                             tExpired  :: Bool
+                           }
+        deriving (Show, Eq)
+
+type TimerStep a = (Integer, a)
+
+-- | Number of times to repeat the animation.
+data Loop = Times Integer -- currentLoop and maxLoop
+          | AlwaysLoop
+     deriving (Show, Eq)
+
+-- todo Monoid (or semigroup) <> for timers [2.0]
+
+------------
+-- CREATE --
+------------
+
+type Timer = TimedRes ()
+
+-- | Creates a 'Timer' expiring in @x@ ticks.
+--
+-- Example:
+--
+-- @
+-- main = count (creaTimer 4)
+--     where
+--           count t | isExpired t = putStrLn "Over!"
+--                   | otherwise   = do putStrLn "Ticking."
+--                                      count (tick t)
+--
+--    -- λ> main
+--    -- Ticking.
+--    -- Ticking.
+--    -- Ticking.
+--    -- Ticking.
+--    -- Over!
+-- @
+creaTimer :: Integer -> Timer
+creaTimer c = creaTimedRes (Times 1) [(c, ())]
+
+-- | Creates a time-based resource, like an animation.
+creaTimedRes :: Loop -> [(Integer, a)] -> TimedRes a
+creaTimedRes _ [] = error "Cannot create an empty TimedRes"
+creaTimedRes l ss = TimedRes ss l l
+                                  (sum . map fst $ ss)
+                                  0 False
+
+
+-------------
+-- OPERATE --
+-------------
+
+-- | Ticks the timer (one step).
+tick :: TimedRes a -> TimedRes a
+tick t | isExpired t = t
+       | otherwise   =
+            let t' = t { tCurrTick = succ (tCurrTick t) } in
+
+            if tCurrTick t' == tMaxTicks t'
+              then maxed t'
+              else t'
+    where
+          maxed :: TimedRes a -> TimedRes a
+          maxed tm = case tLoop tm of
+                       Times 1    -> tm { tLoop = Times 0,
+                                          tExpired = True }
+                       AlwaysLoop -> tm { tCurrTick = 0 }
+                       Times n    -> tm { tLoop = Times (n-1),
+                                          tCurrTick = 0 }
+
+-- | Ticks the timer (multiple steps).
+ticks :: Integer -> TimedRes a -> TimedRes a
+ticks 1 t = tick t
+ticks n t | n < 1     = error "negative number passed to `ticks`"
+          | otherwise = ticks (n-1) (tick t)
+
+-- | Equal to @not isExpired@.
+isLive :: TimedRes a -> Bool
+isLive t = not $ tExpired t
+
+-- | Checks wheter the timer is expired (an expired timer will not
+-- respond to 'tick').
+isExpired :: TimedRes a -> Bool
+isExpired t = tExpired t
+
+-- | Fetches the current resource of the timer.
+fetch :: TimedRes a -> a
+fetch t = bl !! (fromIntegral $ tCurrTick t)
+    where
+          bl = concatMap (\(c, a) -> replicate (fromIntegral c) a) $ tSteps t
+
+-- todo having another input apart from []? maybe a function?
+
+-- | Resets the timer to its original state.
+reset :: TimedRes a -> TimedRes a
+reset t = t { tCurrTick = 0,
+              tExpired = False,
+              tLoop = tOrigLoop t }
+
+-- todo elapsed time? ticking time?
diff --git a/test/Control/Timer/TickSpec.hs b/test/Control/Timer/TickSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Control/Timer/TickSpec.hs
@@ -0,0 +1,62 @@
+module Control.Timer.TickSpec where
+
+import Control.Timer.Tick
+
+import Test.Hspec
+import qualified Control.Exception as E
+
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+
+  describe "creaTimedResource" $ do
+    it "does not allow creation of empty timed resources" $
+      E.evaluate (creaTimedResource AlwaysLoop [])
+        `shouldThrow` anyException
+
+  describe "tick" $ do
+    it "ticks a simple timer" $
+      let st = creaTimer 1 in
+      isExpired (tick st) `shouldBe` True
+
+  describe "ticks" $ do
+    let t = creaTimer 10
+    it "fails on negative integer" $
+      E.evaluate (ticks (-3) t) `shouldThrow` anyException
+    it "performs a number of ticks" $
+      isExpired (ticks 10 t) `shouldBe` True
+    it "does not overtick" $
+      isExpired (ticks  9 t) `shouldBe` False
+    it "does not choke on extra tick" $
+      isExpired (ticks 80 t) `shouldBe` True
+
+  describe "loops" $ do
+    let t  = creaTimedResource (Times 2)  [(1,())]
+    let ta = creaTimedResource AlwaysLoop [(1,())]
+    it "loops appropriately" $
+      isExpired (ticks 2 t) `shouldBe` True
+    it "loops appropriately (forever)" $
+      isExpired (ticks 20 ta) `shouldBe` False
+    it "expires appropriately" $
+      isExpired (ticks 1 t) `shouldBe` False
+
+  describe "isExpired" $ do
+    let st = creaTimer 10
+    it "checks if a timer is expired" $
+      isExpired (ticks 100 st) `shouldBe` True
+    it "complements isLive" $
+      isExpired (ticks 100 st) `shouldBe` not (isLive (ticks 100 st))
+
+  describe "fetch" $ do
+    let ta = creaTimedResource (Times 1) [(1,'a'), (2, 'b'), (1, 'c')]
+    it "gets the underlying resoure" $
+      fetch (ticks 3 ta) `shouldBe` 'c'
+
+  describe "reset" $ do
+    let t = creaTimer 10
+    it "resets the timer" $
+      reset (ticks 30 t) `shouldBe` t
+
diff --git a/test/Tests.hs b/test/Tests.hs
new file mode 100644
--- /dev/null
+++ b/test/Tests.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/timers-tick.cabal b/timers-tick.cabal
new file mode 100644
--- /dev/null
+++ b/timers-tick.cabal
@@ -0,0 +1,42 @@
+name:                timers-tick
+version:             0.1.0.0
+synopsis:            tick based timers
+description:         Tick-based timers and utilities, for games and
+                     discrete-time programs.
+                     Includes types and functions to work with sequence-based
+                     resources (e.g. animations, frames).
+license:             BSD3
+license-file:        LICENSE
+author:              Francesco Ariis
+maintainer:          fa-ml@ariis.it
+copyright:           © 2018 Francesco Ariis
+category:            Control
+build-type:          Simple
+extra-source-files:  changes.txt
+cabal-version:       >=1.10
+
+flag developer
+  description: developer mode - warnings let compilation fail
+  manual: True
+  default: False
+
+library
+  default-language:    Haskell2010
+  exposed-modules:     Control.Timer.Tick
+  build-depends:       base == 4.*
+  hs-source-dirs:      src
+
+test-suite test
+  default-language:    Haskell2010
+  if flag(developer)
+     ghc-options:      -Wall -Werror
+  else
+     ghc-options:      -Wall
+  HS-Source-Dirs:      test, src
+  main-is:             Tests.hs
+  build-depends:       base == 4.*
+                       , hspec == 2.4.*
+  other-modules:       Control.Timer.Tick,
+                       Control.Timer.TickSpec
+  type:                exitcode-stdio-1.0
+
