diff --git a/python/examples/.drawing_from_input_drawing.py.swp b/python/examples/.drawing_from_input_drawing.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..dab6cd932f3d42ae427684d8449babf19a525544
Binary files /dev/null and b/python/examples/.drawing_from_input_drawing.py.swp differ
diff --git a/python/examples/drawing_from_input_drawing.py b/python/examples/drawing_from_input_drawing.py
index a25e7131a5c190773851ae3c427bd3ca16872e65..caa9671d44d0494af92debfb4d85b32cd586d742 100644
--- a/python/examples/drawing_from_input_drawing.py
+++ b/python/examples/drawing_from_input_drawing.py
@@ -137,6 +137,12 @@ def getArgs():
             help="whether you want to do calibration", default=True)
     parser.add_argument('--n-calibration-tests', type=int, \
             help="number of calibration tests you want to run", default=10)
+    parser.add_argument('--clik-goal-error', type=float, \
+            help="the clik error you are happy with", default=1e-2)
+    parser.add_argument('--max-init-clik-iterations', type=int, \
+            help="number of max clik iterations to get to the first point", default=10000)
+    parser.add_argument('--max-running-clik-iterations', type=int, \
+            help="number of max clik iterations between path points", default=1000)
 
     args = parser.parse_args()
     if args.gripper and args.simulation:
@@ -226,7 +232,7 @@ if __name__ == "__main__":
     #                           software setup                            #
     #######################################################################
     args = getArgs()
-    clik_controller = getClikController(args)
+    clikController = getClikController(args)
     robot = RobotManager(args)
     #######################################################################
     #          drawing a path, making a joint trajectory for it           #
@@ -251,7 +257,13 @@ if __name__ == "__main__":
         raise NotImplementedError("you gotta give me that R somehow, 'cos there is no default atm")
     # create a joint space trajectory based on the path
     transf_body_to_board = pin.SE3(R, p)
-    joint_trajectory = clikCartesianPathIntoJointPath(path, robot, transf_body_to_board)
+    #TODO find and fix q_init here
+    # ideally you obtain it as a part of the calibration process.
+    # of course you will or won't use/provide a new one based
+    # on some argument.
+    #q_init = np.array([1.584, -1.859, -0.953, -1.309, 1.578, -0.006, 0.0, 0.0])
+    joint_trajectory = clikCartesianPathIntoJointPath(path, args, robot, \
+        clikController, q_init, transf_body_task_frame)
 
     # create DMP based on the trajectory
     dmp = DMP(joint_trajectory)
diff --git a/python/ur_simple_control/clik/.clik_point_to_point.py.swp b/python/ur_simple_control/clik/.clik_point_to_point.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..a49da600dc00a345bd81c6a1d2409732714750a6
Binary files /dev/null and b/python/ur_simple_control/clik/.clik_point_to_point.py.swp differ
diff --git a/python/ur_simple_control/clik/.clik_trajectory_following.py.swp b/python/ur_simple_control/clik/.clik_trajectory_following.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..3cc7c72825cf0cd7f429c698dc4ced2dd40f36f5
Binary files /dev/null and b/python/ur_simple_control/clik/.clik_trajectory_following.py.swp differ
diff --git a/python/ur_simple_control/clik/clik_trajectory_following.py b/python/ur_simple_control/clik/clik_trajectory_following.py
index f9469c1bb6524c33658bf814304f6977504aafbe..141b90d6ecb38c964b8f3e739911751062cb0bdd 100644
--- a/python/ur_simple_control/clik/clik_trajectory_following.py
+++ b/python/ur_simple_control/clik/clik_trajectory_following.py
@@ -41,14 +41,49 @@ def map2DPathTo3DPlane(path_2D, width, height):
     return path
 
 
-# we now need a transformation from the body frame to the board
-# such that the first quadrant of the x-y plane is 
-# in the bottom left corner of the board (obvious solution)
-def clikCartesianPathIntoJointPath(path, robot, transf_body_to_plane):
-    transf_body_to_plane = pin.SE3(R, p)
+"""
+clikCartesianPathIntoJointPath
+------------------------------
+functionality
+------------
+Follows a provided Cartesian path,
+creates a joint space trajectory for it.
+
+return
+------
+- joint_space_trajectory to follow the given path.
+
+arguments
+----------
+- path:
+  --> cartesian path given in task frame
+TODO: write asserts for these arguments
+- args:
+  --> all the magic numbers used here better be here
+- clikController:
+  --> clik controller you're using
+- robot:
+  --> RobotManager instance (needed for forward kinematics etc)
+TODO: maybe it's better design to expect path in body frame idk
+      the good thing here is you're forced to think about frames.
+TODO: make this a kwarg with a neural transform as default.
+- transf_body_task_frame: 
+  --> A transformation from the body frame to task frame.
+  --> It is assumed that the path was provided in the task frame
+      because 9/10 times that's more convenient,
+      and you can just pass a neural transform if you're not using it.
+- q_init:
+  --> starting point. 
+  --> you can movej to it before executing the trajectory,
+     so this makes perfect sense to ensure correctness
+"""
+def clikCartesianPathIntoJointPath(path, args, robot, \
+        clikController, q_init, transf_body_task_frame):
+    transf_body_to_task_frame = pin.SE3(R, p)
 
     for i in range(len(path)):
