tui: image rendering pipeline — Kitty output, caching, and multi-backend groundwork #110
Labels
No labels
area:agents
area:ai
area:config
area:dashboard
area:design
area:design-review
area:devtools
area:entities
area:gallery
area:generate
area:image
area:infra
area:meta
area:model-browser
area:navigation
area:presets
area:security
area:sessions
area:settings
area:sharing
area:test
area:ux
area:webhook
area:workdir
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/loom#110
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As a user running loom-tui in Kitty (or any graphics-capable terminal), I want generated images to render correctly and efficiently in gallery detail view, generate preview, and entity reference images, so that the TUI is a viable alternative to the GTK frontend for browsing and reviewing images.
Problem
Images are currently broken in gallery detail view despite the Kitty renderer being detected. Root causes identified:
1. Output ordering (partially fixed)
The Kitty renderer was writing escape sequences directly to
stdoutinside the ratatuiterminal.draw()closure. ratatui buffers its own output and flushes after the closure returns, so Kitty commands were interleaved with TUI content.Status: The deferred output buffer (
pending_output+flush_pending()) was merged in the test harness PR, but needs verification on a real Kitty terminal. The escape sequences may still need synchronization markers (\x1b[?2026h/\x1b[?2026lsynchronized output mode) to avoid flicker during the flush window.2. Render guard (partially fixed)
render_detail()was callingctx.render_image()every frame tick (~250ms). ADetailState.last_renderedcache guard was added, but the guard only prevents redundant calls — the initial render still needs to work correctly.3. Image path may not exist
Gallery items created by the generate screen point to paths in
pending_dir(). If the image was moved to the gallery folder during save, the original path is stale.render_detail()checksitem.image_path.exists()but the path stored in the DB may not be the final location.4. PNG-only limitation
The Kitty renderer's
transmit_png()sendsf=100(PNG format). If the source image is JPEG or WebP (common for AI outputs), the renderer silently fails or sends malformed data. Needs format detection and transcoding to PNG before transmission.5. No image cleanup on navigation
When the user leaves detail view, the Kitty image placement persists on screen until overwritten. Should emit
a=d,d=idelete commands when leaving detail view or switching images.Acceptance criteria
Kitty backend
Multi-backend groundwork
ImageRenderertrait is sufficient for Sixel, Chafa, and Halfblock backendsflush_pending()default no-op works for inline renderers (halfblock, chafa)detect_renderer()correctly falls back through the priority chaintui.tomloverride (image_protocolfield)Generate preview
LoomEvent::ImageGeneratedTests
MockRendererrecords all render/delete calls for assertionpending_outputbufferingOut of scope
References
crates/loom-tui/src/image/kitty.rs— renderer implementationcrates/loom-tui/src/image/mod.rs—ImageRenderertraitcrates/loom-tui/src/screens/gallery.rs—render_detail()call sitecrates/loom-tui/src/app.rs— post-drawflush_pending()call