# tween

`import "github.com/matjam/bunyip/tween"`

Package tween animates values over time. A Tween moves a number from one value to another with an easing curve, and Sequence chains them.

To make a tween, call New with a start, an end, a duration in seconds and an Ease. The usual easing curves are provided, and any func(t float32) float32 works. Call Update each step to advance a tween, then read Value, or set OnDone to be called when it finishes. Use tweens for menus sliding in, health bars draining, cameras easing to a target and damage numbers floating up. NewSequence runs several in order. For keyframed curves over vectors, colours and component fields, see the anim package. Tweens and sequences are not safe for concurrent use; advance them with finite, nonnegative steps on the game loop goroutine.

## Types

<a id="Ease"></a>

### Ease

```go
type Ease func(t float32) float32
```

Ease maps progress t in \[0,1] to eased progress.

<a id="Linear"></a>

<a id="InQuad"></a>

<a id="OutQuad"></a>

<a id="InOutQuad"></a>

<a id="InCubic"></a>

<a id="OutCubic"></a>

<a id="InOutCubic"></a>

<a id="InSine"></a>

<a id="OutSine"></a>

<a id="InOutSine"></a>

<a id="Smoothstep"></a>

<a id="OutBack"></a>

<a id="OutElastic"></a>

<a id="OutBounce"></a>

```go
var (
	Linear     Ease = func(t float32) float32 { return t }
	InQuad     Ease = func(t float32) float32 { return t * t }
	OutQuad    Ease = func(t float32) float32 { return t * (2 - t) }
	InOutQuad  Ease = func(t float32) float32 { return inOut(t, InQuad, OutQuad) }
	InCubic    Ease = func(t float32) float32 { return t * t * t }
	OutCubic   Ease = func(t float32) float32 { u := 1 - t; return 1 - u*u*u }
	InOutCubic Ease = func(t float32) float32 { return inOut(t, InCubic, OutCubic) }
	InSine     Ease = func(t float32) float32 { return 1 - cos(t*math.Pi/2) }
	OutSine    Ease = func(t float32) float32 { return sin(t * math.Pi / 2) }
	InOutSine  Ease = func(t float32) float32 { return (1 - cos(t*math.Pi)) / 2 }
	Smoothstep Ease = func(t float32) float32 { return t * t * (3 - 2*t) }
	OutBack    Ease = func(t float32) float32 {
		const c1, c3 = 1.70158, 2.70158
		u := t - 1
		return 1 + c3*u*u*u + c1*u*u
	}
	OutElastic Ease = func(t float32) float32 {
		if t <= 0 || t >= 1 {
			return clamp01(t)
		}
		const c4 = 2 * math.Pi / 3
		return pow2(-10*t)*sin((t*10-0.75)*c4) + 1
	}
	OutBounce Ease = func(t float32) float32 {
		const n1, d1 = 7.5625, 2.75
		switch {
		case t < 1/d1:
			return n1 * t * t
		case t < 2/d1:
			t -= 1.5 / d1
			return n1*t*t + 0.75
		case t < 2.5/d1:
			t -= 2.25 / d1
			return n1*t*t + 0.9375
		default:
			t -= 2.625 / d1
			return n1*t*t + 0.984375
		}
	}
)
```

Easing curves. In\* start slowly, Out\* end slowly, InOut\* do both.

<a id="Of"></a>

<a id="Of.Tween"></a>

<a id="Of.From"></a>

<a id="Of.To"></a>

<a id="Of.Lerp"></a>

### Of

```go
type Of[V any] struct {
	*Tween
	From, To V                         // blend endpoints
	Lerp     func(a, b V, t float32) V // required blend function, called with eased progress
}
```

Of animates any value that can be blended: a position, a colour, a size. It wraps a Tween for the timing (delay, repeats, yo-yo, easing) and a Lerp function for the blend, so gfx.Color.Lerp, lin.Vec3.Lerp or a game's own mix all work:

	fade := tween.NewOf(gfx.Transparent, gfx.White, 0.5, tween.OutQuad, gfx.Color.Lerp)
	tint := fade.Update(dt)

<a id="NewOf"></a>

#### NewOf

```go
func NewOf[V any](from, to V, seconds float32, ease Ease, lerp func(a, b V, t float32) V) *Of[V]
```

NewOf makes a tween over any value with a blend function; a nil ease is linear. The blend function must be non-nil. Delay, Repeat and YoYo have the same behavior as on a scalar Tween.

<a id="NewVec2"></a>

#### NewVec2

```go
func NewVec2(from, to lin.Vec2, seconds float32, ease Ease) *Of[lin.Vec2]
```

NewVec2 tweens a 2D vector.

<a id="NewVec3"></a>

#### NewVec3

```go
func NewVec3(from, to lin.Vec3, seconds float32, ease Ease) *Of[lin.Vec3]
```

NewVec3 tweens a 3D vector.

<a id="Of.OnDone"></a>