-        path[i] = transf_body_to_plane.act(path[i])
+        path[i] = transf_body_to_task_frame.act(path[i])
+    # TODO remove print, write a test for this instead
     print(path)
 
     # TODO: finish this
@@ -58,45 +93,51 @@ def clikCartesianPathIntoJointPath(path, robot, transf_body_to_plane):
     # skip inital pos tho
     #q = np.array([-2.256,-1.408,0.955,-1.721,-1.405,-0.31, 0.0, 0.0])
     #q = np.array([-2.014, -1.469, 1.248, -1.97, -1.366, -0.327, 0.0, 0.0])
-    q = np.array([1.584, -1.859, -0.953, -1.309, 1.578, -0.006, 0.0, 0.0])
-    INIT_ITER = 10000
-    n_iter = INIT_ITER
-    RUNNING_ITER = 1000
+    # this is just init_q right now
+    # TODO: make this a flag or something for readability's sake
+    n_iter = args.max_init_clik_iterations
+    # we don't know how many there will be, so a linked list is 
+    # clearly the best data structure here (instert is o(1) still,
+    # and we aren't pressed on time when turning it into an array later)
     qs = []
     for goal in path:
-        # there's no orientation error (you do need it lmao)
-        #Mgoal = pin.SE3(np.zeros((3,3)), goal)
         Mgoal = pin.SE3(R, goal)
         for i in range(n_iter):
-            pin.forwardKinematics(model, data, q)
-            SEerror = data.oMi[JOINT_ID].actInv(Mgoal)
+            # TODO maybe hide pin call with RobotManager call
+            pin.forwardKinematics(robot.model, robot.data, q)
+            SEerror = robot.data.oMi[robot.JOINT_ID].actInv(Mgoal)
             err_vector = pin.log6(SEerror).vector 
-            if np.linalg.norm(err_vector) < eps:
-                if not n_iter == INIT_ITER:
+            if np.linalg.norm(err_vector) < args.clik_goal_error:
+                if not n_iter == args.args.max_init_clik_iterations:
                     print("converged in", i)
                     break
-            J = pin.computeJointJacobian(model, data, q, JOINT_ID)
-            v = J.T @ np.linalg.inv(J @ J.T + np.eye(J.shape[0], J.shape[0]) * 10**-2) @ err_vector
-            #v = J.T @ err_vector
-            q = pin.integrate(model, q, v * dt)
-            if (not n_iter == INIT_ITER) and (i % 10 == 0):
+            J = pin.computeJointJacobian(robot.model, robot.data, q, robot.JOINT_ID)
+            qd = clikController(J, err_vector)
+            # we're integrating this fully offline of course
+            q = pin.integrate(robot.model, q, qd * dt)
+            if (not n_iter == args.args.max_init_clik_iterations) and (i % 10 == 0):
                 qs.append(q[:6])
 
         # just skipping the first run with one stone
-        if n_iter == INIT_ITER:
-            n_iter = RUNNING_ITER
+        if n_iter == args.args.max_init_clik_iterations:
+            n_iter = args.max_running_clik_iterations
         else:
-            if i == RUNNING_ITER-1:
+            if i == args.max_running_clik_iterations - 1:
                 print("DID NOT CONVERGE")
 
-    #######################################################################
-    #                       STEP 3: save joint path                       #
-    #######################################################################
+    ##############################################
+    #  save the obtained joint-space trajectory  #
+    ##############################################
     qs = np.array(qs)
-    # let's assume it takes 10 seconds
-    t = np.linspace(0, 10, len(qs)).reshape((len(qs),1))
-    timed_qs = np.hstack((t, qs))
-    np.savetxt("../new_traj.csv", timed_qs, delimiter=',', fmt='%.5f')
+    # we're putting a dmp over this so we already have the timing ready
+    # TODO: make this general, you don't want to depend on other random
+    # arguments (make this one traj_time, then put tau0 = traj_time there
+    t = np.linspace(0, args.tau0, len(qs)).reshape((len(qs),1))
+    joint_trajectory = np.hstack((t, qs))
+    # TODO handle saving more consistently/intentionally
+    # (although this definitely works right now and isn't bad, just mid)
+    np.savetxt("./new_traj.csv", joint_trajectory, delimiter=',', fmt='%.5f')
+    return joint_trajectory