material-motion-archive / starmap

Issue tracker for the starmap
https://material-motion.github.io/material-motion/
4 stars 0 forks source link

Spec out driving Tween animations #68

Closed jverkoey closed 7 years ago

jverkoey commented 7 years ago

Need to allow Tweens to be driven by arbitrary values, such as a scroll position, gesture value, or time itself.

Important performance consideration is that if time is driving the Tweens, then the system compositor should be used to drive time forward rather than the main thread. This likely requires some hand-off between the main thread and the system compositor if the driver changes.

Proposal 1. Require that all Tween objects accept a Timeline instance

let timeline = Timeline(duration: 0.3)
let tween = Tween(property, timeline.segment(firstHalf))
timeline.paused = true
timeline.progress = 0.5

let timeline = Timeline(duration: 0.3)
let tween = Tween(property, timeline)

Timeline.segment() returns a smaller Timeline whose .parent == timeline. timeline could enumerate all of its children timelines using .childTimelines.

If a timeline is paused, then any associated Tweens will stop reading time increments from the system compositor. On iOS this means setting the layerSpeed to 0.

Setting timeline.progress will update all of the associated Tweens to the relevant time progress. On iOS this means changing the timeOffset of the corresponding layers.

jverkoey commented 7 years ago

How does this connect to TransitionTween?

TimeWindow would need to be associated with the Timeline in some way. A Transition would likely create a Timeline with a given duration and associate this with TimeWindow.

TransitionTween would then emit a Tween with the given Timeline.

jverkoey commented 7 years ago

Mapping gesture recognizer to a timeline

runtime.add(
  RadialTimelineGesture(
    gesture: panGestureRecognizer, 
    withRadius: 50pt), 
  to: timeline
)
jverkoey commented 7 years ago

Building from the bottom up

Probably prefer this to the top-down timeline building because it solves the "cascading animations" problem.

let tween = Tween("opacity", duration: 0.3)
let tween2 = Tween("position", duration: 0.3)

let timeline = Timeline()
timeline.append(tween.timeline)
timeline.append(tween2.timeline)

// timeline.duration == 0.6

runtime.addPlan(tween, to: view)
runtime.addPlan(tween2, to: view)

runtime.add(
  RadialTimelineGesture(
    gesture: panGestureRecognizer, 
    withRadius: 50pt), 
  to: timeline
)
runtime.add(Draggable(gesture: panGestureRecognizer), to: photoView)
jverkoey commented 7 years ago

Driven by a spring

runtime.add(SpringTo("progress", destination: 1), to: timeline)
jverkoey commented 7 years ago

Initially paused animation

let tween = Tween(property, duration: 0.3)
let tween2 = Tween(property, duration: 0.3, delay: 0.3)

let timeline = Timeline()
timeline.add(tween.timeline)
timeline.add(tween2.timeline)

timeline.paused = true
appsforartists commented 7 years ago

From the (admittedly limited) experience I have building TweenPerformerWeb, Web Animations scare me:

Regardless of whether we use Web Animations, I think we're going to need a pure-JS shim on top of transform that caches a target's translation, scale, and rotation; ensuring they're always output in the same order. Every performer that touches transform will need to access it through this shim.

@shans probably has more insight here; he might have a solution to pulling human-readable values out of the matrix. Even if we had one, the other problems still make me lean heavily towards the simpler (and more robust) main-thread solution.

appsforartists commented 7 years ago

This might be a per-platform concern, but I'd expect setters with side effects (e.g. progress, paused) to be methods. At least in JavaScript, setters are expected to be cheap with minimal side effects. Triggering a bunch of recursive writes to progress and thus to the style engine, might be heavy for a setter. Making it a setter does make the spring example simple though. Curious what @shyndman thinks.

pingpongboss commented 7 years ago

FYI they are methods. Swift autogenerates methods for properties.

On Mon, Nov 7, 2016 at 7:51 PM Brenton Simpson notifications@github.com wrote:

This might be a per-platform concern, but I'd expect setters with side effects (e.g. progress, paused) to be methods. At least in JavaScript, setters are expected to be cheap with minimal side effects. Triggering a bunch of recursive writes to progress and thus to the style engine, might be heavy for a setter. Making it a setter does make the spring example simple though. Curious what @shyndman https://github.com/shyndman thinks.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/material-motion/starmap/issues/68#issuecomment-259011964, or mute the thread https://github.com/notifications/unsubscribe-auth/AAr8KmstVKixeX7J9ujoXspcGAdAkp6xks5q78eOgaJpZM4Kr1Us .

appsforartists commented 7 years ago

I'd like to see a more thorough explanation of how the bottoms-up approach would work. Can you sketch out the performer?

I'm mostly wondering how it's all wired together. What happens if the same tween is applied to two different targets? Timeline drives tween's progress, right? How does tween's progress get connected to the view? Can a timeline drive one tween that drives two separate views, or is there an implicit contract that there's a 1:1 relationship between tweens and views?

appsforartists commented 7 years ago

Can we consolidate timeline, window, and segment? They feel similar and overlapping. My intuition says we can express the same behavior with fewer concepts.

jverkoey commented 7 years ago

What happens if the same tween is applied to two different targets?

Same thing that presently happens: the tween is added to each target.

jverkoey commented 7 years ago

Timeline drives tween's progress, right?

Yes.

jverkoey commented 7 years ago

How does tween's progress get connected to the view?

Tween performers would react to changes in the Timeline's progress.

jverkoey commented 7 years ago

Can a timeline drive one tween that drives two separate views?

Yes, though keep in mind it's two performers in this case.

jverkoey commented 7 years ago

Can we consolidate timeline, window, and segment?

We do need an independent representation of structured time between two transition states. Perhaps TransitionWindow is a better name for TimeWindow; this will more accurately reflect the fact that we're planning out the window between two states.

So: