animation

package
v1.118.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package animation provides centralized animation tick management for the TUI. All animated components (spinners, fades, etc.) share a single tick stream to avoid tick storms and ensure synchronized animations.

Thread safety: All exported functions are safe for concurrent use, though the typical usage pattern is single-threaded via Bubble Tea's Update loop.

Index

Constants

View Source
const (
	// MediumDuration is the canonical medium transition duration.
	MediumDuration = 500 * time.Millisecond

	// ShortDuration is the canonical short transition duration.
	ShortDuration = 350 * time.Millisecond

	// LoadingMinDuration is the minimum on-screen time for a loading
	// placeholder before it can be replaced with real content. Together with
	// MediumDuration and ShortDuration this ensures fast network responses still
	// produce a visually-pleasant transition rather than a jarring flash.
	LoadingMinDuration = 250 * time.Millisecond

	// DefaultSpinnerFrameDuration is the fallback cadence for catalog spinners
	// that do not need a specialized speed.
	DefaultSpinnerFrameDuration = 100 * time.Millisecond

	// ChatSpinnerFrameDuration is the default cadence for chat/tool activity
	// spinners.
	ChatSpinnerFrameDuration = 100 * time.Millisecond

	// CardSpinnerFrameDuration is the default cadence for compact activity
	// indicators.
	CardSpinnerFrameDuration = 125 * time.Millisecond

	// WaitingSpinnerFrameDuration is the default cadence for attention/waiting
	// indicators.
	WaitingSpinnerFrameDuration = 100 * time.Millisecond

	// SpinnerLightStepDuration is the default cadence for the loading text
	// highlight sweep in the reusable spinner component.
	SpinnerLightStepDuration = 100 * time.Millisecond

	// SpinnerLightPauseDuration is the default dwell before the loading text
	// highlight reverses direction.
	SpinnerLightPauseDuration = 600 * time.Millisecond
)

Canonical animation durations shared across the TUI. Keeping them together provides consistent pacing wherever content appears, expands, hides, or collapses.

Medium transitions remain visible without feeling sluggish, while short transitions keep dismissals responsive.

View Source
const TickRate = time.Second / 14

TickRate is the shared interval between animation ticks.

Variables

View Source
var (
	Chat    = NewSpinner(Frames{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, ChatSpinnerFrameDuration)
	TabBusy = NewSpinner(Frames{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, CardSpinnerFrameDuration)
	Card    = NewSpinner(Frames{"◓", "◑", "◒", "◐"}, CardSpinnerFrameDuration)
)

Functions

func EaseInOutCubic added in v1.118.0

func EaseInOutCubic(t float64) float64

EaseInOutCubic accelerates then decelerates symmetrically.

func EaseOutCubic added in v1.118.0

func EaseOutCubic(t float64) float64

EaseOutCubic decelerates toward the end — fast start, slow finish.

func EaseOutQuint added in v1.118.0

func EaseOutQuint(t float64) float64

EaseOutQuint decelerates more aggressively than cubic.

func HasActive

func HasActive() bool

func IsCurrentGen added in v1.118.0

func IsCurrentGen(msg TickMsg) bool

IsCurrentGen reports whether msg belongs to the package facade's current tick chain. It is a side-effect-free compatibility check; facade tick delivery, not this predicate, consumes the outstanding lease.

func Linear added in v1.118.0

func Linear(t float64) float64

Linear performs no easing — constant speed.

func Register

func Register()

Register, Unregister, HasActive, StartTick, and StartTickIfFirst preserve the original package-level API while components migrate to program ownership.

func StartTick

func StartTick() tea.Cmd

func StartTickIfFirst

func StartTickIfFirst() tea.Cmd

func StopView added in v1.75.0

func StopView(view any)

StopView stops the animation subscription of a view being removed, when it has one. Safe to call on any view.

func TimedStep added in v1.118.0

func TimedStep(elapsed, frameDuration time.Duration) int

func Unregister

func Unregister()

Types

type Coordinator

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

Coordinator is retained as a compatibility facade for callers that own an isolated coordinator. New code should use the animation Runtime.

func (*Coordinator) HasActive added in v1.89.0

func (c *Coordinator) HasActive() bool

func (*Coordinator) Register added in v1.89.0

func (c *Coordinator) Register()

func (*Coordinator) StartTick added in v1.89.0

func (c *Coordinator) StartTick() tea.Cmd

func (*Coordinator) StartTickIfFirst added in v1.89.0

func (c *Coordinator) StartTickIfFirst() tea.Cmd

func (*Coordinator) Unregister added in v1.89.0

func (c *Coordinator) Unregister()

type EasingFunc added in v1.118.0

type EasingFunc func(t float64) float64

EasingFunc maps a linear progress value in [0,1] to an eased value in [0,1].

type Frames added in v1.118.0

type Frames []string

Frames is an ordered set of spinner characters.

func (Frames) TimedFrame added in v1.118.0

func (f Frames) TimedFrame(elapsed, frameDuration time.Duration) string

func (Frames) TimedFrameIndex added in v1.118.0

func (f Frames) TimedFrameIndex(elapsed, frameDuration time.Duration) int

type Runtime added in v1.118.0

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

func NewRuntime added in v1.118.0

func NewRuntime() *Runtime

NewRuntime creates an isolated program-scoped animation runtime.

func NewRuntimeWithScheduler added in v1.118.0

func NewRuntimeWithScheduler(s Scheduler) *Runtime

NewRuntimeWithScheduler creates a runtime using the supplied production scheduling boundary. Tick creation, leases, and acceptance remain owned by Runtime; only time acquisition and delayed delivery are delegated.

func NewSnapshotRuntime added in v1.118.0

func NewSnapshotRuntime(elapsed time.Duration) *Runtime

NewSnapshotRuntime renders at a fixed elapsed time and is used by the lean TUI for its current frame.

func (*Runtime) Accept added in v1.118.0

func (r *Runtime) Accept(msg TickMsg) (TickMsg, bool)

Accept consumes this animation runtime's current tick lease and advances its clock.

func (*Runtime) ActiveCount added in v1.118.0

func (r *Runtime) ActiveCount() int32

ActiveCount returns this animation runtime's active animation count.

func (*Runtime) Continue added in v1.118.0

func (r *Runtime) Continue() tea.Cmd

Continue schedules the next tick when animations remain active. The root calls it exactly once after fanout of an accepted TickMsg.

func (*Runtime) EnsureRunning added in v1.118.0

func (r *Runtime) EnsureRunning() tea.Cmd

EnsureRunning replaces a potentially lost outstanding tick command.

func (*Runtime) HasActive added in v1.118.0

func (r *Runtime) HasActive() bool

HasActive reports whether this animation runtime has active animations.

func (*Runtime) Now added in v1.118.0

func (r *Runtime) Now() time.Duration

Now returns elapsed time accepted by this animation runtime.

func (*Runtime) Register added in v1.118.0

func (r *Runtime) Register()

Register increments this animation runtime's active animation count.

func (*Runtime) Stop added in v1.118.0

func (r *Runtime) Stop()

Stop invalidates all queued ticks and releases every registration owned by this program. Program teardown calls it after component cleanup as a final ownership boundary; a late queued TickMsg can then never revive the chain.

func (*Runtime) Subscribe added in v1.118.0

func (r *Runtime) Subscribe() Subscription

Subscribe creates an inactive subscription owned by this animation runtime.

func (*Runtime) Transition added in v1.118.0

func (r *Runtime) Transition() Transition

Transition creates an idle transition owned by this animation runtime.

func (*Runtime) Unregister added in v1.118.0

func (r *Runtime) Unregister()

Unregister decrements this animation runtime's active animation count.

type Scheduler added in v1.118.0

type Scheduler interface {
	Now() time.Time
	Tick(delay time.Duration, createMsg func(time.Time) tea.Msg) tea.Cmd
}

Scheduler provides the wall clock and delayed message delivery used by a runtime. Embedders may supply a deterministic scheduler while preserving the exact production tick lease and acceptance path.

type Spinner added in v1.118.0

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

Spinner is an ordered animation with a default wall-clock cadence.

func NewSpinner added in v1.118.0

func NewSpinner(frames Frames, frameDuration time.Duration) Spinner

NewSpinner creates a duration-aware spinner from raw frames.

func (Spinner) DefaultFrameDuration added in v1.118.0

func (s Spinner) DefaultFrameDuration() time.Duration

func (Spinner) FrameAt added in v1.118.0

func (s Spinner) FrameAt(elapsed time.Duration) string

func (Spinner) FrameEveryAt added in v1.118.0

func (s Spinner) FrameEveryAt(elapsed, frameDuration time.Duration) string

func (Spinner) FrameIndexAt added in v1.118.0

func (s Spinner) FrameIndexAt(elapsed time.Duration) int

func (Spinner) FrameIndexEveryAt added in v1.118.0

func (s Spinner) FrameIndexEveryAt(elapsed, frameDuration time.Duration) int

func (Spinner) Frames added in v1.118.0

func (s Spinner) Frames() Frames

func (Spinner) Len added in v1.118.0

func (s Spinner) Len() int

func (Spinner) StepAt added in v1.118.0

func (s Spinner) StepAt(elapsed time.Duration) int

func (Spinner) StepEveryAt added in v1.118.0

func (s Spinner) StepEveryAt(elapsed, frameDuration time.Duration) int

type Stopper added in v1.75.0

type Stopper interface {
	StopAnimation()
}

Stopper is implemented by views that register with the animation coordinator. When such a view is removed from the UI, StopAnimation must be called to unregister its subscription; a leaked subscription keeps the tick stream alive forever.

type Subscription

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

Subscription represents a component's subscription to animation ticks. It encapsulates the registration/unregistration lifecycle, making it easier to manage animation state correctly.

Usage:

type MyComponent struct {
    animSub animation.Subscription
}

func (m *MyComponent) Init() tea.Cmd {
    return m.animSub.Start()
}

func (m *MyComponent) Cleanup() {
    m.animSub.Stop()
}

func NewSubscription added in v1.118.0

func NewSubscription(ar *Runtime) Subscription

NewSubscription returns an inactive subscription owned by an animation runtime.

func (*Subscription) IsActive

func (s *Subscription) IsActive() bool

IsActive returns whether the subscription is currently active.

func (*Subscription) Reset

func (s *Subscription) Reset() Subscription

Reset returns a new inactive subscription. Useful when recreating a component that needs fresh animation state.

func (*Subscription) SetRuntime added in v1.118.0

func (s *Subscription) SetRuntime(ar *Runtime)

SetRuntime binds an inactive subscription to a program's animation runtime.

func (*Subscription) Start

func (s *Subscription) Start() tea.Cmd

Start activates the subscription if not already active. Returns a command to start the tick if this is the first subscription. Safe to call multiple times - only the first call registers.

func (*Subscription) Stop

func (s *Subscription) Stop()

Stop deactivates the subscription if currently active. Safe to call multiple times - only the first call unregisters.

type TickMsg

type TickMsg struct {
	// Frame is retained for compatibility with components that have not yet
	// adopted elapsed-time animation. Program runtimes use their accepted tick
	// count; legacy standalone ticks use the compatibility coordinator count.
	Frame int
	// contains filtered or unexported fields
}

TickMsg is broadcast to all animated components on each animation frame. Components should handle this message to update their animation state.

func (TickMsg) Dirty added in v1.118.0

func (m TickMsg) Dirty() bool

Dirty reports whether any visible component marked this accepted tick dirty.

func (TickMsg) ElapsedBounds added in v1.118.0

func (m TickMsg) ElapsedBounds() (time.Duration, time.Duration)

ElapsedBounds returns the animation clock immediately before and after this accepted tick.

func (TickMsg) MarkDirty added in v1.118.0

func (m TickMsg) MarkDirty()

MarkDirty records that this accepted tick changed visible output. TickMsg copies share the marker, so root can decide after complete fanout whether a new view must be composed.

type Transition added in v1.118.0

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

func NewTransition added in v1.118.0

func NewTransition(ar *Runtime) Transition

NewTransition returns an idle transition owned by an animation runtime.

func (*Transition) Cancel added in v1.118.0

func (tr *Transition) Cancel()

Cancel stops the transition immediately and unregisters from the coordinator. Safe to call when not running.

func (*Transition) Duration added in v1.118.0

func (tr *Transition) Duration() time.Duration

Duration returns the configured transition duration.

func (*Transition) Elapsed added in v1.118.0

func (tr *Transition) Elapsed() time.Duration

Elapsed returns the elapsed time within the transition.

func (*Transition) Lerp added in v1.118.0

func (tr *Transition) Lerp(from, to int) int

Lerp returns the linearly-interpolated value between from and to at the current eased progress: from + (to-from) * Value().

func (*Transition) Progress added in v1.118.0

func (tr *Transition) Progress() float64

Progress returns the linear progress in [0, 1].

func (*Transition) Running added in v1.118.0

func (tr *Transition) Running() bool

Running reports whether the transition is in progress.

func (*Transition) SetRuntime added in v1.118.0

func (tr *Transition) SetRuntime(ar *Runtime)

SetRuntime binds an idle transition to a program's animation runtime.

func (*Transition) Start added in v1.118.0

func (tr *Transition) Start(duration time.Duration, fn EasingFunc) tea.Cmd

Start begins the transition over the given duration using the provided easing function. If a transition is already running it is replaced without re-registering. Returns a command to start the tick chain when this is the first registration.

func (*Transition) Tick added in v1.118.0

func (tr *Transition) Tick()

Tick samples the animation-runtime-owned clock. When the transition completes it stops automatically and unregisters from the coordinator.

func (*Transition) Value added in v1.118.0

func (tr *Transition) Value() float64

Value returns the eased progress in [0, 1]. Returns 0 before Start, and 1 after the transition completes.

Jump to

Keyboard shortcuts

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