Skip to content

Fix terminal flickering — raw ANSI escape codes bypass Ink render system #254

Closed

Description

@bradygaster

Problem

Users report terminal flickering when using Copilot CLI + Squad (Discussion #170). After audit, this is a Squad code issue, not a Copilot CLI platform problem.

Squad writes raw ANSI escape codes directly to process.stdout while Ink (React-based terminal UI) expects exclusive terminal access. This corrupts Ink's internal screen state and forces costly re-renders.

Findings

Critical (direct flicker causes)

Location Code Impact
shell/index.ts:1142 \x1b[2J\x1b[3J\x1b[H Full screen + scrollback clear BEFORE Ink renders = visible blackout on every squad shell start
shell/index.ts:1131 \x1b[2J\x1b[3J\x1b[H Same clear on /resume while Ink is actively rendering
commands/rc.ts:290 \r... rapid writes Carriage returns bypass Ink's render buffer

Compounding factors

Location Issue
useAnimation.ts:33 67ms typewriter interval (15fps) + multiple independent setInterval() timers = 60-120 uncoordinated re-renders/sec
commands.ts:110 /clear writes ANSI directly, bypassing Ink
Multiple *.tsx components Independent animation timers not synchronized with each other or Ink's render cycle

Fix Approach

  1. Remove direct ANSI writes — replace process.stdout.write('\x1b[...') with Ink-native clearing (clearOutput() or state reset)
  2. Coordinate animation timers — consolidate intervals, use Ink's useInput/useStdout hooks instead of raw setInterval
  3. Reduce typewriter FPS — 67ms (15fps) is aggressive. 200ms (5fps) would reduce render pressure significantly
  4. Gate screen clears — only clear when Ink is NOT actively rendering, or use Ink's built-in clear

References

Activity

  1. github-actions commented on Mar 7, 2026

    @github-actions
    Contributor

    📋 Assigned to Fenster (Core Dev)

    Issue: #254 — Fix terminal flickering — raw ANSI escape codes bypass Ink render system

    Fenster will pick this up in the next Copilot session.

    For Copilot coding agent: If enabled, this issue will be worked automatically.
    Otherwise, start a Copilot session and say:
    Fenster, work on issue #254

  2. bradygaster commented on Mar 7, 2026

    @bradygaster
    CollaboratorAuthor

    ✅ Fix in progress on branch squad/254-fix-terminal-flicker.

    Root cause: raw ANSI escape codes (\x1b[2J\x1b[3J\x1b[H) written directly to process.stdout while Ink expected exclusive terminal access, causing render state corruption.

    What was fixed:

    • Removed 3 raw ANSI screen clears from shell/index.ts (lines 1131, 1142, 1212)
    • Reduced animation FPS from 15fps (67ms) to 5fps (200ms) in useAnimation.ts
    • Consolidated 4 component timers (AgentPanel, InputPrompt, MessageStream, ThinkingIndicator) to use shared FRAME_MS constant
    • Fixed rc.ts raw stdout write pattern

    Tests: 26 regression tests in test/flicker-fix.test.ts (22 passing, 4 skipped pending integration). Validates FRAME_MS throttling, ANSI removal, NO_COLOR handling.

    Community reporters @Gareth064 and @diberry — thank you for surfacing this (Discussion #170). Your feedback drove the fix.

    — Fenster 🔧 & Hockney 🧪

  3. added a commit that references this issue on Mar 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions