diff --git a/options.go b/options.go index 30f7e6c..249d3bf 100644 --- a/options.go +++ b/options.go @@ -200,3 +200,12 @@ func WithFilter(filter func(Model, Msg) Msg) ProgramOption { p.filter = filter } } + +// WithMaxFPS sets a custom maximum FPS at which the renderer should run. If +// less than 1, the default value of 60 will be used. If over 120, the FPS +// will be capped at 120. +func WithFPS(fps int) ProgramOption { + return func(p *Program) { + p.fps = fps + } +} diff --git a/standard_renderer.go b/standard_renderer.go index 0ab9473..c6a1b61 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -16,7 +16,8 @@ import ( const ( // defaultFramerate specifies the maximum interval at which we should // update the view. - defaultFramerate = time.Second / 60 + defaultFPS = 60 + maxFPS = 120 ) // standardRenderer is a framerate-based terminal renderer, updating the view @@ -54,12 +55,17 @@ type standardRenderer struct { // newRenderer creates a new renderer. Normally you'll want to initialize it // with os.Stdout as the first argument. -func newRenderer(out *termenv.Output, useANSICompressor bool) renderer { +func newRenderer(out *termenv.Output, useANSICompressor bool, fps int) renderer { + if fps < 1 { + fps = defaultFPS + } else if fps > maxFPS { + fps = maxFPS + } r := &standardRenderer{ out: out, mtx: &sync.Mutex{}, done: make(chan struct{}), - framerate: defaultFramerate, + framerate: time.Second / time.Duration(fps), useANSICompressor: useANSICompressor, queuedMessageLines: []string{}, } diff --git a/tea.go b/tea.go index 2e024ed..c1d8caf 100644 --- a/tea.go +++ b/tea.go @@ -144,6 +144,10 @@ type Program struct { windowsStdin *os.File //nolint:golint,structcheck,unused filter func(Model, Msg) Msg + + // fps is the frames per second we should set on the renderer, if + // applicable, + fps int } // Quit is a special command that tells the Bubble Tea program to exit. @@ -445,7 +449,7 @@ func (p *Program) Run() (Model, error) { // If no renderer is set use the standard one. if p.renderer == nil { - p.renderer = newRenderer(p.output, p.startupOptions.has(withANSICompressor)) + p.renderer = newRenderer(p.output, p.startupOptions.has(withANSICompressor), p.fps) } // Check if output is a TTY before entering raw mode, hiding the cursor and