<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slosh.git/contrib/shader-plugin/Makefile, branch docs-new</title>
<subtitle>an opinionated terminal multiplexer in C with programmable pane chrome</subtitle>
<id>https://git.sl0p.foo/slosh.git/atom/contrib/shader-plugin/Makefile?h=docs-new</id>
<link rel='self' href='https://git.sl0p.foo/slosh.git/atom/contrib/shader-plugin/Makefile?h=docs-new'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/'/>
<updated>2026-08-19T11:46:57Z</updated>
<entry>
<title>slosh: defaults most people can live in, said by shaders</title>
<updated>2026-08-19T11:46:57Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-19T11:46:57Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=42b3c10995eb67778d9dd3aa2fd80624896acd5f'/>
<id>urn:sha1:42b3c10995eb67778d9dd3aa2fd80624896acd5f</id>
<content type='text'>
The out-of-the-box look, rethought as one piece:

- the compiled-in palette calms down: muted blue #7aa2f7 on the same
  neutral darks, with the colours that mean something kept semantic --
  amber bell, red-orange dead. sl0p stays one include away as the house
  style, and contrib/themes/default.kdl is the starting point written
  down (theme-tour shows it).

- derived state defaults now actually follow the theme: the scrolled
  wash is rebuilt from scroll_bg after the theme block (it used to bake
  the compiled accent), and declaring a state -- in any file of an
  include chain -- still wins. The dump writes derived states as
  comments so C-a e cannot pin what is meant to keep following.

- a bell you can see: the frame blinks three times in theme's bell
  colour then breathes until answered, and a soft diagonal shimmer --
  the bell colour halved towards default_fg, width breathing on a sine
  -- crosses the body for the same 900ms. bell_indicator false silences
  all of it; states { bell { } } replaces it like any state. since
  carries the clock dependency, so an idle session pays nothing.

- scrollback says where it continues: while scrolled, the viewport's
  top and bottom rows melt towards an edge with content past it and
  turn solid at the buffer's end. New expression variables above/below
  (lines hidden past each edge, own dependency bit, cached per scroll
  position), carried in shade_ctx_t -- SLOSH_SHADER_ABI 3 -&gt; 4.

- expressions survive the dump: a program keeps its source and cb_chain
  writes it back, so amount="(y % 2) * 40" no longer dumps as a number.

- headers move to include/, -Iinclude everywhere; the plugin Makefile's
  SLOSH var becomes SLOSH_DIR because slosh exports SLOSH=1 into every
  pane it runs, and building from inside a session read that as a path.

- comment drift culled where features outran the prose, and the
  derivation boilerplate folded into derived_pass()/ctx_scroll().
</content>
</entry>
<entry>
<title>slosh: rename the project from sl0ppty</title>
<updated>2026-08-18T19:26:00Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-18T19:26:00Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=b9e53cace4eb75263077df8623b011e66f5f2241'/>
<id>urn:sha1:b9e53cace4eb75263077df8623b011e66f5f2241</id>
<content type='text'>
sl0p + pty was error-prone to type and the zero made it worse; slosh
(slop + sh) is one syllable, impossible to typo, and slosh.foo is ours.

Mechanical rename everywhere it appears: binary, env vars (SLOSH,
SLOSH_SESSION, SLOSH_BIN, SLOSH_CONFIG), socket dir (/tmp/slosh-&lt;uid&gt;,
$XDG_RUNTIME_DIR/slosh), config path (~/.config/slosh), header guards,
src/sl0ppty.h -&gt; src/slosh.h, contrib/sl0ppty-dev -&gt; contrib/slosh-dev,
the driving-slosh skill, docs and tests. The sl0ppi fork references and
the sl0p theme stay: one is history, the other is the brand.

The rename surfaced a latent bug in test_osc5577: the hello-reply
answer always appeared on screen twice (ECHOCTL echo plus cat -v), but
a seven-character implementation name happened to wrap the second copy
across the 60-column boundary, so counting substrings in wrapped text
found one and passed for the wrong reason. A five-character name moved
the wrap and exposed it. The loop guard itself is correct -- with echo
off before the request there is exactly one reply -- so the test now
counts on de-wrapped text and tolerates the pane's own echo.
</content>
</entry>
<entry>
<title>sl0ppty: shaders can be loaded from shared libraries</title>
<updated>2026-08-14T20:06:57Z</updated>
<author>
<name>user</name>
<email>user@clank</email>
</author>
<published>2026-08-14T20:06:57Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/slosh.git/commit/?id=2ae507a8a331799875e07c327730a1a4ca0363f4'/>
<id>urn:sha1:2ae507a8a331799875e07c327730a1a4ca0363f4</id>
<content type='text'>
Adding an effect meant editing shader.c and rebuilding, which is fine for us
and useless to anyone else. Now any `*.so` in the shader directory that
exports a plugin table is loaded at startup, and what it declares is named in
the config exactly like a built-in -- same syntax, same three parameters,
same pass. Default location is a `shaders` directory beside the config file,
so dropping the .so next to config.kdl is the whole installation.

The interesting part is what a plugin can see, which is one header.
shader_abi.h holds cell_t, color_t, shade_ctx_t, shader_t and nothing else:
no libghostty-vt, no pty, no layout, no session. A shader is therefore
unable to reach anything but the cell it was handed, not by rule but because
nothing else is declared where it can find it. cell_t and color_t moved
there from sl0ppty.h for the same reason -- that is the one place they are a
contract with code compiled outside this tree rather than an internal type.

Loading is deliberately narrow:

- refused unless the library reports our ABI version *and* matching struct
  sizes. The version says which contract; the sizes catch someone editing
  their copy of the header, which a version number alone calls fine and a
  running session calls garbled colours;
- refused if it redefines an existing name, because a config naming `dim`
  means the `dim` it was written against;
- all-or-nothing per file, and per file: a bad library is a line on stderr
  and everything else still loads (D9 fail-open);
- nothing is ever unloaded. A shade_fn may be sitting in a live config or on
  a pane, so dlclose() is a jump into an unmapped page. A reload picks up
  newly *added* plugins; replacing one needs a new session.

This is the single exception to D9's "a plugin is a subprocess", and it is
argued in D15 rather than drifted into: a shader is called per cell, per
pass, per frame, which no subprocess can be in the path of, and the measured
alternative -- interpreting bytecode per cell -- is 56ns against 8ns for the
compiled function. On trust, `shell` and a layout's `command=` already let a
file in the config directory run anything as you, so a .so beside them is
not a new boundary. The docs say so plainly rather than implying a sandbox.

contrib/shader-plugin is a working skeleton: Makefile, two commented effects
(one positional, one animated), and the three rules a shader has to keep. It
is built and loaded by the test suite, so a broken example is a failing test
rather than someone else's afternoon.
</content>
</entry>
</feed>
