diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Khalil Fazal (c) 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 Khalil Fazal 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/src/Data/Char/SScript.hs b/src/Data/Char/SScript.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Char/SScript.hs
@@ -0,0 +1,56 @@
+-- |
+-- Module      : sscript
+-- License     : BSD3
+-- Maintainer  : khalil.fazal@uoit.net
+-- Portability : portable
+--
+-- Formats Strings with subscript or superscript characters
+module Data.Char.SScript (
+    subscript,
+    superscript,
+    formatSS
+) where
+
+import Control.Monad (ap)
+import Data.Maybe    (fromMaybe)
+
+convertOrId :: Eq a => [(a, a)] -> a -> a
+convertOrId = ap fromMaybe . flip lookup
+
+subscripts :: [(Char, Char)]
+subscripts =
+    zip "0123456789+-=()aeioruvx"
+        "₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑᵢₒᵣᵤᵥₓ"
+
+-- | subscripts a char
+--
+-- @'subscript' '0' == '₀'@
+subscript :: Char -> Char
+subscript = convertOrId subscripts
+
+superscripts :: [(Char, Char)]
+superscripts =
+    zip "0123456789+-=()abcdefghijklmnoprstuvwxyzABDEGHIJKLMNOPRTUW"
+        "⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖʳˢᵗᵘᵛʷˣʸᶻᴬᴮᴰᴱᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾᴿᵀᵁᵂ"
+
+-- | superscripts a char
+--
+-- @'subscript' '0' == '⁰'@
+superscript :: Char -> Char
+superscript = convertOrId superscripts
+
+-- | formats a string
+--
+-- @'formatSS' "x_1^2 + x_2^2 + x_3^2 = z^2" == "x₁² + x₂² + x₃² = z²"@
+formatSS :: String -> String
+formatSS ('^' : '{' : xs) = formatUntilBrace superscript xs
+formatSS ('_' : '{' : xs) = formatUntilBrace subscript   xs
+formatSS ('^' :  x  : xs) = superscript x : formatSS xs
+formatSS ('_' :  x  : xs) = subscript   x : formatSS xs
+formatSS (x         : xs) = x : formatSS xs
+formatSS []               = []
+
+formatUntilBrace :: (Char -> Char) -> String -> String
+formatUntilBrace ss xs = map ss x ++ formatSS ys
+    where
+        (x, _ : ys) = break (== '}') xs
diff --git a/sscript.cabal b/sscript.cabal
new file mode 100644
--- /dev/null
+++ b/sscript.cabal
@@ -0,0 +1,33 @@
+name:                sscript
+version:             0.1.0.0
+synopsis:            Formats Strings with subscript or superscript characters
+description:         Please see README.md
+homepage:            https://github.com/khalilfazal/sscript#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Khalil Fazal
+maintainer:          khalil.fazal@uoit.net
+copyright:           2016 <khalil.fazal@uoit.net>
+category:            String
+build-type:          Simple
+cabal-version:       >= 1.10
+
+library
+  hs-source-dirs:   src
+  exposed-modules:  Data.Char.SScript
+  default-language: Haskell2010
+  build-depends:    base < 5
+
+test-suite sscript-test
+  hs-source-dirs:   test
+  main-is:          Spec.hs
+  other-modules:    Data.Char.SScriptSpec
+  type:             exitcode-stdio-1.0
+  default-language: Haskell2010
+  build-depends:    base < 5,
+                    hspec,
+                    sscript
+
+source-repository head
+  type:     git
+  location: https://github.com/khalilfazal/sscript
diff --git a/test/Data/Char/SScriptSpec.hs b/test/Data/Char/SScriptSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/Char/SScriptSpec.hs
@@ -0,0 +1,59 @@
+module Data.Char.SScriptSpec where
+
+import Data.Char.SScript
+
+import Control.Monad (ap)
+import Test.Hspec
+
+-- A fixed point is a value that doesn't change under application of a function
+shouldBeFixed :: (Eq a, Show a) => (a -> a) -> a -> Expectation
+shouldBeFixed = ap shouldBe
+
+convertDecimals :: (Char -> Char) -> String
+convertDecimals f = (map f . concatMap show) [0 .. 9]
+
+symbols :: String
+symbols = "+-=()"
+
+spec :: Spec
+spec = do
+    context "Char.SScript.subscript" $ do
+        it "should work for a single char" $
+            subscript '0' `shouldBe` '₀'
+        it "should work for all single digit decimals" $
+            convertDecimals subscript `shouldBe` "₀₁₂₃₄₅₆₇₈₉"
+        it "should work for +-=() symbols" $
+            map subscript symbols `shouldBe` "₊₋₌₍₎"
+        it "should work for selected letters" $
+            map subscript "aeioruvx" `shouldBe` "ₐₑᵢₒᵣᵤᵥₓ"
+        it "should return the same char if it can't be subscripted" $
+            shouldBeFixed (map subscript) "AEIORUVX"
+
+    context "Char.SScript.superscript" $ do
+        it "should work for a single char" $
+            superscript '0' `shouldBe` '⁰'
+        it "should work for all single digit decimals" $
+            convertDecimals superscript `shouldBe` "⁰¹²³⁴⁵⁶⁷⁸⁹"
+        it "should work for +-=() symbols" $
+            map superscript symbols `shouldBe` "⁺⁻⁼⁽⁾"
+        it "should work for all letters except qCFQSVXYZ" $
+            map superscript "abcdefghijklmnoprstuvwxyzABDEGHIJKLMNOPRTUW"
+            `shouldBe`
+            "ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖʳˢᵗᵘᵛʷˣʸᶻᴬᴮᴰᴱᴳᴴᴵᴶᴷᴸᴹᴺᴼᴾᴿᵀᵁᵂ"
+        it "should return the same char if it can't be superscripted" $
+            shouldBeFixed (map superscript) "qCFQSVXYZ"
+
+    context "Char.SScript.formatSS" $ do
+        it "should convert chars following an underscore to its subscript, \
+            \like in the chemical formula for dravite: \
+            \https://en.wikipedia.org/wiki/Tourmaline#Dravite" $
+            formatSS "NaMg_{3}(Al,Mg)_6B_3Si_6O_{27}(OH)"
+            `shouldBe`
+            "NaMg₃(Al,Mg)₆B₃Si₆O₂₇(OH)"
+        it "should convert chars following a caret to its superscript" $
+            formatSS "(a^n)^{r+s}" `shouldBe` "(aⁿ)ʳ⁺ˢ"
+        it "should convert strings containing a mixture of \
+            \underscores and carets" $
+            formatSS "(x_{12} - x_{21})^{25} + (y_1 - y_2)^2"
+            `shouldBe`
+            "(x₁₂ - x₂₁)²⁵ + (y₁ - y₂)²"
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
