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/pardes.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/pardes.zig') diff --git a/src/pardes.zig b/src/pardes.zig index 6294b6cb..cbdc3037 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4260,6 +4260,12 @@ pub const Pardes = struct { /// spring. `lift_serials` says whose it is, so a reused slot starts flat. lifts: [MAX_PANES]animation.Spring = @splat(.{}), lift_serials: [MAX_PANES]u32 = @splat(0), + /// The focused cursor's quad on its springs (animation.CursorGlide), + /// the pane and view origin it was last aimed in, and the last key or + /// click, which a blink holds for. + cursor_glide: animation.CursorGlide = .{}, + cursor_view: struct { serial: u32 = 0, line: i64 = 0 } = .{}, + input_ns: u64 = 0, animate_theme_changes: bool = false, native_images: bool = false, /// The shell can take a changed image a few rows at a time (a texture row @@ -5311,6 +5317,7 @@ pub const Pardes = struct { } switch (ev) { .key, .mouse => { + if (ev == .key or ev.mouse.kind != .motion) p.input_ns = p.now_ns; for (p.panes) |slot| { if (slot) |pane| Messages.dismissMessage(p, pane); } @@ -6441,13 +6448,14 @@ pub const Pardes = struct { return if (frames) |n| p.stepped_ns + n * animation.frame_ns else null; } + /// A render-time animation is moving (a pane's lift): it is sampled at /// each frame's own `now`, so while it moves the shell draws every loop /// and its present (vsync) paces it, at the display's rate. `nextWake` /// is for the stepped animations, which count frames of `frame_ns`. pub fn continuous(p: *const Pardes) bool { for (p.lifts) |spring| if (!spring.settled) return true; - return false; + return p.cursor_glide.moving(); } /// For shells that only need a yes or no: macOS and the board, which -- cgit v1.3