Skip to content

Sixel Encoding Optimization#89

Merged
lnqs merged 1 commit intolnqs:mainfrom
uriyyo:feature/sixel-size-optimization
Apr 7, 2026
Merged

Sixel Encoding Optimization#89
lnqs merged 1 commit intolnqs:mainfrom
uriyyo:feature/sixel-size-optimization

Conversation

@uriyyo
Copy link
Copy Markdown
Contributor

@uriyyo uriyyo commented Mar 30, 2026

Sixel Encoding Optimization

Reworked sixel encoding to reduce output size and improve end-to-end terminal rendering performance.

Most of the core compression and emission ideas in this rewrite were adapted from libsixel, with a Python implementation and an optional NumPy-accelerated fast path.

All encoder settings are now grouped in a SixelOptions dataclass for a clean API that is easy to extend.

Encoding speed

Benchmarks were run on two groups of animated image frames:

  • smaller sample frames with simple animation and lighter photographic content
  • larger HD-style frames resized to a common benchmark resolution, covering natural scenes, space imagery, UI/motion graphics, abstract animation, and noisy/detail-heavy content

On the larger HD-style set, the new encoder is typically faster while also producing much smaller output:

Dataset Median speedup
Small animated samples 1.06x
Larger HD-style samples 1.77x

Representative results from the larger HD-style set:

Sample type Speedup
Urban timelapse 1.76x
Colorful abstract animation 2.10x
Natural scene 2.18x
Clean mechanical animation 2.66x
Planet / space imagery 1.83x

Output size reduction

The biggest win is output size, which directly reduces the amount of sixel data written over the PTY.

Dataset Median reduction
Small animated samples -63%
Larger HD-style samples -76%

Representative results from the larger HD-style set:

Sample type Reduction
Urban timelapse -70%
Colorful abstract animation -85%
Natural scene -84%
Clean mechanical animation -89%
Planet / space imagery -91%

Key optimizations

  1. Band-based encoding — Processes full 6-row sixel bands at once instead of encoding row-by-row.

  2. Interleaved segment emission — Emits non-overlapping color segments in shared sweeps, reducing redundant carriage returns and padding.

  3. Fillable first sweep — Uses a libsixel-style fill pass that compresses especially well with RLE.

  4. Gap splitting — Large empty gaps are split into separate segments instead of being bridged with excessive ? padding.

  5. Palette compaction — Deduplicates colors that map to the same sixel RGB values and reorders palette entries for smaller output.

  6. Active color reuse — Avoids re-emitting color-select commands when the same color is already active.

  7. NumPy vectorized path — Adds an accelerated path for band packing with a pure-Python fallback.

@uriyyo
Copy link
Copy Markdown
Contributor Author

uriyyo commented Mar 30, 2026

Demo how you can play gif using textual serve in your browser

Screen.Recording.2026-03-30.181124.mp4

@lnqs
Copy link
Copy Markdown
Owner

lnqs commented Apr 2, 2026

That's impressive. Happy to merge the PR once the conflict is resolved.

@uriyyo uriyyo force-pushed the feature/sixel-size-optimization branch 3 times, most recently from 92bc6f8 to 95e176b Compare April 6, 2026 12:51
@uriyyo
Copy link
Copy Markdown
Contributor Author

uriyyo commented Apr 6, 2026

Hi @lnqs,

I update PR, I used https://github.com/saitoha/libsixel as ref to see what are best ways to optimize sixel encoding.

@uriyyo uriyyo force-pushed the feature/sixel-size-optimization branch 2 times, most recently from ae90c03 to a7d93b3 Compare April 6, 2026 19:12
@uriyyo
Copy link
Copy Markdown
Contributor Author

uriyyo commented Apr 6, 2026

Update PR again to fix all lint errors

@uriyyo uriyyo force-pushed the feature/sixel-size-optimization branch from a7d93b3 to baef9c8 Compare April 6, 2026 19:16
@uriyyo
Copy link
Copy Markdown
Contributor Author

uriyyo commented Apr 6, 2026

Now it's green ✅

@lnqs
Copy link
Copy Markdown
Owner

lnqs commented Apr 7, 2026

Merge and release are on the way, thanks!

@lnqs lnqs merged commit c73b2f7 into lnqs:main Apr 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants