<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pardes.git/src/esp32p4.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-02T03:46:14Z</updated>
<entry>
<title>A mouse report before the first row or column (SGR's 0, a drag past the window's top or left, in cells or 1016's pixels) is the window's edge in the terminal and the ESP32 shells, never a panic that lost unsaved text; the GUI already clamped</title>
<updated>2026-10-02T03:46:14Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-10-02T03:46:14Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=b70ef491f1553929920b9b653ad3240466478e3e'/>
<id>urn:sha1:b70ef491f1553929920b9b653ad3240466478e3e</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>F1-F25, Insert and the keypad reach a GUI's terminal panes: one vaxis key map, vaxis_input.zig, for the tty, the gui and the board</title>
<updated>2026-10-01T03:12:17Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-30T00:44:44Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=714da820136ac89d6a79ed0141e7325829ab8204'/>
<id>urn:sha1:714da820136ac89d6a79ed0141e7325829ab8204</id>
<content type='text'>
The vaxis-to-Event key mapping was copied in tty.zig, gui.zig and esp32p4.zig, and the copies had drifted: the gui's (its stdin feed, which test windows and a gui started in a terminal read) had 9 arms against the tty's 26, without the function keys, Insert or the keypad, so they reached a terminal pane as private-use codepoints. vaxis_input.zig holds effCp, mapKey and keyEvent once; the gui posts through postKey, and a test runs F5, Insert and the keypad's Up through it into a terminal pane.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Trial merge: 9P + helix + render</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T20:14:29Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=8509453c2fa78357187f1c4a7e99bfddf29027d8'/>
<id>urn:sha1:8509453c2fa78357187f1c4a7e99bfddf29027d8</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Errors are said in words, and a refusal names what it takes</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T19:52:18Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=0e2afeecf6b8c0e9ac81da51f5f8c23a5be1a5ae'/>
<id>urn:sha1:0e2afeecf6b8c0e9ac81da51f5f8c23a5be1a5ae</id>
<content type='text'>
A failure read `Del k|j: InvalidArgument`, `Kill: NoSuchCommand`, `ill-formed control message`, or nothing at all. reportError now spells an error's name as words, and the refusals name their accepted forms: pty/ctl lists its verbs, a flag file takes 1 or 0, a setting word takes on or off, Del takes k, j or nothing, Repl takes - or a language. Kill with nothing to stop says so, /focus says pane, a Look that found nothing says no match, and pty/run on a command pane says it is not a shell. A ctl write's failure has room for the Repl list and is cut between words, the Repl word at a character.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Step core animation by the shell's clock and sleep to the next wake</title>
<updated>2026-10-01T03:12:14Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T16:15:41Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=e0b5564f04aa0ae6666f29ef29c768d800fbabce'/>
<id>urn:sha1:e0b5564f04aa0ae6666f29ef29c768d800fbabce</id>
<content type='text'>
A shell now answers Host.now, its monotonic clock in ns, and the pump
advances core animation to it: one .tick per whole 16 ms frame since core
time last stood still. The same animation therefore takes the same time at
60, 120 and 144 Hz, over ssh and after a slow frame (the GUI's re-armed
clock ran them ~25% slow at 144 Hz; the tty's post-frame sleep drifted).
nextWake() lists every core animation in one place: a frame from now while
anything moves, the end of the wait while something only waits (a message
lingering, the look-hover delay), null when idle. Shells sleep exactly that
long, and a wait is jumped to its end in one step, so an 800 ms linger
costs one frame instead of fifty. An overshoot under 1.5 ms after a step is
let go: at 60 and 120 Hz every display frame takes exactly one step (a 16 ms
frame against a 16.67 ms vsync would otherwise double-step every 24th).

The six tick drivers are gone: tty's timer thread only times the wait,
interruptibly (a newer, shorter request cuts short a sleep still timing a
longer one); the GUI's
AnimationClock, web's JS tick bank (pardes_tick now takes rAF's timestamp),
the detached server's and the board's ticks; grid mode steps a virtual
clock straight to each wake. PARDES_TEST_CLOCK, set by the snapshot
harness, gives tty and the detached server the same virtual clock.

Every stepped frame is drawn. The old pump never drew the last frame of a
fade (a .tick asks for no frame, and the fade was over by the check), so a
theme switch stopped at 9/10 of the way until the next input: theme.golden,
themesel.golden and the GUI's acme-light scene move to the theme's true
colours, and nothing else changes. The frozen previous grid is captured only
while a panel transition is chosen, not on every idle frame.
</content>
</entry>
<entry>
<title>Refactor panes and filesystem; replace FUSE with 9P</title>
<updated>2026-09-07T16:59:12Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-06T21:11:36Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=60367d8fe23f6af98ec28e3cf6c2094dfe332df0'/>
<id>urn:sha1:60367d8fe23f6af98ec28e3cf6c2094dfe332df0</id>
<content type='text'>
Consolidate pane, layout, memory and host code. Serve 9P by default over Unix sockets, with runtime mounts and optional TCP/QUIC transports. Remove FUSE and obsolete proof-of-concept examples.

Fix highlighting and terminal-history performance, expand differential and stress-test infrastructure, sort navigation results while preserving the next occurrence, add syntax-colored Braille minimaps, remove SPC-k, and document 9P interaction as a repository skill.
</content>
</entry>
<entry>
<title>One core behind N frontends, the board's own runner moved in, and every board cap on one screen</title>
<updated>2026-08-27T12:47:39Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-08-26T16:27:46Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=11f380f6d7222f2cad93c2cdf13701ea1f903d47'/>
<id>urn:sha1:11f380f6d7222f2cad93c2cdf13701ea1f903d47</id>
<content type='text'>
## The wire is the effect stream, not a new protocol

`pardes --detach` leaves a core running with no terminal; `pardes --attach` is a frontend that owns
a terminal and a socket and nothing else. N frontends on one core all look at the same screen —
`screen -x`, not N sessions.

The codec (`src/detached/wire.zig`) carries exactly one `Event` or one `Host.VTable` call per
message. That is not a coincidence and it is why there is no third vocabulary to keep in step: the
core's IO seam was already a struct of function pointers with plain-data arguments, so a socket is
a legal implementation of it. `nested.zig`'s socket could not be reused — it carries a builtin
command line, and a command line cannot carry a frame.

ARCHITECTURE-NEUTRAL on purpose, not as decoration. The frontend on the far end may be
riscv32-freestanding on the ESP32-P4 while the core is x86_64 Linux, so every field is an explicit
little-endian fixed width and no message is a blit of a native struct. A protocol that only works
between two builds of the same compiler would have thrown away the one frontend that motivated it.

## The board comes in; its toolchain stays out

`src/p4.zig` becomes `src/esp32p4.zig`, and the pardes half of `../05-zig-p4` — the vaxis-over-
serial runner, the UART editor terminal, the keystroke rescue ring, the on-die test suite — moves
into `src/esp32p4/`. `build.zig.zon` gains `.zig_p4 = .{ .path = "../05-zig-p4" }`, so
`zig build -Dplatform=esp32p4 -Desp32p4-firmware` builds, flashes, monitors and self-tests the
board from this repo's `build.zig`.

The DIVISION is the point. What moved is what only pardes wants: the runner that drives a pardes
core over a serial line. What stayed is everything a second project would also want — the HAL, the
register/radio/oracle layers, the linker script, `_start`. `zig_p4` declares no dependencies of its
own and its `build()` early-returns when it is not the root package, so this costs the package
graph exactly zero packages and the editor's own builds nothing at all.

## limits.zig: nine forgettable places become one budget

Nine `platform == .esp32p4` capacity tests lived in nine files. They were never nine decisions —
they are ONE decision, how much memory this build may spend, taken nine times where no reader could
see the total. `src/limits.zig` puts the whole budget on one screen with every cap named against
what it is measured against, derived from two booleans.

The payoff is testability on a machine that is not the board: the caps are ordinary comptime values,
so a host build can be compiled against the board's numbers and the parking, eviction and clamping
paths a 240 KiB core takes get exercised by the normal test suite instead of only over a UART.

## A bare `zig build`

`zig build` with no arguments now builds the tty and GUI binaries and installs them into
`~/.local/bin`, and says so once on stdout with the flag that overrides it. The old default built
one binary into `zig-out` — a path nothing on a `PATH` ever looks at, which made "build it" and
"use it" two different commands for no reason.
</content>
</entry>
</feed>
