One tool at a time, picked from a strip down the left of the stage or by its letter, as in Photoshop, Illustrator and Flash: V selects and transforms, P is the pen, B the brush, E the eraser. The options bar above the stage holds the tool's settings, and the palette is a grid under the tools with the colour a new shape gets above it, as Deluxe Paint's was. The pen's draft is filled into the picture as it is drawn, so the edge on screen is the pixels the shape will be. Click the first point, Enter, Esc or leaving the pen closes it; the pen stays the tool. Editing a shape's points is the pen ON that shape — Figma's vector edit mode — so the separate points mode is gone: click an edge to add a point, ⌥-click one to delete it, on every key at once so tweens keep meaning something. The brush paints a mask, and what it will be is shown while painting: the stroke is traced round its pixel edges, holes and all, and simplified to a point every so many pixels of outline by the same function the saved shapes come from. A hole is bridged into the one ring along a whole-pixel row, which the fill never samples. Blender's Adjust Last Operation re-traces the last stroke from what it was made of. A shape coloured CLEAR is a knockout: its symbol is drawn into a layer of its own and the knockout clears it, every colour or one. The eraser makes one in the symbol it starts on, of the colour it starts on, or of every colour with ⌥. A click goes through a knockout to what shows. Previews are drawn in the stacking context of what they will land in. The polygon's points no longer stay behind when the shape is moved: they were read off the saved document while the box handles read the one mid-drag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
2.4 KiB
Clojure
46 lines
2.4 KiB
Clojure
(ns arthur.domain.paint-test
|
|
(:require [cljs.test :refer [deftest is]]
|
|
[arthur.demo :as demo]
|
|
[arthur.domain.channel :as channel]
|
|
[arthur.domain.leaf :as leaf]
|
|
[arthur.domain.node :as node]
|
|
[arthur.domain.paint :as paint]
|
|
[arthur.domain.palette :as pal]
|
|
[arthur.domain.symbol :as symbol]))
|
|
|
|
(defn- geometry [clip]
|
|
(get-in clip [:symbols :main :nodes :paint-test :channels paint/geometry]))
|
|
|
|
(deftest drawing-keys-hold-and-tween-on-the-symbol-clock
|
|
(let [a [10 10 30 10 20 30]
|
|
c0 (paint/new-shape demo/clip :main :paint-test 3 a :brow)
|
|
c1 (paint/add-key c0 :main :paint-test 9)
|
|
c2 (paint/set-vertex c1 :main :paint-test 9 0 [22 10])
|
|
c3 (paint/add-key c2 :main :paint-test 15)
|
|
c4 (paint/set-vertex c3 :main :paint-test 15 0 [34 10])
|
|
held (geometry c4)
|
|
mixed-clip (update-in c4 [:symbols :main :nodes :paint-test]
|
|
node/set-segment-interp paint/geometry 9 :linear)
|
|
mixed (geometry mixed-clip)]
|
|
(is (= [3 229] (get-in c2 [:symbols :main :nodes :paint-test :span])))
|
|
(is (= a (channel/value-at held 8 nil)))
|
|
(is (= 10 (first (channel/value-at held 8 nil))))
|
|
(is (= 22 (first (channel/value-at held 9 nil))))
|
|
(is (= 10 (first (channel/value-at mixed 6 nil))) "the first gap cuts")
|
|
(is (= 28 (first (channel/value-at mixed 12 nil))) "the second gap tweens")
|
|
(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)))
|
|
(is (= mixed-clip (leaf/clip :c1 (leaf/leaves :c1 mixed-clip))))))
|
|
|
|
(deftest a-point-is-added-and-taken-away-on-every-key
|
|
(let [c0 (-> (paint/new-shape demo/clip :main :p 0 [0 0 10 0 10 10] :brow)
|
|
(paint/add-key :main :p 6)
|
|
(paint/set-vertex :main :p 6 1 [20 0]))
|
|
c1 (paint/insert-vertex c0 :main :p 0 0.5)
|
|
ks #(get-in % [:symbols :main :nodes :p :channels paint/geometry :keys])]
|
|
(is (= {0 [0 0 5 0 10 0 10 10] 6 [0 0 10 0 20 0 10 10]} (ks c1))
|
|
"half way along the same edge of each key")
|
|
(is (= (ks c0) (ks (paint/delete-vertex c1 :main :p 1))))
|
|
(is (= (ks c0) (ks (paint/delete-vertex c0 :main :p 0))) "a triangle keeps its three")))
|