Skip to content

Terminal renders CJK (Japanese/Chinese/Korean) text as black boxes — WebGL renderer + Latin-only fontFamily #822

@mhit

Description

@mhit

Describe the bug

In the built-in terminal (Shell view), CJK characters (Japanese / Chinese / Korean)
are frequently rendered as solid black boxes (□ "tofu") instead of the real glyphs.

The same Japanese text renders correctly everywhere else in the app (chat panel,
sidebar, etc.), so this is specific to the xterm.js terminal — not the OS fonts.

The breakage is per-glyph / intermittent: most CJK in a line renders, but common
kana/kanji (e.g. ク, レ, 差, 正) randomly turn into boxes. That pattern is the
signature of a font-fallback / glyph-atlas problem in the WebGL renderer, not of
missing OS fonts (a real coverage gap would drop all CJK, not a random subset).

Steps to reproduce

  1. Open the terminal and run a command that prints CJK, e.g. echo 日本語テスト 中文 한국어
    (or run any CLI that emits Japanese/Chinese/Korean output).
  2. Some CJK characters render as solid black boxes.

Screenshots

Image

Environment

  • claudecodeui: main, self-hosted
  • Browser: Brave (Chromium) on Linux / Wayland
  • OS CJK fonts installed (noto-fonts-cjk); identical text renders fine in the
    non-terminal UI, confirming the OS has the glyphs.

Root cause (from source)

Two compounding issues under src/components/shell/:

  1. fontFamily has no CJK fontsrc/components/shell/constants/constants.ts:

    export const TERMINAL_OPTIONS: ITerminalOptions = {
      // ...
      fontFamily: 'Menlo, Monaco, "Courier New", monospace',
      // ...
    };

    Menlo / Monaco / Courier New have no CJK coverage, so CJK can only come from the
    generic monospace fallback.

  2. WebGL renderer is loaded unconditionallysrc/components/shell/hooks/useShellTerminal.ts:

    try {
      nextTerminal.loadAddon(new WebglAddon());
    } catch {
      console.warn('[Shell] WebGL renderer unavailable, using Canvas fallback');
    }
    The xterm.js WebGL (and canvas) renderer rasterizes glyphs into a texture atlas and
    handles *fallback* glyphs (those not in the specified fonts) poorly  CJK obtained
    via the generic `monospace` fallback frequently comes out as the missing-glyph box.
    The DOM renderer doesn't have this issue because it uses native browser text
    rendering / font fallback.

Suggested fix

  • Minimal: add cross-platform CJK monospace fonts to TERMINAL_OPTIONS.fontFamily,
    giving the atlas an explicit CJK font to rasterize from:
    fontFamily:
      'Menlo, Monaco, "Courier New", "Noto Sans Mono CJK JP", "Noto Sans CJK JP", ' +
      'Meiryo, "MS Gothic", "Microsoft YaHei", "PingFang SC", "Hiragino Sans", monospace',
  • Robust: make fontFamily user-configurable (relates to Feature/font customization #730) and/or expose an
    option to disable the WebGL addon (fall back to the DOM renderer), which renders CJK
    reliably even with an imperfect font stack.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions