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
- Variables
- func EaseInOutCubic(t float64) float64
- func EaseOutCubic(t float64) float64
- func EaseOutQuint(t float64) float64
- func HasActive() bool
- func IsCurrentGen(msg TickMsg) bool
- func Linear(t float64) float64
- func Register()
- func StartTick() tea.Cmd
- func StartTickIfFirst() tea.Cmd
- func StopView(view any)
- func TimedStep(elapsed, frameDuration time.Duration) int
- func Unregister()
- type Coordinator
- type EasingFunc
- type Frames
- type Runtime
- func (r *Runtime) Accept(msg TickMsg) (TickMsg, bool)
- func (r *Runtime) ActiveCount() int32
- func (r *Runtime) Continue() tea.Cmd
- func (r *Runtime) EnsureRunning() tea.Cmd
- func (r *Runtime) HasActive() bool
- func (r *Runtime) Now() time.Duration
- func (r *Runtime) Register()
- func (r *Runtime) Stop()
- func (r *Runtime) Subscribe() Subscription
- func (r *Runtime) Transition() Transition
- func (r *Runtime) Unregister()
- type Scheduler
- type Spinner
- func (s Spinner) DefaultFrameDuration() time.Duration
- func (s Spinner) FrameAt(elapsed time.Duration) string
- func (s Spinner) FrameEveryAt(elapsed, frameDuration time.Duration) string
- func (s Spinner) FrameIndexAt(elapsed time.Duration) int
- func (s Spinner) FrameIndexEveryAt(elapsed, frameDuration time.Duration) int
- func (s Spinner) Frames() Frames
- func (s Spinner) Len() int
- func (s Spinner) StepAt(elapsed time.Duration) int
- func (s Spinner) StepEveryAt(elapsed, frameDuration time.Duration) int
- type Stopper
- type Subscription
- type TickMsg
- type Transition
- func (tr *Transition) Cancel()
- func (tr *Transition) Duration() time.Duration
- func (tr *Transition) Elapsed() time.Duration
- func (tr *Transition) Lerp(from, to int) int
- func (tr *Transition) Progress() float64
- func (tr *Transition) Running() bool
- func (tr *Transition) SetRuntime(ar *Runtime)
- func (tr *Transition) Start(duration time.Duration, fn EasingFunc) tea.Cmd
- func (tr *Transition) Tick()
- func (tr *Transition) Value() float64
Constants ¶
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.
const TickRate = time.Second / 14
TickRate is the shared interval between animation ticks.
Variables ¶
var ( Chat = NewSpinner(Frames{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, ChatSpinnerFrameDuration) TabBusy = NewSpinner(Frames{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, CardSpinnerFrameDuration) Card = NewSpinner(Frames{"◓", "◑", "◒", "◐"}, CardSpinnerFrameDuration) )
Functions ¶
func EaseInOutCubic ¶ added in v1.118.0
EaseInOutCubic accelerates then decelerates symmetrically.
func EaseOutCubic ¶ added in v1.118.0
EaseOutCubic decelerates toward the end — fast start, slow finish.
func EaseOutQuint ¶ added in v1.118.0
EaseOutQuint decelerates more aggressively than cubic.
func IsCurrentGen ¶ added in v1.118.0
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 Register ¶
func Register()
Register, Unregister, HasActive, StartTick, and StartTickIfFirst preserve the original package-level API while components migrate to program ownership.
func StartTickIfFirst ¶
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 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
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
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
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
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
Accept consumes this animation runtime's current tick lease and advances its clock.
func (*Runtime) ActiveCount ¶ added in v1.118.0
ActiveCount returns this animation runtime's active animation count.
func (*Runtime) Continue ¶ added in v1.118.0
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
EnsureRunning replaces a potentially lost outstanding tick command.
func (*Runtime) HasActive ¶ added in v1.118.0
HasActive reports whether this animation runtime has active animations.
func (*Runtime) Now ¶ added in v1.118.0
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
NewSpinner creates a duration-aware spinner from raw frames.
func (Spinner) DefaultFrameDuration ¶ added in v1.118.0
func (Spinner) FrameEveryAt ¶ added in v1.118.0
func (Spinner) FrameIndexAt ¶ added in v1.118.0
func (Spinner) FrameIndexEveryAt ¶ added in v1.118.0
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
Dirty reports whether any visible component marked this accepted tick dirty.
func (TickMsg) ElapsedBounds ¶ added in v1.118.0
ElapsedBounds returns the animation clock immediately before and after this accepted tick.
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.