diff --git a/curvepy/__init__.py b/curvepy/__init__.py
index 6f12c9058587148a0c9d485beaabf419b3219385..e2a8efe69a94cddbb02ef9a9a8f36fb45eeef567 100644
--- a/curvepy/__init__.py
+++ b/curvepy/__init__.py
@@ -1,3 +1,13 @@
 """
-Welcome to curvepy! More documentation will be written soon.
+Welcome to curvepy!
+
+curvepy is an computational geometric library. It's main focus lies on
+
+- Different Bézier curve implementations and their viability
+- A Green-Sibson/Bowyer/Watson based Delaunay triangulation, with translation in it's Voronoi dual graph
+
+The technical information can be found in the single modules, the mathematical explanations and design decisions
+can be found in the accompanying paper.
+
+Please read the paper for more information.
 """
diff --git a/curvepy/types.py b/curvepy/types.py
index 2cf83572983a62fe3ce7b456271b2094c36f69fb..8db3d2a512d5fa97d8b459f5b034367a2c432286 100644
--- a/curvepy/types.py
+++ b/curvepy/types.py
@@ -5,7 +5,6 @@ import sys
 from abc import ABC, abstractmethod
 from collections.abc import Sequence
 from dataclasses import dataclass
-from enum import Enum
 from functools import cached_property, lru_cache, partial
 from typing import (Any, Callable, Deque, Dict, List, NamedTuple, Optional,
                     Tuple, Union)
@@ -15,18 +14,25 @@ import scipy.special as scs
 
 from curvepy.utilities import create_straight_line_function
 
-
-class CurveTypes(Enum):
-    bezier_curve = 0
-    bezier_curve_threaded = 1
-    bezier_curve_blossoms = 2
-
-
 Point2D = Tuple[float, float]
 Edge2D = Tuple[Point2D, Point2D]
 
 
 class TriangleNode(NamedTuple):
+    """
+    Auxiliary datastructure for easier triangle graph traversal.
+    Views the triangle from one specific point.
+
+    Attributes
+    -------
+    ccw: Point2D
+        The point counterclockwise to our pt.
+    cw: Point2D
+        The point clockwise to our pt.
+    pt: Point2D
+        The third point, from which cw and ccw are semantically defined.
+    ccc: The circumcircle center.
+    """
     ccw: Point2D
     cw: Point2D
     pt: Point2D
@@ -34,27 +40,100 @@ class TriangleNode(NamedTuple):
 
 
 class Circle:
+    """
+    A computational representation of a geometric circle.
+
+
+    Parameters
+    ----------
+    center: Point2D
+        The circle center
+    radius: float
+        The circle radius
+
+    Attributes
+    -------
+    _center: np.ndarray
+        The circle center
+    radius: float
+        The radius
+    """
+
     def __init__(self, center: Point2D, radius: float):
         self._center = np.array(center)
         self.radius = radius
 
     @property
     def center(self) -> Point2D:
+        """
+        Property that converts and returns the circle center.
+
+        Returns
+        -------
+        Point2D
+            The circle center
+        """
         return tuple(self._center)
 
     def __contains__(self, pt: Point2D) -> bool:
+        """
+        Checks whether a point lies within the convex set spanned by the circle.
+
+        Parameters
+        ----------
+        pt: Point2D
+            The point which needs to be checked.
+
+        Returns
+        -------
+        Whether pt lies in the circle.
+        """
         return np.linalg.norm(np.array(pt) - self._center) <= self.radius
 
     def __str__(self) -> str:
+        """
+        Generating human readable string representation of circles.
+
+        Returns
+        -------
+        Human readable string representation of circles.
+        """
         return f"(CENTER: {self.center}, RADIUS: {self.radius})"
 
     def __repr__(self) -> str:
+        """
+        Generating machine readable string representation of circles.
+
+        Returns
+        -------
+        Machine readable string representation of circles.
+        """
         return f"<CIRCLE: {str(self)}>"
 
     def __eq__(self, other: Any) -> bool:
+        """
+        Checks whether 2 objects are the same.
+        An object is the same iff it is a circle with the same center and radius.
+
+        Parameters
+        ----------
+        other: Any
+            The compared object.
+
+        Returns
+        -------
+        Whether they are the same circle.
+        """
         return isinstance(other, Circle) and self.center == other.center and self.radius == other.radius
 
     def __hash__(self) -> int:
+        """
+        Hashing function, hashes the 3 numbers (x, y, r).
+
+        Returns
+        -------
+        The hash generated by a unique seed.
+        """
         return hash((*self.center, self.radius))
 
 
@@ -62,6 +141,13 @@ class Polygon(Sequence):
     """
     Class for creating a 2D or 3D Polygon.
 
+    Parameters
+    ----------
+    points: List[np.ndarray]
+        The points the Polygon is made of
+    make_copy: bool
+        whether the points should be deep copied
+
     Attributes
     ----------
     _points: np.ndArray
@@ -70,7 +156,6 @@ class Polygon(Sequence):
         dimension of the polygon
     _piece_funcs: list
         list containing all between each points, _points[i] and _points[i+1]
-
     """
 
     def __init__(self, points: List[np.ndarray], make_copy: bool = True) -> None:
@@ -97,13 +182,27 @@ class Polygon(Sequence):
 
     def __getitem__(self, item: Any) -> Callable[[float], np.ndarray]:
         """
-        Throws ValueError when casting to int.
-        Throws IndexError when out of bounds.
-        And probably something else.
+        Allows us to use the index operator on the underlying vertex array.
+
+        Parameters
+        ----------
+        item: Any
+            The index
+
+        Returns
+        -------
+        The vertex at the provided index.
         """
         return self._piece_funcs[int(item)]
 
     def __len__(self) -> int:
+        """
+        Returns the number of points that make up the polygon.
+
+        Returns
+        -------
+        The number of points that make up the polygon.
+        """
         return len(self._points)
 
     def blossom(self, ts: List[float]) -> np.ndarray:
@@ -128,6 +227,13 @@ class Polygon(Sequence):
 
 
 class AbstractTriangle(ABC):
+    """
+    Abstract class representing a Triangle.
+
+    Attributes
+    ----------
+    _points: The 3 points representing a triangle.
+    """
 
     @abstractmethod
     def __init__(self):
@@ -136,16 +242,37 @@ class AbstractTriangle(ABC):
 
     @cached_property
     def lines(self) -> Union[List[Edge2D], List[Tuple[np.ndarray]]]:
+        """
+        Returns the 3 lines of a triangle.
+
+        Returns
+        -------
+        The 3 lines of a triangle.
+        """
         a, b, c = self.points
         return [(a, b), (b, c), (a, c)]
 
     @cached_property
     def points(self) -> Union[Tuple[Point2D, Point2D, Point2D], List[np.ndarray]]:
+        """
+        Returns the 3 points of a triangle.
+
+        Returns
+        -------
+        The 3 points of a triangle.
+        """
         # If it was mutable caching would break
         return self._points
 
     @cached_property
     def area(self) -> float:
+        """
+        Returns the area of the triangle.
+
+        Returns
+        -------
+        The area of the triangle.
+        """
         a, b, c = self.points
         # print(f"{a.shape}, {b.shape}, {c.shape}")
         return self.calc_area(np.array(a), np.array(b), np.array(c))
@@ -177,9 +304,11 @@ class AbstractTriangle(ABC):
     @cached_property
     def circumcircle(self) -> Circle:
         """
-        see: https://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html
-        :return:
+        Computes the circumcircle of a triangle.
 
+        Returns
+        -------
+        The circumcircle of a triangle.
         """
         a, b, c = self.points
 
@@ -192,27 +321,89 @@ class AbstractTriangle(ABC):
         return Circle(center=center, radius=radius)
 
     def __str__(self) -> str:
+        """
+        Generating human readable string representation of triangles.
+
+        Returns
+        -------
+        Human readable string representation of triangles.
+        """
         return str(self.points)
 
     def __repr__(self) -> str:
+        """
+        Generating machine readable string representation of triangles.
+
+        Returns
+        -------
+        Machine readable string representation of triangles.
+        """
         return f"<TRIANLGE: {str(self)}>"
 
 
 class TupleTriangle(AbstractTriangle):
+    """
+    Class for creating a tuple based triangle.
+
+    Parameters
+    ----------
+    a: Point2D
+        The first point of a triangle.
+    b: Point2D
+        The second point of a triangle.
+    c: Point2D
+        The third point of a triangle.
+
+    Attributes
+    ----------
+    _points: Tuple[Point2D, Point2D, Point2D]
+        tuple containing copy of points that create the polygon
+    """
+
     def __init__(self, a: Point2D, b: Point2D, c: Point2D):
         self._points: Tuple[Point2D, Point2D, Point2D] = (a, b, c)
 
     def __eq__(self, other: Any) -> bool:
