Skip to content

Releases: zzjcool/krd

krd v0.2.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 19:58

What's Changed

  • fix: idle frames are counted as idle, not bad (#25) by @zzjcool in #32
  • feat: krd ax — the headless text channel (read-only) (#27) by @zzjcool in #29
  • feat: kitty keyboard protocol — Cmd combinations and key release (#15) by @zzjcool in #30
  • ci: scale the runner's timing budgets, never bytes (#31) by @zzjcool in #33
  • fix: a backdrop window is refused, not captured black (#24) by @zzjcool in #34
  • feat: --zoom / --region — show less of the desktop at full density (#22) by @zzjcool in #35
  • fix: --window posts input to the window's own process (#17) by @zzjcool in #36
  • feat: krd ax step 2 — refs on disk, find, press/set with read-back (#28) by @zzjcool in #37
  • feat: clipboard bridge, NSPasteboard to OSC 52 and back (#18) by @zzjcool in #38
  • feat: follow display-set changes without a restart (#19) by @zzjcool in #39
  • feat: --ime, raw keys so the target's own input method composes (#16) by @zzjcool in #40
  • docs: status table — display-set changes ship, so the "not yet" row is now something else (#19) by @zzjcool in #42
  • docs: cost the colour-heavy case — the fix is 16-bit tiles, not a codec (#26) by @zzjcool in #41
  • refactor: extract krdcore (tiles, level policy, writer) + pinned byte contract (#21, part 1) by @zzjcool in #43
  • refactor: move the CSI/SS3 parser into krdcore, numeric events only (#45) by @zzjcool in #46
  • docs: Rust decision record — the language is 1.2x of what is left, and #21 made the option cheap (#9) by @zzjcool in #47
  • docs: re-estimate dirty rectangles on today's encoder — recommend closing #7 by @zzjcool in #48
  • probe: a 30-minute soak, which found the stream dying quietly (#44) by @zzjcool in #49
  • feat: hide the pointer by default (--cursor draws it) — a moving mouse costs ~47 tiles/s by @zzjcool in #51
  • feat: a TUI layer over the picture (--dev) by @zzjcool in #50
  • perf: do not compress a tile zlib cannot help (#53) by @zzjcool in #55
  • perf: pan with updateConfiguration instead of tearing down the stream (#54) by @zzjcool in #57
  • fix: derive the cell size from CSI 14t when the terminal answers nothing else (#56) by @zzjcool in #58
  • perf: quantise incompressible tiles to 5-6-5 before zlib, no protocol change (#59) by @zzjcool in #61
  • feat: --scale captures a fraction of the pane's pixels (#60) by @zzjcool in #62
  • docs: M2/M3 shipped — colour-heavy motion is 68 MB/s at 20 fps now, so the status table says so by @zzjcool in #63
  • bench: add photoReal, a deterministic case with photographic statistics (#65) by @zzjcool in #66
  • feat: --scale auto steps resolution down when the pipe is behind (#64) by @zzjcool in #67
  • fix: size --window's capture from the source, not the pane (#69) by @zzjcool in #70
  • feat(wall): the landing screen, phase 1 — text only, no capture by @zzjcool in #68
  • fix: place the picture as large as the pane, and give --scale only the pixels (#71) by @zzjcool in #72
  • fix: --zoom asked for the window's pixels out of the crop (--window/--display + --zoom) by @zzjcool in #76
  • feat: --scale defaults to auto, so a slow link drops resolution instead of freezing (#73) by @zzjcool in #75
  • probe: does this terminal take grey / paletted PNG (f=100), and what does it cost by @zzjcool in #77
  • feat: one number for colour -- --quality (100 = lossless, 80 = today, 70, 50) by @zzjcool in #78
  • probe: drop the duplicate demo, point the docs at the sliders by @zzjcool in #79
  • ci: move off macos-14 before its retirement by @zzjcool in #81
  • diag: split the frame, and ask the terminal how far away it is (#52) by @zzjcool in #80
  • the mascot card that fills the first capture, and the test that was measuring my desktop by @zzjcool in #82
  • fix(mirror): a tile's image is its own cell box, and a placeholder frame is never smaller than its cells by @zzjcool in #121
  • fix(wall): the card band holds as many rows of previews as it fits by @zzjcool in #137
  • docs: the README mascot is the crab alone, not the whole loading card (#85) by @zzjcool in #138
  • docs(brand): the --png comment says a dot is 1/68 of width=680, not 1/10 by @zzjcool in #142
  • test(mirror): pin the window page to its cell box — #84 is #86/#121 on the page whose source is smaller than the box by @zzjcool in #145
  • fix(input): swallow an over-cap OSC reply instead of typing it (#127) by @zzjcool in #149
  • fix(wall): a one-cell shaft answers with the page its thumb shows, not page 0 (#135) by @zzjcool in #150
  • fix(tiles): the picture's cell box and fit come from the pane, not from --tile (#143) by @zzjcool in #151
  • fix(cli): an unknown option or a missing value is a usage error, not a mirror (#122) by @zzjcool in #152
  • fix(ax): clamp a title by grapheme cluster, not by unicode scalar (#128) by @zzjcool in #154
  • fix(chrome): one number per row in the stats panel, and frame — ms where nothing was measured (#117) by @zzjcool in #153
  • fix(ax): --json answers a failure with one object, and doctor stops exiting 0 (#123) by @zzjcool in #155
  • fix(replay): a manifest line's frame size is that frame's, and a replay that cannot honour one says so (#133) by @zzjcool in #156
  • fix(#132): a clear that lands mid-frame is sent after the frame, not inside it by @zzjcool in #148
  • docs(#125): one exit-code table — six codes, the --json contract, and doctor's 3/4 by @zzjcool in #157
  • fix(#134): every mode a session turns on, its teardown and its heal turn off by @zzjcool in #158
  • perf(ax): children ride in the walk's batch, so a node costs two round trips (#104) by @zzjcool in #163
  • perf(#95): one scan per delivered frame answers both dedupe and dirty by @zzjcool in #160
  • fix(mirror): the cell is the terminal's, the chrome budget is only the box (#146) by @zzjcool in #164
  • fix(wall): the band header's ⤢ N is a real control, and a pane with no band claims no range (#112) by @zzjcool in #161
  • perf(#96): the bench's zlib column is three stages — heuristic, quantise, deflate by @zzjcool in #165
  • perf(ax): one index read and one index write per dump, and prune stops decoding snapshots (#102) by @zzjcool in #171
  • perf(#105): a mouse report is read where it lies, not parsed as text by @zzjcool in #170
  • perf(wall): a --wall-quality rung, so the first picture costs bits not bytes (#88) by @zzjcool in #166
  • docs: the conditions #121 and #96 put on the rules, in both languages by @zzjcool in #172
  • perf(#94): the incompressibility vote is settled early, not sampled — 2.8x, bytes unchanged, refs #94 (not closing) by @zzjcool in #167
  • perf(ax): the preflight runs when a verb has something to report, not before every verb (#103) by @zzjcool in #168
  • fix(#118): a panel keeps its rows, says which of them it holds, and the wheel reaches the rest by @zzjcool in #159
  • fix(list): --list writes only its listing, and answers --json (#124) by @zzjcool in #175
  • perf(#92): hoist and unroll quantise — 5.6x load-matched, every byte unchanged (refs #92, not closing) by @zzjcool in #177
  • feat(#107): tmux — DCS-passthrough every graphics APC, so a pane draws the picture instead of tofu by @zzjcool in #173
  • perf(#90): the log panel reads what was appended, not the whole log by @zzjcool in #176
  • feat(ax): ax tree --diff prints only what changed, or the word unchanged (#108) by @zzjcool in #174
  • fix(input): hear the terminal — parse graphics replies, never type them (#109) by @zzjcool in #162
  • perf(wall): a trigger, a 2s fingerprint poll (2.7x), and no card outlives 2.5 s (#141) by @zz...
Read more

krd v0.1.2

Choose a tag to compare

@github-actions github-actions released this 29 Oct 14:43

Everything in this release comes from the performance issues, and every number below is from the new
krd --bench (no terminal needed):

krd --bench --pane 137x44 --cell 17x33

Compression now runs on all cores. It was >90 % of the frame budget, single-threaded. The dirty
tiles of a frame are compressed with DispatchQueue.concurrentPerform; escape assembly stays serial so
the pty writes stay ordered. A full repaint went from 39.8 ms → 3.8 ms on noisy content and
5.9 ms → 0.7 ms on text.

zlib level per tile. Text compresses to 2 % at level 9; sensor noise gains 1 % going 1 → 9 for six
times the CPU. Each tile now remembers the previous frame's ratio and picks 9 / 5 / 1 with a 3 %
hysteresis band.

Tiles are 8×4 cells instead of 16×8. One character now costs 727 B instead of 2132 B (−66 %);
one text line 8.6 KB instead of 12.8 KB. (A full text repaint costs ~46 % more, but that only happens
on resize/reconnect.)

f=24 instead of f=32. The desktop is opaque, so alpha was 25 % dead weight: a full photo costs
3.56 MB instead of 4.07 MB. --format rgba is the fallback if a terminal mishandles RGB.

One synchronized-update block per frame, not per tile: 16 bytes per frame instead of 16 × 66, and
the per-tile environment lookups are gone.

Capture no longer copies the whole frame. Two rotating buffers + vImageConvert_BGRA8888toRGB888.

Also new: --bench and --pane, a Tests/krdTests target (9 tests, swift test is green), and
docs/ENCODING.md with the full benchmark matrix and the reasoning.

If a picture that used to work now looks black or garbled, run with --format rgba and open an issue.

krd v0.1.1

Choose a tag to compare

@github-actions github-actions released this 29 Oct 13:31

A macOS desktop inside a terminal pane. ScreenCaptureKit captures the screen, the picture
goes out as kitty graphics escapes on stdout, mouse and keyboard come back on stdin and are
injected with CGEvent. No VNC, no codec, no second port, no client to install.

krd demo

Install

tar xzf krd-v0.1.1-macos-universal.tar.gz
codesign --force --sign - --identifier com.kkrt.macdesk krd-v0.1.1-macos-universal/krd
./krd-v0.1.1-macos-universal/krd --list      # asks for Screen Recording once
./krd-v0.1.1-macos-universal/krd --fps 20

Then from anywhere: ssh -t host krd --fps 20 (exit with Ctrl-\).

  • macOS 14 or newer, universal binary (Apple Silicon + Intel)
  • the binary in this archive is not signed with a Developer ID — sign it once as shown above,
    or macOS will forget the Screen Recording / Accessibility grant on every rebuild
  • needs a terminal that speaks the kitty graphics protocol: rex, Ghostty, kitty, WezTerm
    (Terminal.app does not, and Herdr's delete semantics are still unfriendly)

In this release

  • tile-based dirty updates — a static screen sends nothing, a caret costs about 1 KB
  • pixel-accurate pointer via ?1016h SGR-Pixels with an automatic cell fallback
  • left / middle / right buttons, double and triple click, modifier-clicks, wheel (vertical and
    horizontal), pointer following via ?1003h
  • fixes clicks turning into macOS right clicks when a Control modifier was left behind
  • bilingual documentation (English / 简体中文), a self-test path that needs no permissions, and
    --version

Full Changelog: https://github.com/zzjcool/krd/commits/v0.1.1

Full Changelog: https://github.com/zzjcool/krd/commits/v0.1.1

Full Changelog: https://github.com/zzjcool/krd/commits/v0.1.1

Full Changelog: https://github.com/zzjcool/krd/commits/v0.1.1