Skip to content

feat(flterm): render Kitty Unicode placements - #152

Draft
elias8 wants to merge 2 commits into
mainfrom
feat/kitty-unicode-placement
Draft

feat(flterm): render Kitty Unicode placements#152
elias8 wants to merge 2 commits into
mainfrom
feat/kitty-unicode-placement

Conversation

@elias8

@elias8 elias8 commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Resolves #125

Expose Kitty Unicode placement iteration through libghostty bindings and render resolved occurrences in flterm while suppressing protocol placeholder glyphs and preserving image generation matching.

Blocked by ghostty-org/ghostty#13523

@elias8 elias8 added pkg:libghostty Core Dart bindings package pkg:flterm Flutter terminal widget package feat New feature or request labels Aug 20, 2026
adonm added a commit to adonm/zuko that referenced this pull request Sep 3, 2026
Yazi image previews stay tofu for a precise reason, now evidenced: yazi
transmits quietly (q=2) with U=1 and writes U+10EEEE placeholder cells
instead of an explicit placement. The core stores the image and exposes
the virtual placement, but flterm skips every non-viewport-visible
placement — which virtual ones always are — so nothing paints. Plain a=T
+ a=p painting was proven working pixel-level in the process (earlier
zero-pixel readings were a test-harness artifact: engine decode needs
real-loop yields, fixed in the yazi capture settle). The repro covers the
yazi path exactly and is skipped until flterm renders virtual placements
(upstream elias8/libghostty#152 / ghostty-org/ghostty#13523).
@adonm

adonm commented Sep 3, 2026

Copy link
Copy Markdown

Reproduced the yazi path end to end against 0.0.5/0.0.12 and can confirm the diagnosis: yazi sends q=2,a=T,C=1,U=1,… plus U+10EEEE placeholder cells (id in fg color) and never sends a=p. KittyGraphics.placements() yields the isVirtual entry and image() returns decoded RGBA — but viewportVisible is always false for virtual placements, so KittyPlacementCache.sync skips them and previews stay visible as tofu.

I verified plain a=T + a=p painting works pixel-level (DPR scaling, alt screen, chunked transmits all paint), so this is U=1-specific.

Workaround I landed in a fork ( opportunistic, no new C API needed): resolve placeholder runs from grid content — maximal same-id rectangles via GridRef codepoint + truecolor fg, screen-space rects converted with the viewport offset — into paint snapshots with the virtual placement's z-index, and return null for U+10EEEE in CellContentResolver.resolveCell (kitty proper hides placeholders too). Branch: adonm/libghostty zuko/kitty-unicode-placeholders (based on the 0.0.5 source commit 492d380), with fork-side cache tests (resolve/erase/unknown-id) and a pixel-level widget test proving yazi-style U=1 paints. Happy to PR it if useful before #13523 lands.

Two harnesses notes that cost me time: (1) image decode completes via a native callback, so widget-test captures need real-loop yields (runAsync) plus a post-decode pump — fake-async pumps alone capture pre-decode frames; (2) placeholder cells are non-BMP, so test bytes must be utf8.encoded — Dart string .codeUnits are UTF-16 and arrive as U+FFFD, which the resolver correctly ignores.

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

Labels

feat New feature or request pkg:flterm Flutter terminal widget package pkg:libghostty Core Dart bindings package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(flterm) ? yazi and android inputs

2 participants