From faa5ee1d81e2b9c4be6925b7178db2d2dc4577f8 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 23:34:20 -0300 Subject: G3: the focused cursor glides a jump on the Motion flavour's springs, and blinks 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. --- src/config.zig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/config.zig') diff --git a/src/config.zig b/src/config.zig index 24c48770..4581536e 100644 --- a/src/config.zig +++ b/src/config.zig @@ -119,6 +119,7 @@ pub const leader_path = paths: { if (builtins.capabilities.window_opacity) table.set(.WindowOpacity, null); if (builtins.capabilities.window_blur) table.set(.WindowBlur, null); if (builtins.capabilities.ligatures) table.set(.Ligatures, null); + if (builtins.capabilities.lift) table.set(.CursorBlink, null); if (builtins.capabilities.lift) table.set(.Lift, null); table.set(.Motion, null); table.set(.InactiveDim, null); @@ -647,6 +648,10 @@ pub const Runtime = struct { verbose: bool = true, /// A message falls into its row and dissolves out of it. message_animation: bool = true, + /// The cursor blinks, a pixel shell's (docs/render-pipeline.md ยง5.4): + /// solid while typing and for half a second after, eased at each edge, + /// solid again after ten idle seconds. + cursor_blink: bool = true, /// How long a message stays after the key or click that dismisses it. message_linger_ms: u16 = 800, /// How long its ease-in fall into the row takes. @@ -863,7 +868,7 @@ pub const Runtime = struct { /// The message timings a setting word sets, each in milliseconds. pub const MessageTime = enum { linger, fall, dissolve }; - pub const Toggle = enum { colors, wrap, tree_context_tag_style, tag_bottom, debug, focus_tint, syntax_bold, verbose, message_animation, ligatures }; + pub const Toggle = enum { colors, wrap, tree_context_tag_style, tag_bottom, debug, focus_tint, syntax_bold, verbose, message_animation, ligatures, cursor_blink }; /// The bundled post pass, a Shadertoy file in shaders/post/. pub const Scene = enum { crt }; @@ -918,6 +923,7 @@ pub const Runtime = struct { .{ .word = "Verbose", .action = .{ .toggle = .verbose } }, .{ .word = "MessageAnimation", .action = .{ .toggle = .message_animation } }, .{ .word = "Ligatures", .action = .{ .toggle = .ligatures }, .availability = .ligatures }, + .{ .word = "CursorBlink", .action = .{ .toggle = .cursor_blink }, .availability = .lift }, .{ .word = "Lift", .action = .lift, .availability = .lift }, .{ .word = "Motion", .action = .motion }, .{ .word = "InactiveDim", .action = .inactive_dim }, @@ -990,6 +996,9 @@ pub const Runtime = struct { .toggle => |field| if (field == .ligatures) { if (setting.availability != .ligatures) @compileError("the ligatures toggle must use the ligatures capability"); + } else if (field == .cursor_blink) { + if (setting.availability != .lift) + @compileError("CursorBlink must use the lift capability (a pixel shell's)"); } else if (setting.availability != null) @compileError("unconditional toggles cannot carry a backend capability"), else => if (setting.availability != null) @@ -1618,6 +1627,7 @@ pub const Runtime = struct { .verbose => "Verbose off\n", .message_animation => "MessageAnimation off\n", .ligatures => "Ligatures off\n", + .cursor_blink => "CursorBlink off\n", }, .shell => "Shell requested (new panes) fish\n", .tagline_size => "TaglineSize 73\n", -- cgit v1.3