diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Shpadoinkle Template aka S11 Core
+Copyright © 2021 Isaac Shapira
+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 Shpadoinkle nor the names of its 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# Shpadoinkle Template
+
+[![Goldwater](https://gitlab.com/fresheyeball/Shpadoinkle/badges/master/pipeline.svg)](https://gitlab.com/fresheyeball/Shpadoinkle)
+[![Haddock](https://img.shields.io/badge/haddock-master-informational)](https://shpadoinkle.org/template)
+[![BSD-3](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
+[![built with nix](https://img.shields.io/badge/built%20with-nix-41439a)](https://builtwithnix.org)
+[![Hackage](https://img.shields.io/hackage/v/Shpadoinkle-template.svg)](https://hackage.haskell.org/package/Shpadoinkle-template)
+[![Hackage Deps](https://img.shields.io/hackage-deps/v/Shpadoinkle-template.svg)](http://packdeps.haskellers.com/reverse/Shpadoinkle-template)
+[![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-template/badge)](https://matrix.hackage.haskell.org/#/package/Shpadoinkle-template)
+
+This module provides the ability to read files into Shpadoinkle views.
+
+## Usage
+
+Lets say you have `template.html`
+
+```html
+<h1>Hi!</h1>
+<div>Nice to meat you</div>
+```
+
+you can now embed it into a Shpadoinkle
+
+```haskell
+view :: Html m a
+view = div [ className "my-view" ] $(embedHtml "./template.html")
+```
+
+
+which will render as
+
+```html
+<div class="my-view">
+  <h1>Hi!</h1>
+  <div>Nice to meat you</div>
+</div>
+```
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/Shpadoinkle-template.cabal b/Shpadoinkle-template.cabal
new file mode 100644
--- /dev/null
+++ b/Shpadoinkle-template.cabal
@@ -0,0 +1,62 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.33.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: b12f6991d22c408f646249268554550793acbdcedcc5d8b448606f1de6cda389
+
+name:           Shpadoinkle-template
+version:        0.0.0.1
+synopsis:       Read standard file formats into Shpadoinkle with Template Haskell
+description:    This package provides TH functions to read files at compile time and embed them into Shpadoinkle views.
+category:       Web
+author:         Isaac Shapira
+maintainer:     fresheyeball@protonmail.com
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    CHANGELOG.md
+
+source-repository head
+  type: git
+  location: https://gitlab.com/fresheyeball/Shpadoinkle.git
+
+library
+  exposed-modules:
+      Shpadoinkle.Template.TH
+      Shpadoinkle.Template
+  hs-source-dirs:
+      ./.
+  ghc-options: -Wall -Wcompat -fwarn-redundant-constraints -fwarn-incomplete-uni-patterns -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-identities
+  build-depends:
+      Shpadoinkle
+    , Shpadoinkle-backend-static
+    , base >=4.12.0 && <4.16
+    , html-parse
+    , template-haskell
+    , text >=1.2.3 && <1.3
+  default-language: Haskell2010
+
+test-suite sample
+  type: exitcode-stdio-1.0
+  main-is: Test.hs
+  other-modules:
+      Shpadoinkle.Template
+      Shpadoinkle.Template.TH
+      Paths_Shpadoinkle_template
+  hs-source-dirs:
+      ./.
+  ghc-options: -Wall -Wcompat -fwarn-redundant-constraints -fwarn-incomplete-uni-patterns -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-identities
+  build-depends:
+      Shpadoinkle
+    , Shpadoinkle-backend-static
+    , Shpadoinkle-template
+    , base >=4.12.0 && <4.16
+    , file-embed
+    , html-parse
+    , template-haskell
+    , text >=1.2.3 && <1.3
+  default-language: Haskell2010
diff --git a/Shpadoinkle/Template.hs b/Shpadoinkle/Template.hs
new file mode 100644
--- /dev/null
+++ b/Shpadoinkle/Template.hs
@@ -0,0 +1,17 @@
+module Shpadoinkle.Template where
+
+
+import           Data.Text
+import           Shpadoinkle
+
+
+template :: (Text -> Text) -> Html m a -> Html m a
+template r (Html html) = Html $ \n p t ->
+  html (\tn ps cs ->
+    n (r tn)
+      ((\(k,v) -> (r k, case v of PText pt -> PText (r pt); x -> x)) <$> ps)
+      cs)
+    p $
+    \t' -> t $ r t'
+
+
diff --git a/Shpadoinkle/Template/TH.hs b/Shpadoinkle/Template/TH.hs
new file mode 100644
--- /dev/null
+++ b/Shpadoinkle/Template/TH.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE LambdaCase #-}
+
+
+module Shpadoinkle.Template.TH where
+
+
+import           Data.Text                  (Text, cons, unpack)
+import           Data.Text.IO
+import           Language.Haskell.TH.Syntax
+import           Prelude                    hiding (readFile)
+import           Text.HTML.Parser           (Attr (..), Token (..), parseTokens)
+
+
+embedHtml :: FilePath -> Q Exp
+embedHtml path = do
+  ts <- runIO $ parseTokens <$> readFile path
+  pure . ListE $ tokenToExp ts
+
+
+tokenToExp :: [Token] -> [Exp]
+tokenToExp =
+  let h    = UnboundVarE $ mkName "h"
+      text = UnboundVarE $ mkName "text" in \case
+  TagOpen tn attrs:ts ->
+    let attrs' = ListE $ attrToExp <$> attrs
+        name = asText tn
+        (children, siblings) = break (\case TagClose tn' | tn' == tn -> True; _ -> False) ts
+    in AppE (AppE (AppE h name) attrs') (ListE $ tokenToExp children) : tokenToExp (drop 1 siblings)
+  TagSelfClose tn attrs:ts ->
+    let attrs' = ListE $ attrToExp <$> attrs
+        name = asText tn
+    in AppE (AppE (AppE h name) attrs') (ListE []) : tokenToExp ts
+  TagClose _:ts -> tokenToExp ts
+  ContentText content:ts ->
+    let content' = asText content
+    in AppE text content' : tokenToExp ts
+  ContentChar char:ts ->
+    let char' = asText $ cons char mempty
+     in AppE text char' : tokenToExp ts
+  Comment _:ts -> tokenToExp ts
+  Doctype _:ts -> tokenToExp ts
+  [] -> []
+
+
+attrToExp :: Attr -> Exp
+attrToExp (Attr name value) = TupE [name', AppE textProp value']
+  where textProp = UnboundVarE $ mkName "textProp"
+        name'    = asText name
+        value'   = asText value
+
+
+asText :: Text -> Exp
+asText = AppE (UnboundVarE $ mkName "pack") . LitE . StringL . unpack
diff --git a/Test.hs b/Test.hs
new file mode 100644
--- /dev/null
+++ b/Test.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell   #-}
+
+
+module Main where
+
+
+import           Data.FileEmbed
+import           Data.Text
+import           Data.Text.Encoding
+import           Shpadoinkle
+import           Shpadoinkle.Backend.Static
+import           Shpadoinkle.Template
+import           Shpadoinkle.Template.TH
+
+
+testHtmlIngestion :: IO ()
+testHtmlIngestion =
+  let x = mconcat $ renderStatic <$> $(embedHtml "./test.html")
+      y = decodeUtf8 $(embedFile "./test.html")
+  in if x == y then pure () else
+     error $ "test.html did not parse correctly. Got: " ++ unpack x
+
+testTemplate :: IO ()
+testTemplate =
+  let x = renderStatic $ template (replace "{{x}}" "yoddle") $
+            h "div{{x}}" [ ("{{x}}class", textProp "bar{{x}}") ]
+              [ h "span" [] [ "Hi {{x}}" ]
+              ]
+      y = "<divyoddle yoddleclass=\"baryoddle\"><span>Hi yoddle</span></divyoddle>"
+  in if x == y then pure () else
+     error $ "template did not interpolate. Got: " ++ unpack x
+
+main :: IO ()
+main = do
+  testHtmlIngestion
+  testTemplate
+  putStrLn "SUCCESS"
