diff --git a/src/main/java/de/oshgnacknak/gruphi/Gruphi.java b/src/main/java/de/oshgnacknak/gruphi/Gruphi.java
index 7437afd..0f6cbc7 100644
--- a/src/main/java/de/oshgnacknak/gruphi/Gruphi.java
+++ b/src/main/java/de/oshgnacknak/gruphi/Gruphi.java
@@ -6,13 +6,30 @@ import java.util.function.BiPredicate;
 
 public interface Gruphi {
 
+    /**
+     * @return Delay between draw calls
+     */
     long getFrameDelay();
 
+    /**
+     * @return Velocity to move camera and selected node with
+     */
     double getVelocity();
 
+    /**
+     * @return Horizontal and vertical spacing between nodes whilst generating a grid
+     */
     double getGridSpacing();
 
+    /**
+     * @return A {@link BiPredicate} that returns true
+     * iff a pair of nodes should be considered neighbours
+     * by the {@link MazeGenerator}.
+     */
     BiPredicate getNeighbourPredicate();
 
+    /**
+     * @return A {@link DirectedGraphFactory} to create the initial {@link h07.graph.DirectedGraph}
+     */
     DirectedGraphFactory getDirectedGraphFactory();
 }
diff --git a/src/main/java/de/oshgnacknak/gruphi/GruphiBuilder.java b/src/main/java/de/oshgnacknak/gruphi/GruphiBuilder.java
new file mode 100644
index 0000000..0c4a0e0
--- /dev/null
+++ b/src/main/java/de/oshgnacknak/gruphi/GruphiBuilder.java
@@ -0,0 +1,42 @@
+package de.oshgnacknak.gruphi;
+
+import h07.graph.DirectedGraphFactory;
+
+import java.util.function.BiPredicate;
+
+public class GruphiBuilder {
+    private Long frameDelay;
+    private Double velocity;
+    private Double gridSpacing;
+    private BiPredicate neighbourPredicate;
+    private DirectedGraphFactory directedGraphFactory;
+
+    public GruphiBuilder setFrameDelay(Long frameDelay) {
+        this.frameDelay = frameDelay;
+        return this;
+    }
+
+    public GruphiBuilder setVelocity(Double velocity) {
+        this.velocity = velocity;
+        return this;
+    }
+
+    public GruphiBuilder setGridSpacing(Double gridSpacing) {
+        this.gridSpacing = gridSpacing;
+        return this;
+    }
+
+    public GruphiBuilder setNeighbourPredicate(BiPredicate neighbourPredicate) {
+        this.neighbourPredicate = neighbourPredicate;
+        return this;
+    }
+
+    public GruphiBuilder setDirectedGraphFactory(DirectedGraphFactory directedGraphFactory) {
+        this.directedGraphFactory = directedGraphFactory;
+        return this;
+    }
+
+    public GruphiImpl createGruphi() {
+        return new GruphiImpl(frameDelay, velocity, gridSpacing, neighbourPredicate, directedGraphFactory);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/de/oshgnacknak/gruphi/GruphiImpl.java b/src/main/java/de/oshgnacknak/gruphi/GruphiImpl.java
new file mode 100644
index 0000000..d53a216
--- /dev/null
+++ b/src/main/java/de/oshgnacknak/gruphi/GruphiImpl.java
@@ -0,0 +1,64 @@
+package de.oshgnacknak.gruphi;
+
+import h07.graph.DirectedGraphFactory;
+
+import java.util.Objects;
+import java.util.function.BiPredicate;
+
+public class GruphiImpl implements Gruphi {
+
+    private static final long DEFAULT_FRAME_DELAY = 1000 / 60;
+    private static final double DEFAULT_VELOCITY = 5;
+    private static final double DEFAULT_GRID_SPACING = 50;
+
+    private final long frameDelay;
+
+    private final double velocity;
+
+    private final double gridSpacing;
+
+    private final BiPredicate neighbourPredicate;
+
+    private final DirectedGraphFactory directedGraphFactory;
+
+    public GruphiImpl(Long frameDelay,
+                      Double velocity,
+                      Double gridSpacing,
+                      BiPredicate neighbourPredicate,
+                      DirectedGraphFactory directedGraphFactory) {
+        this.frameDelay = frameDelay == null ? DEFAULT_FRAME_DELAY : frameDelay;
+        this.velocity = velocity == null ? DEFAULT_VELOCITY : velocity;
+        this.gridSpacing = gridSpacing == null ? DEFAULT_GRID_SPACING : gridSpacing;
+        this.neighbourPredicate = neighbourPredicate == null ? this::defaultAreNeighbours : neighbourPredicate;
+        this.directedGraphFactory = Objects.requireNonNull(directedGraphFactory, "A directedGraphFactory must be set");
+    }
+
+    private boolean defaultAreNeighbours(Node a, Node b) {
+        return a.pos.dist(b.pos) <= gridSpacing;
+    }
+
+    @Override
+    public long getFrameDelay() {
+        return frameDelay;
+    }
+
+    @Override
+    public double getVelocity() {
+        return velocity;
+    }
+
+    @Override
+    public double getGridSpacing() {
+        return gridSpacing;
+    }
+
+    @Override
+    public BiPredicate getNeighbourPredicate() {
+        return neighbourPredicate;
+    }
+
+    @Override
+    public DirectedGraphFactory getDirectedGraphFactory() {
+        return directedGraphFactory;
+    }
+}
diff --git a/src/main/java/de/oshgnacknak/gruphi/GruphiMain.java b/src/main/java/de/oshgnacknak/gruphi/GruphiMain.java
index 25beb44..9e8d8e7 100644
--- a/src/main/java/de/oshgnacknak/gruphi/GruphiMain.java
+++ b/src/main/java/de/oshgnacknak/gruphi/GruphiMain.java
@@ -1,42 +1,11 @@
 package de.oshgnacknak.gruphi;
 
-import h07.graph.DirectedGraphFactory;
-
-import java.util.function.BiPredicate;
-
 public class GruphiMain {
 
     public static void main(String[] args) {
-        var spacing = 50;
-
-        var gruphi = new Gruphi() {
-
-            @Override
-            public long getFrameDelay() {
-                return 1000 / 60;
-            }
-
-            @Override
-            public double getVelocity() {
-                return 5;
-            }
-
-            @Override
-            public double getGridSpacing() {
-                return spacing;
-            }
-
-            @Override
-            public BiPredicate getNeighbourPredicate() {
-                return (a, b) ->
-                    a.pos.dist(b.pos) <= spacing;
-            }
-
-            @Override
-            public DirectedGraphFactory getDirectedGraphFactory() {
-                return DirectedGraphFactory.defaultFactory();
-            }
-        };
+        var gruphi = new GruphiBuilder()
+            // .setDirectedGraphFactory(someFactory)
+            .createGruphi();
 
         var frame = new GruphiFrame(gruphi);
         frame.setVisible(true);