+        """
+        Checks whether 2 objects are the same.
+        An object is the same iff it is a triangle with the same points.
+
+        Parameters
+        ----------
+        other: Any
+            The compared object.
+
+        Returns
+        -------
+        Whether they are the same triangle.
+        """
         return isinstance(other, TupleTriangle) and sorted(self.points) == sorted(other.points)
 
     def __hash__(self) -> int:
+        """
+        Hashing function, hashes the 3 points.
+        It is sorted such that ordering does not matter.
+
+        Returns
+        -------
+        The hash generated by a unique seed.
+        """
         return hash(tuple(sorted(self.points)))
 
 
 class PolygonTriangle(Polygon, AbstractTriangle):
+    """
+    Class for creating a polygon based triangle.
+
+    Parameters
+    ----------
+    points: List[np.ndarray]
+        The points the Polygon is made of
+    make_copy: bool
+        whether the points should be deep copied
+    """
 
     def __init__(self, points: List[np.ndarray], make_copy: bool = True) -> None:
-        # points.append(points[0])
         # https://stackoverflow.com/a/26927718
         Polygon.__init__(self, points, make_copy)
 
@@ -241,8 +432,7 @@ class PolygonTriangle(Polygon, AbstractTriangle):
         for all points of the TupleTriangle to the plane, so that cramer's rule can easily be applied to them
         in order to calculate the calc_area of the TupleTriangle corresponding to every 3 out of the 4 points.
         But this method does not overwrite the self._points.
-
-        TODO this is allowed since we use a parallel projection, which is a proper affine transformation.
+        This is allowed since we use a parallel projection, which is a proper affine transformation.
 
         Parameters
         ----------
@@ -296,8 +486,8 @@ class PolygonTriangle(Polygon, AbstractTriangle):
     def get_bary_coords(self, p: np.ndarray) -> np.ndarray:
         """
         Calculates the barycentric coordinates of p with respect to the points defining the TupleTriangle.
-        TODO: Explizit dazuschreiben, dass wir bei rg(A) = 1 trotz Punkt auf der Hyperline verweigern weil degenerate.
-        TODO: write that p needs to have same dim.
+        Note that the rg(A) can't be 1 because this would be a degenerated case.
+        Futher note that p needs to have the same dimension.
 
         Parameters
         ----------
@@ -322,7 +512,32 @@ class PolygonTriangle(Polygon, AbstractTriangle):
 
 
 class Triangle:
+    """
+    Helper "Factory" that decides which Triangle to instanciate
+    """
+
     def __call__(self, a, b, c):
+        """
+        Helper method that decides which Triangle to instanciate.
+        Think of it as a constructor with less overhead.
+        Pythons call order is
+        - `__call__`
+        - `__new__`
+        - `__init__`
+
+        Parameters
+        ----------
+        a
+            The first point
+        b
+            The second point
+        c
+            The third point
+
+        Returns
+        -------
+        The appropriate triangle.
+        """
         if isinstance(a, tuple):
             return TupleTriangle(a, b, c)
         elif isinstance(a, np.ndarray):
@@ -336,10 +551,25 @@ VoronoiRegions2D = Dict[Point2D, Deque[TriangleNode]]
 
 @dataclass(frozen=True)
 class MinMaxBox:
+    """
+    Dataclass to represent a MinMaxBox, which is an axis parallel rectangle.
+
+    Attributes
+    ----------
+    min_maxs: List[float]
+        the xmin, xmax, ymin, ymax, ... (for more dimensions)
+    """
     min_maxs: List[float]  # [x_min, x_max, y_min, y_max, ...]
 
     @cached_property
     def area(self) -> float:
+        """
+        Calculates the area of the MinMaxBox.
+
+        Returns
+        -------
+        The area of the MinMaxBox.
+        """
         return math.prod([d_max - d_min for d_min, d_max in zip(self[::2], self[1::2])])
 
     @classmethod
@@ -350,28 +580,101 @@ class MinMaxBox:
         return cls(sum([[m[i, :].min(), m[i, :].max()] for i in range(m.shape[0])], []))
 
     def __getitem__(self, item) -> Union[float, List[float]]:
+        """
+        Overrides the [] operator to access the values of the underlying list.
+
+        Parameters
+        ----------
+        item: index
+            Index or slice
+
+        Returns
+        -------
+        The sliced value of the underlying list.
+        """
         return self.min_maxs.__getitem__(item)
 
     def __and__(self, other: MinMaxBox) -> Optional[MinMaxBox]:
+        """
+        Returns the intersection area of two MinMaxBoxes.
+
+        Parameters
+        ----------
+        other: MinMaxBox
+            The other MinMaxBox from which to generate the intersection.
+
+        Returns
+        -------
+        The intersection area of two MinMaxBoxes.
+        """
         return self.intersect(other)
 
     __rand__ = __and__
 
     # For iterators
     def __len__(self):
+        """
+        Returns the length of the underlying list to make iterators works.
+
+        Returns
+        -------
+        The length of the underlying list to make iterators works.
+        """
         return len(self.min_maxs)
 
     def dim(self):
+        """
+        Returns the number of box dimensions.
+
+        Returns
+        -------
+        The number of box dimensions.
+        """
         return len(self) // 2
 
     def __contains__(self, point: Tuple[float, ...]) -> bool:
-        return self.dim() == len(point) \
-            and all(self[2 * i] <= point[i] <= self[(2 * i) + 1] for i in range(len(point)))
+        """
+        Returns whether a point is contained in the MinMaxBox
 
-    def same_dimension(self, other: MinMaxBox):
+        Parameters
+        ----------
+        point: Tuple[float, ...]
+            The point. Has to be the same dimension to be contained.
+
+        Returns
+        -------
+        Whether a point is contained in the MinMaxBox
+        """
+        return self.dim() == len(point) and all(self[2 * i] <= point[i] <= self[(2 * i) + 1] for i in range(len(point)))
+
+    def same_dimension(self, other: MinMaxBox) -> bool:
+        """
+        Checks whether 2 MinMaxBoxes have the same dimension.
+
+        Parameters
+        ----------
+        other: MinMaxBox
+            The other MinMaxBox to compare to.
+
+        Returns
+        -------
+        Whether 2 MinMaxBoxes have the same dimension.
+        """
         return len(self) == len(other)
 
     def intersect(self, other: MinMaxBox) -> Optional[MinMaxBox]:
+        """
+        Returns the intersection of two MinMaxBoxes, if they intersect, otherwise None.
+
+        Parameters
+        ----------
+        other: MinMaxBox
+            The other MinMaxBox to check the intersection with.
+
+        Returns
+        -------
+        The intersection of two MinMaxBoxes, if they intersect, otherwise None.
+        """
         if not self.same_dimension(other):
             return None
         res = np.zeros((len(self),))
diff --git a/curvepy/utilities.py b/curvepy/utilities.py
index 053e903534846d5aecbbddb63aaef30ef1aeb9aa..74b9bb904b1469a36eac32445eced217cadd36e2 100644
--- a/curvepy/utilities.py
+++ b/curvepy/utilities.py
@@ -110,15 +110,12 @@ a + x(b + x(c+x*(d)))
 
 def horner(m: np.ndarray, t: float = 0.5) -> Tuple[Union[float, Any], ...]:
     """
-    TODO show which problem this is
-    TODO besserer Name sowie auch BezierCurveHorner mit horner-bez
-    TODO First coeff == Highest Degree
-    Method using horner's method to calculate point with given t
+    Method using horner schema of the De Casteljau algorithm to calculate a single point.
 
     Parameters
     ----------
     m: np.ndarray:
-        array containing coefficients
+        array containing coefficients. Note that the first coefficient is the highest degree.
 
     t: float:
         value for which point is calculated
@@ -233,8 +230,32 @@ def intersect_lines(p1: np.ndarray, p2: np.ndarray, p3: np.ndarray, p4: np.ndarr
 
 
 def flatten_list_of_lists(xss: List[List[Any]]) -> List[Any]:
+    """
+    Reduces one list dimension by using using it's `__add__`.
+
+    Parameters
+    ----------
+    xss: List[List[Any]]
+        Any list that needs a reduced version.
+
+    Returns
+    -------
+    The same list, flattened by one dimension
+    """
     return sum(xss, [])
 
 
 def prod(xs: Iterable[Number]):
+    """
+    The multiplical product of a bunch of numbers.
+
+    Parameters
+    ----------
+    xs: Iterable[Number]
+        The numbers to multiply
+
+    Returns
+    -------
+    The product, 1 if empty.
+    """
     return functools.reduce(operator.mul, xs, 1)