summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 16:44:51 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commita007457cb007b03f310bca55c339e8cd5d9baafc (patch)
tree31e57644c6df2eef04fb3c2a200482571c6e6857 /src
parent1ed34e1538f45daecc2c8a551dc0fb7aba5f3f54 (diff)
downloadpardes-a007457cb007b03f310bca55c339e8cd5d9baafc.tar.gz
pardes-a007457cb007b03f310bca55c339e8cd5d9baafc.zip
Ripple and Glitch are gone; Crt stays
The user tried them live and wants them removed entirely: the builtins, their levels, config keys and leader paths (tR, tg), their slots in the built-in chain, their shaders (source and prebuilt), EffectCode paths, and on macOS their scene flags (pardes.h), the Metal kernel's coordinate warps and the Swift pointer mapping that mirrored them. Docs say so (decision 8 in docs/render-pipeline.md); config.md documents Crt's levels, Shader and ShaderAnimation instead. Shared files touched: macos.zig (flags). Not touched: pardes.zig, Messages.zig, mouse.zig, gui.zig, detached/*.
Diffstat (limited to 'src')
-rw-r--r--src/config.zig22
-rw-r--r--src/effect_sources.zig8
-rw-r--r--src/gui/Post.zig8
-rw-r--r--src/macos.zig17
-rw-r--r--src/macos/Sources/PardesView.swift2
-rw-r--r--src/macos/Sources/ScenePostprocessor.swift48
-rw-r--r--src/macos/pardes.h5
7 files changed, 19 insertions, 91 deletions
diff --git a/src/config.zig b/src/config.zig
index e8c5a705..d1e5f23d 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -129,8 +129,6 @@ pub const leader_path = paths: {
}
if (builtins.capabilities.scene_shaders) {
table.set(.Crt, "tr");
- table.set(.Ripple, "tR");
- table.set(.Glitch, "tg");
table.set(.Shader, null);
table.set(.ShaderAnimation, null);
}
@@ -622,7 +620,7 @@ pub const Runtime = struct {
pub const ShaderAnimation = enum { off, on, always };
- /// Each pass a bundled effect (Crt, Ripple, Glitch) or a Shadertoy file.
+ /// Each pass the bundled Crt or a Shadertoy file.
pub const Post = struct {
pub const max = 8;
pub const Entry = struct {
@@ -774,8 +772,8 @@ pub const Runtime = struct {
pub const MessageTime = enum { linger, fall, dissolve };
pub const Toggle = enum { colors, wrap, tree_context_tag_style, tag_bottom, debug, focus_tint, column_tags, syntax_bold, verbose, message_animation, ligatures };
- /// The bundled post passes, each a Shadertoy file in shaders/post/.
- pub const Scene = enum { crt, ripple, glitch };
+ /// The bundled post pass, a Shadertoy file in shaders/post/.
+ pub const Scene = enum { crt };
pub const Action = union(enum) {
toggle: Toggle,
@@ -843,8 +841,6 @@ pub const Runtime = struct {
.{ .word = "PanelScramble", .action = .{ .transition = .scramble }, .availability = .panel_transitions },
.{ .word = "PanelType", .action = .{ .transition = .typewriter }, .availability = .panel_transitions },
.{ .word = "Crt", .action = .{ .scene = .crt }, .availability = .scene_shaders },
- .{ .word = "Ripple", .action = .{ .scene = .ripple }, .availability = .scene_shaders },
- .{ .word = "Glitch", .action = .{ .scene = .glitch }, .availability = .scene_shaders },
.{ .word = "Shader", .action = .shader, .availability = .scene_shaders },
.{ .word = "ShaderAnimation", .action = .shader_animation, .availability = .scene_shaders },
};
@@ -1263,18 +1259,18 @@ pub const Runtime = struct {
test "the post chain runs in the order its passes were put in, and Shader off empties it of files" {
var state: Runtime = .{};
try std.testing.expect(apply(&state, find("Shader").?, " ~/a.glsl\n"));
- try std.testing.expect(apply(&state, find("Glitch").?, "on"));
+ try std.testing.expect(apply(&state, find("Crt").?, "on"));
try std.testing.expect(apply(&state, find("Shader").?, "/b.glsl"));
const chain = state.post.list();
try std.testing.expectEqual(@as(usize, 3), chain.len);
try std.testing.expectEqualStrings("~/a.glsl", chain[0].path.get());
- try std.testing.expectEqual(Scene.glitch, chain[1].scene.?);
+ try std.testing.expectEqual(Scene.crt, chain[1].scene.?);
try std.testing.expectEqualStrings("/b.glsl", chain[2].path.get());
const moved = state.post.generation;
// A file named again leaves; the others keep their order.
try std.testing.expect(apply(&state, find("Shader").?, "~/a.glsl"));
try std.testing.expect(state.post.generation != moved);
- try std.testing.expectEqual(Scene.glitch, state.post.list()[0].scene.?);
+ try std.testing.expectEqual(Scene.crt, state.post.list()[0].scene.?);
try std.testing.expect(apply(&state, find("Shader").?, "off"));
try std.testing.expectEqual(@as(usize, 1), state.post.len);
try std.testing.expect(!apply(&state, find("Shader").?, null));
@@ -1288,7 +1284,7 @@ pub const Runtime = struct {
const crt = find("Crt").?;
try std.testing.expect(apply(&state, crt, "on"));
try std.testing.expectEqual(@as(u8, Post.default_level), state.post.level(.crt));
- try std.testing.expect(apply(&state, find("Glitch").?, "1"));
+ try std.testing.expect(apply(&state, find("Shader").?, "/after.glsl"));
const moved = state.post.generation;
try std.testing.expect(apply(&state, crt, "3"));
try std.testing.expectEqual(@as(u8, 3), state.post.level(.crt));
@@ -1472,8 +1468,6 @@ pub const Runtime = struct {
},
.scene => |effect| switch (effect) {
.crt => "Crt 2\n",
- .ripple => "Ripple 2\n",
- .glitch => "Glitch 2\n",
},
.shader => "Shader ~/crt.glsl\n",
.shader_animation => "ShaderAnimation always\n",
@@ -1544,8 +1538,6 @@ pub const Runtime = struct {
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Font requested") == null);
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Panel transition off\n") != null);
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Crt unsupported\n") != null);
- try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Ripple unsupported\n") != null);
- try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Glitch unsupported\n") != null);
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "TaglineSize unsupported\n") != null);
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Look hover delay: off\n") != null);
try std.testing.expect(std.mem.indexOf(u8, defaults_report, "Native images: off\n") != null);
diff --git a/src/effect_sources.zig b/src/effect_sources.zig
index 6ce11160..83bd1313 100644
--- a/src/effect_sources.zig
+++ b/src/effect_sources.zig
@@ -12,10 +12,8 @@ const ui_fragment_path = shader_dir ++ "ui.frag.glsl";
const image_vertex_path = shader_dir ++ "image.vert.glsl";
const image_fragment_path = shader_dir ++ "image.frag.glsl";
const post_vertex_path = shader_dir ++ "post.vert.glsl";
-// The bundled post passes as compiled: the prefix and the pass together.
+// The bundled post pass as compiled: the prefix and the pass together.
const post_crt_path = shader_dir ++ "post-crt.frag.glsl";
-const post_ripple_path = shader_dir ++ "post-ripple.frag.glsl";
-const post_glitch_path = shader_dir ++ "post-glitch.frag.glsl";
pub const Backend = @TypeOf(build_config.platform);
pub const backend: Backend = build_config.platform;
@@ -55,8 +53,6 @@ pub const files = switch (backend) {
.{ .path = image_fragment_path, .contents = @embedFile("effect-source-image.frag.glsl") },
.{ .path = post_vertex_path, .contents = @embedFile("effect-source-post.vert.glsl") },
.{ .path = post_crt_path, .contents = @embedFile("effect-source-post-crt.frag.glsl") },
- .{ .path = post_ripple_path, .contents = @embedFile("effect-source-post-ripple.frag.glsl") },
- .{ .path = post_glitch_path, .contents = @embedFile("effect-source-post-glitch.frag.glsl") },
},
.macos => [_]filesystem.Source{
.{ .path = "src/macos/Sources/PardesView.swift", .contents = @embedFile("macos/Sources/PardesView.swift") },
@@ -77,8 +73,6 @@ pub fn forSetting(setting: config.Runtime.Setting) ?[]const []const u8 {
.scene => |effect| switch (backend) {
.gui => switch (effect) {
.crt => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_crt_path },
- .ripple => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_ripple_path },
- .glitch => &.{ "src/gui/Post.zig", "src/gui/gui.zig", post_vertex_path, post_glitch_path },
},
.macos => &.{ "src/macos/Sources/PardesView.swift", "src/macos/Sources/ScenePostprocessor.swift", "shaders/crt.ci.metal" },
.tty, .web, .esp32p4 => null,
diff --git a/src/gui/Post.zig b/src/gui/Post.zig
index d9d3d53e..f715965f 100644
--- a/src/gui/Post.zig
+++ b/src/gui/Post.zig
@@ -1,7 +1,7 @@
//! The post chain (docs/render-pipeline.md ยง6): Shadertoy passes over the
//! finished frame, each reading the one before it (the frame first) and the
-//! last one writing the window. A pass is bundled (Crt, Ripple, Glitch:
-//! shaders/post/, compiled with the build) or a user's file (Shader <path>),
+//! last one writing the window. A pass is the bundled Crt (shaders/post/,
+//! compiled with the build) or a user's file (Shader <path>),
//! compiled when it joins the chain by the build's own glslc invocation on a
//! thread of its own, never on the frame path. A file whose compile fails
//! keeps its last good pipeline, and glslc missing is said once.
@@ -28,8 +28,6 @@ const prefix = @embedFile("post-prefix.glsl");
const vert_spv = @embedFile("post.vert.spv");
const bundled_spv = std.EnumArray(Scene, []const u8).init(.{
.crt = @embedFile("post-crt.frag.spv"),
- .ripple = @embedFile("post-ripple.frag.spv"),
- .glitch = @embedFile("post-glitch.frag.spv"),
});
/// ghostty's Shadertoy uniform block, member for member in the GLSL block's
@@ -170,7 +168,7 @@ fn collect(post: *Post, gpa: std.mem.Allocator, device: *c.SDL_GPUDevice, format
.none => {},
.missing => if (!post.missing_said) {
post.missing_said = true;
- core.setMessage(core.active, "Shader: glslc is not on PATH, so Shadertoy files do not run (Crt, Ripple and Glitch do)");
+ core.setMessage(core.active, "Shader: glslc is not on PATH, so Shadertoy files do not run (Crt does)");
},
.failed => |text| {
defer gpa.free(text);
diff --git a/src/macos.zig b/src/macos.zig
index 0bad86ee..6cd7838f 100644
--- a/src/macos.zig
+++ b/src/macos.zig
@@ -112,8 +112,6 @@ const cell_flag_default: u8 = 1;
const cell_flag_tagline: u8 = 2;
const cell_flag_hover: u8 = 4;
const scene_flag_crt: u32 = 1 << 0;
-const scene_flag_ripple: u32 = 1 << 1;
-const scene_flag_glitch: u32 = 1 << 2;
const scene_frame_hz: u32 = 60;
const scene_wrap_ns: u64 = 4096 * std.time.ns_per_s;
@@ -850,13 +848,11 @@ export fn pardes_should_quit() bool {
return st.core.quit;
}
-// The Metal shell keeps its own CRT, ripple and glitch kernel: the bundled
-// passes of the GUI's post chain, as flags.
+// The Metal shell keeps its own CRT kernel: the GUI's bundled post pass, as
+// a flag.
fn encodeSceneEffects(post: *const pardes.config.Runtime.Post) u32 {
var flags: u32 = 0;
if (post.has(.crt)) flags |= scene_flag_crt;
- if (post.has(.ripple)) flags |= scene_flag_ripple;
- if (post.has(.glitch)) flags |= scene_flag_glitch;
return flags;
}
@@ -2842,8 +2838,6 @@ test "pardes.h matches the Zig boundary" {
try expectEqual(@as(u8, c.PARDES_CELL_HOVER), cell_flag_hover);
try expectEqual(@as(u16, c.PARDES_TOPBAR_H), pardes.TOPBAR_H);
try expectEqual(@as(u32, c.PARDES_SCENE_CRT), scene_flag_crt);
- try expectEqual(@as(u32, c.PARDES_SCENE_RIPPLE), scene_flag_ripple);
- try expectEqual(@as(u32, c.PARDES_SCENE_GLITCH), scene_flag_glitch);
try expectEqual(@as(u8, c.PARDES_PANEL_OPENING), @intFromEnum(animation.Phase.opening));
try expectEqual(@as(u8, c.PARDES_PANEL_MOVING), @intFromEnum(animation.Phase.moving));
try expectEqual(@as(u8, c.PARDES_PANEL_CLOSING), @intFromEnum(animation.Phase.closing));
@@ -2918,13 +2912,6 @@ test "scene effect flags and display clock are compact and independent" {
try expectEqual(@as(u32, 0), encodeSceneEffects(&post));
_ = post.set(.crt, "", true);
try expectEqual(scene_flag_crt, encodeSceneEffects(&post));
- _ = post.set(.ripple, "", true);
- _ = post.set(.glitch, "", true);
- try expectEqual(scene_flag_crt | scene_flag_ripple | scene_flag_glitch, encodeSceneEffects(&post));
- try expectEqual(
- scene_flag_crt | scene_flag_ripple | scene_flag_glitch,
- encodeSceneEffects(.{ .crt = true, .ripple = true, .glitch = true }),
- );
var st: State = undefined;
st.scene_ns = scene_wrap_ns - (std.time.ns_per_ms * 5);
diff --git a/src/macos/Sources/PardesView.swift b/src/macos/Sources/PardesView.swift
index 70f467e3..8ba9c84b 100644
--- a/src/macos/Sources/PardesView.swift
+++ b/src/macos/Sources/PardesView.swift
@@ -684,7 +684,7 @@ final class PardesView: NSView {
private var latchedButton: pardes_mouse_button_e?
private var latchedCell: GridPoint?
/// Last physical point delivered by AppKit and its mapping through the
- /// accepted scene. Ripple/glitch can move a source cell under a stationary
+ /// accepted scene. The CRT's barrel moves a source cell under a stationary
/// hand, so successful scene presentations reconcile this point again.
private var pointerPoint: CGPoint?
private var pointerCell: GridPoint?
diff --git a/src/macos/Sources/ScenePostprocessor.swift b/src/macos/Sources/ScenePostprocessor.swift
index cf7892b3..41d54e34 100644
--- a/src/macos/Sources/ScenePostprocessor.swift
+++ b/src/macos/Sources/ScenePostprocessor.swift
@@ -205,11 +205,9 @@ final class ScenePostprocessor {
if scene.flags != 0 {
let crt: Float = scene.flags & UInt32(PARDES_SCENE_CRT) != 0 ? 1 : 0
- let ripple: Float = scene.flags & UInt32(PARDES_SCENE_RIPPLE) != 0 ? 1 : 0
- let glitch: Float = scene.flags & UInt32(PARDES_SCENE_GLITCH) != 0 ? 1 : 0
// SDL samples the scene with CLAMP_TO_EDGE. A finite Core Image
// instead supplies transparent black outside its extent, which
- // would make ripple/glitch tear dark seams at the window edge.
+ // would tear dark seams at the window edge.
// Clamp the input only; the kernel still emits true black before
// sampling when a destination lies outside the CRT tube.
let sceneInput = filtered.clampedToExtent()
@@ -218,7 +216,7 @@ final class ScenePostprocessor {
roiCallback: { _, _ in extent },
arguments: [
sceneInput, scene.time_seconds, Float(scene.frame),
- crt, ripple, glitch,
+ crt,
CIVector(x: extent.width, y: extent.height),
CIVector(x: extent.minX, y: extent.minY),
])
@@ -291,7 +289,7 @@ final class ScenePostprocessor {
/// The scene kernel is a destination-to-source mapping. Pointer input must
/// apply that same mapping before the grid and its panel tracks see a cell,
- /// otherwise a visible word under ripple/glitch is not the word Look gets.
+ /// otherwise a visible word under the barrel is not the word Look gets.
static func sourcePoint(
_ point: CGPoint,
size: CGSize,
@@ -311,27 +309,8 @@ final class ScenePostprocessor {
ccY *= barrel
uvX = ccX * 0.5 + 0.5
uvY = ccY * 0.5 + 0.5
- // Only CRT has a black tube. Ripple/glitch without CRT sample through
- // the texture's clamp-to-edge policy and remain clickable there.
+ // The CRT's black tube has no cell under it.
if crt > 0.5 && min(min(uvX, uvY), min(1 - uvX, 1 - uvY)) <= 0 { return nil }
-
- let time = scene.time_seconds
- if scene.flags & UInt32(PARDES_SCENE_RIPPLE) != 0 {
- let centeredX = uvX - 0.5
- let centeredY = uvY - 0.5
- let radius = sqrtf(centeredX * centeredX + centeredY * centeredY)
- let envelope = 1 - smoothstep(0.04, 0.72, radius)
- let wave = sinf(radius * 42 - time * 5.2)
- let travel = wave * envelope * 0.0032 / max(radius, 0.00001)
- uvX += centeredX * travel
- uvY += centeredY * travel
- }
- if scene.flags & UInt32(PARDES_SCENE_GLITCH) != 0 {
- let band = floorf(uvY * 96)
- let seed = noise(band, floorf(time * 13))
- let tear = smoothstep(0.955, 1, seed)
- uvX += (noise(seed, band) - 0.5) * tear * 0.020
- }
uvX = min(max(uvX, 0), max(0, 1 - 1 / Float(size.width)))
uvY = min(max(uvY, 0), max(0, 1 - 1 / Float(size.height)))
return CGPoint(
@@ -339,23 +318,4 @@ final class ScenePostprocessor {
y: CGFloat(1 - uvY) * size.height)
}
- private static func smoothstep(_ edge0: Float, _ edge1: Float, _ x: Float) -> Float {
- let t = min(max((x - edge0) / (edge1 - edge0), 0), 1)
- return t * t * (3 - 2 * t)
- }
-
- /// Scalar spelling of pardesNoise in crt.ci.metal. Float arithmetic is
- /// deliberate: the shader's band decision must not move at a Double round.
- private static func noise(_ x: Float, _ y: Float) -> Float {
- var qx = fract(x * 0.1031)
- var qy = fract(y * 0.1031)
- var qz = fract(x * 0.1031)
- let d = qx * (qy + 33.33) + qy * (qz + 33.33) + qz * (qx + 33.33)
- qx += d
- qy += d
- qz += d
- return fract((qx + qy) * qz)
- }
-
- private static func fract(_ x: Float) -> Float { x - floorf(x) }
}
diff --git a/src/macos/pardes.h b/src/macos/pardes.h
index f74330e5..29f8a37d 100644
--- a/src/macos/pardes.h
+++ b/src/macos/pardes.h
@@ -82,8 +82,7 @@ typedef struct {
// from the background colour, which a real selection shares.
#define PARDES_CELL_HOVER 0x04u
-// One coherent snapshot for the full-window shader pass. The bitmask lets the
-// host run CRT, ripple and glitch in one kernel instead of stacking filters;
+// One coherent snapshot for the full-window shader pass (CRT);
// time/frame advance only on pardes_animation_tick's display clock.
typedef struct {
uint32_t flags;
@@ -92,8 +91,6 @@ typedef struct {
} pardes_scene_s;
#define PARDES_SCENE_CRT 0x01u
-#define PARDES_SCENE_RIPPLE 0x02u
-#define PARDES_SCENE_GLITCH 0x04u
// One backend-neutral pane transition. Boxes are logical cell rectangles;
// the native shader converts them to backing pixels using the same measured