From 624242b407e945047b88ae2787b74205a1837872 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 30 Sep 2026 12:21:12 -0400 Subject: [PATCH] An options map for the resolvers, and sid beside the clip it is in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finishing the last commit, which traded a simpler definition for noisier call sites: deleting the arity ladders left `(symbol/resolver sym st pal/index-of nil nil)` at twenty-odd places, and two trailing nils tell a reader nothing except to go and count positions. The ladder was a symptom. The disease is five positional parameters, and the split that matters is which of them are OPTIONAL: store, palette positional, because neither is optional. A dense channel cannot be read without the store it names — that is the crash two commits ago — and every op carries a colour. pose-tracks one call site, in `clip/resolver`'s own recursion source/picture-fps two call sites So the last three become one `opts` map, and the common call loses a nil. The point is not the nil: it is that the sixth option, whenever it arrives, is a key at one call site rather than a nil at fifty. `clip/resolver` also had `sid` FOURTH, behind two arguments that say nothing about which symbol is being resolved. It is second now, beside the clip it is in: `(clip/resolver c :main store pal/index-of nil)`. 62 call sites rewritten by parsing the forms rather than by regex, because `clip/resolver`'s arguments move past each other and a regex cannot see that. An earlier attempt at this dropped `palette` on the floor and still compiled at 62 sites — it only surfaced as an arity error, so if that had been a same-arity mistake the tests would have been the last line of defence. Co-Authored-By: Claude Opus 5 --- frontend/src/arthur/demo.cljs | 2 +- frontend/src/arthur/domain/clip.cljs | 9 ++-- frontend/src/arthur/domain/nest.cljs | 2 +- frontend/src/arthur/domain/pick.cljs | 2 +- frontend/src/arthur/domain/symbol.cljs | 20 +++++--- frontend/src/arthur/export.cljs | 3 +- frontend/src/arthur/subs/render.cljs | 2 +- frontend/src/arthur/ui/drag.cljs | 2 +- frontend/test/arthur/bench_test.cljs | 2 +- frontend/test/arthur/domain/gesture_test.cljs | 2 +- .../test/arthur/domain/instance_test.cljs | 18 +++---- frontend/test/arthur/domain/nest_test.cljs | 8 +-- frontend/test/arthur/domain/paint_test.cljs | 2 +- frontend/test/arthur/domain/project_test.cljs | 2 +- frontend/test/arthur/domain/symbol_test.cljs | 50 +++++++++---------- frontend/test/arthur/domain/trace_test.cljs | 4 +- .../test/arthur/flow/eye_occlusion_test.cljs | 2 +- frontend/test/arthur/flow/freeze_test.cljs | 23 ++++----- .../test/arthur/flow/multi_face_test.cljs | 6 +-- frontend/test/arthur/support/ops.cljs | 4 +- 20 files changed, 84 insertions(+), 81 deletions(-) diff --git a/frontend/src/arthur/demo.cljs b/frontend/src/arthur/demo.cljs index 8bc3146..0e0b096 100644 --- a/frontend/src/arthur/demo.cljs +++ b/frontend/src/arthur/demo.cljs @@ -26,4 +26,4 @@ "Draw ops for one frame, via the specification path. The page uses `symbol/resolver` instead; this is here for the REPL." [f] - (symbol/eval-frame main f nil pal/index-of nil nil)) + (symbol/eval-frame main f nil pal/index-of nil)) diff --git a/frontend/src/arthur/domain/clip.cljs b/frontend/src/arthur/domain/clip.cljs index 56a9b5b..d7db89f 100644 --- a/frontend/src/arthur/domain/clip.cljs +++ b/frontend/src/arthur/domain/clip.cljs @@ -174,7 +174,7 @@ own frame. Nil for a node that was not on that frame. It is how something drawn beside the picture, like a tracing photo, rides a node inside it without resolving anything a second time." - [clip store palette sid {:keys [picture-fps] :as opts}] + [clip sid store palette {:keys [picture-fps] :as opts}] (letfn [(build [sid chain pose-tracks] (when (some #{sid} chain) (throw (ex-info "symbol cycle" {:chain (conj chain sid)}))) @@ -183,8 +183,9 @@ nodes (:nodes sym) rank (symbol/draw-rank nodes (symbol/order nodes)) ids (sort-by rank (keys nodes)) - own (symbol/resolver sym store palette pose-tracks - (assoc opts :source-fps (:fps clip))) + own (symbol/resolver sym store palette + (assoc opts :pose-tracks pose-tracks + :source-fps (:fps clip))) children (into {} (for [[id n] nodes :when (= :instance (:kind n))] [id (build (:of n) (conj chain sid) @@ -243,7 +244,7 @@ Effects' anchor point are set once and left. A symbol that grows later keeps its instances' pivots where they were, so nothing on screen moves." [clip store sid] - (let [resolve (resolver clip store pal/index-of sid nil) + (let [resolve (resolver clip sid store pal/index-of nil) bounds (fn [[x0 y0 x1 y1 :as b] x y] (if b [(min x0 x) (min y0 y) (max x1 x) (max y1 y)] [x y x y])) [x0 y0 x1 y1] diff --git a/frontend/src/arthur/domain/nest.cljs b/frontend/src/arthur/domain/nest.cljs index 9b0aef9..a706e1f 100644 --- a/frontend/src/arthur/domain/nest.cljs +++ b/frontend/src/arthur/domain/nest.cljs @@ -33,7 +33,7 @@ [clip store sid frame id] (let [sym (clip/symbol clip sid) sym (update sym :nodes select-keys (symbol/lineage (:nodes sym) id)) - r (symbol/resolver sym store pal/index-of nil {:source-fps (:fps clip)})] + r (symbol/resolver sym store pal/index-of {:source-fps (:fps clip)})] (r frame) r)) diff --git a/frontend/src/arthur/domain/pick.cljs b/frontend/src/arthur/domain/pick.cljs index 7957544..91c63a3 100644 --- a/frontend/src/arthur/domain/pick.cljs +++ b/frontend/src/arthur/domain/pick.cljs @@ -101,7 +101,7 @@ (let [sid (:of n) frames (clip/frames document sid) loop? (get-in n [:time :loop?]) - resolve (clip/resolver document store pal/index-of sid nil)] + resolve (clip/resolver document sid store pal/index-of nil)] (fn [f] (let [f (if loop? (mod f frames) f)] (when (< -1 f frames) diff --git a/frontend/src/arthur/domain/symbol.cljs b/frontend/src/arthur/domain/symbol.cljs index cb65360..e852290 100644 --- a/frontend/src/arthur/domain/symbol.cljs +++ b/frontend/src/arthur/domain/symbol.cljs @@ -26,11 +26,13 @@ Two ways to evaluate one at a frame: - (eval-frame sym f store) THE SPECIFICATION. Allocating, order-free, + (eval-frame sym f store palette opts) + THE SPECIFICATION. Allocating, order-free, obviously correct. Use it in tests and for a one-off render. - (resolver sym store) -> (fn [f] ops). What playback uses. Caches the + (resolver sym store palette opts) + -> (fn [f] ops). What playback uses. Caches the topological order and the z paths, holds one CURSOR per channel and one PREALLOCATED point buffer per node, so a frame allocates the op @@ -422,11 +424,10 @@ the only place the space changes. This is the definition of what a frame means. `resolver` is what plays it." - [sym f store palette pose-tracks opts] + [sym f store palette {:keys [pose-tracks source-fps picture-fps]}] (let [nodes (nodes-of sym) choices (pose/prepare pose-tracks) traces (prepared-traces nodes) - {:keys [source-fps picture-fps]} opts ord (order nodes)] (eval-into {:read (fn [id path c lf] (ch/value-at c (channel-frame choices traces nodes @@ -481,8 +482,15 @@ The op maps themselves are allocated fresh, and deliberately: there are a dozen of them per frame against hundreds of points, so pooling them would buy - nothing and cost the ability to hand an op list around as plain data." - [sym store palette pose-tracks {:keys [source-fps picture-fps]}] + nothing and cost the ability to hand an op list around as plain data. + + `store` and `palette` are POSITIONAL because neither is optional: a dense + channel cannot be read without the store it names, and every op carries a + colour index. `opts` is a map because the rest genuinely are optional, and + because a fifth of them later is then a key rather than a nil at every one of + these call sites — which is what the arity ladder that used to be here was + standing in for." + [sym store palette {:keys [pose-tracks source-fps picture-fps]}] (let [nodes (nodes-of sym) choices (pose/prepare pose-tracks) traces (prepared-traces nodes) diff --git a/frontend/src/arthur/export.cljs b/frontend/src/arthur/export.cljs index 2aee8d2..4a94cd7 100644 --- a/frontend/src/arthur/export.cljs +++ b/frontend/src/arthur/export.cljs @@ -195,8 +195,7 @@ ;; inside it still resolve — clip/resolver is the function that knows ;; how. doc (assoc-in clip [:symbols sid] sym) - resolve-frame (clip/resolver doc store palette sid - {:picture-fps picture-fps}) + resolve-frame (clip/resolver doc sid store palette {:picture-fps picture-fps}) ras (raster/make width height) bg (get palette :bg 0)] (-> (audio! doc sid store audio-url) diff --git a/frontend/src/arthur/subs/render.cljs b/frontend/src/arthur/subs/render.cljs index 221d0dc..6716f47 100644 --- a/frontend/src/arthur/subs/render.cljs +++ b/frontend/src/arthur/subs/render.cljs @@ -126,7 +126,7 @@ :<- [::playback/display-fps] (fn [[document sid store palette picture-fps] _] (when (and document (clip/symbol document sid)) - (clip/resolver document store palette sid {:picture-fps picture-fps})))) + (clip/resolver document sid store palette {:picture-fps picture-fps})))) (rf/reg-sub ::shown diff --git a/frontend/src/arthur/ui/drag.cljs b/frontend/src/arthur/ui/drag.cljs index 9bbfde0..e3b2188 100644 --- a/frontend/src/arthur/ui/drag.cljs +++ b/frontend/src/arthur/ui/drag.cljs @@ -29,7 +29,7 @@ :disc (select-keys op [:kind :cx :cy :r]) :rect (select-keys op [:kind :cx :cy :size]) nil)) - ((clip/resolver document st pal/index-of sid nil) 0)))) + ((clip/resolver document sid st pal/index-of nil) 0)))) (defn symbol! "Start carrying symbol `sid` of the loaded document into the open symbol." diff --git a/frontend/test/arthur/bench_test.cljs b/frontend/test/arthur/bench_test.cljs index adc331d..84ca2a3 100644 --- a/frontend/test/arthur/bench_test.cljs +++ b/frontend/test/arthur/bench_test.cljs @@ -24,7 +24,7 @@ (/ dt n)))) (deftest bench - (let [res (symbol/resolver (clip/symbol @swarm/clip :main) @swarm/store pal/index-of nil nil) + (let [res (symbol/resolver (clip/symbol @swarm/clip :main) @swarm/store pal/index-of nil) ras (raster/make 320 200) dest (js/Uint8ClampedArray. (* 320 200 4)) n 120] diff --git a/frontend/test/arthur/domain/gesture_test.cljs b/frontend/test/arthur/domain/gesture_test.cljs index 064c888..eb3fae6 100644 --- a/frontend/test/arthur/domain/gesture_test.cljs +++ b/frontend/test/arthur/domain/gesture_test.cljs @@ -34,7 +34,7 @@ (defn- drawn [c path] (partition 2 (take 6 (array-seq (:pts (first (filter #(= path (:node %)) - ((clip/resolver c nil pal/index-of :main nil) 16)))))))) + ((clip/resolver c :main nil pal/index-of nil) 16)))))))) (defn- near? [a b] (every? #(< (js/Math.abs %) 1e-9) (map - (flatten a) (flatten b)))) diff --git a/frontend/test/arthur/domain/instance_test.cljs b/frontend/test/arthur/domain/instance_test.cljs index 1080dca..3d12ebc 100644 --- a/frontend/test/arthur/domain/instance_test.cljs +++ b/frontend/test/arthur/domain/instance_test.cljs @@ -36,7 +36,7 @@ :channels {[:xform :pos] (ch/framed [120 50])}}}}) (assoc-in [:symbols :sym/test] (assoc (get-in source [:symbols :main]) :id :sym/test))) - resolve (clip/resolver document nil pal/index-of :main nil) + resolve (clip/resolver document :main nil pal/index-of nil) at (fn [f] (mapv (juxt :node :cx) (resolve f)))] (is (empty? (clip/problems document))) (is (= [[[:left :mark] 110]] (at 1))) @@ -75,9 +75,9 @@ :parent :root :z "a2" :playback {:tracks {:mouth {0 0, 8 8}}}}}} :sym/poses symbol}} - resolve (clip/resolver document {"sizes" {:data values}} pal/index-of :main nil) - low-resolve (clip/resolver document {"sizes" {:data values}} - pal/index-of :main {:picture-fps 8}) + store {"sizes" {:data values}} + resolve (clip/resolver document :main store pal/index-of nil) + low-resolve (clip/resolver document :main store pal/index-of {:picture-fps 8}) at (fn [f] (into {} (map (fn [op] [(:node op) op])) (resolve f))) low-at (fn [f] (into {} (map (fn [op] [(:node op) op])) (low-resolve f)))] (is (empty? (clip/problems document))) @@ -98,14 +98,12 @@ "an explicit cut occurs at its exact local frame, even off the picture grid") (is (= 8 (:cx (get (low-at 8) [:first :eye]))) "authored position ignores the picture grid") - (let [sym (get-in document [:symbols :sym/poses]) - opts {:source-fps 30 :picture-fps 8}] + (let [sym (get-in document [:symbols :sym/poses]) + opts {:source-fps 30 :picture-fps 8 :pose-tracks {:mouth {0 0, 8 20}}}] (is (= (mapv #(select-keys % [:node :cx :size]) - (symbol/eval-frame sym 8 {"sizes" {:data values}} - pal/index-of {:mouth {0 0, 8 20}} opts)) + (symbol/eval-frame sym 8 store pal/index-of opts)) (mapv #(select-keys % [:node :cx :size]) - ((symbol/resolver sym {"sizes" {:data values}} - pal/index-of {:mouth {0 0, 8 20}} opts) 8))) + ((symbol/resolver sym store pal/index-of opts) 8))) "pure evaluation and playback apply the same pose choice")))) (deftest stage-pose-edits-preserve-earlier-motion-and-survive-save diff --git a/frontend/test/arthur/domain/nest_test.cljs b/frontend/test/arthur/domain/nest_test.cljs index d59b97a..1912252 100644 --- a/frontend/test/arthur/domain/nest_test.cljs +++ b/frontend/test/arthur/domain/nest_test.cljs @@ -40,7 +40,7 @@ {:keys [sid frame pts]} (nest/drawn-inside c nil :main [u] 16 drawn) c (paint/new-shape c sid :shape frame pts :brow) [op] (filter #(= [u :shape] (:node %)) - ((clip/resolver c nil pal/index-of :main nil) 16))] + ((clip/resolver c :main nil pal/index-of nil) 16))] (is (= :box sid)) (is (= 6 frame) "frame 16 of main is frame 6 of an instance placed at 10") (is (every? #(< (js/Math.abs %) 1e-9) @@ -64,7 +64,7 @@ (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 nil) 16)))))) + ((clip/resolver % :main nil pal/index-of nil) 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)))) @@ -105,7 +105,7 @@ "What `sid` draws at each of `fs`, without the node paths a move changes: per frame, the sorted marks with their points rounded to a thousandth." [c sid fs] - (let [resolve (clip/resolver c nil pal/index-of sid nil) + (let [resolve (clip/resolver c sid nil pal/index-of nil) round #(/ (js/Math.round (* 1000 %)) 1000)] (mapv (fn [f] (sort-by str (map (fn [op] @@ -251,7 +251,7 @@ (is (= [0 8] (:span heard)) "own frames 0-8: it starts on inner's 2 and inner ends on 10") (is (= [7 15] (node/placed-span heard)) "inner starts on 5 of outer") - (is (empty? ((clip/resolver c nil pal/index-of :inner nil) 3)) + (is (empty? ((clip/resolver c :inner nil pal/index-of nil) 3)) "and it draws nothing") (is (= c (clip/place-sound c :inner {:sound "tone"} "tone.mp3" 40 1 10 (random-uuid))) "nor lands past the end of its symbol") diff --git a/frontend/test/arthur/domain/paint_test.cljs b/frontend/test/arthur/domain/paint_test.cljs index a8c01e4..f5d1e5f 100644 --- a/frontend/test/arthur/domain/paint_test.cljs +++ b/frontend/test/arthur/domain/paint_test.cljs @@ -31,5 +31,5 @@ (is (empty? (channel/problems mixed))) ;; The demo's root is exposed on 2s. Paint at frame 3 must still appear at 3. (is (some #(= :paint-test (:node %)) - (symbol/eval-frame (get-in c2 [:symbols :main]) 3 nil pal/index-of nil nil))) + (symbol/eval-frame (get-in c2 [:symbols :main]) 3 nil pal/index-of nil))) (is (= mixed-clip (leaf/clip :c1 (leaf/leaves :c1 mixed-clip)))))) diff --git a/frontend/test/arthur/domain/project_test.cljs b/frontend/test/arthur/domain/project_test.cljs index 3b16ef2..a4fec3f 100644 --- a/frontend/test/arthur/domain/project_test.cljs +++ b/frontend/test/arthur/domain/project_test.cljs @@ -148,7 +148,7 @@ ;; frame rather than hidden, and its partner is not. (let [back (wired :c1 @gappy) drawn (into #{} (map :node) - ((symbol/resolver (face-symbol (:clip back)) (:store back) pal/index-of nil nil) 12))] + ((symbol/resolver (face-symbol (:clip back)) (:store back) pal/index-of nil) 12))] (is (not (contains? drawn :eye-r))) (is (contains? drawn :eye-l)) (is (contains? drawn :mouth)))) diff --git a/frontend/test/arthur/domain/symbol_test.cljs b/frontend/test/arthur/domain/symbol_test.cljs index 126b5ec..80fb8d6 100644 --- a/frontend/test/arthur/domain/symbol_test.cljs +++ b/frontend/test/arthur/domain/symbol_test.cljs @@ -27,7 +27,7 @@ {:nodes (into {} (map (juxt :id identity)) nodes)}) (defn- ids-at [scene f] - (mapv :node (symbol/eval-frame scene f nil pal/index-of nil nil))) + (mapv :node (symbol/eval-frame scene f nil pal/index-of nil))) (def ^:private pts-of ops/points) @@ -70,9 +70,9 @@ (is (identical? (get-in s [:nodes :b]) (get-in s' [:nodes :b])) "and so is the new one") (is (= [[0 0] [10 0] [10 10]] - (pts-of (first (filter #(= :c (:node %)) (symbol/eval-frame s 0 nil pal/index-of nil nil)))))) + (pts-of (first (filter #(= :c (:node %)) (symbol/eval-frame s 0 nil pal/index-of nil)))))) (is (= [[100 0] [110 0] [110 10]] - (pts-of (first (filter #(= :c (:node %)) (symbol/eval-frame s' 0 nil pal/index-of nil nil)))))))) + (pts-of (first (filter #(= :c (:node %)) (symbol/eval-frame s' 0 nil pal/index-of nil)))))))) ;; ---- draw order ---- @@ -129,7 +129,7 @@ :channels {[:xform :pos] (ch/framed [100 50]) [:xform :scale] (ch/framed [2 2])}} (poly :p :g "a1" [0 0 10 0 10 10 0 10] :skin-base)) - op (first (symbol/eval-frame s 0 nil pal/index-of nil nil))] + op (first (symbol/eval-frame s 0 nil pal/index-of nil))] (is (= [[100 50] [120 50] [120 70] [100 70]] (pts-of op))))) (deftest a-keyed-group-position-moves-its-children-and-holds-between-keys @@ -139,7 +139,7 @@ :channels {[:xform :pos] (ch/keyed {0 [0 0], 4 [10 0], 8 [10 10], 12 [0 10]} :hold)}} (poly :p :g "a1" [0 0 2 0 2 2] :skin-base)) - at #(first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil nil))))] + at #(first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil))))] (is (= [0 0] (at 0))) (is (= [0 0] (at 3)) "held") (is (= [10 0] (at 4))) @@ -156,7 +156,7 @@ {:id :g :kind :group :parent :root :z "a1" :channels {[:xform :pos] (ch/keyed (into {} (map (juxt identity #(vector % 0))) (range 12)) :hold)}} (poly :p :g "a1" [0 0 1 0 1 1] :skin-base)) - x-at #(first (first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil nil)))))] + x-at #(first (first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil)))))] (is (= [0 0 0 3 3 3 6 6 6 9 9 9] (mapv x-at (range 12))))) (testing "and a node may set its own grid, which the model permits deliberately" @@ -164,7 +164,7 @@ {:id :g :kind :group :parent :root :z "a1" :time {:mode :map :expose 4} :channels {[:xform :pos] (ch/keyed (into {} (map (juxt identity #(vector % 0))) (range 12)) :hold)}} (poly :p :g "a1" [0 0 1 0 1 1] :skin-base)) - x-at #(first (first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil nil)))))] + x-at #(first (first (pts-of (first (symbol/eval-frame s % nil pal/index-of nil)))))] (is (= [0 0 0 0 4 4 4 4 8 8 8 8] (mapv x-at (range 12))))))) (deftest offset-is-per-node-which-is-the-entire-point-of-mouth-lead @@ -178,7 +178,7 @@ {:id :mouth :kind :group :parent :root :z "a2" :time {:mode :map :offset 2} :channels {[:xform :pos] (ch/keyed keys :hold)}} (poly :mouth-p :mouth "a1" [0 0 1 0 1 1] :mouth-dark)) - x-of (fn [f id] (->> (symbol/eval-frame s f nil pal/index-of nil nil) + x-of (fn [f id] (->> (symbol/eval-frame s f nil pal/index-of nil) (filter #(= id (:node %))) first pts-of first first))] (is (= [0 1 2 3] (mapv #(x-of % :plate-p) (range 4)))) (is (= [2 3 4 5] (mapv #(x-of % :mouth-p) (range 4))) "the mouth reads ahead"))) @@ -221,11 +221,11 @@ :dense {:store "pts" :offset 0 :stride 6 :frames 2}} [:style :color] (ch/framed :mouth-dark)}} (poly :teeth :m "a2" [0 0 1 0 1 1] :teeth))] - (is (= [:child] (mapv :node (symbol/eval-frame absent-pos 0 store pal/index-of nil nil)))) - (is (= [] (mapv :node (symbol/eval-frame absent-pos 1 store pal/index-of nil nil))) + (is (= [:child] (mapv :node (symbol/eval-frame absent-pos 0 store pal/index-of nil)))) + (is (= [] (mapv :node (symbol/eval-frame absent-pos 1 store pal/index-of nil))) "an absent transform gives the children nowhere to be") - (is (= [:m :teeth] (mapv :node (symbol/eval-frame absent-pts 0 store pal/index-of nil nil)))) - (is (= [:teeth] (mapv :node (symbol/eval-frame absent-pts 1 store pal/index-of nil nil))) + (is (= [:m :teeth] (mapv :node (symbol/eval-frame absent-pts 0 store pal/index-of nil)))) + (is (= [:teeth] (mapv :node (symbol/eval-frame absent-pts 1 store pal/index-of nil))) "an absent outline removes only itself"))) ;; ---- stencils ---- @@ -239,7 +239,7 @@ {:id :iris :kind :disc :parent :root :stencil :sclera :z "a2" :channels {[:geom :radius] (ch/framed 4) [:style :color] (ch/framed :iris)}}) - ops (symbol/eval-frame s 0 nil pal/index-of nil nil)] + ops (symbol/eval-frame s 0 nil pal/index-of nil)] (is (= [:sclera :iris] (mapv :node ops))) (is (= (:eye-white pal/index-of) (:stencil (second ops)))))) @@ -266,7 +266,7 @@ :channels {[:geom :radius] (ch/framed 3) [:style :color] (ch/framed :iris)}} {:id :r :kind :rect :parent :g :z "a2" :channels {[:geom :size] (ch/framed 1.7) [:style :color] (ch/framed :pupil)}}) - [d r] (symbol/eval-frame s 0 nil pal/index-of nil nil)] + [d r] (symbol/eval-frame s 0 nil pal/index-of nil)] (is (= [50 60 6] [(:cx d) (:cy d) (:r d)])) (is (= 3.4 (:size r))))) @@ -291,7 +291,7 @@ (deftest the-resolver-reuses-one-buffer-per-node ;; At 30fps per-frame allocation is the only thing that will make this stutter, ;; and fixed topology is what makes the buffer size knowable at all. - (let [res (symbol/resolver demo/main nil pal/index-of nil nil) + (let [res (symbol/resolver demo/main nil pal/index-of nil) buf-of (fn [f id] (->> (res f) (filter #(= id (:node %))) first :pts))] (is (identical? (buf-of 0 :card) (buf-of 30 :card))))) @@ -308,15 +308,15 @@ ;; The mistake this split makes easy: both are maps with an :id, and the wrong ;; one resolves to no ops rather than to an error. (is (thrown-with-msg? ExceptionInfo #"not a symbol" - (symbol/resolver demo/clip nil pal/index-of nil nil))) + (symbol/resolver demo/clip nil pal/index-of nil))) (is (thrown-with-msg? ExceptionInfo #"not a symbol" - (symbol/eval-frame demo/clip 0 nil pal/index-of nil nil))))) + (symbol/eval-frame demo/clip 0 nil pal/index-of nil))))) (deftest the-hand-written-clip-renders-and-moves ;; port-plan step 2's done condition, as an assertion rather than a look: the ;; scene rasterises, it writes only palette indices, and the pixels are not the ;; same on every frame. - (let [res (symbol/resolver demo/main nil pal/index-of nil nil) + (let [res (symbol/resolver demo/main nil pal/index-of nil) render (fn [f] (let [r (raster/make (:width demo/clip) (:height demo/clip))] (raster/clear! r (:bg pal/index-of)) @@ -334,7 +334,7 @@ ;; Exposure 2 on the clip root, inherited, so odd frames are identical to the ;; even frame before them. If this fails, exposure is being applied somewhere ;; other than the frame the channels are sampled at. - (let [res (symbol/resolver demo/main nil pal/index-of nil nil) + (let [res (symbol/resolver demo/main nil pal/index-of nil) render (fn [f] (let [r (raster/make (:width demo/clip) (:height demo/clip))] (raster/clear! r (:bg pal/index-of)) @@ -351,7 +351,7 @@ (deftest the-hand-written-clip-keeps-the-iris-and-pupil-inside-the-card ;; The stencil chain, on real pixels: the iris is clipped by the card and the ;; pupil by the iris, and neither is expressed anywhere as a chain. - (let [res (symbol/resolver demo/main nil pal/index-of nil nil)] + (let [res (symbol/resolver demo/main nil pal/index-of nil)] (doseq [f (range 0 demo/frames 4)] (let [before (raster/make (:width demo/clip) (:height demo/clip)) after (raster/make (:width demo/clip) (:height demo/clip)) @@ -384,9 +384,9 @@ (poly :p :root "a1" [0 0 10 0 10 10] :skin-base)) day {:skin-base 1} night {:skin-base 17}] - (is (= 1 (:color (first (symbol/eval-frame s 0 nil day nil nil))))) - (is (= 17 (:color (first (symbol/eval-frame s 0 nil night nil nil))))) - (is (= 17 (:color (first ((symbol/resolver s nil night nil nil) 0)))) + (is (= 1 (:color (first (symbol/eval-frame s 0 nil day nil))))) + (is (= 17 (:color (first (symbol/eval-frame s 0 nil night nil))))) + (is (= 17 (:color (first ((symbol/resolver s nil night nil) 0)))) "and the playback path agrees"))) (deftest a-tone-the-ramp-does-not-define-is-loudly-wrong @@ -394,7 +394,7 @@ ;; authored data and should be impossible to miss. (let [s (sc {:id :root :kind :group :z "a1"} (poly :p :root "a1" [0 0 10 0 10 10] :skin-base))] - (is (= 255 (:color (first (symbol/eval-frame s 0 nil {} nil nil))))))) + (is (= 255 (:color (first (symbol/eval-frame s 0 nil {} nil))))))) (deftest partitioning-the-index-space-stops-two-palettes-colliding-on-a-stencil ;; A stencil is a colour key, so two nodes sharing a tone share a stencil — @@ -407,6 +407,6 @@ [:style :color] (ch/framed :iris)}}) ;; :night's tones sit above :day's in one concatenated space night {:eye-white 14 :iris 15} - ops (symbol/eval-frame s 0 nil night nil nil)] + ops (symbol/eval-frame s 0 nil night nil)] (is (= 14 (:stencil (second ops))) "the stencil resolves to the index the stencil node actually drew in"))) diff --git a/frontend/test/arthur/domain/trace_test.cljs b/frontend/test/arthur/domain/trace_test.cljs index a5ab51f..a9c3303 100644 --- a/frontend/test/arthur/domain/trace_test.cljs +++ b/frontend/test/arthur/domain/trace_test.cljs @@ -52,7 +52,7 @@ (defn- photo-at "The photo matrix of face-1 alone at frame `f`, the still being 1000px tall." [c f] - (let [r (symbol/resolver (clip/symbol c :face-1) @store pal/index-of nil nil) + (let [r (symbol/resolver (clip/symbol c :face-1) @store pal/index-of nil) h (head c)] (r f) (vec (array-seq (trace/photo-matrix (symbol/world-of r :head) h @store @@ -111,7 +111,7 @@ ;; The same answer as `nest/placement`, which walks and resolves the path all ;; over again — the resolver has it already, from drawing the frame. (let [c (wrapped) - r (clip/resolver c @store pal/index-of :wrap nil) + r (clip/resolver c :wrap @store pal/index-of nil) path [:m :face-1 :head]] (doseq [f [0 17 60]] (r f) diff --git a/frontend/test/arthur/flow/eye_occlusion_test.cljs b/frontend/test/arthur/flow/eye_occlusion_test.cljs index 18e4376..16791ee 100644 --- a/frontend/test/arthur/flow/eye_occlusion_test.cljs +++ b/frontend/test/arthur/flow/eye_occlusion_test.cljs @@ -59,7 +59,7 @@ (is (not (ch/nothing? (sample :eye-l f)))) (is (not (ch/nothing? (sample :mouth f))))) (let [drawn (into #{} (map :node) - ((symbol/resolver (clip/symbol clip :face-1) store pal/index-of nil nil) 11))] + ((symbol/resolver (clip/symbol clip :face-1) store pal/index-of nil) 11))] (is (not (contains? drawn :eye-r))) (is (not (contains? drawn :iris-r))) (is (contains? drawn :eye-l)) diff --git a/frontend/test/arthur/flow/freeze_test.cljs b/frontend/test/arthur/flow/freeze_test.cljs index 2223581..09512cf 100644 --- a/frontend/test/arthur/flow/freeze_test.cljs +++ b/frontend/test/arthur/flow/freeze_test.cljs @@ -56,7 +56,7 @@ (defn- ops-at "Ops for one frame of a TIMELINE." [sym f] - ((symbol/resolver sym @store pal/index-of nil nil) f)) + ((symbol/resolver sym @store pal/index-of nil) f)) (defn- render "One frame of a CLIP into a byte buffer. The stage's size comes off the clip and @@ -64,7 +64,7 @@ [c f] (let [r (raster/make (:width c) (:height c))] (raster/clear! r (get pal/index-of :bg)) - (raster/draw-ops! r ((clip/resolver c @store pal/index-of :main nil) f)) + (raster/draw-ops! r ((clip/resolver c :main @store pal/index-of nil) f)) (vec (array-seq (:buf r))))) (defn- drawn @@ -195,7 +195,7 @@ ;; checking arithmetic against itself; this checks `node/local!`, `node/world!` ;; and `emit` as well. (let [c (freeze/head-mode {} @frozen) - res (clip/resolver c @store pal/index-of :main nil) + res (clip/resolver c :main @store pal/index-of nil) k (first (:value (chan :face [:xform :scale]))) anc (:value (chan :face [:xform :anchor])) pos (:value (chan :face [:xform :pos])) @@ -249,14 +249,11 @@ "the trace survives the document round trip"))) (deftest trace-keys-hold-the-whole-measured-transform - (let [free (symbol/resolver (face-symbol (freeze/head-mode {} @frozen)) - @store pal/index-of nil nil) + (let [free (symbol/resolver (face-symbol (freeze/head-mode {} @frozen)) @store pal/index-of nil) held (symbol/resolver (face-symbol - (freeze/head-mode {:trace {:origin :keys :frames [12 88]}} @frozen)) - @store pal/index-of nil nil) + (freeze/head-mode {:trace {:origin :keys :frames [12 88]}} @frozen)) @store pal/index-of nil) start (symbol/resolver (face-symbol - (freeze/head-mode {:trace {:origin :start :frames [12 88]}} @frozen)) - @store pal/index-of nil nil) + (freeze/head-mode {:trace {:origin :start :frames [12 88]}} @frozen)) @store pal/index-of nil) world (fn [resolver frame] (resolver frame) (vec (array-seq (symbol/world-of resolver :head))))] @@ -511,7 +508,7 @@ (is (not (ch/nothing? (at :eye-r 60)))) (is (not (ch/nothing? (at :eye-l 50)))) (is (not (ch/nothing? (at :mouth 50)))) - (let [drawn-nodes (into #{} (map :node) ((symbol/resolver sym (:store c) pal/index-of nil nil) 50))] + (let [drawn-nodes (into #{} (map :node) ((symbol/resolver sym (:store c) pal/index-of nil) 50))] (is (not (contains? drawn-nodes :eye-r))) (is (contains? drawn-nodes :eye-l)) (is (contains? drawn-nodes :mouth))) @@ -586,7 +583,7 @@ ;; Hoisted: the resolver caches its order and reuses its buffers, so the ;; node ids come out before the next frame is asked for. nodes-at (fn [c] - (let [r (symbol/resolver (face-symbol (:clip c)) (:store c) pal/index-of nil nil)] + (let [r (symbol/resolver (face-symbol (:clip c)) (:store c) pal/index-of nil)] (fn [f] (into #{} (map :node) (r f))))) ref-at (nodes-at ref) occ-at (nodes-at occ) @@ -623,7 +620,7 @@ c (freeze/clip (assoc take/params :name "gappy") {:face-1 (assoc @take/measured :detected det)}) sym (face-symbol (:clip c)) - res (symbol/resolver sym (:store c) pal/index-of nil nil)] + res (symbol/resolver sym (:store c) pal/index-of nil)] (doseq [f [39 40 50 59 60]] (let [ops (res f)] (if (contains? gap f) @@ -682,7 +679,7 @@ shot (fn [f] (let [r (raster/make W H) mouth (filter #(= [:face-1 :mouth] (:node %)) - ((clip/resolver locked @store pal/index-of :main nil) f))] + ((clip/resolver locked :main @store pal/index-of nil) f))] (raster/clear! r (get pal/index-of :bg)) (raster/draw-ops! r mouth) (vec (array-seq (:buf r))))) diff --git a/frontend/test/arthur/flow/multi_face_test.cljs b/frontend/test/arthur/flow/multi_face_test.cljs index 53f16ec..7099adb 100644 --- a/frontend/test/arthur/flow/multi_face_test.cljs +++ b/frontend/test/arthur/flow/multi_face_test.cljs @@ -35,7 +35,7 @@ (defn channel [entry subject node path] (get-in entry [:clip :symbols subject :nodes node :channels path])) -(defn snapshot [c store f] (ops/snapshot ((clip/resolver c store pal/index-of :main nil) f))) +(defn snapshot [c store f] (ops/snapshot ((clip/resolver c :main store pal/index-of nil) f))) (defn by-node [c store f] (into {} (map (juxt :node identity)) (snapshot c store f))) (deftest subjects-share-local-names-without-sharing-blocks @@ -178,8 +178,8 @@ (merge (dissoc (:nodes (clip/symbol clip :main)) :face-1) (assoc-in (get-in clip [:symbols :face-1 :nodes]) [:head :parent] :face))) - nested (clip/resolver clip store pal/index-of :main nil) - reference (clip/resolver flat store pal/index-of :main nil)] + nested (clip/resolver clip :main store pal/index-of nil) + reference (clip/resolver flat :main store pal/index-of nil)] (doseq [f [0 1 7 20 39]] (let [a (ops/snapshot (nested f)) b (ops/snapshot (reference f))] (is (= (mapv (comp second :node) a) (mapv :node b))) diff --git a/frontend/test/arthur/support/ops.cljs b/frontend/test/arthur/support/ops.cljs index 054cfda..5c579fc 100644 --- a/frontend/test/arthur/support/ops.cljs +++ b/frontend/test/arthur/support/ops.cljs @@ -52,11 +52,11 @@ "(fn [f] -> snapshot) through `eval-frame`, the specification." ([sym store] (specified sym store pal/index-of)) ([sym store palette] - (fn [f] (snapshot (symbol/eval-frame sym f store palette nil nil))))) + (fn [f] (snapshot (symbol/eval-frame sym f store palette nil))))) (defn resolved "(fn [f] -> snapshot) through `resolver`, the playback path." ([sym store] (resolved sym store pal/index-of)) ([sym store palette] - (let [res (symbol/resolver sym store palette nil nil)] + (let [res (symbol/resolver sym store palette nil)] (fn [f] (snapshot (res f))))))