Edit shapes nested in other symbols, from any symbol above them
`nest/inside` walked a row path only through instances. Every node has the same two maps to its parent, so the walk now steps into any node: inside an instance is the symbol it places, inside a shape is where its points and keys are. The selected shape at any depth is `inside` over its full path, which gives the stage editor its handles (through the matrix, drags back through the inverse) and the inspector the shape's own frame to key at, and the time map back for jumping to a key. `inside` resolves only the node's lineage: where a node is depends on its parents and nothing else, and resolving the whole symbol cost more than a stage frame (7.9ms against 3ms on the swarm; now 0.09ms). Checked equal to the whole-symbol resolve on every node and frame of the swarm, two instances deep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
6a53adb5e0
commit
1b8bbc7372
6 changed files with 130 additions and 49 deletions
|
|
@ -47,6 +47,42 @@
|
|||
(map - drawn (take 6 (array-seq (:pts op)))))
|
||||
"resolved back out through the instance, it is exactly what was drawn")))
|
||||
|
||||
(deftest a-shape-two-instances-down-is-edited-where-it-is-seen
|
||||
(let [u #uuid "00000000-0000-4000-8000-0000000000d1"
|
||||
v #uuid "00000000-0000-4000-8000-0000000000d2"
|
||||
turn (fn [c host id pos rot k]
|
||||
(update-in c [:symbols host :nodes id :channels] merge
|
||||
{[:xform :pos] (ch/framed pos)
|
||||
[:xform :rot] (ch/framed rot)
|
||||
[:xform :scale] (ch/framed [k k])}))
|
||||
c (-> (clip/blank)
|
||||
(assoc-in [:symbols :mid] {:id :mid :frames 40 :nodes {}})
|
||||
(assoc-in [:symbols :box] {:id :box :frames 30 :nodes {}})
|
||||
(clip/place-symbol nil :main :mid 10 u nil)
|
||||
(clip/place-symbol nil :mid :box 2 v nil)
|
||||
(turn :main u [40 20] (/ js/Math.PI 2) 2)
|
||||
(turn :mid v [5 -3] 0.3 1.5)
|
||||
(paint/new-shape :box :shape 4 [0 0 10 0 5 10] :brow))
|
||||
draw #(take 6 (array-seq (:pts (first (filter (fn [op] (= [u [v :shape]] (:node op)))
|
||||
((clip/resolver % nil pal/index-of :main) 16))))))
|
||||
{:keys [frame matrix time]} (nest/inside c nil :main [u v :shape] 16)
|
||||
out (js/Float64Array. 2)
|
||||
seen (mapcat (fn [[x y]] (vec (array-seq (node/apply-pt! out 0 matrix x y))))
|
||||
(partition 2 [0 0 10 0 5 10]))
|
||||
[x y] (array-seq (node/apply-pt! out 0 (nest/invert matrix) 7 3))
|
||||
moved (paint/set-vertex c :box :shape frame 0 [x y])
|
||||
keyed (paint/add-key c :box :shape (:frame (nest/inside c nil :main [u v :shape] 20)))]
|
||||
(is (= 4 frame) "16 of main is 6 of mid, which is 4 of box and of the shape in it")
|
||||
(is (= {:at 12 :rate 1} time))
|
||||
(is (= #{4 8} (set (keys (get-in keyed [:symbols :box :nodes :shape :channels paint/geometry :keys]))))
|
||||
"a key added at 20 of main lands at 8, the shape's own time")
|
||||
(is (nil? (nest/inside c nil :main [u v :shape] 13))
|
||||
"and where the shape is not on screen there is nothing to edit")
|
||||
(is (every? #(< (js/Math.abs %) 1e-9) (map - (draw c) seen))
|
||||
"the handles sit on what the stage draws")
|
||||
(is (every? #(< (js/Math.abs %) 1e-9) (map - [7 3] (take 2 (draw moved))))
|
||||
"and a vertex dragged to (7, 3) is drawn at (7, 3)")))
|
||||
|
||||
(deftest a-placed-symbols-sound-is-heard-where-it-is-placed
|
||||
(let [voice {:id :v :kind :audio :source {:footage "f"} :z "a1"
|
||||
:span [10 40] :time {:mode :map :at -10 :rate 1}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue