Unify root timing and persistent lane targets

This commit is contained in:
Your Name 2026-10-02 01:11:55 -04:00
parent f5a39aee39
commit 1b2b4ad3d2
11 changed files with 175 additions and 33 deletions

View file

@ -45,6 +45,36 @@
(is (= 3 (clip/first-output-frame doc :main 7)))
(is (= [0 60] (:span (first (timeline/rows doc :main #{})))))))
(deftest changing-fps-before-authoring-moves-the-empty-canvas-to-that-grid
(let [doc (clip/set-fps (clip/blank) 12)]
(is (= 12 (:fps doc)))
(is (nil? (get-in doc [:symbols :main :fps])))
(is (= 48 (clip/frames doc :main)))
(is (= 48 (clip/output-frames doc :main)))
(is (= 8 (clip/shown-frame doc :main 8)))
(is (= 8 (clip/first-output-frame doc :main 8)))))
(deftest changing-fps-after-authoring-preserves-the-symbols-native-grid
(let [started (assoc-in (clip/blank) [:symbols :main :nodes :mark]
{:id :mark :kind :rect :z "a"})
doc (clip/set-fps started 12)]
(is (= 30 (get-in doc [:symbols :main :fps])))
(is (= 120 (clip/frames doc :main)))
(is (= 48 (clip/output-frames doc :main)))))
(deftest project-fps-is-the-root-symbols-editing-grid
(let [doc (-> (clip/blank)
(assoc-in [:symbols :main :nodes :child]
{:id :child :kind :instance :z "a"
:source {:symbol :nested}})
(assoc-in [:symbols :nested]
{:id :nested :fps 30 :frames 90 :nodes {}})
(clip/set-root-fps 12))]
(is (= 12 (:fps doc)) "the output grid")
(is (= 12 (clip/fps doc :main)) "is also the root editing grid")
(is (= 30 (clip/fps doc :nested)) "while a nested symbol keeps its own grid")
(is (= 120 (clip/frames doc :main)) "frame positions are not rewritten")))
(deftest crossing-to-the-output-grid-and-back-lands-on-the-frame-it-names
;; `first-output-frame` is the inverse of `shown-frame` as far as a floor has
;; one: seeking to the output frame it names puts the playhead on a frame at or

View file

@ -3,6 +3,7 @@
[arthur.domain.clip :as clip]
[arthur.domain.history :as history]
[arthur.domain.leaf :as leaf]
[arthur.domain.node :as node]
[arthur.domain.sequence-test :as fixture]
[arthur.domain.span :as span]
[arthur.events.ui :as ui]
@ -16,20 +17,41 @@
(let [doc (clip/blank)
id (store/install! {:clip doc :store {}} key)]
(reset! rf-db/app-db {:clip/current id :paint/revision 0
:ui {:open :main} :playback {:frame 0}})
:ui {:open :main} :playback {:frame 6}})
(rf/dispatch-sync event)
(let [db @rf-db/app-db
saved (:clip (store/entry id))
[_ _ instance-id] (get-in db [:ui :selection])
sid (get-in saved [:symbols :main :nodes instance-id :source :symbol])]
{:db db :symbol (clip/symbol saved sid)})))]
{:db db :document saved :instance-id instance-id
:symbol (clip/symbol saved sid)})))]
(let [{ordinary :symbol} (run [::ui/new-symbol :inside] "explicit-symbol")
{lane :symbol lane-db :db} (run [::ui/new-lane] "explicit-lane")]
{lane :symbol lane-db :db document :document instance-id :instance-id}
(run [::ui/new-lane] "explicit-lane")]
(is (nil? (:display ordinary)) "new symbol means ordinary symbol")
(is (= :lane (:display lane)) "only the lane command creates a lane")
(is (= [0 (clip/frames document :main)]
(node/placed-span (get-in document [:symbols :main :nodes instance-id])))
"a lane exists across the open symbol, independent of the playhead")
(let [longer (assoc-in document [:symbols :main :frames] 300)
fitted (:clip (span/finish longer :main
(get-in longer [:symbols :main :nodes])
nil :keep))
lane-id (node/source (get-in fitted [:symbols :main :nodes instance-id]))]
(is (= [0 300]
(node/placed-span (get-in fitted [:symbols :main :nodes instance-id])))
"the lane follows a later change to its parent's extent")
(is (= 300 (clip/frames fitted lane-id))))
(is (some? (get-in lane-db [:ui :target]))
"the new lane is aimed so drawing and pool drops can go into it"))))
(deftest aiming-the-root-clears-selection-and-drawing-target
(let [db {:ui {:selection [:node :main :shape [:lane :shape]]
:target {:sid :main :id :lane :path [:lane]}}}
after (ui/aimed db nil)]
(is (nil? (get-in after [:ui :selection])))
(is (nil? (get-in after [:ui :target])))))
(deftest an-explicit-lane-is-one-row-of-clips
(let [doc (fixture/document)
rows (timeline/rows doc :main #{})