diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Sven Heyll (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 Author name here 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/isobmff-builder.cabal b/isobmff-builder.cabal
new file mode 100644
--- /dev/null
+++ b/isobmff-builder.cabal
@@ -0,0 +1,57 @@
+name:                isobmff-builder
+version:             0.1.0.0
+synopsis:            A (bytestring-) builder for the ISO base media file format ISO-14496-12
+description:         Please see README.md
+homepage:            https://github.com/sheyll/isobmff-builder#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Sven Heyll
+maintainer:          sven.heyll@gmail.com
+copyright:           2016 Sven Heyll
+category:            Codec
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Data.ByteString.IsoBaseFileFormat.Builder
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.Box
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.FileType
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.MediaData
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.Skip
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation
+                     , Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox
+  build-depends:       base >= 4.7 && < 5
+                     , bytestring >= 0.10.8.1
+                     , type-list >= 0.5.0.0
+  default-language:    Haskell2010
+  default-extensions:  ConstraintKinds
+                     , CPP
+                     , DataKinds
+                     , DefaultSignatures
+                     , DeriveDataTypeable
+                     , DeriveFunctor
+                     , DeriveGeneric
+                     , FlexibleInstances
+                     , FlexibleContexts
+                     , FunctionalDependencies
+                     , GADTs
+                     , GeneralizedNewtypeDeriving
+                     , KindSignatures
+                     , MultiParamTypeClasses
+                     , OverloadedStrings
+                     , QuasiQuotes
+                     , RecordWildCards
+                     , RankNTypes
+                     , ScopedTypeVariables
+                     , StandaloneDeriving
+                     , TemplateHaskell
+                     , TupleSections
+                     , TypeFamilies
+                     , TypeInType
+                     , TypeOperators
+                     , TypeSynonymInstances
+source-repository head
+  type:     git
+  location: https://github.com/githubuser/isobmff-builder
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/Box.hs
@@ -0,0 +1,407 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+-- | Definition of the most basic elements in an ISOBMFF file /boxes/.
+-- See Chapter 4 in the standard document. Since the standard
+module Data.ByteString.IsoBaseFileFormat.Boxes.Box
+       (module Data.ByteString.IsoBaseFileFormat.Boxes.Box, module X)
+       where
+
+import Data.Bits as X
+import Data.ByteString.Builder as X
+import Data.Monoid as X
+import Data.Proxy as X
+import Data.Word as X
+import GHC.TypeLits as X
+import Data.String
+import Data.Type.Equality
+
+import Data.Type.List
+import Data.Type.Bool
+import Data.Type.Equality
+import GHC.Exts
+
+-- * Type-safe box composition
+
+-- | A box that may contain nested boxes. The nested boxes are type checked to
+-- be valid in the container box. This results in a container-box with only
+-- valid and all required child boxes. This is checked by the type system.
+boxes :: forall ts t.
+         (IsBoxType t,ValidBoxes t ts)
+      => Boxes t ts -> Box t
+boxes = box
+
+-- | A container-box with child boxes.
+data Boxes (cont :: x) (boxTypes :: [x]) where
+        Parent :: IsBoxType t => Box t -> Boxes t '[]
+        (:-) :: IsBoxType t => Boxes c ts -> Box t -> Boxes c (t ': ts)
+
+infixl 2 :-
+
+-- | A container box that contains only the parent, and no children (yet).
+type Container parent = Boxes parent '[]
+
+-- | An operator for @Parent parent :- firstChild@
+(^-) :: (IsBoxType t, IsBoxType u) => Box t -> Box u -> Boxes t '[u]
+parent ^- firstChild = Parent parent :- firstChild
+
+infixl 2 ^-
+
+-- | To be nested into a box, 'Boxes' must be an instance of 'IsBoxContent'.
+-- This instance concatenates all nested boxes.
+instance (IsBoxType t,ValidBoxes t bs) => IsBoxContent (Boxes t bs) where
+  boxSize bs = boxSize (UnverifiedBoxes bs)
+  boxBuilder bs = boxBuilder (UnverifiedBoxes bs)
+
+-- | An internal wrapper type around 'Boxes' for the 'IsBoxContent' instance.
+-- Since the 'IsBoxContent' instance recursivly deconstructs a 'Boxes' the
+-- constraints for the validity 'ValidBoxes' cannot be asserted. To circumvent
+-- this the 'IsBoxContent' instance for 'Boxes' delegates to the instance of
+-- 'UnverifiedBoxes', which has no 'ValidBoxes' constraint in the instance head.
+newtype UnverifiedBoxes t ts = UnverifiedBoxes (Boxes t ts)
+
+instance IsBoxContent (UnverifiedBoxes t bs) where
+  boxSize (UnverifiedBoxes (Parent c)) = boxSize c
+  boxSize (UnverifiedBoxes (bs :- b)) = boxSize (UnverifiedBoxes bs) + boxSize b
+  boxBuilder (UnverifiedBoxes (Parent c)) = boxBuilder c
+  boxBuilder (UnverifiedBoxes (bs :- b)) = boxBuilder (UnverifiedBoxes bs) <> boxBuilder b
+
+-- * Type level consistency checks
+
+-- | A type-level check that uses 'BoxRules' to check that the contained boxes
+-- are standard conform.
+type ValidBoxes t ts =
+  ( AllAllowedIn t ts ~ 'True
+  , HasAllRequiredBoxes t (RequiredNestedBoxes t) ts ~ 'True
+  , CheckTopLevelOk t ~ 'True)
+
+-- | A type function to check that all nested boxes are allowed in the
+-- container.
+type family AllAllowedIn (container :: k) (boxes :: [k]) :: Bool
+     where
+        AllAllowedIn c '[] = 'True
+        AllAllowedIn c (t ': ts) =
+          If (CheckAllowedIn c t (RestrictedTo t))
+             (AllAllowedIn c ts)
+             (TypeError (NotAllowedMsg c t))
+
+type family CheckAllowedIn (c :: k) (t :: k) (a :: Maybe [k]) :: Bool where
+  CheckAllowedIn c t 'Nothing   = 'True
+  CheckAllowedIn c t ('Just rs) = Find c rs
+
+
+-- | The custom (type-) error message for 'AllAllowedIn'.
+type NotAllowedMsg c t =
+  Text "Boxes of type: "
+  :<>: ShowType c
+  :<>: Text " may not contain boxes of type "
+  :<>: ShowType t
+  :$$: Text "Valid containers for "
+  :<>: ShowType t
+  :<>: Text " boxes are: "
+  :$$: ShowType (RestrictedTo t)
+  :$$: ShowType t
+  :<>: If (IsTopLevelBox c)
+          (Text " boxes may appear top-level in a file.")
+          (Text " boxes must be nested.")
+
+
+-- | Check that all required boxes have been nested.
+type family HasAllRequiredBoxes (c :: k) (req :: [k]) (nested :: [k]) :: Bool
+     where
+       HasAllRequiredBoxes c '[] nested = 'True
+       HasAllRequiredBoxes c (r ': restReq) nested =
+         If (Find r nested)
+            (HasAllRequiredBoxes c restReq nested)
+            (TypeError (MissingRequired c r nested))
+
+type IsSubSet base sub = Intersection base sub == sub
+
+-- | The custom (type-) error message for 'HasAllRequiredBoxes'.
+type MissingRequired c r nested =
+  Text "Boxes of type: "
+  :<>: ShowType c
+  :<>: Text " require these nested boxes: "
+  :<>: ShowType (RequiredNestedBoxes c)
+  :$$: Text "but only these box types were nested: "
+  :<>: ShowType nested
+  :$$: Text "e.g. this type is missing: "
+  :<>: ShowType r
+
+-- | Check that the box may appear top-level.
+type family CheckTopLevelOk (t :: k) :: Bool where
+   CheckTopLevelOk t = IsTopLevelBox t || TypeError (NotTopLevenError t)
+
+-- | The custom (type-) error message indicating that a box may not appear
+-- top-level.
+type NotTopLevenError c =
+       Text "Boxes of type "
+  :<>: ShowType c
+  :<>: Text " MUST be nested inside boxes of these types: "
+  :$$: ShowType (RestrictedTo c)
+
+-- * Common box /combinators/
+
+-- | A `Box` with /version/ and /branding/ information
+type FullBox t = Extend FullBoxHeader t
+
+-- | Create a 'FullBox' from a 'FourCc' 'StdType' and the nested box content.
+fullBox
+ :: (IsBoxType t, IsBoxContent c)
+ => BoxVersion -> BoxFlags 24 -> c -> Box t
+fullBox ver fs cnt = box (Extend (FullBoxHeader ver fs) cnt)
+
+-- | The additional header with /version/ and /branding/ information
+data FullBoxHeader =
+  FullBoxHeader BoxVersion
+                (BoxFlags 24)
+
+instance IsBoxContent FullBoxHeader where
+  boxSize (FullBoxHeader _ f) = 1 + boxSize f
+  boxBuilder (FullBoxHeader (BoxVersion v) f) = word8 v <> boxBuilder f
+
+-- | The box version (in a 'FullBox') is a single byte
+newtype BoxVersion =
+  BoxVersion Word8
+
+-- | In addition to a 'BoxVersion' there can be 24 bits for custom flags etc in
+-- a 'FullBox'.
+newtype BoxFlags bits =
+  BoxFlags Integer
+  deriving (Eq,Show,Num)
+
+-- | Internal function that creates a bit mask with all bits in a 'BoxFlags' set
+-- to 1.
+boxFlagBitMask :: KnownNat bits
+               => BoxFlags bits -> Integer
+boxFlagBitMask px = 2 ^ natVal px - 1
+
+-- | Internal function that masks-out all bits higher than 'bits'.
+cropBits :: KnownNat bits
+         => BoxFlags bits -> BoxFlags bits
+cropBits f@(BoxFlags b) = BoxFlags (b .&. boxFlagBitMask f)
+
+-- | Get the number of bytes required to store a number of bits.
+instance KnownNat bits => IsBoxContent (BoxFlags bits) where
+  boxSize f =
+    let minBytes = fromInteger $ natVal f `div` 8
+        modBytes = fromInteger $ natVal f `mod` 8
+    in BoxSize $ minBytes + signum modBytes
+  boxBuilder f@(BoxFlags b) =
+    let bytes =
+          let (BoxSize bytes') = boxSize f
+          in fromIntegral bytes'
+        wordSeq n
+          | n <= bytes =
+            word8 (fromIntegral (shiftR b ((bytes - n) * 8) .&. 255)) <>
+            wordSeq (n + 1)
+          | otherwise = mempty
+    in wordSeq 1
+
+instance KnownNat bits => Bits (BoxFlags bits) where
+  (.&.) lf@(BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r
+  (.|.) lf@(BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ l .&. r
+  xor (BoxFlags l) (BoxFlags r) = cropBits $ BoxFlags $ xor l r
+  complement (BoxFlags x) = cropBits $ BoxFlags $ complement x
+  shift (BoxFlags x) = cropBits . BoxFlags . shift x
+  rotateL = error "TODO rotateL"
+  rotateR = error "TODO rotateR"
+  bitSize = fromInteger . natVal
+  bitSizeMaybe = Just . fromInteger . natVal
+  isSigned _ = False
+  testBit f n =
+    let (BoxFlags b) = cropBits f
+    in testBit b n
+  bit = cropBits . BoxFlags . bit
+  popCount f =
+    let (BoxFlags b) = cropBits f
+    in popCount b
+  zeroBits = BoxFlags 0
+
+-- * /The/ actual Box
+
+-- | Create a 'Box' with a 'StdType' 'FourCc' type.
+box :: forall t c.
+       (IsBoxType t,IsBoxContent c)
+    => c -> Box t
+box cnt = Box (toBoxType (Proxy :: Proxy t)) cnt
+
+-- | An /empty/ box. This is for boxes without fields. All these boxes contain
+-- is their obligatory 'BoxHeader' possibly nested boxes.
+emptyBox :: forall t . (IsBoxType t) => Box t
+emptyBox = box ()
+
+-- | A type that wraps the contents of a box and the box type.
+data Box (b :: t) where
+        Box :: (IsBoxType t,IsBoxContent c) => BoxType -> c -> Box t
+
+instance IsBoxContent (Box t) where
+  boxBuilder b@(Box t cnt) = sFix <> tFix <> sExt <> tExt <> boxBuilder cnt
+    where s = boxSize b
+          sFix = boxBuilder s
+          sExt = boxBuilder (BoxSizeExtension s)
+          tFix = boxBuilder t
+          tExt = boxBuilder (BoxTypeExtension t)
+  boxSize b@(Box t cnt) = sPayload + boxSize (BoxSizeExtension sPayload)
+    where sPayload =
+            boxSize sPayload + boxSize t + boxSize cnt +
+            boxSize (BoxTypeExtension t)
+
+-- * Box Meta Data
+-- | The box header contains a size and a type. Both can be compact (32bit) or
+-- large (64bit size, 17*32bit type).
+data BoxHeader =
+  BoxHeader BoxSize
+            BoxType
+  deriving (Show,Eq)
+
+-- | The size of the box. If the size is limited to a (fixed) value, it can be
+-- provided as a 'Word64' which will be represented as either a 32bit compact
+-- size or as 64 bit /largesize/. If 'UnlimitedSize' is used, the box extends to
+-- the end of the file.
+data BoxSize
+  = UnlimitedSize
+  | BoxSize Word64
+  deriving (Show,Eq)
+
+instance IsBoxContent BoxSize where
+  boxSize _ = BoxSize 4
+  boxBuilder UnlimitedSize = word32BE 0
+  boxBuilder (BoxSize n) =
+    word32BE $
+    if n < 2 ^ 32
+       then fromIntegral n
+       else 1
+
+instance Num BoxSize where
+  (+) UnlimitedSize _ = UnlimitedSize
+  (+) _ UnlimitedSize = UnlimitedSize
+  (+) (BoxSize l) (BoxSize r) = BoxSize (l + r)
+  (-) UnlimitedSize _ = UnlimitedSize
+  (-) _ UnlimitedSize = UnlimitedSize
+  (-) (BoxSize l) (BoxSize r) = BoxSize (l - r)
+  (*) UnlimitedSize _ = UnlimitedSize
+  (*) _ UnlimitedSize = UnlimitedSize
+  (*) (BoxSize l) (BoxSize r) = BoxSize (l * r)
+  abs UnlimitedSize = UnlimitedSize
+  abs (BoxSize n) = BoxSize (abs n)
+  signum UnlimitedSize = UnlimitedSize
+  signum (BoxSize n) = BoxSize (signum n)
+  fromInteger n = BoxSize $ fromInteger n
+
+-- | The 'BoxSize' can be > 2^32 in which case an 'BoxSizeExtension' must be
+-- added after the type field.
+data BoxSizeExtension =
+  BoxSizeExtension BoxSize
+
+instance IsBoxContent BoxSizeExtension where
+  boxBuilder (BoxSizeExtension UnlimitedSize) = mempty
+  boxBuilder (BoxSizeExtension (BoxSize n)) =
+    if n < 2 ^ 32
+       then mempty
+       else word64BE n
+  boxSize (BoxSizeExtension UnlimitedSize) = 0
+  boxSize (BoxSizeExtension (BoxSize n)) =
+    BoxSize $
+    if n < 2 ^ 32
+       then 0
+       else 8
+
+-- | A box has a /type/, this is the value level representation for the box type.
+data BoxType
+  =
+    -- | `FourCc` can be used as @boxType@ in `Box`, standard four letter character
+    -- code, e.g. @ftyp@
+    StdType FourCc
+  |
+    -- | CustomBoxType defines custom @boxType@s in `Box`es.
+    CustomBoxType String
+  deriving (Show,Eq)
+
+-- | Convert type level box types to values
+class BoxRules t => IsBoxType (t :: k) where
+  toBoxType :: proxy t -> BoxType
+
+instance (BoxRules t, KnownSymbol t) => IsBoxType t where
+  toBoxType _ = StdType (fromString (symbolVal (Proxy :: Proxy t)))
+
+-- | A class that describes (on the type level) how a box can be nested into
+-- other boxes (see 'Boxes').
+class BoxRules (t :: k) where
+  -- | List of boxes that this box can be nested into.
+  type RestrictedTo t :: Maybe [k]
+  type RestrictedTo t = 'Just '[]
+  -- | If the box is also allowed 'top-level' i.e. in the file directly, not
+  -- nested in an other box.
+  type IsTopLevelBox t :: Bool
+  type IsTopLevelBox t = 'True
+  -- | Describes which nested boxes MUST be present in a box using 'boxes'.
+  type RequiredNestedBoxes t :: [k]
+  type RequiredNestedBoxes t = '[]
+  -- | Describes how many times a box should be present in a container (-box).
+  type GetCardinality t (c :: k) :: Cardinality
+  type GetCardinality t any = ExactlyOnce
+
+-- | Describes how many times a box should be present in a container.
+data Cardinality = AtMostOnce | ExactlyOnce | OnceOrMore
+
+-- | A type containin a printable four letter character code.
+newtype FourCc =
+  FourCc (Char,Char,Char,Char)
+  deriving (Show,Eq)
+
+instance IsString FourCc where
+  fromString str
+    | length str == 4 =
+      let [a,b,c,d] = str
+      in FourCc (a,b,c,d)
+    | otherwise =
+      error ("cannot make a 'FourCc' of a String which isn't exactly 4 bytes long: " ++
+             show str ++ " has a length of " ++ show (length str))
+
+instance IsBoxContent FourCc where
+  boxSize _ = 4
+  boxBuilder (FourCc (a,b,c,d)) = putW a <> putW b <> putW c <> putW d
+    where putW = word8 . fromIntegral . fromEnum
+
+instance IsBoxContent BoxType where
+  boxSize _ = boxSize (FourCc undefined)
+  boxBuilder t =
+    case t of
+      StdType x -> boxBuilder x
+      CustomBoxType u -> boxBuilder (FourCc ('u','u','i','d'))
+
+-- | When using custom types extra data must be written after the extra size
+-- information. Since the box type and the optional custom box type are not
+-- guaranteed to be consequtive, this type handles the /second/ part seperately.
+data BoxTypeExtension =
+  BoxTypeExtension BoxType
+
+instance IsBoxContent BoxTypeExtension where
+  boxSize (BoxTypeExtension (StdType _)) = 0
+  boxSize (BoxTypeExtension (CustomBoxType _)) = 16 * 4
+  boxBuilder (BoxTypeExtension (StdType _)) = mempty
+  boxBuilder (BoxTypeExtension (CustomBoxType str)) =
+    mconcat (map (word8 . fromIntegral . fromEnum)
+                 (take (16 * 4) str) ++
+             repeat (word8 0))
+
+-- | Box content composed of box contents @a@ and @b@.
+data Extend a b =
+  Extend a
+         b
+
+instance (IsBoxContent p,IsBoxContent c) => IsBoxContent (Extend p c) where
+  boxSize (Extend p c) = boxSize p + boxSize c
+  boxBuilder (Extend p c) = boxBuilder p <> boxBuilder c
+
+-- | Types that go into a box. A box content is a piece of data that can be
+-- reused in different instances of 'IsBox'. It has no 'BoxType' and hence
+-- defines no box.
+class IsBoxContent a  where
+  boxSize :: a -> BoxSize
+  boxBuilder :: a -> Builder
+
+-- | An empty box content can by represented by @()@ (i.e. /unit/).
+instance IsBoxContent () where
+  boxSize _ = 0
+  boxBuilder _ = mempty
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/FileType.hs
@@ -0,0 +1,24 @@
+module Data.ByteString.IsoBaseFileFormat.Boxes.FileType where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box
+
+-- | File Type Box
+type FileTypeBox = Box "ftyp"
+
+instance BoxRules "ftyp"
+
+-- | Create a 'FileTypeBox' from a major brand, a minor version and a list of
+-- compatible brands
+fileTypeBox :: FileType -> FileTypeBox
+fileTypeBox = box
+
+-- | Contents of a 'ftyp' box are some 'FourCc' /brands/ and a version.
+data FileType =
+  FileType {majorBrand :: FourCc
+           ,minorVersion :: Word32
+           ,compatibleBrands :: [FourCc]}
+
+instance IsBoxContent FileType where
+  boxSize (FileType maj ver comps) = boxSize maj + 4 + sum (boxSize <$> comps)
+  boxBuilder (FileType maj ver comps) =
+    boxBuilder maj <> word32BE ver <> mconcat (boxBuilder <$> comps)
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/MediaData.hs
@@ -0,0 +1,21 @@
+module Data.ByteString.IsoBaseFileFormat.Boxes.MediaData where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box
+import qualified Data.ByteString as B
+
+-- | Media data box
+type MediaDataBox = Box "mdat"
+
+instance BoxRules "mdat"
+
+-- | Create a 'MediaDataBox' from a strict 'ByteString'
+mediaDataBox :: MediaData -> MediaDataBox
+mediaDataBox = box
+
+-- | Contents of a 'mdat' box are just bytes from a strict 'ByteString'
+newtype MediaData =
+  MediaData B.ByteString
+
+instance IsBoxContent MediaData where
+  boxSize (MediaData bs) = fromIntegral $ B.length bs
+  boxBuilder (MediaData bs) = byteString bs
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieBox.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieBox.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/MovieBox.hs
@@ -0,0 +1,39 @@
+-- | Meta data for a presentation of a /movie/.
+module Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box
+
+-- Uncomment this to see what the custom compiler errors look like:
+--
+-- import Data.ByteString.IsoBaseFileFormat.Boxes.Skip
+-- xxx :: Box "moov"
+-- xxx = movieBox
+--         (movieBoxContainer :- skipBox (Skip 100))
+
+-- | The metadata for a presentation, a single 'MovieBox' which occurs only once
+-- and top-level. It is pretty empty on it's own, but it contains nested boxes
+-- with all the relevant meta data.
+type MovieBox = Box "moov"
+
+instance BoxRules "moov" where
+  type RequiredNestedBoxes "moov" = '["mvhd", "trak"]
+
+-- | Compose a movie box from the required 'Boxes'.
+movieBox :: forall ts. ValidBoxes "moov" ts => Boxes "moov" ts -> Box "moov"
+movieBox = boxes
+
+-- | The movie box container, use this to create movie boxes filled with nested
+--   boxes, for example:
+--
+-- >  xxx :: Box "moov"
+-- >  xxx = movieBox
+-- >          (movieBoxContainer
+-- >           :- movieHeaderBox (MovieHeader ...)
+-- >           :- trackBox
+-- >              (trackBoxContainer
+-- >               :- trackHeaderBox
+-- >               :- trackReferenceBox
+-- >               :- trackGroupingIndication))
+--
+movieBoxContainer :: Container "moov"
+movieBoxContainer = Parent emptyBox
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/ProgressiveDownloadInformation.hs
@@ -0,0 +1,25 @@
+module Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation
+       where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box
+
+-- | A Box with progressive download information
+type ProgressiveDownloadInformationBox = Box "pdin"
+
+instance BoxRules "pdin"
+
+-- | Create a 'pdin' box
+progressiveDownloadInformationBox
+  :: ProgressiveDownloadInformation -> ProgressiveDownloadInformationBox
+progressiveDownloadInformationBox = fullBox (BoxVersion 0) zeroBits
+
+-- | Information for progressive media data download/playback encompasses the
+-- delay for initial playback and expected download bit rate.
+data ProgressiveDownloadInformation =
+  ProgressiveDownloadInformation {pdinRate :: Word32 -- ^ Effective download bitrate in byte/sec
+                                 ,pdinDelay :: Word32 -- ^ Delay in milli seconds
+                                 }
+
+instance IsBoxContent ProgressiveDownloadInformation where
+  boxSize _ = 8
+  boxBuilder pdin = word32BE (pdinRate pdin) <> word32BE (pdinDelay pdin)
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs b/src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Boxes/Skip.hs
@@ -0,0 +1,21 @@
+module Data.ByteString.IsoBaseFileFormat.Boxes.Skip where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box
+
+-- | A filler box, the contents are skipped
+type SkipBox = Box "skip"
+
+instance BoxRules "skip" where
+  type RestrictedTo "skip" = 'Nothing
+
+-- | Create a 'SkipBox' with a given size.
+skipBox :: Skip -> SkipBox
+skipBox = box
+
+-- | Contents of a 'skip' box are just any number of filler bytes.
+newtype Skip =
+  Skip Int
+
+instance IsBoxContent Skip where
+  boxSize (Skip bs) = fromIntegral bs
+  boxBuilder (Skip bs) = mconcat (replicate bs (word8 0))
diff --git a/src/Data/ByteString/IsoBaseFileFormat/Builder.hs b/src/Data/ByteString/IsoBaseFileFormat/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/IsoBaseFileFormat/Builder.hs
@@ -0,0 +1,11 @@
+-- | This module re-exports all modules needed to build /ISOBMFF/ documents.
+module Data.ByteString.IsoBaseFileFormat.Builder
+  (module Data.ByteString.IsoBaseFileFormat.Builder, module X)
+  where
+
+import Data.ByteString.IsoBaseFileFormat.Boxes.Box as X
+import Data.ByteString.IsoBaseFileFormat.Boxes.FileType as X
+import Data.ByteString.IsoBaseFileFormat.Boxes.MediaData as X
+import Data.ByteString.IsoBaseFileFormat.Boxes.MovieBox as X
+import Data.ByteString.IsoBaseFileFormat.Boxes.ProgressiveDownloadInformation as X
+import Data.ByteString.IsoBaseFileFormat.Boxes.Skip as X
