anim

package
v0.183.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: BSD-3-Clause Imports: 2 Imported by: 0

Documentation

Overview

Package anim is a backend-agnostic timeline driver for the go-widgets toolkit. It turns the host's existing per-frame tick (a tui EventTick, a wasm requestAnimationFrame callback, …) into wall-clock-eased animations, and suppresses idle frames once nothing is animating so the host can stop scheduling work (saving battery and CPU).

The driver owns no goroutine and no timer: the host owns the loop, exactly like the rest of the toolkit, whose widgets already expose a manual Tick(dt). The host calls Driver.Tick with the current wall-clock time each frame; when it returns busy=false the active set is empty and the host may stop scheduling frames until the next interaction starts a new animation.

Animations reuse the toolkit's existing toolkit.Easing curves, so the package makes easing.go load-bearing.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Animation

type Animation struct {
	// Dur is the wall-clock duration of the animation. A Dur <= 0 completes
	// the animation on its very first tick (progress jumps straight to 1).
	Dur time.Duration
	// Ease shapes the linear 0..1 progress into the eased value handed to
	// Apply. A nil Ease behaves as [toolkit.Linear].
	Ease toolkit.Easing
	// Apply pushes the eased progress (0..1) to the target each tick. A nil
	// Apply makes the animation a pure timer (only OnEnd matters).
	Apply func(progress float64)
	// OnEnd, if non-nil, is called once when the animation completes.
	OnEnd func()
}

Animation describes a single time-bounded animation. Its progress runs from 0 at the first tick after it starts to 1 at Dur, shaped by Ease, and is pushed to the target via Apply. OnEnd fires once, on the tick that reaches progress 1, right after the final Apply.

type Driver

type Driver struct {
	// contains filtered or unexported fields
}

Driver advances a set of active animations from the host's frame loop. It holds no goroutine and no timer; the zero value is ready to use, though NewDriver reads more clearly at call sites.

Example (Spinner)

ExampleDriver_spinner drives a toolkit.Spinner's Phase from the anim Driver instead of the widget's manual Tick(dt). The host loop advances the driver with wall-clock time each frame and stops scheduling frames once Tick reports busy=false. This is the load-bearing consumer: the Spinner's cadence now comes from an eased anim.Animation over the toolkit's Easing curves.

package main

import (
	"fmt"
	"time"

	"github.com/go-widgets/toolkit"
	"github.com/go-widgets/toolkit/anim"
)

func main() {
	sp := toolkit.NewSpinner()
	sp.Active = true

	d := anim.NewDriver()
	// One full 0..1 phase sweep over 1s, linear so the spin is steady.
	d.Start(&anim.Animation{
		Dur:   time.Second,
		Ease:  toolkit.Linear,
		Apply: func(p float64) { sp.Phase = p },
	})

	// A fake host loop: step 250ms per frame, quit when the driver goes idle.
	origin := time.Unix(0, 0)
	for frame := 0; ; frame++ {
		busy := d.Tick(origin.Add(time.Duration(frame) * 250 * time.Millisecond))
		fmt.Printf("frame %d phase=%.2f busy=%v\n", frame, sp.Phase, busy)
		if !busy {
			break
		}
	}
}
Output:
frame 0 phase=0.00 busy=true
frame 1 phase=0.25 busy=true
frame 2 phase=0.50 busy=true
frame 3 phase=0.75 busy=true
frame 4 phase=1.00 busy=false

func NewDriver

func NewDriver() *Driver

NewDriver returns an empty, ready-to-use Driver.

func (*Driver) Start

func (d *Driver) Start(a *Animation) *Handle

Start registers a to run and returns a Handle for cancelling it. The animation begins on the next Driver.Tick (that tick is progress 0). Start may grow the active set, but Driver.Tick itself never allocates.

func (*Driver) Tick

func (d *Driver) Tick(now time.Time) (busy bool)

Tick advances every active animation by the wall-clock delta since it started, calls each animation's Apply with the eased progress, fires OnEnd and removes any animation that has reached progress 1 (or was cancelled), and reports whether any animation remains active. When busy is false the active set is empty and the host may stop scheduling frames.

Tick performs no allocation: finished and cancelled entries are filtered in place, reusing the backing array.

func (*Driver) Tween

func (d *Driver) Tween(tw *toolkit.Tween, dur time.Duration, set func(v float64), onEnd func()) *Handle

Tween is a convenience over Driver.Start that animates a scalar from the tween's From to its To over dur, shaped by the tween's Ease, invoking set with each interpolated value and onEnd (if non-nil) once at the end. It reuses the toolkit's toolkit.Tween fields, making easing.go's Tween load-bearing here too. The integer Tween.Duration (tick-based) is ignored in favour of the wall-clock dur.

type Handle

type Handle struct {
	// contains filtered or unexported fields
}

Handle refers to a running animation so the caller can cancel it. It is returned by Driver.Start; a zero Handle is not useful on its own.

func (*Handle) Cancel

func (h *Handle) Cancel()

Cancel stops the animation before it completes. The next Driver.Tick drops it without a further Apply and without firing OnEnd. Cancelling an already-finished (or already-cancelled) animation is a harmless no-op.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL