<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pardes.git/src/surface.zig, branch main</title>
<subtitle>Pardes</subtitle>
<id>https://git.0x4200.cafe/pardes.git/atom?h=main</id>
<link rel='self' href='https://git.0x4200.cafe/pardes.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/'/>
<updated>2026-10-01T22:57:27Z</updated>
<entry>
<title>Tab N sets a tab's width in cells, 1 through 16, in every pane, drawn and counted (wrapping, clicks, the cursor); bare Tab says it; the ctl read and a Dump keep it</title>
<updated>2026-10-01T22:57:27Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T22:20:19Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=2868516c215a96d9e1e933ded7ac5744ec16c368'/>
<id>urn:sha1:2868516c215a96d9e1e933ded7ac5744ec16c368</id>
<content type='text'>
A session setting, not acme's per window: the width is read by File's pure
width functions (~130 callers that are given no pane), so it is one value,
config.tab_now, that Runtime.apply sets and a new session resets. A file:L:C
column counts runes, as compilers do, and never depended on it.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>A terminal pane draws the kitty graphics its program places, so yazi's image and PDF previews show</title>
<updated>2026-10-01T03:53:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-01T03:35:37Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=28c74918cde4092d964daa847c026ed3de282683'/>
<id>urn:sha1:28c74918cde4092d964daa847c026ed3de282683</id>
<content type='text'>
yazi asks the pane XTVERSION, and ghostty-vt answers "libghostty": yazi
takes it for Ghostty and sends its previews by the kitty graphics protocol
with Unicode placeholders (a=T,U=1, then U+10EEEE cells). ghostty-vt stored
the images, but nothing drew them: the placeholders showed as tofu in the
GUI and as raw codepoints in the tty, in every build since terminal panes
answered queries (vkznsvzs, 2026-07-01). Before that no query was answered
and yazi fell back to chafa's text art.

Each frame, TerminalImages.zig reads the active screen's images and
placements (virtual ones through their placeholder runs, and ones placed on
a cell), cuts each into the cell rows it covers, maps those rows through
the body's own row walk, clips them to the pane, and hands them on as
ImagePlaces with exact geometry (NativePlacement.exact). The GUI draws
them as textures; the tty passes them to an outer terminal with kitty
graphics as one placement per row, its source cropped to whole cells.
Placeholder cells draw no text. Scrolling, a delete, a resize, the
alternate screen and a closed pane all fall out of reading the emulator's
state every frame.

A pane now knows its size in pixels: CSI 14/16/18 t are answered, the
emulator's width_px/height_px follow the shell's cells, and the pty's
winsize carries pixels (host_io.ptyWinsize), so yazi and a nested pardes
size their images right. ghostty-vt's image store is 64 MiB per screen
(its library default, 10 MB, refused a large preview), PNG transmissions
are decoded with stb_image, and RGB images are converted only while shown.

test/yazi_preview.py runs yazi in a hidden window on a PNG and a PDF and
checks the captures, also through a tty pardes nested in the pane.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Afterglow (G14) is removed</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T14:28:55Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=3bc0796def5c1c1013bf3e11d7c94264ed330713'/>
<id>urn:sha1:3bc0796def5c1c1013bf3e11d7c94264ed330713</id>
<content type='text'>
The user, looking at the lapis showcase: "one of the animations is like a
flashing on the whole pane or something, that is really bad, just remove it".
Every changed cell glowing meant a pane whose whole text changed (a file
opened, a +Search refilled, a terminal's output) lit up at once: replacing a
pane's text took its mean brightness from 38 to 70 and back over 250 ms.
Gone like Ripple and Glitch: the builtin, the setting, its Chrome fx bit,
the GUI's diff state and decor, the test, and the docs, which keep the
user's words.
</content>
</entry>
<entry>
<title>G14: Afterglow, changed text glows a moment and fades</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T11:37:12Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=52f9c1423bc4e58079b008e763b5485ae49911f7'/>
<id>urn:sha1:52f9c1423bc4e58079b008e763b5485ae49911f7</id>
<content type='text'>
Afterglow on|off (off, a pixel shell's; Chrome.fx bit 4): the GUI keeps
the grid it last drew and when each cell changed; a body cell whose text
changed glows in the theme's accent, at most 18% and under the text's
contrast floor, fading with an ease-out over 250 ms, one flat rectangle a
run of cells that changed together; never a tag or a grip, the cursor or a
selection; a scrolled body (its first line moved) starts over rather than
lighting up whole. On the continuous path while anything glows.

Tests: three changed cells glow as a run of two (the cursor's left out),
gone by 250 ms, a scroll lights nothing. Gates as before; goldens
byte-identical. Feel review: .scratch/render/afterglow/.
</content>
</entry>
<entry>
<title>G13: Parallax, lapis's dots drift with the text at a quarter of its speed</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T11:28:40Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=0a2694e935fa8a79f1a399f2d2cbc643f8c3734e'/>
<id>urn:sha1:0a2694e935fa8a79f1a399f2d2cbc643f8c3734e</id>
<content type='text'>
Parallax on|off (off, a pixel shell's; Chrome.fx bit 3). A body region
carries its first line (Region.line, a file's scroll or a terminal's grid
offset; the wire's region record grows a u32). The GUI offsets each
body's page dots by a quarter of its line in rows, and of G6's glide
offset while one runs, so the pattern drifts with the text and settles
with it; the cell shader reads it from the instance's serial slot, whose
per-cell dissolve noise G7 left unused (the dead noise code goes).

Tests: a scrolled body tells its line; the shift handed to the shader is
a quarter of it within the dots' period. Measured in a capture: four lines
move the dots 13 px (140 px / 4 mod 22). Gates as before, goldens
byte-identical. Feel review: .scratch/render/parallax/.
</content>
</entry>
<entry>
<title>G12: Occlusion, pane bodies darkening faintly toward their edges</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T10:47:39Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=ab668719385c94df3e274f71cb744f5917c1da7e'/>
<id>urn:sha1:ab668719385c94df3e274f71cb744f5917c1da7e</id>
<content type='text'>
Occlusion on|off (off, a pixel shell's; Chrome.fx bit 2 — the glow bits
field is now `fx`): four soft strips cast from just outside each pane body
inward, clipped to the body and round a cursor, black pre-warped to
linear light, 2% at most (§9.1) and under the lift's contrast ceiling,
in the pane's own group.

Tests: the shade stays inside the body, off the cursor, at most 2%.
Gates as G11. Feel review: .scratch/render/occlusion/ (with an x40 diff).
</content>
</entry>
<entry>
<title>G11: HoverGlow, a soft underline of light under a look-hover's word</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T10:31:35Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=87ad46cb7e7410c53419c20cef7df53ed4c15f60'/>
<id>urn:sha1:87ad46cb7e7410c53419c20cef7df53ed4c15f60</id>
<content type='text'>
HoverGlow on|off (off, a pixel shell's; Chrome.glows bit 1, SelectionGlow
bit 0 now that there are two): under the word a look-hover would open (its
cells in the affordance's tint) a strip three logical pixels tall along
its foot, blurred by one, in the theme's accent, at most 22% and under
the text's contrast floor, fading in over 80 ms; kept to the bodies and
split round a cursor. glowBlocks serves G9 and G11. The strip is cast from
a row away so addSoft's caster cut-out misses it.

Tests: the glow comes up by 90 ms and never falls on the cursor's cell.
Gates as G10 (a loaded machine shifted the GUI goldens a scene once; a
rerun matched 01-08). Feel review: .scratch/render/hover/.
</content>
</entry>
<entry>
<title>G9: SelectionGlow, a soft halo round the body's selection</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T10:17:07Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=99c088e277e7d79d7b4341d3f546c02e7254e107'/>
<id>urn:sha1:99c088e277e7d79d7b4341d3f546c02e7254e107</id>
<content type='text'>
SelectionGlow on|off (off; a pixel shell's, Chrome.selection_glow): each
block of selected rows in a pane body casts Lift's soft kind in the
selection's own colour, the block its caster (never touched) and a cursor
beside it joined to the caster; clipped to the bodies (never a tag or a
grip); at most 22% (§8.2), less where the text round it would drop below
min(its contrast, 4.5); fading in over 100 ms with an ease-out, on the
core's continuous path (shell_continuous); none while panes move. Blocks
come from the cells in the theme's selection colour (documented).

Tests: the halo's colour, its clip to the body, nothing at its first frame
and up to its cap after 100 ms, fading done. Gates as G8. Feel review:
.scratch/render/selection/.
</content>
</entry>
<entry>
<title>G5: lapis, 0x4200.cafe's manuscript, as a theme with its ornament</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T09:04:28Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=09ec515c5e94de741104038cd61f18b2b997e78c'/>
<id>urn:sha1:09ec515c5e94de741104038cd61f18b2b997e78c</id>
<content type='text'>
A native theme `lapis` (src/themes/lapis.zig) from web/theme/lapis.css:
a lapis-deep page, lapis tags with gold names, vellum text, vermilion
rubrics, gold rules and a vermilion tag rule, gold selection in lapis ink.
Its ornament is the theme's new `decor` (colors.Decor), drawn by a pixel
shell inside the chrome it already has (decision 1), all of it off every
focus indicator:

- page_dots: the site's gold dot grid (#e8c46a22, 22 px), drawn by the
  cell shader on page-coloured cells alone (flag 0x10000000), so it lies
  under the text and never under a selection, a tag or the cursor; fixed
  to the window, a page the panes lie on.
- rail_checker: the dither frame's gold and lapis checker in the scroll
  track (a decor kind, flag 0x08000000), anchored to its rail; the thumb
  stays solid gold.
- tag plaques (tag_border, tag_shadow, tag_stripe): every tag a raised
  plaque inside its own band, the site's trail: a 2px gold frame and a
  hard 5px vermilion shadow down and right, both within the band's rows
  and columns (down, what the slack under the text leaves), so no shadow
  reaches a body, a grip or the next pane. The focused pane's plaque is
  the code window's title bar, gold and lapis stripes of 2px, its words
  on plates of the focused ground; unfocused ones are plain; column and
  workspace tags take the object-label language (1px frame, 2px shadow
  toward the page). Drawn as decor under the cells (a group's under
  range), with blank tag cells see-through and the cells blended
  premultiplied (pipeline_over) on such frames; opaque windows only.
- title_shadow: the titles' vermilion offset shadow under a file name's
  letters, sampled in the cell shader inside the letters' own cells (flag
  0x08000000), none on a cursor.

Chrome carries the decor (decor_*, name_ink, active_name_ink); a theme
file folds a nested decor literal field by field. Left out, with why, in
docs/effects.md: the fonts, the ornaments, a decor crossfade, and in the
tty anything but the colours (a tag row has no spare cell for a shadow).
An empty column is the page. The effect id is masked to 27 bits (ui.vert/ui.frag) for the
fifth flag.

Tests: the cell flags land only on page ground and file-name cells, never
a cursor, nothing without decor; lapis's plaques stay inside their tag's
band, clear of every grip, only the focused one striped; its checker is in
the track; no other theme draws any; the separator and focus
tests cover lapis. Goldens: theme and themesel (the ring gains lapis after
acme). Gates as G4. Feel review: .scratch/render/lapis/ (lapis.png, lapis-2x.png,
tags-focused-vs-unfocused-2x.png, a PanelSlide at 60 fps and a quarter).
</content>
</entry>
<entry>
<title>G3: the focused cursor glides a jump on the Motion flavour's springs, and blinks</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T02:34:20Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=faa5ee1d81e2b9c4be6925b7178db2d2dc4577f8'/>
<id>urn:sha1:faa5ee1d81e2b9c4be6925b7178db2d2dc4577f8</id>
<content type='text'>
The core owns the motion, as Lift: animation.CursorGlide keeps the focused
cursor's four corners on springs (leading corners at the flavour's pace x2.4,
trailing ones x follow, so a jump smears and collapses; a long jump bows by
the flavour's arc), sampled at each frame's own time. A step of a cell or
less, insert mode, a focus change and any scroll (a file's view, a
terminal's output) land at once; a snap lands a glide under way too. The
quad is clamped to the focused pane when drawn (never its springs). Chrome
carries it on the wire (cursor_glide: bit 1 a cursor, bit 0 gliding;
cursor_alpha; cursor_quad, grid cells; cursor_idle_ms): the GUI draws the
quad as an overlay in the cursor's colour, at 85% (70% on the long
flavours) rising to solid as it lands, and hides the cells' cursors while it
does: one or the other every frame. Only the focused cursor glides.

Blink (CursorBlink, on by default in pixel shells) is the shell's: from
cursor_idle_ms and when the frame arrived, solid while typing and 500 ms
after, 530 ms halves with 80 ms eased edges, solid after 10 s idle, and
never while the window is unfocused or minimized or on a virtual clock. An
edge redraws the last frame with no core render (level B, blink_redraws);
an attached GUI blinks from the same field without a frame per edge.

Tests: snaps a cell, glides a jump with smear and bow, arrives under a pixel
by 150 ms on smooth and lands exactly, shifts with a scroll; blink holds,
eases, stops; the core glides a jump (ge) frame by frame (gliding exactly
while it moves, alpha rising, exact at rest), snaps a step (j) and a switch
to insert mid-glide; a terminal's scrolling output lands its cursor; wire
round-trip of the cursor record.

Shared files: src/animation.zig, src/pardes.zig, src/config.zig (toggle
CursorBlink), src/surface.zig, src/detached/wire.zig.
</content>
</entry>
</feed>
