Skip to content

terminal-pilot: joined emoji leaves stale cells after absolute-position redraw #629

Description

@kamilio

Summary

terminal-pilot treats a joined emoji as multiple terminal cells rather than one
two-column grapheme. Absolute-position incremental redraw then leaves stale
emoji components and shifts following text. This affects read-screen as well
as screenshots, so it is not only a missing-font rendering issue.

Reproduced September 5, 2026 on Linux, Node 22.22.0, terminal-pilot 0.0.1.
The reproduction uses only Node stdout/stdin and ANSI, without Toolcraft or
application UI components.

Reproduce

Save this as /tmp/emoji-redraw.mjs:

process.stdout.write("\x1b[2J\x1b[H|A👩‍💻B|\r\n|A🚀B|\r\n");
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on("data", (chunk) => {
  if (chunk.includes(0x12)) process.stdout.write("\x1b[1;3H  \x1b[2;3H  ");
  if (chunk.includes(0x03)) {
    process.stdin.setRawMode(false);
    process.stdin.pause();
  }
});
terminal-pilot create-session --session emoji-redraw --cwd /tmp --cols 64 --rows 12 node /tmp/emoji-redraw.mjs
terminal-pilot press-key Control+r --session emoji-redraw
terminal-pilot read-screen --session emoji-redraw --output json
terminal-pilot screenshot --session emoji-redraw -o /tmp/emoji-redraw.png
terminal-pilot close-session --session emoji-redraw

Both emoji should occupy two columns. Writing two spaces at column 3 should
therefore leave both rows as |A B|.

Actual read-screen rows:

["|A  ‍💻 B|", "|A  B|"]

The first row retains U+200D and U+1F4BB, with B| shifted right. The single
code-point rocket control behaves correctly. The PNG also retains the laptop
component (shown as a missing-font box with the installed font).

Impact and suggested coverage

Grapheme-aware TUI editors erase the correct two cells, but terminal-pilot shows
leftover text and displaced borders. This produces false layout and deletion
failures during terminal QA. No application output workaround should be needed.

Please cover joined emoji, variation selectors, flags, and combining sequences
in the emulator, including graphemes split across writes and absolute-position
overwrites of wide cells. Assert identical final cells for full-frame output
and incremental redraw, then verify screenshot geometry separately from font
fallback support. Local QA evidence includes an executable
reproduction plus visually inspected before/after PNGs.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions