Slide rows along time and restack them, at any depth
A node's bar drags along the timeline: one write to its :at, for every node alike, carried down through the instances above it. The stage and rows show the slide live through ::render/clip, and it lands as one edit on release. A row dropped on another's top or bottom edge goes in front of it or behind: one write to :z, between its new neighbours (symbol/z-between). Onto the edge of a row in another symbol, it moves there first. Neither needs anything on screen — nest/down walks a row path by structure, without a frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1b8bbc7372
commit
38850a29ba
8 changed files with 306 additions and 32 deletions
|
|
@ -192,3 +192,49 @@
|
|||
(select-keys (get-in moved [:symbols :box :nodes :tri :time]) [:at :rate]))
|
||||
"half speed inside something at double speed, so it runs as it did")
|
||||
(is (= (picture c :main fs) (picture moved :main fs)))))
|
||||
|
||||
(deftest sliding-a-shape-inside-a-retimed-instance-moves-it-by-frames-of-the-open-symbol
|
||||
;; `box` runs at double speed from 10, so six frames of main are twelve of box.
|
||||
(let [c (-> (studio)
|
||||
(update-in [:symbols :main :nodes] dissoc :tri)
|
||||
(assoc-in [:symbols :main :nodes a-uuid :time :rate] 2)
|
||||
(assoc-in [:symbols :box :nodes :inner :channels [:geom :pts]]
|
||||
(ch/keyed {4 [5 10 15 10 5 40] 20 [5 10 45 10 5 40]})))
|
||||
{slid :clip :as r} (nest/slide c :main [a-uuid :inner] 6)
|
||||
fs [13 15 18 20]]
|
||||
(is (nil? (:refused r)) (:refused r))
|
||||
(is (= {:mode :map :at 12 :rate 1} (get-in slid [:symbols :box :nodes :inner :time])))
|
||||
(is (= [4 60] (get-in slid [:symbols :box :nodes :inner :span])) "its span and keys are its own")
|
||||
(is (= (picture c :main fs) (picture slid :main (map #(+ 6 %) fs)))
|
||||
"what it did at a frame of main it now does six frames later")
|
||||
(is (seq (first (picture c :main [14]))))
|
||||
(is (empty? (first (picture slid :main [14]))) "and it is not there yet where it was")
|
||||
(testing "sliding it again adds to where it is"
|
||||
(is (= 2 (get-in (:clip (nest/slide slid :main [a-uuid :inner] -5))
|
||||
[:symbols :box :nodes :inner :time :at]))))))
|
||||
|
||||
(deftest sliding-needs-nothing-on-screen-and-refuses-only-a-loop
|
||||
(let [c (studio)]
|
||||
(is (= 3 (get-in (:clip (nest/slide c :main [a-uuid :inner] 3))
|
||||
[:symbols :box :nodes :inner :time :at]))
|
||||
"the instance starts at 10, and where the playhead is has nothing to do with it")
|
||||
(is (:refused (nest/slide (assoc-in c [:symbols :main :nodes a-uuid :time :loop?] true)
|
||||
:main [a-uuid :inner] 3))
|
||||
"but through a loop one frame outside is many inside")))
|
||||
|
||||
(deftest restacking-is-one-write-to-z
|
||||
(let [shape (fn [z] {:kind :poly :z z :channels {}})
|
||||
c (-> (clip/blank)
|
||||
(assoc-in [:symbols :main :nodes] {:a (shape "a1") :b (shape "a2") :c (shape "a3")}))
|
||||
order (fn [c] (map key (sort-by (comp :z val) (get-in c [:symbols :main :nodes]))))
|
||||
front (:clip (nest/restack c :main [:a] [:c] true))
|
||||
back (:clip (nest/restack c :main [:c] [:a] false))
|
||||
mid (:clip (nest/restack c :main [:a] [:b] true))]
|
||||
(is (= [:b :c :a] (order front)) "in front of the front one")
|
||||
(is (= [:c :a :b] (order back)) "behind the back one")
|
||||
(is (= [:b :a :c] (order mid)) "between two")
|
||||
(is (= (dissoc (get-in c [:symbols :main :nodes]) :a)
|
||||
(dissoc (get-in mid [:symbols :main :nodes]) :a))
|
||||
"and nothing else is renumbered")
|
||||
(is (:refused (nest/restack c :main [:a] [a-uuid :inner] true))
|
||||
"only among the things it is beside")))
|
||||
|
|
|
|||
|
|
@ -107,6 +107,21 @@
|
|||
(is (= [:a :b :c] (ids-at with 0)))
|
||||
(is (= (get-in base [:nodes :a]) (get-in with [:nodes :a])) "and :a is untouched")))
|
||||
|
||||
(deftest z-between-always-finds-room
|
||||
(let [between? (fn [a b z] (and (or (nil? a) (neg? (compare a z)))
|
||||
(or (nil? b) (neg? (compare z b)))))]
|
||||
(testing "on the keys scenes already have"
|
||||
(doseq [[a b] [[nil "a1"] ["a1" nil] ["a1" "a2"] ["a1" "a3"] ["a" "a1"]
|
||||
["a1" "z1727000000000-shape"] [nil "0"] [nil "-"] ["c0000" "c0001"]]]
|
||||
(is (between? a b (symbol/z-between a b)) (pr-str [a b (symbol/z-between a b)]))))
|
||||
(testing "and again and again: to the back, to the front, and into one gap from either side"
|
||||
(doseq [[label start step past?] [["back" "a1" #(symbol/z-between nil %) #(between? nil %1 %2)]
|
||||
["front" "a1" #(symbol/z-between % nil) #(between? %1 nil %2)]
|
||||
["under a2" "a1" #(symbol/z-between % "a2") #(between? %1 "a2" %2)]
|
||||
["over a1" "a2" #(symbol/z-between "a1" %) #(between? "a1" %1 %2)]]]
|
||||
(is (every? (fn [[x y]] (past? x y)) (partition 2 1 (take 300 (iterate step start))))
|
||||
label)))))
|
||||
|
||||
;; ---- transform composition through the tree ----
|
||||
|
||||
(deftest geometry-lands-in-the-parents-space
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue