<feed xmlns='http://www.w3.org/2005/Atom'>
<title>pardes.git/src/animation.zig, branch release-0.24</title>
<subtitle>Pardes</subtitle>
<id>https://git.0x4200.cafe/pardes.git/atom?h=release-0.24</id>
<link rel='self' href='https://git.0x4200.cafe/pardes.git/atom?h=release-0.24'/>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/'/>
<updated>2026-10-01T03:12:16Z</updated>
<entry>
<title>The focused cursor rides with a moving pane, and a focus change glides to the new one</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T13:03:10Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=3d262763b304021720f1141ab33265759869d2fe'/>
<id>urn:sha1:3d262763b304021720f1141ab33265759869d2fe</id>
<content type='text'>
G3's springs now keep the cursor's place in its pane: a pane that moves in
the layout carries them, and the quad is drawn through the pane's presented
box (its transition track), so through a slide, zoom or drag the cursor
rides with the text, and with no transition it lands with it. A focus change,
to another pane or into a column's or the workspace's tag, glides from where
the cursor was drawn to the new place instead of snapping, unclamped while it
crosses. While panes move the cursor is drawn as the overlay quad instead of
vanishing (golden 18-mid-transition re-recorded for that: the only change is
the quad, gliding into the new column's tag).

Lapis: a tag plaque starts flush against its grip's button, the scroll gap
between them part of the plaque, so grip and plaque read as one piece, on
pane and column rows alike; below the button's row the grip keeps its band.
Themes without plaques are unchanged (their grip band and tag band are one
colour, no sliver).
</content>
</entry>
<entry>
<title>T3: PanelCurtain wipes behind a soft edge two cells wide</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T12:17:19Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=ab31baff1fbfd38180be8eed921b97082184f185'/>
<id>urn:sha1:ab31baff1fbfd38180be8eed921b97082184f185</id>
<content type='text'>
The curtain's glyph slide becomes a wipe: the new grid behind a head that
crosses the pane, the old ahead, and between them two columns whose colours
step from the old ground to the new in OKLab (CharSource.edge). Only the
head's columns change from frame to frame.
</content>
</entry>
<entry>
<title>T4: the terminal's dissolve swaps cells in ordered (Bayer) order</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T11:55:06Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=137e784bb617438bec5079ec5fef4b16ce8b75fe'/>
<id>urn:sha1:137e784bb617438bec5079ec5fef4b16ce8b75fe</id>
<content type='text'>
animation.dissolveRevealed (the tty compositor's dissolve and the pointer
mapping that follows it) swaps each changed cell once at its place in a
4x4 Bayer matrix, shifted by the pane's serial so two panes differ,
instead of at a hashed noise threshold: the new content comes in as an
even patterned screen (§9.2 T4). Endpoints stay exact.

Tests: a 4x4 block reveals exactly t x 16 cells at t = 1/4, 1/2, 3/4.
Snapshots unchanged. Feel review: .scratch/render/tty/dissolve/ (the
matrix over two real frames; the recorded session's pane did not
animate, noted in docs/effects.md).
</content>
</entry>
<entry>
<title>G10: the theme's chrome fades through OKLab, easing in and out</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T10:25:32Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=5526c68beec454cfe607a579723b97b4848e7d3a'/>
<id>urn:sha1:5526c68beec454cfe607a579723b97b4848e7d3a</id>
<content type='text'>
ChromeTheme.interpolate mixes each colour in OKLab (colors.mixOklab), so a
fade between hues keeps its lightness instead of going dark and muddy mid
way; animation.Fade eases it in and out (smooth), and one retargeted mid
fade eases out from where it shows, so it never stalls. Still 10 frames
(160 ms). The page, text and syntax colours change at once as before.

Tests: OKLab round-trips its ends exactly and keeps a red-to-green mid-way
brighter than the sRGB mix. Gates as G9 (no golden moved). Feel review:
.scratch/render/crossfade/.
</content>
</entry>
<entry>
<title>G7: a moving pane casts a shadow, a retargeted move keeps its speed, a dissolve crossfades</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T09:58:19Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=c1dbb16d069a54f52533f346655b0fc49026c9a4'/>
<id>urn:sha1:c1dbb16d069a54f52533f346655b0fc49026c9a4</id>
<content type='text'>
- Track.launch: a move retargeted mid-way (Presentation.sync) starts at
  the old move's speed along the new one's longest side (carriedLaunch,
  Motion.easeFrom/speedFrom), so a second change during a slide bends the
  motion instead of stopping it dead. The macOS track ABI grows the float
  (pardes.h, 48 bytes; its reserved byte is named motion, as in Zig).
- A pane that slides, zooms or rises casts Lift's soft shadow at
  sin(pi x progress) of its strength, on the other panes' bodies and
  rails alone, under the same contrast ceiling, carried by its track.
- The GUI's PanelDissolve is a crossfade: the new cell drawn first, the
  old one over it at 1 - progress, premultiplied, on the blending cell
  pipeline for such groups (new cells now emitted before old ones, as the
  old layers already came after the new). sRGB blend, not linear light
  (documented). The tty keeps its per-cell swap.

Presentation.zig's and animation.zig's tests were not in any test root;
pardes.zig's test block now takes them in.

Tests: a retargeted move carries its speed and still lands exactly; a
moving pane's shadow is clipped off every tag, grip and its own body,
none at the start or the landing, most mid-way. GUI golden 18 changes by
the shadow (frame 6 of a slide). Gates as G6. Feel review:
.scratch/render/transitions/.
</content>
</entry>
<entry>
<title>G6: a wheel's notch scrolls the core at once and the picture glides after it</title>
<updated>2026-10-01T03:12:16Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-29T09:41:28Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=ff252345bc3e1edc1aee93ca826f294bf9a7874f'/>
<id>urn:sha1:ff252345bc3e1edc1aee93ca826f294bf9a7874f</id>
<content type='text'>
A mouse wheel's notch (SDL's whole-number step, notchOf) scrolls the core
by its lines at once, so keys and clicks act where the text is, and the
picture follows on the Motion flavour's spring at half again its pace,
critically damped whatever the flavour (text never passes its mark),
carried from its current speed (animation.Spring.carry), so notches in a
row flow on. How far the rows moved is measured on the next frame against
the last (Glide.measure: a wrapped line's rows, a terminal's output, with a
couple of rows' slack for the cursor's line and its number); the rows that
left are kept, nearest first, and drawn in the gap the lag opens; the lag
is never more than the body's height. A touchpad's fractions move the
picture under the finger as before; `Motion off` lands a notch at once;
a PDF page scrolls as before.

