Skip to content

tui: settings dialog shows Animations as off while animations are enabled by default #52577

Open

Description

@UlturCat

Description

/settings → Appearance → Animations shows off when the key is absent from
cli.json, but animations actually run. The dialog resolves value ?? registry.default,
while every runtime read falls back to true:

registry:  {title:"Animations", path:["animations"], default: false}   -> dialog shows off
runtime:   config.animations ?? true                                   (7 reads)
toggle:    (data.animations ?? true) ? "Disable animations" : "Enable animations"

Other settings match their registry default (session.scrollbar -> ?? false,
mouse -> ?? true, session.thinking -> ?? "hide", scroll.speed -> 3);
animations is the only mismatch.

Consistently reproducible. Writing animations: true explicitly makes the dialog
truthful — that's the workaround I'm using.

Plugins

None

OpenCode version

v2.0.21

Steps to reproduce

  1. Leave animations unset in ~/.config/opencode/cli.json
  2. Open /settings → Appearance → Animations shows off
  3. Tool spinners still animate (⠋⠙⠹…) and app.toggle.animations offers "Disable animations"

Operating System

Fedora Linux 44 — kernel 7.2.7-200.fc44.x86_64

Terminal

Ptyxis (TERM=xterm-256color, COLORTERM=truecolor)

Activity

  1. github-actions commented on Oct 1, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of or related to existing issues. Please check:

    • #39368: Requests persistent TUI animation controls, including an option to disable animations.
    • #42306: Reports TUI spinner animations continuing to redraw and causing high CPU usage.
  2. aihaipeng commented on Oct 5, 2026

    @aihaipeng

    @simonklee I've submitted #53293 to fix the animation setting default mismatch reported in this issue.

  3. opencodejr commented on Oct 28, 2026

    @opencodejr
    Contributor

    Thanks for the clear report. I reproduced this on 2.0.21, and it still happens on the latest dev (891a020bc).

    With no animations key in cli.json, /settings → Appearance → Animations shows off. After closing the dialog and sending a prompt, the spinner still animates: the two spinner screenshots below are 300 ms apart and show different frames. The recording below shows the whole sequence, and the script below reproduces it.

    The cause matches what you found: the settings registry entry has default: false, while every runtime read falls back to ?? true. Until it's fixed, setting "animations": true explicitly, as you're doing, makes the dialog show the right value.

    recording.mp4

    Screenshot

    Screenshot

    Screenshot

    Reproduction script (drive.ts)
    // Repro for #52577: with `animations` unset in cli.json, /settings shows Animations "off"
    // while spinners still animate (runtime reads use `config.animations ?? true`).
    import { Effect } from "effect"
    import { Llm, OpenCodeDriver } from "opencode-drive"
    
    export default OpenCodeDriver.use(
      {
        ...(process.env.OC_DEV ? { opencode: { dev: process.env.OC_DEV } } : {}),
        tui: { recording: true, keypressOverlay: true },
      },
      ({ ui, llm }) =>
        Effect.gen(function* () {
          yield* Effect.sleep(1500)
          // Settings dialog: Animations row uses registry default (false)
          yield* ui.type("/settings")
          yield* Effect.sleep(500)
          yield* ui.press("return")
          yield* Effect.sleep(1000)
          yield* ui.type("animations")
          yield* Effect.sleep(1000)
          yield* ui.screenshot("settings-animations")
          yield* Effect.sleep(1000)
          yield* ui.press("escape")
          yield* Effect.sleep(500)
          // Animations are actually running: the working spinner animates while the model is busy
          yield* llm.queue(Llm.pause(5000), Llm.text("Done."))
          yield* ui.submit("hello")
          yield* Effect.sleep(1500)
          yield* ui.screenshot("spinner-1")
          yield* Effect.sleep(300)
          yield* ui.screenshot("spinner-2")
          yield* ui.waitFor("Done.")
          yield* Effect.sleep(1000)
        }),
    )

    Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions