From 3bc0796def5c1c1013bf3e11d7c94264ed330713 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 11:28:55 -0300 Subject: Afterglow (G14) is removed The user, looking at the lapis showcase: "one of the animations is like a flashing on the whole pane or something, that is really bad, just remove it". Every changed cell glowing meant a pane whose whole text changed (a file opened, a +Search refilled, a terminal's output) lit up at once: replacing a pane's text took its mean brightness from 38 to 70 and back over 250 ms. Gone like Ripple and Glitch: the builtin, the setting, its Chrome fx bit, the GUI's diff state and decor, the test, and the docs, which keep the user's words. --- docs/config.md | 2 - docs/effects.md | 14 ++--- docs/render-pipeline.md | 2 +- src/config.zig | 10 +--- src/draw.zig | 2 +- src/gui/gui.zig | 152 +----------------------------------------------- src/surface.zig | 3 +- 7 files changed, 12 insertions(+), 173 deletions(-) diff --git a/docs/config.md b/docs/config.md index 58836b7b..b5ec1aa5 100644 --- a/docs/config.md +++ b/docs/config.md @@ -587,8 +587,6 @@ Occlusion on pane bodies darken faintly toward their edges (2%), never over the cursor Parallax on a theme's page pattern (lapis's dots) moves with the text at a quarter of its speed -Afterglow on text that changes glows for a moment in the theme's accent - and fades (250 ms), never on a tag, the cursor or a selection JumpTrail on in a terminal, a jump of the cursor of three cells or more leaves a trail of a few cells that fades in 120 ms (truecolor terminals; a pixel shell glides instead) diff --git a/docs/effects.md b/docs/effects.md index a0edc2ab..894bd75d 100644 --- a/docs/effects.md +++ b/docs/effects.md @@ -47,7 +47,7 @@ why. The verdict is the user's. | G11 look-hover glow | `HoverGlow on\|off` (off) | a soft underline of the theme's accent under the word a look-hover would open, fading in over 80 ms | .scratch/render/hover/ (forge, acme, lapis; zooms) | pending | | G12 ambient occlusion | `Occlusion on\|off` (off) | pane bodies darken toward their edges, at most 2% (§9.1: 1 to 2%) | .scratch/render/occlusion/ (on/off on forge, acme, lapis; acme-diff-x40.png) | pending | | G13 parallax | `Parallax on\|off` (off) | a theme's page pattern under the bodies (lapis's dots) moves with the text at a quarter of its speed, glides included | .scratch/render/parallax/ (lapis, notches down and up) | pending | -| G14 afterglow | `Afterglow on\|off` (off) | a body cell whose text changed glows in the accent at 18% and fades over 250 ms | .scratch/render/afterglow/ (forge, acme: two in-place edits) | pending | +| G14 afterglow | — | removed | live lapis showcase | dropped by the user: "one of the animations is like a flashing on the whole pane or something, that is really bad, just remove it" (a pane whose whole text changed, a file opened, a +Search refilled, a terminal's output, lit up at once) | ## Motion flavours @@ -246,14 +246,10 @@ lines at 35 px move the 22 px grid 13 px, 35 mod 22). The cell shader reads the offset from the instance's serial slot, free since G7 took the dissolve's per-cell noise out. Without a pattern, nothing happens. -Notes on G14: the GUI keeps the grid it last drew and when each cell last -changed; a changed cell of a pane body glows in the theme's accent, 18% at -most and under the text's contrast floor, and fades with an ease-out over -250 ms, drawn as one flat rectangle a run of cells that changed together. -Never on a tag or a grip (bodies only), the cursor's cell or a selection; -a body whose first line moved (a scroll) starts over instead of lighting -up whole. It runs on the continuous path while anything glows, and costs -a compare of the grid a frame while on, nothing while off. +Notes on G14: removed with its builtin, setting and code after the user +saw it in the lapis showcase: "one of the animations is like a flashing on +the whole pane or something, that is really bad, just remove it". Every +changed cell glowing meant a pane whose whole text changed flashed whole. ## Terminal track (§9.2) diff --git a/docs/render-pipeline.md b/docs/render-pipeline.md index 88309d4a..f39504c2 100644 --- a/docs/render-pipeline.md +++ b/docs/render-pipeline.md @@ -694,7 +694,7 @@ character effects (ascii…typewriter) → not a GUI effect (terminal track). | G11 | look-hover affordance: soft underline glow, 80 ms | hover region | P3 | | G12 | pane edge ambient occlusion (inner shadow, 1–2%) | decor `inner_shadow` | P3 | | G13 | parallax body pattern (lapis dots under see-through bodies at 0.25× scroll) | `see_through` style, per-pane view origin | P3 | -| G14 | damage afterglow (changed cells glow briefly) | shell-side diff of instances | P3 | +| G14 | damage afterglow (changed cells glow briefly) | removed: a pane whose whole text changed flashed whole (the user: "really bad, just remove it") | — | ### 9.2 Terminal track (tty, cell-native; separate, smaller) diff --git a/src/config.zig b/src/config.zig index a703f79e..ea7a877a 100644 --- a/src/config.zig +++ b/src/config.zig @@ -127,7 +127,6 @@ pub const leader_path = paths: { if (builtins.capabilities.lift) table.set(.HoverGlow, null); if (builtins.capabilities.lift) table.set(.Occlusion, null); if (builtins.capabilities.lift) table.set(.Parallax, null); - if (builtins.capabilities.lift) table.set(.Afterglow, null); table.set(.JumpTrail, null); table.set(.ChipShadow, null); table.set(.ThumbFlash, null); @@ -691,7 +690,6 @@ pub const Runtime = struct { parallax: bool = false, /// G14: text that changes glows for a moment in the theme's accent and /// fades, a pixel shell's. - afterglow: bool = false, /// T2: in a terminal, a jump of the cursor leaves a short trail that /// fades in 120 ms (a truecolor terminal's; a pixel shell glides). jump_trail: bool = false, @@ -924,7 +922,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, cursor_blink, selection_glow, hover_glow, occlusion, parallax, afterglow, jump_trail, chip_shadow, thumb_flash }; + pub const Toggle = enum { colors, wrap, tree_context_tag_style, tag_bottom, debug, focus_tint, syntax_bold, verbose, message_animation, ligatures, cursor_blink, selection_glow, hover_glow, occlusion, parallax, jump_trail, chip_shadow, thumb_flash }; /// A bundled post pass, a Shadertoy file in shaders/post/: the CRT, and /// G4's bloom, vignette and grain (docs/effects.md). pub const Scene = enum { crt, bloom, vignette, grain }; @@ -987,7 +985,6 @@ pub const Runtime = struct { .{ .word = "HoverGlow", .action = .{ .toggle = .hover_glow }, .availability = .lift, .doc = "A soft underline of light under the word a look-hover would open, on or off." }, .{ .word = "Occlusion", .action = .{ .toggle = .occlusion }, .availability = .lift, .doc = "Pane bodies darken faintly toward their edges, on or off." }, .{ .word = "Parallax", .action = .{ .toggle = .parallax }, .availability = .lift, .doc = "A theme's page pattern moves with the text at a quarter of its speed, on or off." }, - .{ .word = "Afterglow", .action = .{ .toggle = .afterglow }, .availability = .lift, .doc = "Text that changes glows for a moment and fades, on or off." }, .{ .word = "JumpTrail", .action = .{ .toggle = .jump_trail }, .doc = "In a terminal, a jump of the cursor leaves a short trail that fades, on or off." }, .{ .word = "ChipShadow", .action = .{ .toggle = .chip_shadow }, .doc = "In a terminal, a notice chip casts a cell's shadow right and down, on or off." }, .{ .word = "ThumbFlash", .action = .{ .toggle = .thumb_flash }, .doc = "In a terminal, a pane's scroll thumb brightens as it scrolls and fades back, on or off." }, @@ -1067,9 +1064,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 or field == .selection_glow or field == .hover_glow or field == .occlusion or field == .parallax or field == .afterglow) { + } else if (field == .cursor_blink or field == .selection_glow or field == .hover_glow or field == .occlusion or field == .parallax) { if (setting.availability != .lift) - @compileError("CursorBlink, SelectionGlow, HoverGlow, Occlusion, Parallax and Afterglow must use the lift capability (a pixel shell's)"); + @compileError("CursorBlink, SelectionGlow, HoverGlow, Occlusion and Parallax 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) @@ -1728,7 +1725,6 @@ pub const Runtime = struct { .hover_glow => "HoverGlow on\n", .occlusion => "Occlusion on\n", .parallax => "Parallax on\n", - .afterglow => "Afterglow on\n", .jump_trail => "JumpTrail on\n", .chip_shadow => "ChipShadow on\n", .thumb_flash => "ThumbFlash on\n", diff --git a/src/draw.zig b/src/draw.zig index 15411770..992b8ba0 100644 --- a/src/draw.zig +++ b/src/draw.zig @@ -552,7 +552,7 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface { .rail_px = @intCast(@min(255, @as(u32, p.theme().rail_px orelse 12) * p.settings.grip_width / 100)), .name_ink = chrome.tag_name_fg, .active_name_ink = if (p.settings.focus_tint) chrome.tag_active_name_fg else chrome.tag_name_fg, - .fx = @as(u8, @intFromBool(p.settings.selection_glow)) | @as(u8, @intFromBool(p.settings.hover_glow)) << 1 | @as(u8, @intFromBool(p.settings.occlusion)) << 2 | @as(u8, @intFromBool(p.settings.parallax)) << 3 | @as(u8, @intFromBool(p.settings.afterglow)) << 4, + .fx = @as(u8, @intFromBool(p.settings.selection_glow)) | @as(u8, @intFromBool(p.settings.hover_glow)) << 1 | @as(u8, @intFromBool(p.settings.occlusion)) << 2 | @as(u8, @intFromBool(p.settings.parallax)) << 3, }; if (p.theme().decor) |decor| { s.chrome.decor_dots = decor.page_dots; diff --git a/src/gui/gui.zig b/src/gui/gui.zig index cb3bdd97..ac4443ab 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -1876,7 +1876,6 @@ const Gui = struct { sel_glow: SelGlow = .{}, hover_glow: SelGlow = .{}, /// G14: the cells last drawn and when each last changed. - afterglow: Afterglow = .{}, /// The cursor's blink (blinkNow): when the frame drawn last arrived, /// a redraw owed for an edge, and this frame's cursor mode and alpha. @@ -2586,7 +2585,6 @@ fn runNative(init: std.process.Init, opts_in: pardes.Options, attach: ?[]const u defer c.ui_font_free(g.font); defer gpa.free(g.scroll_edge); // grown on demand by stepScroll defer g.glide.deinit(gpa); - defer g.afterglow.deinit(gpa); resetGlyphAtlas(&g); if (attach) |requested| return attachRequested(gpa, &g, requested); @@ -5025,7 +5023,7 @@ fn stepGlide(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void { const glide = &g.glide; // The glide runs on the core's continuous path: frames every loop, and // a virtual clock carried on. - defer core.shell_continuous = glide.moving() or g.sel_glow.fading or g.hover_glow.fading or g.afterglow.glowing; + defer core.shell_continuous = glide.moving() or g.sel_glow.fading or g.hover_glow.fading; glide.now_ns = core.now_ns; glide.motion = pardes.animation.Motion.of(core.settings.motion); if (!glide.spring.settled) { @@ -5852,7 +5850,6 @@ fn renderFrame( g.sel_glow.now_ns = if (core) |p| p.now_ns else c.SDL_GetTicksNS(); // Off, or while panes move, no glow and nothing fading. if (surface.chrome.fx & 1 == 0 or surface.panelTracks().len != 0) g.sel_glow = .{ .now_ns = g.sel_glow.now_ns }; - if (surface.chrome.fx & 16 == 0) g.afterglow.glowing = false; g.hover_glow.now_ns = g.sel_glow.now_ns; if (surface.chrome.fx & 2 == 0 or surface.panelTracks().len != 0) g.hover_glow = .{ .now_ns = g.sel_glow.now_ns }; if (g.glide.moving()) g.glide.offset = g.glide.spring.value(g.glide.now_ns); @@ -8823,7 +8820,6 @@ fn buildDecor(g: *Gui, gpa: std.mem.Allocator, surface: *const pardes.Surface, g // G11: a glow under the word a look-hover would open. if (index == 0 and groups.tracks == 0 and chrome.fx & 2 != 0) try glowBlocks(g, gpa, surface, .hover, layout, win_w, win_h); // G14: what changed glows, while nothing moves. - if (index == 0 and groups.tracks == 0 and chrome.fx & 16 != 0) try afterglowDecor(g, gpa, surface, layout, win_w, win_h); // G12: the bodies' edges shaded, a pane's in its own group. if (chrome.fx & 4 != 0) try occlusion(g, gpa, placed, groups, index, surface, ceilings, layout, win_w, win_h, track); // A single spine runs down each column, through every tag and body. @@ -9256,91 +9252,6 @@ fn occlusion(g: *Gui, gpa: std.mem.Allocator, regions: []const pardes.Region, gr } } -/// G14's state: the grid last drawn, when each cell last changed, and each -/// body's line then (a scroll changes every cell and is not a change). -const Afterglow = struct { - cells: []pardes.Cell = &.{}, - changed: []u64 = &.{}, - cols: u16 = 0, - rows: u16 = 0, - lines: [pardes.MAX_PANES]i32 = @splat(std.math.minInt(i32)), - /// A cell still glows: the core keeps frames coming. - glowing: bool = false, - - fn deinit(glow: *Afterglow, gpa: std.mem.Allocator) void { - gpa.free(glow.cells); - gpa.free(glow.changed); - } -}; - -const afterglow_ns: u64 = 250 * std.time.ns_per_ms; - -/// G14: a cell of a pane body whose text changed since the last frame -/// glows in the theme's accent at 18% and fades out over 250 ms with an -/// ease-out, as a run of cells a row. Never on a tag or a grip (bodies -/// only), the cursor or a selection; a body whose view moved (a scroll) -/// starts over rather than lighting up whole. -fn afterglowDecor(g: *Gui, gpa: std.mem.Allocator, surface: *const pardes.Surface, layout: CellLayout, win_w: f32, win_h: f32) !void { - const glow = &g.afterglow; - const now = g.sel_glow.now_ns; - const n = @as(usize, surface.cols) * surface.rows; - const fresh = glow.cols != surface.cols or glow.rows != surface.rows or glow.cells.len != n; - if (fresh) { - glow.cells = try gpa.realloc(glow.cells, n); - glow.changed = try gpa.realloc(glow.changed, n); - @memcpy(glow.cells, surface.cells); - @memset(glow.changed, 0); - glow.cols = surface.cols; - glow.rows = surface.rows; - } - const chrome = &surface.chrome; - const page = chrome.page orelse bg_default; - const fg = chrome.fg orelse fg_default; - const cap = @min(0.18, lightenCeiling(fg, page, chrome.accent)); - var glowing = false; - for (surface.regionList()) |body| { - if (body.kind != .body or body.owner >= glow.lines.len) continue; - const scrolled = glow.lines[body.owner] != body.line; - glow.lines[body.owner] = body.line; - var row = body.rect.y; - while (row < body.rect.y + body.rect.h and row < surface.rows) : (row += 1) { - var run_start: ?u16 = null; - var run_age: u64 = 0; - var col = body.rect.x; - while (col <= body.rect.x + body.rect.w and col <= surface.cols) : (col += 1) { - var age: ?u64 = null; - if (col < body.rect.x + body.rect.w and col < surface.cols) { - const at = @as(usize, row) * surface.cols + col; - const cell = surface.cells[at]; - const differs = !std.meta.eql(cell.style, glow.cells[at].style) or !std.mem.eql(u8, cell.grapheme(), glow.cells[at].grapheme()) or cell.default != glow.cells[at].default; - if (differs and !fresh) glow.changed[at] = if (scrolled) 0 else now; - const selected = !cell.default and switch (cell.style.bg) { - .rgb => |rgb| std.mem.eql(u8, &rgb, &chrome.sel_bg), - else => false, - }; - const cursor_here = if (surface.cursor) |cu| cu.x == col and cu.y == row else false; - const since = now -| glow.changed[at]; - if (glow.changed[at] != 0 and since < afterglow_ns and !selected and !cursor_here) age = since; - } - // A run is cells that changed together. - if (run_start) |start| if (age == null or age.? != run_age) { - const t = @as(f32, @floatFromInt(run_age)) / @as(f32, @floatFromInt(afterglow_ns)); - const fade = (1 - t) * (1 - t) * (1 - t); - try addDecor(g, gpa, @as(f32, @floatFromInt(start)) * layout.w, @as(f32, @floatFromInt(row)) * layout.h, @as(f32, @floatFromInt(col)) * layout.w, @as(f32, @floatFromInt(row + 1)) * layout.h, chrome.accent, cap * fade, null, win_w, win_h); - glowing = true; - run_start = null; - }; - if (age) |a| if (run_start == null) { - run_start = col; - run_age = a; - }; - } - } - } - @memcpy(glow.cells, surface.cells); - glow.glowing = glowing; -} - /// A theme's tag plaques (Chrome.decor_box_*), drawn under the cells of /// group `index`: each pane tag, and with the still panes the column and /// workspace tags, becomes a framed box inside its own band with a hard @@ -9991,67 +9902,6 @@ test "a body tells its first line, and lapis's dots under it move a quarter as f try std.testing.expectEqual(@as(f32, 0), decor.parallaxAt(900, 10)); } -test "changed text glows and fades in 250 ms; the cursor and a scroll do not light up" { - const gpa = std.testing.allocator; - const core = try pardes.Pardes.init(gpa, .{ .cols = 80, .rows = 24 }); - defer core.deinit(); - const pane = try core.setTestFile("line\n" ** 60); - core.settings.afterglow = true; - pardes.test_api.sync(core); - const s = try core.render(core.scratch.allocator()); - const body = for (s.regionList()) |region| { - if (region.kind == .body) break region; - } else return error.NoBody; - s.cursor = .{ .x = body.rect.x + 12, .y = body.rect.y + 2 }; - var g: Gui = undefined; - g.decor = .empty; - defer g.decor.deinit(gpa); - g.cell_w = 10; - g.cell_h = 20; - g.afterglow = .{}; - defer g.afterglow.deinit(gpa); - const layout = fixedCellLayout(&g); - const Count = struct { - fn glows(items: []const CellInstance, accent: [3]u8) usize { - var n: usize = 0; - for (items) |item| { - const rgb: [3]u8 = .{ @intFromFloat(@round(item.br * 255)), @intFromFloat(@round(item.bg * 255)), @intFromFloat(@round(item.bb * 255)) }; - if (std.mem.eql(u8, &rgb, &accent) and item.fr > 0.001) n += 1; - } - return n; - } - }; - g.sel_glow = .{ .now_ns = std.time.ns_per_s }; - try afterglowDecor(&g, gpa, s, layout, 800, 480); - try std.testing.expectEqual(@as(usize, 0), g.decor.items.len); - // Three cells of a row change, the cursor's among them. - for (10..13) |x| { - const cell = &s.cells[@as(usize, body.rect.y + 2) * s.cols + body.rect.x + x]; - cell.* = .{ .default = false, .style = .{ .fg = .{ .rgb = .{ 1, 2, 3 } } } }; - cell.text[0] = 'X'; - cell.len = 1; - } - g.sel_glow.now_ns += 16 * std.time.ns_per_ms; - try afterglowDecor(&g, gpa, s, layout, 800, 480); - try std.testing.expectEqual(@as(usize, 1), Count.glows(g.decor.items, s.chrome.accent)); - const lit = g.decor.items[0]; - // Two cells wide: the cursor's is left out. - try std.testing.expectApproxEqAbs(@as(f32, 2 * 10 * 2.0 / 800.0), lit.x1 - lit.x0, 1e-4); - try std.testing.expect(g.afterglow.glowing); - // Gone by 250 ms. - g.decor.clearRetainingCapacity(); - g.sel_glow.now_ns += 260 * std.time.ns_per_ms; - try afterglowDecor(&g, gpa, s, layout, 800, 480); - try std.testing.expectEqual(@as(usize, 0), g.decor.items.len); - try std.testing.expect(!g.afterglow.glowing); - // A scroll changes every cell and lights none. - pane.scrollBy(5); - const scrolled = try core.render(core.scratch.allocator()); - g.sel_glow.now_ns += 16 * std.time.ns_per_ms; - try afterglowDecor(&g, gpa, scrolled, layout, 800, 480); - try std.testing.expectEqual(@as(usize, 0), g.decor.items.len); -} - /// What a bundled post pass leaves alone (Post.Frame.spare), in window /// pixels: every tag with its grip, the column and workspace tags, and the /// notices, the chrome the focus indicators live in. A grip, the gap after diff --git a/src/surface.zig b/src/surface.zig index 22a71a27..d1ea78b1 100644 --- a/src/surface.zig +++ b/src/surface.zig @@ -455,8 +455,7 @@ pub const Chrome = struct { /// A pixel shell's small effects: bit 0 a glow round the body's /// selection (G9, SelectionGlow), bit 1 one under the word a look-hover /// would open (G11, HoverGlow), bit 2 the bodies' edge shade (G12, - /// Occlusion), bit 3 the page pattern's parallax (G13, Parallax), bit 4 - /// changed text's afterglow (G14, Afterglow). + /// Occlusion), bit 3 the page pattern's parallax (G13, Parallax). fx: u8 = 0, }; -- cgit v1.3