The glide runs on the core's continuous path: Pardes.shell_continuous
keeps frames coming every loop while it moves and carries a virtual clock
with it; idle, nothing. The test feed takes wheel events
(ESC]777;mouse;wheel;&lt;amount&gt;;&lt;x&gt;;&lt;y&gt;BEL).

Tests: notch vs fraction; a carried spring keeps its speed and never
passes its mark; a notch over two-row lines lags two rows, keeps the rows
that left, settles frame by frame and leaves the continuous path, and
lands at once with Motion off. Gates as G5. Feel review:
.scratch/render/scroll/glide-{smooth,crisp,bouncy,off}{,-quarter}.mp4 and
strips (a notch down, three, then two up).
</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>
<entry>
<title>Motion flavours differ by design, and drive notice drops and pane moves</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T23:31:56Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=c5c2baf21bba0fb8f66e7d2ee096818d6bd5a8e0'/>
<id>urn:sha1:c5c2baf21bba0fb8f66e7d2ee096818d6bd5a8e0</id>
<content type='text'>
The flavours looked alike because Lift, the only motion that read them,
moves a shadow a few pixels: overshoot and wind-up were sub-pixel. By design
now: crisp leaves at full speed and never passes its mark; smooth (the
default) eases in and out in twice crisp's time, a slide arriving in 208 ms
(inside §8.1's 220); bouncy passes its mark by ~30% and settles twice;
playful winds up, passes by ~40%, and stretches and squashes, text included
(the user's choice). Small motions are exaggerated by the flavour's gain.

Motion gains launch, gain, span and norm, and ease(u)/speed(u) for moves of
fixed length. The notice drop follows ease() over its fall (alpha never
behind its position) and stays inside its pane's body past its row. Panel
tracks carry the flavour in Track.motion (the old padding byte; macOS header
name follows); opening and moving slides, zooms and rises follow it over
span x their frames; landed, a pane is exactly its target; closing keeps
its own exit. A pane past its mark never takes a neighbour's click; a
rising one stays in its box.

Tests: each flavour's lift trajectory distinct; flavour character; exact
landing bit for bit; a stretched pane's drawn cells map back; the overshoot
hit rule; the vertical clip at peak; legacy tests pinned to crisp. GUI
golden 18-mid-transition changes (the retuned smooth slide at frame 6).

Shared files: src/animation.zig, src/Presentation.zig, src/Messages.zig,
src/macos.zig, src/config.zig, src/pardes.zig tests, src/ninep/screen.zig
test, docs/effects.md, docs/config.md.
</content>
</entry>
<entry>
<title>Motion flavours, and Lift is shadow, rim or auto: auto on a dark page recedes the other panes (InactiveDim)</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T21:24:18Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=5dbd21795f6c68bd3c10d409135970e3033364f3'/>
<id>urn:sha1:5dbd21795f6c68bd3c10d409135970e3033364f3</id>
<content type='text'>
Motion off|crisp|smooth|bouncy|playful is one parameter set (animation.Motion)
every fx animation reads. One focus spring per pane drives both the lift and
the dim, at the flavour's pace; a grid snaps.

Lift drops glow and surface. A shadow falls on pane bodies and rails only,
capped so text and the selection keep min(contrast, 4.5); rim is a hairline
along the focused tag's top. auto is a shadow on a light page; on a dark page
the core recedes the unfocused panes' text (InactiveDim, ported from 2e4d97f,
default 30 under auto) with the same floor. Tests: focused text contrast is
never below unfocused in any style, dim or theme; the focused pane's cells and
tag are untouched by a dim.

Shared files: src/config.zig, src/builtins.zig, src/ninep/ctl.zig,
src/surface.zig, src/detached/wire.zig, docs/config.md,
test/snapshots/builtins.snap (one more wheel for the longer help).
</content>
</entry>
<entry>
<title>G1: Lift, soft elevation shadows (off by default)</title>
<updated>2026-10-01T03:12:15Z</updated>
<author>
<name>Gabriel Schneider</name>
<email>gbrls@0x4200.cafe</email>
</author>
<published>2026-09-28T19:44:51Z</published>
<link rel='alternate' type='text/html' href='https://git.0x4200.cafe/pardes.git/commit/?id=deeb8ac54f71d4322a778336db9a7aec411c23ce'/>
<id>urn:sha1:deeb8ac54f71d4322a778336db9a7aec411c23ce</id>
<content type='text'>
`Lift` (a GUI toggle, capability lift) lifts the focused pane on a
critically damped spring (animation.Spring: closed form, about 240 ms to
settle, velocity kept across retargets, settled = no frames) and floats
notices. The core puts the lift on the regions (Region.lift, on the wire);
the GUI casts from it: a soft shadow is decor, an erf rectangle on one
quad grown by 3 sigma (decor.frag, flag 0x10000000), in the quad's own
space so a track's transform carries it; darken-only, the caster's rect
left alone, alpha pre-warped for linear light and IGN-dithered. Cast last
in its group, so a neighbour's rails and rules darken with its text; a
notice's before its rule. Strength is capped per theme so text over the
darkest shadow keeps min(its contrast, 4.5) (test over the native themes).

Opt-in until the focus lift/dim default is decided. Feel review material:
docs/effects.md. Test-mode PARDES_TEST_SERIES keeps every captured frame.

Shared files touched: pardes.zig (two fields, one nextWake line),
detached/wire.zig (lift on the region), config.zig, builtins.zig
(capability), gui.zig. Not touched: Messages.zig, mouse.zig, tty,
host_io.
</content>
</entry>
</feed>
