@@ -17,12 +17,23 @@ import (
1717)
1818
1919const (
20− charCyclingFPS = time.Second / 22
21− colorCycleFPS = time.Second / 5
22− maxCyclingChars = 120
20+ charCyclingFPS = time.Second / 8 // Reduced from 22 to 8 FPS for better CPU efficiency
21+ colorCycleFPS = time.Second / 3 // Reduced from 5 to 3 FPS
22+ maxCyclingChars = 60 // Reduced from 120 to 60 characters
2323)
2424
25−var charRunes = []rune("0123456789abcdefABCDEF~!@#$£€%^&*()+=_")
25+var (
26+ charRunes = []rune("0123456789abcdefABCDEF~!@#$£€%^&*()+=_")
27+ charRunePool = make([]rune, 1000) // Pre-generated pool of random characters
28+ poolIndex = 0
29+)
30+
31+func init() {
32+ // Pre-populate the character pool to avoid runtime random generation
33+ for i := range charRunePool {
34+ charRunePool[i] = charRunes[rand.IntN(len(charRunes))]
35+ }
36+}
2637
2738type charState int
2839
@@ -41,7 +52,9 @@ type cyclingChar struct {
4152}
4253
4354func (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]
4558}
4659
4760func (c cyclingChar) state(start time.Time) charState {
@@ -126,14 +139,18 @@ func New(cyclingCharsSize uint, label string, opts ...animOption) Animation {
126139 // color the cycling characters with a gradient ramp.
127140 const minRampSize = 3
128141 if n >= minRampSize {
129− // Note: double capacity for color cycling as we'll need to reverse and
130− // append the ramp for seamless transitions.
131− c.ramp = make([]lipgloss.Style, n, n*2) //nolint:mnd
142+ // Optimized: single capacity allocation for color cycling
143+ c.ramp = make([]lipgloss.Style, 0, n*2)
132144 ramp := makeGradientRamp(n)
133− for i, color := range ramp {
134− c.ramp[i] = lipgloss.NewStyle().Foreground(color)
145+ for _, color := range ramp {
146+ c.ramp = append(c.ramp, lipgloss.NewStyle().Foreground(color))
135147 }
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
152+ }
153+ c.ramp = append(c.ramp, reversed...)
137154 }
138155
139156 makeDelay := func(a int32, b time.Duration) time.Duration {
@@ -246,29 +263,28 @@ func (a anim) View() tea.View {
246263 b strings.Builder
247264 )
248265
249− // Pre-allocate builder capacity to avoid reallocations.
250− // Estimate: cycling chars + label chars + ellipsis + style overhead.
266+ // Optimized capacity calculation to reduce allocations
251267 const (
252− bytesPerChar = 20 // ANSI styling
253− bufferSize = 50 // ellipsis and safety margin
268+ bytesPerChar = 15 // Reduced estimate for ANSI styling
269+ bufferSize = 30 // Reduced safety margin
254270 )
255271 estimatedCap := len(a.cyclingChars)*bytesPerChar + len(a.labelChars)*bytesPerChar + bufferSize
256272 b.Grow(estimatedCap)
257273
274+ // Render cycling characters with gradient (if available)
258275 for i, c := range a.cyclingChars {
259276 if len(a.ramp) > i {
260277 b.WriteString(a.ramp[i].Render(string(c.currentValue)))
261− continue
278+ } else {
279+ b.WriteRune(c.currentValue)
262280 }
263− b.WriteRune(c.currentValue)
264281 }
265282
283+ // Render label characters and ellipsis
266284 if len(a.labelChars) > 1 {
267285 textStyle := t.S().Text
268286 for _, c := range a.labelChars {
269− b.WriteString(
270− textStyle.Render(string(c.currentValue)),
271− )
287+ b.WriteString(textStyle.Render(string(c.currentValue)))
272288 }
273289 b.WriteString(textStyle.Render(a.ellipsis.View()))
274290 }
@@ -296,12 +312,3 @@ func makeGradientRamp(length int) []color.Color {
296312 }
297313 return c
298314}
299−
300−func reverse[T any](in []T) []T {
301− out := make([]T, len(in))
302− copy(out, 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]
305− }
306− return out
307−}