@@ -17,12 +17,23 @@ import (
20− charCyclingFPS = time.Second / 22
20+ charCyclingFPS = time.Second / 8 // Reduced from 22 to 8 FPS for better CPU efficiency
21− colorCycleFPS = time.Second / 5
21+ colorCycleFPS = time.Second / 3 // Reduced from 5 to 3 FPS
22− maxCyclingChars = 120
22+ maxCyclingChars = 60 // Reduced from 120 to 60 characters
25−var charRunes = []rune("0123456789abcdefABCDEF~!@#$£€%^&*()+=_")
26+ charRunes = []rune("0123456789abcdefABCDEF~!@#$£€%^&*()+=_")
27+ charRunePool = make([]rune, 1000) // Pre-generated pool of random characters
32+ // Pre-populate the character pool to avoid runtime random generation
33+ for i := range charRunePool {
34+ charRunePool[i] = charRunes[rand.IntN(len(charRunes))]
27type charState int
38type charState int
@@ -41,7 +52,9 @@ type cyclingChar struct {
43func (c cyclingChar) randomRune() rune {
54func (c cyclingChar) randomRune() rune {
44− return (charRunes)[rand.IntN(len(charRunes))] //nolint:gosec
55+ // Use pre-generated pool instead of runtime random generation
56+ poolIndex = (poolIndex + 1) % len(charRunePool)
57+ return charRunePool[poolIndex]
47func (c cyclingChar) state(start time.Time) charState {
60func (c cyclingChar) state(start time.Time) charState {
@@ -126,14 +139,18 @@ func New(cyclingCharsSize uint, label string, opts ...animOption) Animation {
126 // color the cycling characters with a gradient ramp.
139 // color the cycling characters with a gradient ramp.
127 const minRampSize = 3
140 const minRampSize = 3
128 if n >= minRampSize {
141 if n >= minRampSize {
129− // Note: double capacity for color cycling as we'll need to reverse and
142+ // Optimized: single capacity allocation for color cycling
130− // append the ramp for seamless transitions.
131− c.ramp = make([]lipgloss.Style, n, n*2) //nolint:mnd
143+ c.ramp = make([]lipgloss.Style, 0, n*2)
132 ramp := makeGradientRamp(n)
144 ramp := makeGradientRamp(n)
133− for i, color := range ramp {
145+ for _, color := range ramp {
134− c.ramp[i] = lipgloss.NewStyle().Foreground(color)
146+ c.ramp = append(c.ramp, lipgloss.NewStyle().Foreground(color))
136− c.ramp = append(c.ramp, reverse(c.ramp)...) // reverse and append for color cycling
148+ // Create reversed copy for seamless color cycling
149+ reversed := make([]lipgloss.Style, len(c.ramp))
150+ for i, style := range c.ramp {
151+ reversed[len(c.ramp)-1-i] = style
153+ c.ramp = append(c.ramp, reversed...)
139 makeDelay := func(a int32, b time.Duration) time.Duration {
156 makeDelay := func(a int32, b time.Duration) time.Duration {
@@ -246,29 +263,28 @@ func (a anim) View() tea.View {
246 b strings.Builder
263 b strings.Builder
249− // Pre-allocate builder capacity to avoid reallocations.
266+ // Optimized capacity calculation to reduce allocations
250− // Estimate: cycling chars + label chars + ellipsis + style overhead.
252− bytesPerChar = 20 // ANSI styling
268+ bytesPerChar = 15 // Reduced estimate for ANSI styling
253− bufferSize = 50 // ellipsis and safety margin
269+ bufferSize = 30 // Reduced safety margin
255 estimatedCap := len(a.cyclingChars)*bytesPerChar + len(a.labelChars)*bytesPerChar + bufferSize
271 estimatedCap := len(a.cyclingChars)*bytesPerChar + len(a.labelChars)*bytesPerChar + bufferSize
256 b.Grow(estimatedCap)
272 b.Grow(estimatedCap)
274+ // Render cycling characters with gradient (if available)
258 for i, c := range a.cyclingChars {
275 for i, c := range a.cyclingChars {
259 if len(a.ramp) > i {
276 if len(a.ramp) > i {
260 b.WriteString(a.ramp[i].Render(string(c.currentValue)))
277 b.WriteString(a.ramp[i].Render(string(c.currentValue)))
261− continue
278+ } else {
279+ b.WriteRune(c.currentValue)
263− b.WriteRune(c.currentValue)
283+ // Render label characters and ellipsis
266 if len(a.labelChars) > 1 {
284 if len(a.labelChars) > 1 {
267 textStyle := t.S().Text
285 textStyle := t.S().Text
268 for _, c := range a.labelChars {
286 for _, c := range a.labelChars {
270− textStyle.Render(string(c.currentValue)),
287+ b.WriteString(textStyle.Render(string(c.currentValue)))
273 b.WriteString(textStyle.Render(a.ellipsis.View()))
289 b.WriteString(textStyle.Render(a.ellipsis.View()))
@@ -296,12 +312,3 @@ func makeGradientRamp(length int) []color.Color {
300−func reverse[T any](in []T) []T {
301− out := make([]T, len(in))
303− for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
304− out[i], out[j] = out[j], out[i]