 
 (defn hinge-nodes [h]
     (map h [:node-a :node-b :node-c]))
+
+(defn now-in-milliseconds []
+    (. (goog.date.UtcDateTime.) (getTime)))
+
+(defn delta [f]
+    (let [prev (atom (f))] (fn []
+        (let [next (f) result (- next @prev)] (do
+            (reset! prev next)
+            result)))))
+
+(defn limiter [f]
+    (fn [] (Math/min (* 1000 worst-tick-step) (f))))
+
+(defn smooth [f]
+    (let [prev (atom 0.0)] (fn []
+        (let [next (f) result (+ (* 0.01 next) (* 0.99 @prev))] (do
+            (reset! prev result)
+            result)))))
+
+(def real-tick-step
+    (smooth (limiter (delta now-in-milliseconds))))
 
 (defn tick-imp [state tick-step input-state]
     (assoc state

    ])
    (map (partial apply make-hinge) [
        [:tail :head :h-l-k -0.7 0.7]
        [:head :h-l-k :h-l-f -1 0.0]
        [:tail :head :h-t-k -0.7 0.7]
        [:head :h-t-k :h-t-f -1 0.0]
        [:head :tail :t-l-k -0.7 0.7]
        [:tail :t-l-k :t-l-f -1 0.0]
        [:head :tail :t-t-k -0.7 0.7]
        [:tail :t-t-k :t-t-f -1 0.0]
        [:tail :head :top-of-head 0.0 0.0]
        [:head :tail :tail-a 0.0 0.0]
        [:tail :tail-a :head-a 0.0 0.0]
        [:tail-a :head-a :head 0.0 0.0]
        [:head-a :head :tail 0.0 0.0]
    ])
))



(defn calculate-ground-forces [nodes]
    (zipmap (keys nodes)
        (map (fn [{[ _ y ] :pos}]
            (if (< y 0)
                (vec* [0 (- y)] ground-rebound-strength)
                [0 0]))
            (vals nodes))))

(defn calculate-ground-impulses [nodes time-step]
    (let [loss (- 1.0 (Math/exp (- (* time-step ground-drag-factor))))]
        (zipmap (keys nodes)
            (map (fn [{[ _ y ] :pos [ xv yv ] :vel mass :mass}]
                (if (< y 0)
                    (vec* [(- xv) (Math/max 0 (- yv))] (* loss mass))
                    [0 0]))
                (vals nodes)))))

(defn calculate-air-impulses [nodes time-step]
    (let [loss (- 1.0 (Math/exp (- (* time-step air-drag-factor))))]
        (zipmap (keys nodes)
            (map (fn [{[_ y] :pos vel :vel mass :mass}]
                (if (< y 0)
                    [0 0]
                    (vec* vel (* -1 loss mass))))
                (vals nodes)))))

(defn calculate-all-node-forces [{:keys [nodes springs hinges]}]
    (merge-with vec+
        (calculate-spring-forces nodes springs)
        (calculate-hinge-forces nodes hinges)
        (calculate-gravity-forces nodes)
        (calculate-ground-forces nodes)))

(defn calculate-all-node-impulses [nodes time-step]
    (merge-with vec+
        (calculate-ground-impulses nodes time-step)
        (calculate-air-impulses nodes time-step)))

(defn update-node-velocities [nodes forces impulses time-step]
    (merge-with
        (fn [n i] (assoc n
            :vel (vec+
                (:vel n)
                (vec* i (/ 1.0 (:mass n))))))
        (merge-with
            (fn [n f] (assoc n
                :vel (vec+
                    (:vel n)
                    (vec* f (/ time-step (:mass n))))))
            nodes
            forces)
        impulses))

(defn update-node-positions [nodes time-step]
    (zipmap (keys nodes) (map (fn [n]
