Commit 8fd4b3a
Changed files (2)
.config
ghostty
.config/ghostty/config
@@ -7,10 +7,19 @@ keybind = ctrl+shift+r=reload_config
keybind = ctrl+shift+i=unbind
font-family = Hack Nerd Font Propo
-background-opacity = 0.95
+background-opacity = 0.9
cursor-color = #b4befe
-
+custom-shader = cursor_smear.glsl
cursor-style = bar
cursor-style-blink = true
+
+#shell-integration = zsh
shell-integration-features = no-cursor
+
+term = xterm-ghostty
+mouse-hide-while-typing = true
+
+command = /bin/zsh -c "tmux new"
+
+
.config/ghostty/cursor_smear.glsl
@@ -0,0 +1,173 @@
+// Cursor trail shader that creates a hexagonal trailing effect
+//
+// The effect works by:
+// 1. Constructing a hexagon from current and previous cursor positions
+// 2. Using signed distance fields (SDF) for smooth antialiased rendering
+// 3. Animating the trailing corner with easing for fluid motion
+// 4. Enhancing color saturation for visual impact
+
+// Process each edge: compute distance and determine if point is inside
+void processEdge(vec2 p, vec2 a, vec2 b, inout float minDist, inout float inside) {
+ vec2 edge = b - a;
+ vec2 pa = p - a;
+ float lenSq = dot(edge, edge);
+ float invLenSq = 1.0 / lenSq;
+
+ float t = clamp(dot(pa, edge) * invLenSq, 0.0, 1.0);
+ vec2 diff = pa - edge * t;
+ minDist = min(minDist, dot(diff, diff));
+
+ float cross = edge.x * pa.y - edge.y * pa.x;
+ inside = min(inside, step(0.0, cross));
+}
+
+// Signed distance field for hexagon (negative inside, positive outside)
+// Vertices must be in counter-clockwise order
+float sdHexagon(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3, in vec2 v4, in vec2 v5) {
+ float minDist = 1e20;
+ float inside = 1.0;
+
+ processEdge(p, v0, v1, minDist, inside);
+ processEdge(p, v1, v2, minDist, inside);
+ processEdge(p, v2, v3, minDist, inside);
+ processEdge(p, v3, v4, minDist, inside);
+ processEdge(p, v4, v5, minDist, inside);
+ processEdge(p, v5, v0, minDist, inside);
+
+ float dist = sqrt(max(minDist, 0.0));
+ return mix(dist, -dist, inside);
+}
+
+// Signed distance field for rectangle (negative inside, positive outside)
+float sdRectangle(in vec2 p, in vec2 center, in vec2 halfSize) {
+ vec2 d = abs(p - center) - halfSize;
+ return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
+}
+
+// Represents cursor as a quad with four corners
+struct Quad {
+ vec2 topLeft;
+ vec2 topRight;
+ vec2 bottomLeft;
+ vec2 bottomRight;
+};
+
+// Construct quad from top-left position and size
+Quad getQuad(vec2 pos, vec2 size) {
+ Quad q;
+ q.topLeft = pos;
+ q.topRight = pos + vec2(size.x, 0.0);
+ q.bottomLeft = pos - vec2(0.0, size.y);
+ q.bottomRight = pos + vec2(size.x, -size.y);
+ return q;
+}
+
+// Select 3 corners from quad based on movement direction
+// sel.x: 0=left, 1=right | sel.y: 0=top, 1=bottom
+// Returns corners in counter-clockwise order for hexagon construction
+void selectTrailCorners(Quad q, vec2 sel, out vec2 p1, out vec2 p2, out vec2 p3) {
+ p1 = mix(mix(q.topRight, q.topLeft, sel.x),
+ mix(q.bottomRight, q.bottomLeft, sel.x),
+ sel.y);
+
+ p2 = mix(mix(q.topLeft, q.bottomLeft, sel.x),
+ mix(q.topRight, q.bottomRight, sel.x),
+ sel.y);
+ p3 = mix(mix(q.bottomRight, q.topRight, sel.x),
+ mix(q.bottomLeft, q.topLeft, sel.x),
+ sel.y);
+}
+
+// Select 4 corners from quad based on movement direction
+// sel.x: 0=left, 1=right | sel.y: 0=top, 1=bottom
+// Returns corners in counter-clockwise order for hexagon construction
+void selectCorners(Quad q, vec2 sel, out vec2 p1, out vec2 p2, out vec2 p3, out vec2 p4) {
+ selectTrailCorners(q, sel, p1, p2, p3);
+
+ p4 = mix(mix(q.bottomLeft, q.bottomRight, sel.x),
+ mix(q.topLeft, q.topRight, sel.x),
+ sel.y);
+}
+
+// Cubic ease-out function for smooth animation (expects clamped input)
+float easeClamped(float x) {
+ float t = 1.0 - x;
+ return 1.0 - t * t * t;
+}
+
+// Trail animation duration in seconds
+const float DURATION = 0.25;
+
+void mainImage(out vec4 fragColor, in vec2 fragCoord) {
+ // Calculate animation progress with easing
+ float baseProgress = clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0);
+
+ vec2 uv = fragCoord / iResolution.xy;
+ vec4 background = texture(iChannel0, uv);
+
+ // Skip further work when animation is complete
+ if (baseProgress >= 1.0) {
+ fragColor = background;
+ return;
+ }
+
+ fragColor = background;
+
+ // Precompute reused values
+ float invResY = 1.0 / iResolution.y;
+ float scale = 2.0 * invResY;
+ float aaWidth = scale;
+ vec2 normOffset = iResolution.xy * invResY;
+
+ // Normalize cursor positions and sizes to screen-independent coordinates
+ vec2 currentPos = iCurrentCursor.xy * scale - normOffset;
+ vec2 previousPos = iPreviousCursor.xy * scale - normOffset;
+ vec2 currentSize = iCurrentCursor.zw * scale;
+ vec2 previousSize = iPreviousCursor.zw * scale;
+
+ // Determine movement direction and construct cursor quads
+ vec2 deltaPos = currentPos - previousPos;
+ Quad currentCursor = getQuad(currentPos, currentSize);
+ Quad previousCursor = getQuad(previousPos, previousSize);
+ vec2 selector = step(vec2(0.0), deltaPos);
+
+ // Select corners based on movement direction
+ vec2 currP1, currP2, currP3, currP4;
+ vec2 prevP1, prevP2, prevP3;
+ selectCorners(currentCursor, selector, currP1, currP2, currP3, currP4);
+ selectTrailCorners(previousCursor, selector, prevP1, prevP2, prevP3);
+
+ float easedProgress = easeClamped(baseProgress);
+ float stretchedProgress = min(baseProgress * 2.0, 1.0);
+ float easedProgressDouble = easeClamped(stretchedProgress);
+
+ // Create trailing effect by moving diagonal point slower
+ vec2 trailP1 = mix(prevP1, currP1, easedProgress);
+ vec2 trailP2 = mix(prevP2, currP2, easedProgressDouble);
+ vec2 trailP3 = mix(prevP3, currP3, easedProgressDouble);
+
+ // Compute hexagon SDF and convert to alpha with antialiasing
+ vec2 normCoord = fragCoord * scale - normOffset;
+ float sdfHex = sdHexagon(normCoord, trailP1, trailP2, currP2, currP4, currP3, trailP3);
+ float alpha = 1.0 - smoothstep(-aaWidth, aaWidth, sdfHex);
+
+ // Compute current cursor SDF
+ vec2 halfCurrentSize = currentSize * 0.5;
+ vec2 currentCenter = currentPos + vec2(halfCurrentSize.x, -halfCurrentSize.y);
+ float sdfCurrentCursor = sdRectangle(normCoord, currentCenter, halfCurrentSize);
+
+ // Enhance color saturation for more vibrant trail effect
+ float gray = dot(iCurrentCursorColor.rgb, vec3(0.299, 0.587, 0.114));
+ const float saturationBoost = 1.8;
+ vec4 enhancedColor = clamp(
+ mix(vec4(vec3(gray), iCurrentCursorColor.a), iCurrentCursorColor, saturationBoost),
+ 0.0, 1.0
+ );
+
+ // Blend trail color with background
+ vec4 originalColor = fragColor;
+ fragColor.rgb = mix(fragColor.rgb, enhancedColor.rgb, alpha);
+
+ // Remove trail where it overlaps with current cursor
+ fragColor.rgb = mix(fragColor.rgb, originalColor.rgb, step(sdfCurrentCursor, 0.0));
+}