Documentation
¶
Overview ¶
Package anim is the arithmetic behind things that move.
It is pure functions of a tick and an eased value that advances one step at a time. Nothing here holds a clock, opens anything, or knows what a cell is: the caller decides when time passes, and what these numbers are then used for — brightening a colour, growing a pane — is the caller's.
Why ticks rather than durations ¶
A transition measured in wall-clock time has to ask what time it is, and a animation that asks what time it is cannot be stepped by a test or paused by its owner that parked because nothing was happening. Everything here counts ticks instead, and a tick is whatever the caller's scheduler decided one is. That makes an animation exactly as deterministic as the thing driving it, which is the property the rest of this library is built on.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EaseOutCubic ¶
EaseOutCubic maps a linear position in [0,1] to an eased one.
Out-cubic rather than anything else because it is the curve that reads as "arrived": most of the distance is covered early and the last part settles, which is what makes a pane that grows look like it stopped rather than like it was cut off.
func Shimmer ¶
Shimmer is the brightness at one column of a row being swept by a moving highlight — the "this is still arriving" effect on streamed text.
pos is the column, width the row's width, and the result is in [0.35, 1]. It is meant for [grid.View.Fade]: fade the column by one minus this, and the sweep reads as light rather than as characters changing. A fade rather than a colour, because what the text dissolves into is whatever that column is drawn on.
Types ¶
type Keyframe ¶ added in v0.0.2
type Keyframe struct {
// At is how many ticks into the timeline this value is reached.
At uint64
// Value is what it is then.
Value float64
}
Keyframe is a value a Timeline passes through, and when.
type Spring ¶ added in v0.0.2
type Spring struct {
// Frequency is how fast it moves, in radians per tick: higher is stiffer. Zero
// uses the default.
Frequency float64
// Damping is how much it overshoots. One arrives and stops; below one it goes
// past and comes back, and the further below, the more it bounces; above one it
// creeps in slowly. Zero uses the default, which is one.
Damping float64
// contains filtered or unexported fields
}
Spring moves a value toward a target the way a weight on a spring does: it gathers speed, arrives, and — if it is allowed to — goes a little past and comes back.
It is the other kind of movement from Transition, and the difference is what happens when the target changes half way. A transition restarts, easing from wherever it was, and the change reads as a stop and a fresh start. A spring keeps the speed it already had, so a target that moves twice reads as one continuous movement, which is useful whenever a target can change while motion is under way.
Like everything here it is stepped in ticks rather than in seconds, so a test steps it and gets the same numbers every time.
The zero Spring is settled at zero and moves nothing. Given a target it uses the defaults above, which arrive without overshooting.
func (*Spring) Done ¶ added in v0.0.2
Done reports whether the spring has arrived: near enough its target and slow enough that nothing further would be visible. It is what tells its owner it can stop the clock driving this, and it is the same question Transition.Done answers.
func (*Spring) Set ¶ added in v0.0.2
Set puts the value where it is asked and stops it there, which is how to place a spring without animating it — the first frame, or a resize nobody should watch.
func (*Spring) Tick ¶ added in v0.0.2
func (s *Spring) Tick()
Tick advances the spring by one step.
The step is the exact solution of the equation rather than a small step of it, which matters at ordinary tick rates: stepping a stiff spring approximately is how a spring turns into an oscillation that grows instead of one that dies away. There are three solutions and which one applies is decided by the damping — under one it rings, at one it just arrives, above one it creeps — so all three are here rather than the one that is usually enough.
func (*Spring) To ¶ added in v0.0.2
To sets what the spring is moving toward, keeping the speed it already has.
type Timeline ¶ added in v0.0.2
type Timeline struct {
// Frames are the values it passes through, in the order their ticks say. They are
// read as given: frames out of order are the caller's mistake and are left as
// such, because sorting them would hide it.
Frames []Keyframe
// Ease shapes the movement between two frames. Nil is linear, which is what a
// sequence of steps usually wants — each step already says how long it takes, and
// easing every one of them separately reads as a stutter.
Ease func(t float64) float64
// Loop starts again from the beginning once the last frame is reached, which is
// what anything idling — a pulse, a sweep — is made of.
Loop bool
// contains filtered or unexported fields
}
Timeline is a value that follows a sequence of keyframes: it eases from each to the next and holds the last one.
It is the third kind of movement here, and the one the other two cannot express. A Transition goes from one value to another and a Spring chases a target; a sequence — appear, hold, fade — is neither, and writing one out of transitions means keeping a step number and a counter beside them and remembering to advance both.
The zero Timeline holds zero for ever, which is what a caller who never set any frames should get.
func (*Timeline) Done ¶ added in v0.0.2
Done reports whether the last frame has been reached. A looping timeline is never done, which is the honest answer: nothing is waiting for it.
func (*Timeline) Reset ¶ added in v0.0.2
func (t *Timeline) Reset()
Reset takes the timeline back to its beginning.
func (*Timeline) Span ¶ added in v0.0.2
Span is how long the whole timeline is, which is when its last frame is reached.
func (*Timeline) Tick ¶ added in v0.0.2
func (t *Timeline) Tick()
Tick advances the timeline by one step. It is safe to keep calling after the end, which is what lets a caller drive several from one clock without checking each.
func (*Timeline) Value ¶ added in v0.0.2
Value is where the timeline is now.
Before the first frame it is the first frame's value, and after the last it is the last one's — a timeline holds its ends rather than running off them, so a caller that draws one tick late draws the end state instead of nothing.
type Transition ¶
type Transition struct {
// contains filtered or unexported fields
}
Transition moves a value toward a target over a number of ticks, eased.
The zero Transition is settled at zero and animates nothing, so a caller who never starts one pays for nothing. Transition.Tick is what advances it, and a caller with several can drive them all from the one clock they already have.
func (*Transition) Done ¶
func (t *Transition) Done() bool
Done reports whether the transition has arrived, which is what tells its owner it can stop the clock driving it.
func (*Transition) Tick ¶
func (t *Transition) Tick()
Tick advances the transition by one step. It is safe to keep calling after it has arrived, so a caller does not have to check before stepping.
func (*Transition) To ¶
func (t *Transition) To(target float64, span uint64)
To retargets the transition, starting from wherever it is now. A span of zero arrives immediately, which is how to set a value without animating it.
func (*Transition) Value ¶
func (t *Transition) Value() float64
Value is where the transition is now.