diff --git a/LICENCE b/LICENCE
new file mode 100644
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,30 @@
+Copyright (c) 2021 Tony Morris
+
+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 Tony Morris 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/aviation-navigation.cabal b/aviation-navigation.cabal
new file mode 100644
--- /dev/null
+++ b/aviation-navigation.cabal
@@ -0,0 +1,57 @@
+name:                 aviation-navigation
+version:              0.1.0.0
+synopsis:             Aviation Navigation functions
+description:          Aviation Navigation functions e.g. wind correction
+license:              BSD3
+license-file:         LICENCE
+author:               Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+maintainer:           Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+copyright:            Copyright (C) 2021 Tony Morris
+category:             Test
+build-type:           Simple
+extra-source-files:   changelog.md
+cabal-version:        >=1.10
+homepage:             https://gitlab.com/tonymorris/aviation-navigation
+bug-reports:          https://gitlab.com/tonymorris/aviation-navigation/issues
+tested-with:          GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.5
+
+source-repository     head
+  type:               git
+  location:           git@github.com:tonymorris/aviation-navigation.git
+
+library
+  exposed-modules:    Data.Aviation.Navigation
+                      Data.Aviation.Navigation.WindComponent
+                      Data.Aviation.Navigation.WindCorrection
+                      Data.Aviation.Navigation.WindParameters
+                      Data.Aviation.Navigation.Vector
+
+  build-depends:        base >= 4.8 && < 6
+                      , lens >= 4 && < 6
+                      , mtl >= 2.2 && < 2.3
+                      , radian >= 0.2 && < 1
+                      , optparse-applicative > 0.14 && < 0.15
+
+  hs-source-dirs:     src
+  default-language:   Haskell2010
+  ghc-options:        -Wall
+
+executable            wind-correction
+  other-modules:      Data.Aviation.Navigation
+                      Data.Aviation.Navigation.WindComponent
+                      Data.Aviation.Navigation.WindCorrection
+                      Data.Aviation.Navigation.WindParameters
+                      Data.Aviation.Navigation.Vector
+
+  build-depends:      base >= 4.8 && < 6
+                      , lens >= 4 && < 6
+                      , mtl >= 2.2 && < 2.3
+                      , radian >= 0.2 && < 1
+                      , optparse-applicative > 0.14 && < 0.15
+                      , aviation-navigation
+
+  hs-source-dirs:     exe/wind-correction
+                      src
+  default-language:   Haskell2010
+  main-is:            Main.hs
+  ghc-options:        -Wall
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,3 @@
+0.1.0.0
+
+* The initial version of aviation-navigation.
diff --git a/exe/wind-correction/Main.hs b/exe/wind-correction/Main.hs
new file mode 100644
--- /dev/null
+++ b/exe/wind-correction/Main.hs
@@ -0,0 +1,16 @@
+{-# OPTIONS_GHC -Wall #-}
+
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE CPP #-}
+
+module Main(
+  main
+) where
+
+import Data.Aviation.Navigation ( run )
+import Prelude
+
+main ::
+  IO ()
+main =
+  run VERSION_aviation_navigation
diff --git a/src/Data/Aviation/Navigation.hs b/src/Data/Aviation/Navigation.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aviation/Navigation.hs
@@ -0,0 +1,11 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Aviation.Navigation(
+  module T
+) where
+
+import Data.Aviation.Navigation.Vector as T
+import Data.Aviation.Navigation.WindComponent as T
+import Data.Aviation.Navigation.WindCorrection as T
+import Data.Aviation.Navigation.WindParameters as T
diff --git a/src/Data/Aviation/Navigation/Vector.hs b/src/Data/Aviation/Navigation/Vector.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aviation/Navigation/Vector.hs
@@ -0,0 +1,68 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Aviation.Navigation.Vector(
+  Vector(..)
+, vectorDegrees
+, HasVector(..)
+) where
+
+import Control.Category ( Category(id, (.)) )
+import Control.Lens ( view, Lens' )
+import Data.Eq ( Eq )
+import Data.Functor ( Functor(fmap) )
+import Data.Monoid ( Monoid(mempty) )
+import Data.Ord ( Ord )
+import Data.Radian ( fromRadians )
+import Data.Semigroup ( Semigroup((<>)) )
+import GHC.Show(Show)
+import Prelude(Double, Num((*), (-), (+)), Fractional((/)), sqrt, atan, sin, cos, pi)
+
+data Vector =
+  Vector
+    Double -- angle
+    Double -- magnitude
+  deriving (Eq, Ord, Show)
+
+vectorDegrees ::
+  Double
+  -> Double
+  -> Vector
+vectorDegrees =
+  Vector . view fromRadians
+
+instance Semigroup Vector where
+  Vector aa am <> Vector ba bm =
+    let square x = x * x
+        t = aa - ba
+        mag = sqrt (square am + square bm - 2 * am * bm * cos (pi - t))
+        ang = atan (bm * sin t / (am + bm * cos t))
+    in  Vector (aa - ang) mag
+
+instance Monoid Vector where
+  mempty =
+    Vector 0 0
+
+class HasVector a where
+  vector ::
+    Lens' a Vector
+  {-# INLINE angle #-}
+  angle ::
+    Lens' a Double
+  angle =
+    vector . angle
+  {-# INLINE magnitude #-}
+  magnitude ::
+    Lens' a Double
+  magnitude =
+    vector . magnitude
+
+instance HasVector Vector where
+  vector =
+    id
+  {-# INLINE angle #-}
+  angle f (Vector a m) =
+    fmap (\a' -> Vector a' m) (f a)
+  {-# INLINE magnitude #-}
+  magnitude f (Vector a m) =
+    fmap (\m' -> Vector a m') (f m)
diff --git a/src/Data/Aviation/Navigation/WindComponent.hs b/src/Data/Aviation/Navigation/WindComponent.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aviation/Navigation/WindComponent.hs
@@ -0,0 +1,63 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Aviation.Navigation.WindComponent(
+  WindComponent(..)
+, HasWindComponent(..)
+, calculateWindComponent
+) where
+
+import Control.Category ( Category(id, (.)) )
+import Control.Lens ( view, Lens' )
+import Data.Aviation.Navigation.Vector
+    ( HasVector(magnitude, angle) )
+import Data.Aviation.Navigation.WindParameters
+    ( HasWindParameters(windParameters, trackTAS, windSpeedDirection) )
+import Data.Eq ( Eq )
+import Data.Functor ( Functor(fmap) )
+import Data.Ord ( Ord )
+import GHC.Show(Show)
+import Prelude(Double, Num((*), (-)), sin, cos)
+
+data WindComponent =
+  WindComponent
+    Double
+    Double
+  deriving (Eq, Ord, Show)
+
+class HasWindComponent a where
+  windComponent ::
+    Lens' a WindComponent
+  {-# INLINE crosswind #-}
+  crosswind ::
+    Lens' a Double
+  crosswind =
+    windComponent . crosswind
+  {-# INLINE headwind #-}
+  headwind ::
+    Lens' a Double
+  headwind =
+    windComponent . headwind
+
+instance HasWindComponent WindComponent where
+  windComponent =
+    id
+  {-# INLINE crosswind #-}
+  crosswind f (WindComponent c h) =
+    fmap (\c' -> WindComponent c' h) (f c)
+  {-# INLINE headwind #-}
+  headwind f (WindComponent c h) =
+    fmap (\h' -> WindComponent c h') (f h)
+
+calculateWindComponent ::
+  HasWindParameters s =>
+  s
+  -> WindComponent
+calculateWindComponent wp =
+  let t = view (windParameters . trackTAS) wp
+      w = view (windParameters . windSpeedDirection) wp
+      diff = view angle w - view angle t
+      wm = view magnitude w
+      cw = wm * sin diff
+      hw = wm * cos diff
+  in  WindComponent cw hw
diff --git a/src/Data/Aviation/Navigation/WindCorrection.hs b/src/Data/Aviation/Navigation/WindCorrection.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aviation/Navigation/WindCorrection.hs
@@ -0,0 +1,114 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Aviation.Navigation.WindCorrection(
+  WindCorrection(..)
+, HasWindCorrection(..)
+, calculateWindCorrection
+, printWindCorrection
+, run
+) where
+
+import Control.Category ( Category(id, (.)) )
+import Control.Lens ( view, Lens' )
+import Options.Applicative
+    ( (<**>), fullDesc, header, info, execParser, helper )
+import Text.Printf ( printf, PrintfType )
+import Data.String ( IsString, String )
+import Data.Radian ( toRadians )
+import Data.Aviation.Navigation.Vector
+    ( Vector(..), HasVector(..) )
+import Data.Aviation.Navigation.WindComponent
+    ( WindComponent, HasWindComponent(windComponent, headwind, crosswind), calculateWindComponent )
+import Data.Aviation.Navigation.WindParameters
+    ( HasWindParameters(trackTAS), optWindParametersVersion )
+import Data.Eq ( Eq )
+import Data.Function(($))
+import Data.Functor ( Functor(fmap) )
+import Data.Maybe ( Maybe(Just, Nothing) )
+import Data.Ord ( Ord )
+import Data.Semigroup ( Semigroup((<>)) )
+import GHC.Show(Show)
+import Prelude(Double, Num((-), (+), (*)), Fractional((/)), sqrt)
+import System.IO ( IO, putStrLn )
+
+data WindCorrection =
+  WindCorrection
+    WindComponent -- crosswind/headwind
+    Double -- effective TAS
+    Vector -- heading/ground speed
+  deriving (Eq, Ord, Show)
+
+calculateWindCorrection ::
+  HasWindParameters s =>
+  s
+  -> WindCorrection
+calculateWindCorrection wp =
+  let square x = x * x
+      pythagoras a b = sqrt (square a + square b)
+      tas = view (trackTAS . magnitude) wp
+      wc = calculateWindComponent wp
+      hdg = view (trackTAS . angle) wp + view crosswind wc / tas
+      emag = pythagoras tas (view crosswind wc)
+      etas = square tas / emag
+      gs = etas - view headwind wc
+  in  WindCorrection wc etas (Vector hdg gs)
+
+printWindCorrection ::
+  (PrintfType a, IsString a, Semigroup a, HasWindCorrection s, HasWindComponent s, HasVector s) =>
+  s
+  -> a
+printWindCorrection r =
+  "Ground Speed   " <> printf "%06.2f" (view magnitude r) <> " KT\n" <>
+  "Effective TAS  " <> printf "%06.2f" (view effectiveTAS r) <> " KT\n" <>
+  "Heading        " <> printf "%06.2f" (view (angle . toRadians) r) <> " °\n" <>
+  "Crosswind      " <> printf "%06.2f" (view crosswind r) <> " KT\n" <>
+  "Headwind       " <> printf "%06.2f" (view headwind r) <> " KT"
+
+run ::
+  String
+  -> IO ()
+run v =
+  let desc =
+        "Aviation Navigation wind-correction (" <> v <> ")"
+      execopts =
+        execParser
+          (info (optWindParametersVersion <**> helper) (
+            fullDesc <>
+            header desc
+          )
+        )
+  in  do  conf' <- execopts
+          putStrLn $
+            case conf' of
+              Nothing ->
+                desc
+              Just wp ->
+                printWindCorrection (calculateWindCorrection wp)
+
+class HasWindCorrection a where
+  windCorrection ::
+    Lens' a WindCorrection
+  {-# INLINE effectiveTAS #-}
+  effectiveTAS ::
+    Lens' a Double
+  effectiveTAS =
+    windCorrection . effectiveTAS
+
+instance HasWindCorrection WindCorrection where
+  windCorrection =
+    id
+  {-# INLINE effectiveTAS #-}
+  effectiveTAS f (WindCorrection wc etas hdg) =
+    fmap (\etas' -> WindCorrection wc etas' hdg) (f etas)
+
+instance HasWindComponent WindCorrection where
+  {-# INLINE windComponent #-}
+  windComponent f (WindCorrection wc etas hdg) =
+    fmap (\wc' -> WindCorrection wc' etas hdg) (f wc)
+
+instance HasVector WindCorrection where
+  {-# INLINE vector #-}
+  vector f (WindCorrection wc etas hdg) =
+    fmap (\hdg' -> WindCorrection wc etas hdg') (f hdg)
diff --git a/src/Data/Aviation/Navigation/WindParameters.hs b/src/Data/Aviation/Navigation/WindParameters.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aviation/Navigation/WindParameters.hs
@@ -0,0 +1,104 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Aviation.Navigation.WindParameters (
+  WindParameters(..)
+, HasWindParameters(..)
+, optWindParameters
+, optWindParametersVersion
+) where
+
+import Control.Category ( Category(id, (.)) )
+import Control.Lens ( Lens' )
+import Data.Aviation.Navigation.Vector ( Vector, vectorDegrees )
+import Data.Eq ( Eq )
+import Data.Functor ( Functor(fmap), (<$>) )
+import Data.Maybe ( Maybe(Just, Nothing) )
+import Data.Ord ( Ord )
+import Data.Semigroup((<>))
+import GHC.Show(Show)
+import Options.Applicative
+    ( Applicative((<*>)),
+      Alternative((<|>)),
+      auto,
+      flag',
+      help,
+      long,
+      metavar,
+      option,
+      short,
+      Parser )
+
+data WindParameters =
+  WindParameters
+    Vector -- TAS, trk
+    Vector -- wind speed/dir
+  deriving (Eq, Ord, Show)
+
+class HasWindParameters a where
+  windParameters ::
+    Lens' a WindParameters
+  {-# INLINE trackTAS #-}
+  trackTAS ::
+    Lens' a Vector
+  trackTAS =
+    windParameters . trackTAS
+  {-# INLINE windSpeedDirection #-}
+  windSpeedDirection ::
+    Lens' a Vector
+  windSpeedDirection =
+    windParameters . windSpeedDirection
+
+instance HasWindParameters WindParameters where
+  windParameters =
+    id
+  {-# INLINE trackTAS #-}
+  trackTAS f (WindParameters tt wsd) =
+    fmap (\tt' -> WindParameters tt' wsd) (f tt)
+  {-# INLINE windSpeedDirection #-}
+  windSpeedDirection f (WindParameters tt wsd) =
+    fmap (\wsd' -> WindParameters tt wsd') (f wsd)
+
+optWindParameters ::
+  Parser WindParameters
+optWindParameters =
+  (\trk tas wd ws -> WindParameters (vectorDegrees trk tas) (vectorDegrees wd ws)) <$>
+    option auto (
+      long "trk" <>
+      short 't' <>
+      metavar "TRACK" <>
+      help "Track Direction °"
+    )
+    <*>
+    option auto (
+      long "tas" <>
+      short 'a' <>
+      metavar "TRUE_AIRSPEED" <>
+      help "True Air Speed kt"
+    )
+    <*>
+    option auto (
+      long "wd" <>
+      short 'd' <>
+      metavar "WIND_DIRECTION" <>
+      help "Wind Direction °"
+    )
+    <*>
+    option auto (
+      long "ws" <>
+      short 's' <>
+      metavar "WIND_SPEED" <>
+      help "Wind Speed kt"
+    )
+
+optWindParametersVersion ::
+  Parser (Maybe WindParameters)
+optWindParametersVersion =
+  flag'
+    Nothing
+    (
+      short 'v' <>
+      long "version" <>
+      help "the program version"
+    ) <|>
+    Just <$> optWindParameters
