diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -34,4 +34,35 @@
 functions and optional arguments.  It basically exports a minimal
 version of diagrams-lib to the command-line. See ``brldia --help`` for details.
 
+## Usage
+
+```shell
+brldia circle 1
+```
+
+```
+⢠⠖⠋⠉⠉⠙⠲⡄
+⡏⠀⠀⠀⠀⠀⠀⢹
+⣇⠀⠀⠀⠀⠀⠀⣸
+⠘⠦⣄⣀⣀⣠⠴⠃
+```
+
+You can also combine various shapes into a single diagram:
+
+```shell
+brldia --width=32 circle 1 square 1.4
+```
+
+```
+⠀⠀⢀⡤⠖⠋⠉⠉⠉⠉⠙⠲⢤⡀⠀⠀
+⠀⡴⡏⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢹⢦⠀
+⡼⠁⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠈⢧
+⡇⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢸
+⡇⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢸
+⢳⡀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢀⡞
+⠀⠳⣇⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣸⠞⠀
+⠀⠀⠈⠓⠦⣄⣀⣀⣀⣀⣠⠴⠚⠁⠀⠀
+```
+
+See ``--help`` for a full list of available commands and options.
 
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,11 +1,13 @@
+-- A monoidal command line interface to some diagrams primitives
 {-# LANGUAGE NoMonomorphismRestriction #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE TypeFamilies #-}
 module Main where
 
-import Diagrams.Backend.Braille.CmdLine
+import Diagrams.Backend.Braille.CmdLine (B, mainWith)
 import Diagrams.Backend.CmdLine (Parseable(..))
-import Diagrams.Prelude hiding (option, value)
+import Diagrams.Prelude hiding (option)
+import Diagrams.TwoD.Text (Text)
 import Options.Applicative
 
 d = f 1 `atop` f (sqrt 2 / 2) `atop` f (sqrt 2 * (sqrt 2 / 2) / 2) where
@@ -32,63 +34,83 @@
   where hilbert' = rotateBy (1/4) . hilbert
 
 newtype Opts = Opts { draw :: Diagram B }
+instance Parseable Opts where parser = Opts . mconcat <$> commands
 
-instance Parseable Opts where
-  parser = fmap (Opts . mconcat) $ some $ hsubparser $ mconcat [
-      commandGroup "Diagrams"
-    , cmd "hrule" "A centered horizontal (L-R) line of the given length." $
-      hrule <$> arg (metavar "LENGTH")
-    , cmd "vrule" "A centered vertical (T-B) line of the given length." $
-      vrule <$> arg (metavar "LENGTH")
-    , cmd "triangle" "An equilateral triangle, with sides of the given length and base parallel to the x-axis." $
-      triangle <$> arg (metavar "LENGTH")
-    , cmd "rect" "An axis-aligned rectangle of the given width and height, centered at the origin." $
-      rect <$> arg (metavar "WIDTH")
-           <*> arg (metavar "HEIGHT")
-    , cmd "roundedRect" "An axis-aligned rectangle with the given width and height with circular rounded corners of radius, centered at the origin." $
-      roundedRect <$> arg (metavar "WIDTH")
-                  <*> arg (metavar "HEIGHT")
-                  <*> arg (metavar "RADIUS")
-    , cmd "square" "A square with its center at the origin and sides of the given length, oriented parallel to the axes." $
-      square <$> arg (metavar "LENGTH")
-    , cmd "pentagon" "A regular pentagon, with sides of the given length and base parallel to the x-axis." $
-      pentagon <$> arg (metavar "LENGTH")
-    , cmd "hexagon" "A regular hexagon, with sides of the given length and base parallel to the x-axis." $
-      hexagon <$> arg (metavar "LENGTH")
-    , cmd "heptagon" "A regular heptagon, with sides of the given length and base parallel to the x-axis." $
-      heptagon <$> arg (metavar "LENGTH")
-    , cmd "octagon" "A regular octagon, with sides of the given length and base parallel to the x-axis." $
-      octagon <$> arg (metavar "LENGTH")
-    , cmd "nonagon" "A regular nonagon, with sides of the given length and base parallel to the x-axis." $
-      nonagon <$> arg (metavar "LENGTH")
-    , cmd "decagon" "A regular decagon, with sides of the given length and base parallel to the x-axis." $
-      decagon <$> arg (metavar "LENGTH")
-    , cmd "hendecagon" "A regular hendecagon, with sides of the given length and base parallel to the x-axis." $
-       hendecagon <$> arg (metavar "LENGTH")
-    , cmd "dodecagon" "A regular dodecagon, with sides of the given length and base parallel to the x-axis." $
-      dodecagon <$> arg (metavar "LENGTH")
-    , cmd "circle" "A circle of the given radius, centered at the origin." $
-      circle <$> arg (metavar "RADIUS")
-    , cmd "text" "Print text." $ text <$> strArgument (metavar "STRING")
-    , cmd "baselineText" "Print text." $ baselineText <$> strArgument (metavar "STRING")
-    , cmd "clock" "A clock showing the time given in hours and minutes." $
-      clock <$> arg (metavar "HOUR")
-            <*> arg (metavar "MINUTE")
-    , cmd "flower-of-life" "The \"flower of life\"." $
-      pure fol
-    , cmd "hilbert" "A hilbert curve of the given order." $
-      strokeT . hilbert <$> arg (metavar "ORDER")
-    , cmd "seed-of-life" "The \"seed of life\"." $ pure sol
-    ] where cmd s d p = command s $ info (foldr ($) <$> p <*> many modifier) $
-                        progDesc d
-            arg = argument auto
+commands :: ( TypeableFloat n, Enum n, Read n
+            , Renderable (Text n) b, Renderable (Path V2 n) b
+            )
+         => Parser [QDiagram b V2 n Any]
+commands = some $ hsubparser $ mconcat [
+    commandGroup "Diagrams"
+  , cmd "strut" "A diagram which produces no output, but with respect to alignment and envelope acts like a 1-dimensional segment oriented along the vector denoted by vx and vy, with local origin at its center." $
+    (\x y -> strut (V2 x y)) <$> arg (metavar "vx") <*> arg (metavar "vy")
+  , cmd "hrule" "A centered horizontal (L-R) line of the given length." $
+    hrule <$> arg (metavar "LENGTH")
+  , cmd "vrule" "A centered vertical (T-B) line of the given length." $
+    vrule <$> arg (metavar "LENGTH")
+  , cmd "triangle" "An equilateral triangle, with sides of the given length and base parallel to the x-axis." $
+    triangle <$> arg (metavar "LENGTH")
+  , cmd "rect" "An axis-aligned rectangle of the given width and height, centered at the origin." $
+    rect <$> arg (metavar "WIDTH")
+         <*> arg (metavar "HEIGHT")
+  , cmd "roundedRect" "An axis-aligned rectangle with the given width and height with circular rounded corners of radius, centered at the origin." $
+    roundedRect <$> arg (metavar "WIDTH")
+                <*> arg (metavar "HEIGHT")
+                <*> arg (metavar "RADIUS")
+  , cmd "square" "A square with its center at the origin and sides of the given length, oriented parallel to the axes." $
+    square <$> arg (metavar "LENGTH")
+  , cmd "pentagon" "A regular pentagon, with sides of the given length and base parallel to the x-axis." $
+    pentagon <$> arg (metavar "LENGTH")
+  , cmd "hexagon" "A regular hexagon, with sides of the given length and base parallel to the x-axis." $
+    hexagon <$> arg (metavar "LENGTH")
+  , cmd "heptagon" "A regular heptagon, with sides of the given length and base parallel to the x-axis." $
+    heptagon <$> arg (metavar "LENGTH")
+  , cmd "octagon" "A regular octagon, with sides of the given length and base parallel to the x-axis." $
+    octagon <$> arg (metavar "LENGTH")
+  , cmd "nonagon" "A regular nonagon, with sides of the given length and base parallel to the x-axis." $
+    nonagon <$> arg (metavar "LENGTH")
+  , cmd "decagon" "A regular decagon, with sides of the given length and base parallel to the x-axis." $
+    decagon <$> arg (metavar "LENGTH")
+  , cmd "hendecagon" "A regular hendecagon, with sides of the given length and base parallel to the x-axis." $
+    hendecagon <$> arg (metavar "LENGTH")
+  , cmd "dodecagon" "A regular dodecagon, with sides of the given length and base parallel to the x-axis." $
+    dodecagon <$> arg (metavar "LENGTH")
+  , cmd "circle" "A circle of the given radius, centered at the origin." $
+    circle <$> arg (metavar "RADIUS")
+  , cmd "cubicSpline" "" $
+    cubicSpline <$> switch (long "closed")
+                <*> some (curry p2 <$> arg (metavar "X") <*> arg (metavar "Y"))
+  , cmd "arrowAt" "" $
+    (\a b c d -> arrowAt (p2 (a, b)) (V2 c d)) <$> arg (metavar "px")
+                                                <*> arg (metavar "py")
+                                                <*> arg (metavar "vx")
+                                                <*> arg (metavar "vy")
+  , cmd "text" "Print text." $ text <$> strArgument (metavar "STRING")
+  , cmd "baselineText" "Print text." $ baselineText <$> strArgument (metavar "STRING")
+  , cmd "clock" "A clock showing the time given in hours and minutes." $
+    clock <$> arg (metavar "HOUR")
+          <*> arg (metavar "MINUTE")
+  , cmd "flower-of-life" "The \"flower of life\"." $
+    pure fol
+  , cmd "hilbert" "A hilbert curve of the given order." $
+    strokeT . hilbert <$> arg (metavar "ORDER")
+  , cmd "seed-of-life" "The \"seed of life\"." $ pure sol
+  ] where cmd s d p = command s $ info (foldr ($) <$> p <*> many modifier) $
+                      progDesc d
+          arg = argument auto
 
-modifier = flag' alignL (long "alignL") <|> flag' alignR (long "alignR")
-       <|> flag' alignT (long "alignT") <|> flag' alignB (long "alignB")
+modifier :: (Semigroup m, Monoid m, Read n, TypeableFloat n, Renderable (Path V2 n) b)
+         => Parser (QDiagram b V2 n m -> QDiagram b V2 n m)
+modifier = flag' alignL (long "alignL" <> help "Align along the left edge, i.e. translate the diagram in a horizontal direction so that the local origin is on the left edge of the envelope.")
+       <|> flag' alignR (long "alignR" <> help "Align along the right edge.")
+       <|> flag' alignT (long "alignT" <> help "Align along the top edge.")
+       <|> flag' alignB (long "alignB" <> help "Align along the bottom edge.")
        <|> flag' centerX (long "centerX" <> help "Center the local origin along the X-axis.")
        <|> flag' centerY (long "centerY" <> help "Center the local origin along the Y-axis.")
        <|> flag' centerXY (long "centerXY" <> help "Center along both the X- and Y-axes.")
-       <|> (named :: String -> Diagram B -> Diagram B) <$> option auto (long "named" <> metavar "NAME")
+       <|> frame <$> option auto (long "frame" <> metavar "SIZE" <> help "Increase the envelope of a diagram by an absolute amount SIZE, SIZE is in the local units of the diagram.")
+--     <|> (named :: String -> Diagram B -> Diagram B) <$> option auto (long "named" <> metavar "NAME")
+       <|> pad <$> option auto (long "pad" <> metavar "FACTOR" <> help "\"pads\" a diagram, expanding its envelope by a FACTOR (factors between 0 and 1 can be used to shrink the envelope).")
        <|> flag' reflectX (long "reflectX" <> help "Flip a diagram from left to right, i.e. send the point (x,y) to (-x,y).")
        <|> flag' reflectY (long "reflectY" <> help "Flip a diagram from top to bottom, i.e. send the point (x,y) to (x,-y).")
        <|> flag' reflectXY (long "reflectXY" <> help "Flips the diagram about x=y, i.e. send the point (x,y) to (y,x).")
diff --git a/diagrams-braille.cabal b/diagrams-braille.cabal
--- a/diagrams-braille.cabal
+++ b/diagrams-braille.cabal
@@ -1,13 +1,13 @@
--- This file has been generated from package.yaml by hpack version 0.20.0.
+-- This file has been generated from package.yaml by hpack version 0.28.2.
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 9465bc70f6e2bb819638c30b903cd5a923b59057a28e760f4c910062967ff50c
+-- hash: 96caba720e58cac73984f3fcda9daadf5ea39d885b5711eb94e9e14dd30a1edb
 
 name:           diagrams-braille
-version:        0.1.0.1
+version:        0.1.0.2
 synopsis:       Braille diagrams with plain text
-description:    Please see the README on Github at <https://github.com/mlang/diagrams-braille#readme>
+description:    Please see the README at <https://github.com/mlang/diagrams-braille#readme>
 category:       Graphics
 homepage:       https://github.com/mlang/diagrams-braille#readme
 bug-reports:    https://github.com/mlang/diagrams-braille/issues
@@ -18,7 +18,6 @@
 license-file:   LICENSE
 build-type:     Simple
 cabal-version:  >= 1.10
-
 extra-source-files:
     README.md
 
@@ -27,6 +26,11 @@
   location: https://github.com/mlang/diagrams-braille
 
 library
+  exposed-modules:
+      Diagrams.Backend.Braille
+      Diagrams.Backend.Braille.CmdLine
+  other-modules:
+      Paths_diagrams_braille
   hs-source-dirs:
       src
   build-depends:
@@ -43,15 +47,12 @@
     , mtl
     , optparse-applicative
     , time
-  exposed-modules:
-      Diagrams.Backend.Braille
-      Diagrams.Backend.Braille.CmdLine
-  other-modules:
-      Paths_diagrams_braille
   default-language: Haskell2010
 
 executable brldia
   main-is: Main.hs
+  other-modules:
+      Paths_diagrams_braille
   hs-source-dirs:
       app
   ghc-options: -threaded -rtsopts -with-rtsopts=-N
@@ -70,6 +71,4 @@
     , mtl
     , optparse-applicative
     , time
-  other-modules:
-      Paths_diagrams_braille
   default-language: Haskell2010
diff --git a/src/Diagrams/Backend/Braille.hs b/src/Diagrams/Backend/Braille.hs
--- a/src/Diagrams/Backend/Braille.hs
+++ b/src/Diagrams/Backend/Braille.hs
@@ -116,7 +116,7 @@
 type RenderM n = ReaderT (Style V2 n) (Writer Draw)
 
 newtype Draw = Draw (R.Drawing PixelRGBA8 (), [((Int, Int), String)])
-             deriving (Monoid)
+             deriving (Semigroup, Monoid)
 
 tellR :: R.Drawing PixelRGBA8 () -> RenderM n ()
 tellR = tell . Draw . (,mempty)
@@ -157,9 +157,11 @@
 runR :: Render Braille V2 n -> RenderM n ()
 runR (R r) = r
 
+instance Semigroup (Render Braille V2 n) where
+  R rd1 <> R rd2 = R (rd1 >> rd2)
+
 instance Monoid (Render Braille V2 n) where
   mempty = R $ return ()
-  R rd1 `mappend` R rd2 = R (rd1 >> rd2)
 
 instance Hashable n => Hashable (Options Braille V2 n) where
   hashWithSalt s (BrailleOptions sz) = s `hashWithSalt` sz