#### Of.OnDone

```go
func (o *Of[V]) OnDone(f func()) *Of[V]
```

OnDone replaces the completion callback and returns the same typed tween for chaining. It follows Tween.OnDone's callback timing.

Example:

```go
package main

import (
	"fmt"

	"github.com/matjam/bunyip/lin"
	"github.com/matjam/bunyip/tween"
)

func main() {
	done := false
	move := tween.NewVec2(lin.V2(0, 0), lin.V2(10, 20), 1, nil).
		OnDone(func() { done = true })
	move.Repeat, move.YoYo = 1, true
	fmt.Println(move.Update(1), done)
	fmt.Println(move.Update(1), done)
}
```

Output:

```
{10 20} false
{0 0} true
```

<a id="Of.Update"></a>

#### Of.Update

```go
func (o *Of[V]) Update(dt float32) V
```

Update advances the tween and returns the blended value.

<a id="Of.Value"></a>

#### Of.Value

```go
func (o *Of[V]) Value() V
```

Value is the blended value at the tween's current progress.

<a id="Sequence"></a>

### Sequence

```go
type Sequence struct {
	// contains filtered or unexported fields
}
```

Sequence plays tweens one after another.

Example:

```go
package main

import (
	"fmt"

	"github.com/matjam/bunyip/tween"
)

func main() {
	// Fade in, hold, fade out: each step starts when the previous ends.
	fade := tween.NewSequence(
		tween.New(0, 1, 0.5, nil),
		tween.New(1, 1, 1, nil),
		tween.New(1, 0, 0.5, nil),
	)
	for !fade.Done() {
		fade.Update(0.5)
	}
	fmt.Println(fade.Update(0))
}
```

Output:

```
0
```

<a id="NewSequence"></a>

#### NewSequence

```go
func NewSequence(steps ...*Tween) *Sequence
```

NewSequence chains tweens.

<a id="Sequence.Done"></a>

#### Sequence.Done

```go
func (s *Sequence) Done() bool
```

Done reports whether every step has finished.

<a id="Sequence.Reset"></a>

#### Sequence.Reset

```go
func (s *Sequence) Reset()
```

Reset restarts from the first step.

<a id="Sequence.Update"></a>

#### Sequence.Update

```go
func (s *Sequence) Update(dt float32) float32
```

Update advances the sequence and returns the current tween's value.

<a id="Tween"></a>

<a id="Tween.From"></a>

<a id="Tween.To"></a>

<a id="Tween.Duration"></a>

<a id="Tween.Ease"></a>

<a id="Tween.Delay"></a>

<a id="Tween.Repeat"></a>

<a id="Tween.YoYo"></a>

### Tween

```go
type Tween struct {
	From, To float32 // endpoints of the forward play
	Duration float32 // seconds per play; nonpositive completes after Delay
	Ease     Ease    // progress mapping; nil means linear
	Delay    float32 // seconds before movement starts
	Repeat   int     // extra plays after the first; -1 forever
	YoYo     bool    // alternate direction on repeats
	// contains filtered or unexported fields
}
```

Tween moves a value from From to To over Duration seconds.

Example:

```go
package main

import (
	"fmt"

	"github.com/matjam/bunyip/tween"
)

func main() {
	// Slide a value from 0 to 100 over one second with an ease-out curve.
	slide := tween.New(0, 100, 1, tween.OutQuad)
	for range 4 {
		fmt.Printf("%.0f ", slide.Update(0.25))
	}
	fmt.Println(slide.Done())
}
```

Output:

```
44 75 94 100 true
```

<a id="New"></a>

#### New

```go
func New(from, to, seconds float32, ease Ease) *Tween
```

New makes a tween; a nil ease is linear.

<a id="Tween.Done"></a>

#### Tween.Done

```go
func (tw *Tween) Done() bool
```

Done reports whether the tween has finished.

<a id="Tween.OnDone"></a>

#### Tween.OnDone

```go
func (tw *Tween) OnDone(f func()) *Tween
```

OnDone replaces the callback called synchronously by the Update that finishes the tween. Registration after completion does not invoke it; Reset permits it to run again on the next completed playthrough.

<a id="Tween.Progress"></a>

#### Tween.Progress

```go
func (tw *Tween) Progress() float32
```

Progress is eased progress. The input to Ease is clamped to \[0,1], but curves such as OutBack and OutElastic may overshoot that range. A nonpositive Duration reports 1, including while Delay is pending.

<a id="Tween.Reset"></a>

#### Tween.Reset

```go
func (tw *Tween) Reset()
```

Reset starts the tween over, forwards.

<a id="Tween.Update"></a>

#### Tween.Update

```go
func (tw *Tween) Update(dt float32) float32
```

Update advances by dt seconds and returns the current value.

<a id="Tween.Value"></a>

#### Tween.Value

```go
func (tw *Tween) Value() float32
```

Value is the current value.
