From f1374f54c48affa5ad516c09b4a6db7b3ca06d89 Mon Sep 17 00:00:00 2001 From: mr0xb <47467008+mr0xb@users.noreply.github.com> Date: Mon, 13 Jul 2026 15:10:55 -0400 Subject: [PATCH] initial commit --- dot_config/ghostty/config.ghostty | 37 ++ dot_config/ghostty/shaders/bling99_gold.glsl | 96 +++ dot_config/ghostty/shaders/bloom.glsl | 52 ++ .../ghostty/shaders/cash_money_frame.glsl | 43 ++ dot_config/ghostty/shaders/cubes.glsl | 114 ++++ dot_config/ghostty/shaders/cursor_sweep.glsl | 221 +++++++ dot_config/ghostty/shaders/cursor_tail.glsl | 239 ++++++++ dot_config/ghostty/shaders/cursor_warp.glsl | 308 ++++++++++ .../shaders/custom/bling99_compat.glsl | 170 +++++ .../shaders/custom/cash_money_badge.glsl | 267 ++++++++ .../shaders/custom/cash_money_dvd.glsl | 142 +++++ .../ghostty/shaders/custom/probe_invert.glsl | 5 + .../shaders/dot_claude/settings.local.json | 30 + .../ghostty/shaders/fireworks-rockets.glsl | 109 ++++ dot_config/ghostty/shaders/galaxy.glsl | 139 +++++ dot_config/ghostty/shaders/geocities.glsl | 202 ++++++ .../ghostty/shaders/iamond_teeth_cursor.glsl | 91 +++ .../shaders/rectangle_boom_cursor.glsl | 154 +++++ dot_config/ghostty/shaders/ripple_cursor.glsl | 132 ++++ .../shaders/ripple_rectangle_cursor.glsl | 138 +++++ .../ghostty/shaders/sonic_boom_cursor.glsl | 148 +++++ .../ghostty/shaders/starfield-colors.glsl | 162 +++++ dot_config/ghostty/shaders/starfield.glsl | 135 ++++ dot_config/ghostty/themes/cyberdream | 23 + dot_config/ghostty/themes/cyberdream-light | 23 + dot_config/ghostty/themes/cyberpunk | 23 + ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes .../go/telemetry/local/empty_upload.token | 0 ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-05.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-06.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-07.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes ...4-go1.26.4-linux-amd64-2026-07-04.v1.count | Bin 0 -> 16384 bytes dot_config/go/telemetry/local/weekends | 1 + dot_config/go/telemetry/upload/.keep | 0 .../themes/executable_fzf-challengerdeep.sh | 29 + dot_config/zellij/config.kdl | 580 ++++++++++++++++++ dot_local/bin/executable_fedora-backup-home | 90 +++ dot_local/bin/executable_fedora-clean | 82 +++ dot_local/bin/executable_fedora-reset-audio | 20 + dot_local/bin/executable_fedora-update | 108 ++++ dot_zshrc | 8 + 46 files changed, 4121 insertions(+) create mode 100644 dot_config/ghostty/config.ghostty create mode 100644 dot_config/ghostty/shaders/bling99_gold.glsl create mode 100644 dot_config/ghostty/shaders/bloom.glsl create mode 100644 dot_config/ghostty/shaders/cash_money_frame.glsl create mode 100644 dot_config/ghostty/shaders/cubes.glsl create mode 100644 dot_config/ghostty/shaders/cursor_sweep.glsl create mode 100644 dot_config/ghostty/shaders/cursor_tail.glsl create mode 100644 dot_config/ghostty/shaders/cursor_warp.glsl create mode 100644 dot_config/ghostty/shaders/custom/bling99_compat.glsl create mode 100644 dot_config/ghostty/shaders/custom/cash_money_badge.glsl create mode 100644 dot_config/ghostty/shaders/custom/cash_money_dvd.glsl create mode 100644 dot_config/ghostty/shaders/custom/probe_invert.glsl create mode 100644 dot_config/ghostty/shaders/dot_claude/settings.local.json create mode 100644 dot_config/ghostty/shaders/fireworks-rockets.glsl create mode 100644 dot_config/ghostty/shaders/galaxy.glsl create mode 100644 dot_config/ghostty/shaders/geocities.glsl create mode 100644 dot_config/ghostty/shaders/iamond_teeth_cursor.glsl create mode 100644 dot_config/ghostty/shaders/rectangle_boom_cursor.glsl create mode 100644 dot_config/ghostty/shaders/ripple_cursor.glsl create mode 100644 dot_config/ghostty/shaders/ripple_rectangle_cursor.glsl create mode 100644 dot_config/ghostty/shaders/sonic_boom_cursor.glsl create mode 100644 dot_config/ghostty/shaders/starfield-colors.glsl create mode 100644 dot_config/ghostty/shaders/starfield.glsl create mode 100644 dot_config/ghostty/themes/cyberdream create mode 100644 dot_config/ghostty/themes/cyberdream-light create mode 100644 dot_config/ghostty/themes/cyberpunk create mode 100644 dot_config/go/telemetry/local/asm@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/cgo@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/compile@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/empty_upload.token create mode 100644 dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-05.v1.count create mode 100644 dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-06.v1.count create mode 100644 dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-07.v1.count create mode 100644 dot_config/go/telemetry/local/gofmt@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/link@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/vet@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count create mode 100644 dot_config/go/telemetry/local/weekends create mode 100644 dot_config/go/telemetry/upload/.keep create mode 100644 dot_config/themes/executable_fzf-challengerdeep.sh create mode 100644 dot_config/zellij/config.kdl create mode 100644 dot_local/bin/executable_fedora-backup-home create mode 100644 dot_local/bin/executable_fedora-clean create mode 100644 dot_local/bin/executable_fedora-reset-audio create mode 100644 dot_local/bin/executable_fedora-update create mode 100644 dot_zshrc diff --git a/dot_config/ghostty/config.ghostty b/dot_config/ghostty/config.ghostty new file mode 100644 index 0000000..e8df0ff --- /dev/null +++ b/dot_config/ghostty/config.ghostty @@ -0,0 +1,37 @@ +custom-shader = ./shaders/starfield-colors.glsl +#custom-shader = ./shaders/bloom.glsl +#custom-shader = ./shaders/custom/bling99_compat.glsl +#custom-shader = ./shaders/iamond_teeth_cursor.glsl +#custom-shader = ./shaders/custom/cash_money_badge.glsl + +background-blur-radius = 15 +background-opacity = 0.9 +#theme = dark:cyberdream, light:cyberdream-light +#theme = challengerdeep +#theme = "Challenger Deep" + +#window-theme = system + +shell-integration = zsh +shell-integration-features = ssh-env,ssh-terminfo + +#font-family = "MesloLGS Nerd Font Mono" +font-family = "IBM Plex Mono" +font-size = 12 + +window-padding-x = 2 +window-padding-y = 2 +window-decoration = true +cursor-style = block +adjust-cell-height = 35% +mouse-scroll-multiplier = 2 +copy-on-select = clipboard +window-padding-balance = true +window-save-state = always +background-opacity = 0.8 +window-colorspace = "display-p3" +background-blur = 30 + +macos-option-as-alt = true +macos-titlebar-style = transparent +macos-titlebar-proxy-icon = hidden diff --git a/dot_config/ghostty/shaders/bling99_gold.glsl b/dot_config/ghostty/shaders/bling99_gold.glsl new file mode 100644 index 0000000..c200618 --- /dev/null +++ b/dot_config/ghostty/shaders/bling99_gold.glsl @@ -0,0 +1,96 @@ +#define PI 3.141592653589793 + +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 0.1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +float diamondSparkle(vec2 uv, float density, float threshold, float speed) { + vec2 g = uv * vec2(density, density * 0.55); + vec2 id = floor(g); + vec2 f = fract(g) - 0.5; + + float n = hash12(id); + float gate = step(threshold, n); + float twinkle = pow(max(0.0, sin(iTime * speed + n * 6.2831853)), 36.0); + + float diaD = abs(f.x) + abs(f.y); + float diamond = 1.0 - smoothstep(0.00, 0.10, diaD); + + float vertical = (1.0 - smoothstep(0.00, 0.012, abs(f.x))) * + (1.0 - smoothstep(0.00, 0.38, abs(f.y))); + float horizontal = (1.0 - smoothstep(0.00, 0.012, abs(f.y))) * + (1.0 - smoothstep(0.00, 0.38, abs(f.x))); + + return gate * twinkle * (diamond + 0.40 * (vertical + horizontal)); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec2 px = 1.0 / iResolution.xy; + + // Tiny VHS-ish horizontal wobble. + float wobble = sin(uv.y * 82.0 + iTime * 2.1) * 0.0008 + + sin(uv.y * 11.0 - iTime * 0.35) * 0.0012; + + vec2 uvR = clamp(uv + vec2(wobble + px.x * 1.25, 0.0), vec2(0.001), vec2(0.999)); + vec2 uvG = clamp(uv + vec2(wobble, 0.0), vec2(0.001), vec2(0.999)); + vec2 uvB = clamp(uv + vec2(wobble - px.x * 1.25, 0.0), vec2(0.001), vec2(0.999)); + + vec4 base = texture(iChannel0, uvG); + vec3 src = vec3( + texture(iChannel0, uvR).r, + base.g, + texture(iChannel0, uvB).b + ); + + float lum = dot(src, vec3(0.299, 0.587, 0.114)); + float ink = smoothstep(0.03, 0.22, lum); + float text = smoothstep(0.20, 0.78, lum); + + // Cash-money palette: velvet black, dark leather brown, hot gold, pale diamond gold. + vec3 velvet = vec3(0.014, 0.008, 0.003); + vec3 brown = vec3(0.085, 0.044, 0.012); + vec3 gold = vec3(1.00, 0.66, 0.13); + vec3 paleGold = vec3(1.00, 0.90, 0.55); + + vec3 bg = mix( + velvet, + brown, + uv.y + 0.20 * sin(uv.x * 3.0 + iTime * 0.10) + ); + + vec3 goldText = mix(gold * 0.75, paleGold, pow(lum, 0.75)); + vec3 col = mix(bg, mix(src, goldText + src * 0.50, 0.48), ink); + + // Jewelry-store light sweep / chrome-grille reflection. + float sweepA = pow(max(0.0, sin((uv.x * 1.8 + uv.y * 0.75) * PI * 2.0 - iTime * 0.60)), 22.0); + float sweepB = pow(max(0.0, sin((uv.x * -1.1 + uv.y * 1.25) * PI * 2.0 + iTime * 0.42)), 30.0); + col += (sweepA * 0.16 + sweepB * 0.11) * vec3(1.0, 0.83, 0.42) * (0.35 + text); + + // Thin old-video scan shimmer, subtle enough to keep text readable. + float scan = 0.965 + 0.035 * sin(fragCoord.y * PI); + float vhs = 0.98 + 0.02 * hash12(vec2(floor(uv.y * 360.0), floor(iTime * 24.0))); + col *= scan * vhs; + + // Random diamond/star hits. + float spark = diamondSparkle(uv, 74.0, 0.978, 4.5); + spark += 0.55 * diamondSparkle(uv + vec2(0.17, -0.11), 43.0, 0.970, 3.2); + col += spark * vec3(1.0, 0.88, 0.48) * (0.85 + 0.65 * text); + + // Camera-flash blobs in the corners. + vec2 aspect = vec2(iResolution.x / iResolution.y, 1.0); + float flashL = 1.0 - smoothstep(0.00, 0.28, length((uv - vec2(0.14, 0.82)) * aspect)); + float flashR = 1.0 - smoothstep(0.00, 0.34, length((uv - vec2(0.88, 0.18)) * aspect)); + col += (flashL * 0.10 + flashR * 0.07) * vec3(1.0, 0.72, 0.22); + + // Music-video edge falloff. + float vig = 1.0 - smoothstep(0.20, 0.82, distance(uv, vec2(0.5))); + col *= 0.80 + 0.20 * vig; + + // Legibility save: blend some original terminal text back in. + col = mix(col, src, 0.18 * text); + + fragColor = vec4(clamp(col, 0.0, 1.0), base.a); +} diff --git a/dot_config/ghostty/shaders/bloom.glsl b/dot_config/ghostty/shaders/bloom.glsl new file mode 100644 index 0000000..1d20930 --- /dev/null +++ b/dot_config/ghostty/shaders/bloom.glsl @@ -0,0 +1,52 @@ +// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f +// credits: https://github.com/qwerasd205 +// Golden spiral samples, [x, y, weight] weight is inverse of distance. +const vec3[24] samples = { + vec3(0.1693761725038636, 0.9855514761735895, 1), + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), + vec3(1.554155680728463, -1.2588090085709776, 0.5), + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) + }; + +float lum(vec4 c) { + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + + vec2 step = vec2(1.414) / iResolution.xy; + + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, uv + s.xy * step); + float l = lum(c); + if (l > 0.2) { + color += l * s.z * c * 0.2; + } + } + + fragColor = color; +} diff --git a/dot_config/ghostty/shaders/cash_money_frame.glsl b/dot_config/ghostty/shaders/cash_money_frame.glsl new file mode 100644 index 0000000..031bf20 --- /dev/null +++ b/dot_config/ghostty/shaders/cash_money_frame.glsl @@ -0,0 +1,43 @@ +#define PI 3.141592653589793 + +float diamondAt(vec2 uv, vec2 c, float r) { + vec2 q = (uv - c) * vec2(iResolution.x / iResolution.y, 1.0); + return 1.0 - smoothstep(r * 0.20, r, abs(q.x) + abs(q.y)); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 base = texture(iChannel0, uv); + vec3 col = base.rgb; + + float edgeD = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y)); + float frame = 1.0 - smoothstep(0.0, 0.055, edgeD); + + float chrome = pow( + 0.5 + 0.5 * sin((uv.x * 5.0 + uv.y * 3.0) * PI * 2.0 - iTime * 2.0), + 3.0 + ); + + float bead = pow( + 0.5 + 0.5 * sin((uv.x + uv.y) * 120.0 + iTime * 1.7), + 14.0 + ); + + vec3 darkGold = vec3(0.23, 0.11, 0.02); + vec3 hotGold = vec3(1.00, 0.82, 0.30); + vec3 frameColor = mix(darkGold, hotGold, chrome); + + col = mix(col, col + frameColor * (0.20 + 0.35 * bead), frame * 0.55); + + // Big fake diamonds in the corners. + float corners = 0.0; + corners += diamondAt(uv, vec2(0.035, 0.045), 0.040); + corners += diamondAt(uv, vec2(0.965, 0.045), 0.040); + corners += diamondAt(uv, vec2(0.035, 0.955), 0.040); + corners += diamondAt(uv, vec2(0.965, 0.955), 0.040); + + float twinkle = 0.75 + 0.25 * sin(iTime * 5.0); + col += corners * vec3(1.0, 0.90, 0.55) * twinkle * 0.80; + + fragColor = vec4(clamp(col, 0.0, 1.0), base.a); +} diff --git a/dot_config/ghostty/shaders/cubes.glsl b/dot_config/ghostty/shaders/cubes.glsl new file mode 100644 index 0000000..2a09505 --- /dev/null +++ b/dot_config/ghostty/shaders/cubes.glsl @@ -0,0 +1,114 @@ +// credits: https://github.com/rymdlego + +const float speed = 0.2; +const float cube_size = 1.0; +const float cube_brightness = 1.0; +const float cube_rotation_speed = 2.8; +const float camera_rotation_speed = 0.1; + + + +mat3 rotationMatrix(vec3 m,float a) { + m = normalize(m); + float c = cos(a),s=sin(a); + return mat3(c+(1.-c)*m.x*m.x, + (1.-c)*m.x*m.y-s*m.z, + (1.-c)*m.x*m.z+s*m.y, + (1.-c)*m.x*m.y+s*m.z, + c+(1.-c)*m.y*m.y, + (1.-c)*m.y*m.z-s*m.x, + (1.-c)*m.x*m.z-s*m.y, + (1.-c)*m.y*m.z+s*m.x, + c+(1.-c)*m.z*m.z); +} + +float sphere(vec3 pos, float radius) +{ + return length(pos) - radius; +} + +float box(vec3 pos, vec3 size) +{ + float t = iTime; + pos = pos * 0.9 * rotationMatrix(vec3(sin(t/4.0*speed)*10.,cos(t/4.0*speed)*12.,2.7), t*2.4/4.0*speed*cube_rotation_speed); + return length(max(abs(pos) - size, 0.0)); +} + + +float distfunc(vec3 pos) +{ + float t = iTime; + + float size = 0.45 + 0.25*abs(16.0*sin(t*speed/4.0)); + // float size = 2.3 + 1.8*tan((t-5.4)*6.549); + size = cube_size * 0.16 * clamp(size, 2.0, 4.0); + + //pos = pos * rotationMatrix(vec3(0.,-3.,0.7), 3.3 * mod(t/30.0, 4.0)); + vec3 q = mod(pos, 5.0) - 2.5; + float obj1 = box(q, vec3(size)); + return obj1; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + float t = iTime; + vec2 screenPos = -1.0 + 2.0 * fragCoord.xy / iResolution.xy; + screenPos.x *= iResolution.x / iResolution.y; + vec3 cameraOrigin = vec3(t*1.0*speed, 0.0, 0.0); + // vec3 cameraOrigin = vec3(t*1.8*speed, 3.0+t*0.02*speed, 0.0); + vec3 cameraTarget = vec3(t*100., 0.0, 0.0); + cameraTarget = vec3(t*20.0,0.0,0.0) * rotationMatrix(vec3(0.0,0.0,1.0), t*speed*camera_rotation_speed); + + vec3 upDirection = vec3(0.5, 1.0, 0.6); + + vec3 cameraDir = normalize(cameraTarget - cameraOrigin); + vec3 cameraRight = normalize(cross(upDirection, cameraOrigin)); + vec3 cameraUp = cross(cameraDir, cameraRight); + + vec3 rayDir = normalize(cameraRight * screenPos.x + cameraUp * screenPos.y + cameraDir); + + const int MAX_ITER = 64; + const float MAX_DIST = 48.0; + const float EPSILON = 0.001; + + float totalDist = 0.0; + vec3 pos = cameraOrigin; + float dist = EPSILON; + + for (int i = 0; i < MAX_ITER; i++) + { + if (dist < EPSILON || totalDist > MAX_DIST) + break; + dist = distfunc(pos); + totalDist += dist; + pos += dist*rayDir; + } + + vec4 cubes; + + if (dist < EPSILON) + { + // Lighting Code + vec2 eps = vec2(0.0, EPSILON); + vec3 normal = normalize(vec3( + distfunc(pos + eps.yxx) - distfunc(pos - eps.yxx), + distfunc(pos + eps.xyx) - distfunc(pos - eps.xyx), + distfunc(pos + eps.xxy) - distfunc(pos - eps.xxy))); + float diffuse = max(0., dot(-rayDir, normal)); + float specular = pow(diffuse, 32.0); + vec3 color = vec3(diffuse + specular); + vec3 cubeColor = vec3(abs(screenPos),0.5+0.5*sin(t*2.0))*0.8; + cubeColor = mix(cubeColor.rgb, vec3(0.0,0.0,0.0), 1.0); + color += cubeColor; + cubes = vec4(color, 1.0) * vec4(1.0 - (totalDist/MAX_DIST)); + cubes = vec4(cubes.rgb*0.02*cube_brightness, 0.1); + } + else { + cubes = vec4(0.0); + } + + vec2 uv = fragCoord/iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + vec3 blendedColor = terminalColor.rgb + cubes.rgb; + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/dot_config/ghostty/shaders/cursor_sweep.glsl b/dot_config/ghostty/shaders/cursor_sweep.glsl new file mode 100644 index 0000000..986bb86 --- /dev/null +++ b/dot_config/ghostty/shaders/cursor_sweep.glsl @@ -0,0 +1,221 @@ +// sRGB -> Linear conversion (needed because Ghostty passes sRGB values but the shader pipeline operates in linear color space) +vec3 sRGBToLinear(vec3 c) { + return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), c)); +} + +// --- CONFIGURATION --- +vec4 TRAIL_COLOR = vec4(sRGBToLinear(iCurrentCursorColor.rgb), iCurrentCursorColor.a); // for custom color: vec4(0.2, 0.6, 1.0, 0.5); (wrap in sRGBToLinear for correct brightness) +const float DURATION = 0.2; // in seconds +const float TRAIL_LENGTH = 0.5; +const float BLUR = 2.0; // blur size in pixels (for antialiasing) + +// --- CONSTANTS for easing functions --- +const float PI = 3.14159265359; +const float C1_BACK = 1.70158; +const float C2_BACK = C1_BACK * 1.525; +const float C3_BACK = C1_BACK + 1.0; +const float C4_ELASTIC = (2.0 * PI) / 3.0; +const float C5_ELASTIC = (2.0 * PI) / 4.5; +const float SPRING_STIFFNESS = 9.0; +const float SPRING_DAMPING = 0.9; + +// --- EASING FUNCTIONS --- + +// // Linear +// float ease(float x) { +// return x; +// } + +// // EaseOutQuad +// float ease(float x) { +// return 1.0 - (1.0 - x) * (1.0 - x); +// } + +// EaseOutCubic +float ease(float x) { + return 1.0 - pow(1.0 - x, 3.0); +} + +// // EaseOutQuart +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 4.0); +// } + +// // EaseOutQuint +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 5.0); +// } + +// EaseOutSine +// float ease(float x) { +// return sin((x * PI) / 2.0); +// } + +// // EaseOutExpo +// float ease(float x) { +// return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x); +// } + +// // EaseOutCirc +// float ease(float x) { +// return sqrt(1.0 - pow(x - 1.0, 2.0)); +// } + +// // EaseOutBack +// float ease(float x) { +// return 1.0 + C3_BACK * pow(x - 1.0, 3.0) + C1_BACK * pow(x - 1.0, 2.0); +// } + +// // EaseOutElastic +// float ease(float x) { +// return x == 0.0 ? 0.0 +// : x == 1.0 ? 1.0 +// : pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * C4_ELASTIC) + 1.0; +// } + +// Parametric Spring +// float ease(float x) { +// x = clamp(x, 0.0, 1.0); +// float decay = exp(-SPRING_DAMPING * SPRING_STIFFNESS * x); +// float freq = sqrt(SPRING_STIFFNESS * (1.0 - SPRING_DAMPING * SPRING_DAMPING)); +// float osc = cos(freq * 6.283185 * x) + (SPRING_DAMPING * sqrt(SPRING_STIFFNESS) / freq) * sin(freq * 6.283185 * x); +// return 1.0 - decay * osc; +// } + +float getSdfRectangle(in vec2 point, in vec2 center, in vec2 halfSize) +{ + vec2 d = abs(point - center) - halfSize; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching + +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfParallelogram(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) { + float s = 1.0; + float d = dot(p - v0, p - v0); + + d = seg(p, v0, v3, s, d); + d = seg(p, v1, v0, s, d); + d = seg(p, v2, v1, s, d); + d = seg(p, v3, v2, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(BLUR, BLUR), 0.).x, distance); +} + +float getTopVertexFlag(vec2 a, vec2 b) { + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // if neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} + +vec2 getRectangleCenter(vec4 rectangle) { + return vec2(rectangle.x + (rectangle.z / 2.), rectangle.y - (rectangle.w / 2.)); +} + + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // normalization & setup(-1, 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + vec2 centerCP = previousCursor.xy - (previousCursor.zw * offsetFactor); + + float sdfCurrentCursor = getSdfRectangle(vu, centerCC, currentCursor.zw * 0.5); + + float lineLength = distance(centerCC, centerCP); + + vec4 newColor = vec4(fragColor); + + float minDist = currentCursor.w * 1.5; + float progress = clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0); + if (lineLength > minDist) { + // --- Animation Logic --- + float shrinkFactor = ease(progress); + + // detect straight moves + vec2 delta = abs(centerCC - centerCP); + float threshold = 0.001; + float isHorizontal = step(delta.y, threshold); + float isVertical = step(delta.x, threshold); + float isStraightMove = max(isHorizontal, isVertical); + + // -- Making parallelogram sdf (diagonal moves) --- + float topVertexFlag = getTopVertexFlag(currentCursor.xy, previousCursor.xy); + float bottomVertexFlag = 1.0 - topVertexFlag; + vec2 v0 = vec2(currentCursor.x + currentCursor.z * topVertexFlag, currentCursor.y - currentCursor.w); + vec2 v1 = vec2(currentCursor.x + currentCursor.z * bottomVertexFlag, currentCursor.y); + vec2 v2_full = vec2(previousCursor.x + currentCursor.z * bottomVertexFlag, previousCursor.y); + vec2 v3_full = vec2(previousCursor.x + currentCursor.z * topVertexFlag, previousCursor.y - previousCursor.w); + + vec2 v2_start = mix(v1, v2_full, TRAIL_LENGTH); + vec2 v3_start = mix(v0, v3_full, TRAIL_LENGTH); + vec2 v2_anim = mix(v2_start, v1, shrinkFactor); + vec2 v3_anim = mix(v3_start, v0, shrinkFactor); + + float sdfTrail_diag = getSdfParallelogram(vu, v0, v1, v2_anim, v3_anim); + + // --- Making rectangle sdf (straight moves) --- + vec2 min_center = min(centerCP, centerCC); + vec2 max_center = max(centerCP, centerCC); + + vec2 bBoxSize_full = (max_center - min_center) + currentCursor.zw; + vec2 bBoxCenter_full = (min_center + max_center) * 0.5; + + vec2 bBoxSize_start = mix(currentCursor.zw, bBoxSize_full, TRAIL_LENGTH); + vec2 bBoxCenter_start = mix(centerCC, bBoxCenter_full, TRAIL_LENGTH); + + vec2 animSize = mix(bBoxSize_start, currentCursor.zw, shrinkFactor); + vec2 animCenter = mix(bBoxCenter_start, centerCC, shrinkFactor); + + float sdfTrail_rect = getSdfRectangle(vu, animCenter, animSize * 0.5); + + // -- Selecting and drawing the trail sdf -- + float sdfTrail = mix(sdfTrail_diag, sdfTrail_rect, isStraightMove); + + vec4 trail = TRAIL_COLOR; + float trailAlpha = antialising(sdfTrail); + newColor = mix(newColor, trail, trailAlpha); + + // Punch hole + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + } + + + fragColor = newColor; +} diff --git a/dot_config/ghostty/shaders/cursor_tail.glsl b/dot_config/ghostty/shaders/cursor_tail.glsl new file mode 100644 index 0000000..767469e --- /dev/null +++ b/dot_config/ghostty/shaders/cursor_tail.glsl @@ -0,0 +1,239 @@ +// sRGB -> Linear conversion (needed because Ghostty passes sRGB values but the shader pipeline operates in linear color space) +vec3 sRGBToLinear(vec3 c) { + return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), c)); +} + +// --- CONFIGURATION --- +vec4 TRAIL_COLOR = vec4(sRGBToLinear(iCurrentCursorColor.rgb), iCurrentCursorColor.a); // for custom color: vec4(0.2, 0.6, 1.0, 0.5); (wrap in sRGBToLinear for correct brightness) +const float DURATION = 0.09; // in seconds +const float MAX_TRAIL_LENGTH = 0.2; +const float THRESHOLD_MIN_DISTANCE = 1.5; // min distance to show trail (units of cursor width) +const float BLUR = 2.0; // blur size in pixels (for antialiasing) + +// --- CONSTANTS for easing functions --- +const float PI = 3.14159265359; +const float C1_BACK = 1.70158; +const float C2_BACK = C1_BACK * 1.525; +const float C3_BACK = C1_BACK + 1.0; +const float C4_ELASTIC = (2.0 * PI) / 3.0; +const float C5_ELASTIC = (2.0 * PI) / 4.5; +const float SPRING_STIFFNESS = 9.0; +const float SPRING_DAMPING = 0.9; + +// --- EASING FUNCTIONS --- + +// // Linear +// float ease(float x) { +// return x; +// } + +// // EaseOutQuad +// float ease(float x) { +// return 1.0 - (1.0 - x) * (1.0 - x); +// } + +// // EaseOutCubic +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 3.0); +// } + + +// // EaseOutQuart +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 4.0); +// } + +// // EaseOutQuint +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 5.0); +// } + +// // EaseOutSine +// float ease(float x) { +// return sin((x * PI) / 2.0); +// } + +// // EaseOutExpo +// float ease(float x) { +// return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x); +// } + +// EaseOutCirc +float ease(float x) { + return sqrt(1.0 - pow(x - 1.0, 2.0)); +} + +// // EaseOutBack +// float ease(float x) { +// return 1.0 + C3_BACK * pow(x - 1.0, 3.0) + C1_BACK * pow(x - 1.0, 2.0); +// } + +// // EaseOutElastic +// float ease(float x) { +// return x == 0.0 ? 0.0 +// : x == 1.0 ? 1.0 +// : pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * C4_ELASTIC) + 1.0; +// } + +// Parametric Spring +// float ease(float x) { +// x = clamp(x, 0.0, 1.0); +// float decay = exp(-SPRING_DAMPING * SPRING_STIFFNESS * x); +// float freq = sqrt(SPRING_STIFFNESS * (1.0 - SPRING_DAMPING * SPRING_DAMPING)); +// float osc = cos(freq * 6.283185 * x) + (SPRING_DAMPING * sqrt(SPRING_STIFFNESS) / freq) * sin(freq * 6.283185 * x); +// return 1.0 - decay * osc; +// } + +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching + +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfParallelogram(in vec2 p, in vec2 v0, in vec2 v1, in vec2 v2, in vec2 v3) { + float s = 1.0; + float d = dot(p - v0, p - v0); + + d = seg(p, v0, v3, s, d); + d = seg(p, v1, v0, s, d); + d = seg(p, v2, v1, s, d); + d = seg(p, v3, v2, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance) { + return 1. - smoothstep(0., normalize(vec2(BLUR, BLUR), 0.).x, distance); +} + +float determineIfTopRightIsLeading(vec2 a, vec2 b) { + float condition1 = step(b.x, a.x) * step(a.y, b.y); // a.x < b.x && a.y > b.y + float condition2 = step(a.x, b.x) * step(b.y, a.y); // a.x > b.x && a.y < b.y + + // if neither condition is met, return 1 (else case) + return 1.0 - max(condition1, condition2); +} + +vec2 getRectangleCenter(vec4 rectangle) { + return vec2(rectangle.x + (rectangle.z / 2.), rectangle.y - (rectangle.w / 2.)); +} + + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // normalization & setup(-1, 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + vec2 centerCP = previousCursor.xy - (previousCursor.zw * offsetFactor); + + vec2 delta = centerCP - centerCC; + float lineLength = length(delta); + + float sdfCurrentCursor = getSdfRectangle(vu, centerCC, currentCursor.zw * 0.5); + + vec4 newColor = vec4(fragColor); + + float minDist = currentCursor.w * THRESHOLD_MIN_DISTANCE; + float progress = clamp((iTime - iTimeCursorChange) / DURATION, 0.0, 1.0); + if (lineLength > minDist) { + // ANIMATION logic + + float head_eased = 0.0; + float tail_eased = 0.0; + + float tail_delay_factor = MAX_TRAIL_LENGTH / lineLength; + + float isLongMove = step(MAX_TRAIL_LENGTH, lineLength); + + float head_eased_short = ease(progress); + float tail_eased_short = ease(smoothstep(tail_delay_factor, 1.0, progress)); + float head_eased_long = 1.0; + float tail_eased_long = ease(progress); + + head_eased = mix(head_eased_long, head_eased_short, isLongMove); + tail_eased = mix(tail_eased_long, tail_eased_short, isLongMove); + + // detect straight moves + vec2 delta_abs = abs(centerCC - centerCP); + float threshold = 0.001; + float isHorizontal = step(delta_abs.y, threshold); + float isVertical = step(delta_abs.x, threshold); + float isStraightMove = max(isHorizontal, isVertical); + + // -- Making the parallelogram sdf (diagonal move) -- + + // animate the TOP-LEFT corners + vec2 head_pos_tl = mix(previousCursor.xy, currentCursor.xy, head_eased); + vec2 tail_pos_tl = mix(previousCursor.xy, currentCursor.xy, tail_eased); + + float isTopRightLeading = determineIfTopRightIsLeading(currentCursor.xy, previousCursor.xy); + float isBottomLeftLeading = 1.0 - isTopRightLeading; + + // v0, v1 : "front" of the trail (head) + vec2 v0 = vec2(head_pos_tl.x + currentCursor.z * isTopRightLeading, head_pos_tl.y - currentCursor.w); + vec2 v1 = vec2(head_pos_tl.x + currentCursor.z * isBottomLeftLeading, head_pos_tl.y); + + // v2, v3: "back" of the trail (tail) + vec2 v2 = vec2(tail_pos_tl.x + currentCursor.z * isBottomLeftLeading, tail_pos_tl.y); + vec2 v3 = vec2(tail_pos_tl.x + currentCursor.z * isTopRightLeading, tail_pos_tl.y - previousCursor.w); + + float sdfTrail_diag = getSdfParallelogram(vu, v0, v1, v2, v3); + + // -- Making the rectangle sdf (straight move) -- + + vec2 head_center = mix(centerCP, centerCC, head_eased); + vec2 tail_center = mix(centerCP, centerCC, tail_eased); + + vec2 min_center = min(head_center, tail_center); + vec2 max_center = max(head_center, tail_center); + + vec2 box_size = (max_center - min_center) + currentCursor.zw; + vec2 box_center = (min_center + max_center) * 0.5; + + float sdfTrail_rect = getSdfRectangle(vu, box_center, box_size * 0.5); + + // -- FINAL SELECTING AND DRAWING -- + float sdfTrail = mix(sdfTrail_diag, sdfTrail_rect, isStraightMove); + + vec4 trail = TRAIL_COLOR; + float trailAlpha = antialising(sdfTrail); + newColor = mix(newColor, trail, trailAlpha); + + // punch hole + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + } + + fragColor = newColor; +} diff --git a/dot_config/ghostty/shaders/cursor_warp.glsl b/dot_config/ghostty/shaders/cursor_warp.glsl new file mode 100644 index 0000000..1860c50 --- /dev/null +++ b/dot_config/ghostty/shaders/cursor_warp.glsl @@ -0,0 +1,308 @@ +// sRGB -> Linear conversion (needed because Ghostty passes sRGB values but the shader pipeline operates in linear color space) +vec3 sRGBToLinear(vec3 c) { + return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), c)); +} + +// --- CONFIGURATION --- +vec4 TRAIL_COLOR = vec4(sRGBToLinear(iCurrentCursorColor.rgb), iCurrentCursorColor.a); // for custom color: vec4(0.2, 0.6, 1.0, 0.5); (wrap in sRGBToLinear for correct brightness) +const float DURATION = 0.2; // total animation time +const float TRAIL_SIZE = 0.8; // 0.0 = all corners move together. 1.0 = max smear (leading corners jump instantly) +const float THRESHOLD_MIN_DISTANCE = 1.5; // min distance to show trail (units of cursor height) +const float BLUR = 1.0; // blur size in pixels (for antialiasing) +const float TRAIL_THICKNESS = 1.0; // 1.0 = full cursor height, 0.0 = zero height, >1.0 = funky aah +const float TRAIL_THICKNESS_X = 0.9; + +const float FADE_ENABLED = 0.0; // 1.0 to enable fade gradient along the trail, 0.0 to disable +const float FADE_EXPONENT = 5.0; // exponent for fade gradient along the trail + +// --- CONSTANTS for easing functions --- +const float PI = 3.14159265359; +const float C1_BACK = 1.70158; +const float C2_BACK = C1_BACK * 1.525; +const float C3_BACK = C1_BACK + 1.0; +const float C4_ELASTIC = (2.0 * PI) / 3.0; +const float C5_ELASTIC = (2.0 * PI) / 4.5; +const float SPRING_STIFFNESS = 9.0; +const float SPRING_DAMPING = 0.9; + +// --- EASING FUNCTIONS --- + +// // Linear +// float ease(float x) { +// return x; +// } + +// // EaseOutQuad +// float ease(float x) { +// return 1.0 - (1.0 - x) * (1.0 - x); +// } + +// // EaseOutCubic +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 3.0); +// } + +// // EaseOutQuart +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 4.0); +// } + +// // EaseOutQuint +// float ease(float x) { +// return 1.0 - pow(1.0 - x, 5.0); +// } + +// // EaseOutSine +// float ease(float x) { +// return sin((x * PI) / 2.0); +// } + +// // EaseOutExpo +// float ease(float x) { +// return x == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * x); +// } + +// EaseOutCirc +float ease(float x) { + return sqrt(1.0 - pow(x - 1.0, 2.0)); +} + +// // EaseOutBack +// float ease(float x) { +// return 1.0 + C3_BACK * pow(x - 1.0, 3.0) + C1_BACK * pow(x - 1.0, 2.0); +// } + +// // EaseOutElastic +// float ease(float x) { +// return x == 0.0 ? 0.0 +// : x == 1.0 ? 1.0 +// : pow(2.0, -10.0 * x) * sin((x * 10.0 - 0.75) * C4_ELASTIC) + 1.0; +// } + +// // Parametric Spring +// float ease(float x) { +// x = clamp(x, 0.0, 1.0); +// float decay = exp(-SPRING_DAMPING * SPRING_STIFFNESS * x); +// float freq = sqrt(SPRING_STIFFNESS * (1.0 - SPRING_DAMPING * SPRING_DAMPING)); +// float osc = cos(freq * 6.283185 * x) + (SPRING_DAMPING * sqrt(SPRING_STIFFNESS) / freq) * sin(freq * 6.283185 * x); +// return 1.0 - decay * osc; +// } + +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b) +{ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +// Based on Inigo Quilez's 2D distance functions article: https://iquilezles.org/articles/distfunctions2d/ +// Potencially optimized by eliminating conditionals and loops to enhance performance and reduce branching +float seg(in vec2 p, in vec2 a, in vec2 b, inout float s, float d) { + vec2 e = b - a; + vec2 w = p - a; + vec2 proj = a + e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0); + float segd = dot(p - proj, p - proj); + d = min(d, segd); + + float c0 = step(0.0, p.y - a.y); + float c1 = 1.0 - step(0.0, p.y - b.y); + float c2 = 1.0 - step(0.0, e.x * w.y - e.y * w.x); + float allCond = c0 * c1 * c2; + float noneCond = (1.0 - c0) * (1.0 - c1) * (1.0 - c2); + float flip = mix(1.0, -1.0, step(0.5, allCond + noneCond)); + s *= flip; + return d; +} + +float getSdfConvexQuad(in vec2 p, in vec2 v1, in vec2 v2, in vec2 v3, in vec2 v4) { + float s = 1.0; + float d = dot(p - v1, p - v1); + + d = seg(p, v1, v2, s, d); + d = seg(p, v2, v3, s, d); + d = seg(p, v3, v4, s, d); + d = seg(p, v4, v1, s, d); + + return s * sqrt(d); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float antialising(float distance, float blurAmount) { + return 1. - smoothstep(0., normalize(vec2(blurAmount, blurAmount), 0.).x, distance); +} + +// Determines animation duration based on a corner's alignment with the move direction(dot product) +// dot_val will be in [-2, 2] +// > 0.5 (1 or 2) = Leading +// > -0.5 (0) = Side +// <= -0.5 (-1 or -2) = Trailing +float getDurationFromDot(float dot_val, float DURATION_LEAD, float DURATION_SIDE, float DURATION_TRAIL) { + float isLead = step(0.5, dot_val); + float isSide = step(-0.5, dot_val) * (1.0 - isLead); + + // Start with trailing duration + float duration = mix(DURATION_TRAIL, DURATION_SIDE, isSide); + // Mix in leading duration + duration = mix(duration, DURATION_LEAD, isLead); + return duration; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // normalization & setup(-1, 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + vec2 halfSizeCC = currentCursor.zw * 0.5; + vec2 centerCP = previousCursor.xy - (previousCursor.zw * offsetFactor); + vec2 halfSizeCP = previousCursor.zw * 0.5; + + float sdfCurrentCursor = getSdfRectangle(vu, centerCC, halfSizeCC); + + float lineLength = distance(centerCC, centerCP); + float minDist = currentCursor.w * THRESHOLD_MIN_DISTANCE; + + vec4 newColor = vec4(fragColor); + + float baseProgress = iTime - iTimeCursorChange; + + if (lineLength > minDist && baseProgress < DURATION - 0.001) { + // defining corners of cursors + + // Y (Height) with TRAIL_THICKNESS + float cc_half_height = currentCursor.w * 0.5; + float cc_center_y = currentCursor.y - cc_half_height; + float cc_new_half_height = cc_half_height * TRAIL_THICKNESS; + float cc_new_top_y = cc_center_y + cc_new_half_height; + float cc_new_bottom_y = cc_center_y - cc_new_half_height; + + // X (Width) with TRAIL_THICKNESS + float cc_half_width = currentCursor.z * 0.5; + float cc_center_x = currentCursor.x + cc_half_width; + float cc_new_half_width = cc_half_width * TRAIL_THICKNESS_X; + float cc_new_left_x = cc_center_x - cc_new_half_width; + float cc_new_right_x = cc_center_x + cc_new_half_width; + + vec2 cc_tl = vec2(cc_new_left_x, cc_new_top_y); + vec2 cc_tr = vec2(cc_new_right_x, cc_new_top_y); + vec2 cc_bl = vec2(cc_new_left_x, cc_new_bottom_y); + vec2 cc_br = vec2(cc_new_right_x, cc_new_bottom_y); + + // same thing for previous cursor + float cp_half_height = previousCursor.w * 0.5; + float cp_center_y = previousCursor.y - cp_half_height; + float cp_new_half_height = cp_half_height * TRAIL_THICKNESS; + float cp_new_top_y = cp_center_y + cp_new_half_height; + float cp_new_bottom_y = cp_center_y - cp_new_half_height; + + float cp_half_width = previousCursor.z * 0.5; + float cp_center_x = previousCursor.x + cp_half_width; + float cp_new_half_width = cp_half_width * TRAIL_THICKNESS_X; + float cp_new_left_x = cp_center_x - cp_new_half_width; + float cp_new_right_x = cp_center_x + cp_new_half_width; + + vec2 cp_tl = vec2(cp_new_left_x, cp_new_top_y); + vec2 cp_tr = vec2(cp_new_right_x, cp_new_top_y); + vec2 cp_bl = vec2(cp_new_left_x, cp_new_bottom_y); + vec2 cp_br = vec2(cp_new_right_x, cp_new_bottom_y); + + // calculating durations for every corner + const float DURATION_TRAIL = DURATION; + const float DURATION_LEAD = DURATION * (1.0 - TRAIL_SIZE); + const float DURATION_SIDE = (DURATION_LEAD + DURATION_TRAIL) / 2.0; + + vec2 moveVec = centerCC - centerCP; + vec2 s = sign(moveVec); + + // dot products for each corner, determining alignment with movement direction + float dot_tl = dot(vec2(-1., 1.), s); + float dot_tr = dot(vec2( 1., 1.), s); + float dot_bl = dot(vec2(-1.,-1.), s); + float dot_br = dot(vec2( 1.,-1.), s); + + // assign durations based on dot products + float dur_tl = getDurationFromDot(dot_tl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_tr = getDurationFromDot(dot_tr, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_bl = getDurationFromDot(dot_bl, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + float dur_br = getDurationFromDot(dot_br, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + // check direction of horizontal movement + float isMovingRight = step(0.5, s.x); + float isMovingLeft = step(0.5, -s.x); + + // calculate vertical-rail durations + float dot_right_edge = (dot_tr + dot_br) * 0.5; + float dur_right_rail = getDurationFromDot(dot_right_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + float dot_left_edge = (dot_tl + dot_bl) * 0.5; + float dur_left_rail = getDurationFromDot(dot_left_edge, DURATION_LEAD, DURATION_SIDE, DURATION_TRAIL); + + float final_dur_tl = mix(dur_tl, dur_left_rail, isMovingLeft); + float final_dur_bl = mix(dur_bl, dur_left_rail, isMovingLeft); + + float final_dur_tr = mix(dur_tr, dur_right_rail, isMovingRight); + float final_dur_br = mix(dur_br, dur_right_rail, isMovingRight); + + // calculate progress for each corner based on the duration and time since cursor change + float prog_tl = ease(clamp(baseProgress / final_dur_tl, 0.0, 1.0)); + float prog_tr = ease(clamp(baseProgress / final_dur_tr, 0.0, 1.0)); + float prog_bl = ease(clamp(baseProgress / final_dur_bl, 0.0, 1.0)); + float prog_br = ease(clamp(baseProgress / final_dur_br, 0.0, 1.0)); + + // get the trial corner positions based on progress + vec2 v_tl = mix(cp_tl, cc_tl, prog_tl); + vec2 v_tr = mix(cp_tr, cc_tr, prog_tr); + vec2 v_br = mix(cp_br, cc_br, prog_br); + vec2 v_bl = mix(cp_bl, cc_bl, prog_bl); + + // DRAWING THE TRAIL + float sdfTrail = getSdfConvexQuad(vu, v_tl, v_tr, v_br, v_bl); + + // --- FADE GRADIENT CALCULATION --- + vec2 fragVec = vu - centerCP; + + // project fragment onto movement vector, normalize to [0, 1] + // 0.0 at tail, 1.0 at head + // tiny epsilon to avoid division by zero if moveVec is (0,0) + float fadeProgress = clamp(dot(fragVec, moveVec) / (dot(moveVec, moveVec) + 1e-6), 0.0, 1.0); + + vec4 trail = TRAIL_COLOR; + + float effectiveBlur = BLUR; + if (BLUR < 2.5) { + // no antialising on horizontal/vertical movement, fixes 'pulse' like thing on end cursor + float isDiagonal = abs(s.x) * abs(s.y); // 1.0 if diagonal, 0.0 if H/V + float effectiveBlur = mix(0.0, BLUR, isDiagonal); + } + float shapeAlpha = antialising(sdfTrail, effectiveBlur); // shape mask + + if (FADE_ENABLED > 0.5) { + // apply fade gradient along the trail + // float fadeStart = 0.2; + // float easedProgress = smoothstep(fadeStart, 1.0, fadeProgress); + // easedProgress = pow(2.0, 10.0 * (fadeProgress - 1.0)); + float easedProgress = pow(fadeProgress, FADE_EXPONENT); + trail.a *= easedProgress; + } + + float finalAlpha = trail.a * shapeAlpha; + + // newColor.a to preserve the background alpha. + newColor = mix(newColor, vec4(trail.rgb, newColor.a), finalAlpha); + + // punch hole on the trail, so current cursor is drawn on top + newColor = mix(newColor, fragColor, step(sdfCurrentCursor, 0.)); + + } + + fragColor = newColor; +} diff --git a/dot_config/ghostty/shaders/custom/bling99_compat.glsl b/dot_config/ghostty/shaders/custom/bling99_compat.glsl new file mode 100644 index 0000000..607cfcf --- /dev/null +++ b/dot_config/ghostty/shaders/custom/bling99_compat.glsl @@ -0,0 +1,170 @@ +#define PI 3.141592653589793 + +float spotlightBeam(vec2 uv, vec2 origin, float angle, float width, float lengthFade) { + vec2 p = uv - origin; + + float c = cos(angle); + float s = sin(angle); + + // Rotate into beam space + vec2 q = vec2( + c * p.x + s * p.y, + -s * p.x + c * p.y + ); + + // Beam extends along +Y in local space + float across = abs(q.x); + float along = q.y; + + float beamCore = exp(-pow(across / width, 2.0)); + float beamLength = smoothstep(-0.05, 0.10, along) * (1.0 - smoothstep(lengthFade, 1.35, along)); + + return beamCore * beamLength; +} + +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 0.1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +float sparkleGrid(vec2 uv, float scale, float threshold, float speed) { + vec2 g = uv * vec2(scale, scale * 0.56); + vec2 id = floor(g); + vec2 f = fract(g) - 0.5; + + float n = hash12(id); + float gate = step(threshold, n); + float twinkle = pow(max(0.0, sin(iTime * speed + n * 6.2831853)), 28.0); + + float diamond = 1.0 - smoothstep(0.02, 0.13, abs(f.x) + abs(f.y)); + + float flareX = (1.0 - smoothstep(0.000, 0.016, abs(f.y))) * + (1.0 - smoothstep(0.000, 0.42, abs(f.x))); + float flareY = (1.0 - smoothstep(0.000, 0.016, abs(f.x))) * + (1.0 - smoothstep(0.000, 0.42, abs(f.y))); + + return gate * twinkle * (diamond + 0.35 * flareX + 0.35 * flareY); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec2 px = 1.0 / iResolution.xy; + + // Very light late-90s video wobble. + float wobble = sin(uv.y * 90.0 + iTime * 2.0) * 0.0008 + + sin(uv.y * 12.0 - iTime * 0.35) * 0.0010; + + vec2 tUv = clamp(uv + vec2(wobble, 0.0), vec2(0.001), vec2(0.999)); + + // Tiny chromatic shift. + vec3 src; + src.r = texture(iChannel0, clamp(tUv + vec2(px.x * 1.1, 0.0), vec2(0.001), vec2(0.999))).r; + src.g = texture(iChannel0, tUv).g; + src.b = texture(iChannel0, clamp(tUv - vec2(px.x * 1.1, 0.0), vec2(0.001), vec2(0.999))).b; + + float lum = dot(src, vec3(0.299, 0.587, 0.114)); + float glyph = smoothstep(0.06, 0.30, lum); + + // Velvet / leather background. + vec3 velvet = vec3(0.012, 0.007, 0.002); + vec3 brown = vec3(0.075, 0.038, 0.010); + vec3 bg = mix(velvet, brown, uv.y + 0.15 * sin(uv.x * 4.0 + iTime * 0.12)); + + // Cash Money gold. + vec3 gold = vec3(1.00, 0.62, 0.10); + vec3 paleGold = vec3(1.00, 0.88, 0.45); + vec3 hotGold = mix(gold, paleGold, pow(lum, 0.65)); + + // Tint glyphs gold while preserving some original terminal color. + vec3 col = mix(bg, src, glyph * 0.28); + col = mix(col, hotGold + src * 0.28, glyph * 0.82); + + // Chrome sweep, like jewelry-store lights / spinning rims. + float sweep1 = pow(max(0.0, sin((uv.x * 1.8 + uv.y * 0.65) * PI * 2.0 - iTime * 0.55)), 22.0); + float sweep2 = pow(max(0.0, sin((uv.x * -1.1 + uv.y * 1.20) * PI * 2.0 + iTime * 0.40)), 30.0); + col += (sweep1 * 0.15 + sweep2 * 0.10) * vec3(1.0, 0.77, 0.32) * (0.35 + glyph); + + // Independent moving spotlight trails + float ray1 = spotlightBeam( + uv, + vec2(0.10, 1.10), + -0.95 + 0.22 * sin(iTime * 0.63 + 0.3), + 0.045 + 0.008 * sin(iTime * 1.10 + 0.7), + 1.00 + ); + + float ray2 = spotlightBeam( + uv, + vec2(0.35, 1.12), + -1.20 + 0.18 * sin(iTime * 0.47 + 1.7), + 0.055 + 0.006 * sin(iTime * 0.90 + 2.1), + 1.05 + ); + + float ray3 = spotlightBeam( + uv, + vec2(0.72, 1.08), + -1.55 + 0.20 * sin(iTime * 0.71 + 2.8), + 0.050 + 0.010 * sin(iTime * 1.30 + 0.5), + 0.95 + ); + + float ray4 = spotlightBeam( + uv, + vec2(0.92, 1.15), + -1.85 + 0.24 * sin(iTime * 0.58 + 4.0), + 0.060 + 0.007 * sin(iTime * 0.80 + 3.4), + 1.10 + ); + + // Optional faint upward beam from bottom-left for extra motion + float ray5 = spotlightBeam( + uv, + vec2(-0.05, -0.05), + 0.70 + 0.15 * sin(iTime * 0.52 + 5.2), + 0.040 + 0.005 * sin(iTime * 1.00 + 1.3), + 0.90 + ); + + float rays = 0.0; + rays += ray1 * (0.75 + 0.25 * sin(iTime * 0.90 + 0.2)); + rays += ray2 * (0.65 + 0.35 * sin(iTime * 0.70 + 1.9)); + rays += ray3 * (0.80 + 0.20 * sin(iTime * 1.10 + 2.6)); + rays += ray4 * (0.70 + 0.30 * sin(iTime * 0.85 + 4.3)); + rays += ray5 * (0.45 + 0.25 * sin(iTime * 0.95 + 3.1)); + + // Warm gold spotlight tint + vec3 rayColorA = vec3(1.00, 0.74, 0.22); + vec3 rayColorB = vec3(1.00, 0.86, 0.48); + + // Mix two shades so it feels less flat + vec3 spotlightColor = mix(rayColorA, rayColorB, 0.5 + 0.5 * sin(iTime * 0.33)); + + // Add trails mostly into background, not too hard on text + col += rays * spotlightColor * (0.10 + 0.10 * (1.0 - glyph)); + + // Diamond glints. + float spark = sparkleGrid(uv, 62.0, 0.978, 4.0); + spark += 0.50 * sparkleGrid(uv + vec2(0.13, -0.09), 38.0, 0.965, 3.0); + col += spark * vec3(1.0, 0.90, 0.55) * (0.8 + 0.5 * glyph); + + // Gold frame around the terminal. + float edgeD = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y)); + float frame = 1.0 - smoothstep(0.000, 0.045, edgeD); + float frameWave = pow(0.5 + 0.5 * sin((uv.x + uv.y) * 90.0 - iTime * 1.8), 8.0); + col += frame * vec3(1.0, 0.72, 0.20) * (0.10 + 0.22 * frameWave); + + // Scanline shimmer, not too heavy. + float scan = 0.965 + 0.035 * sin(fragCoord.y * PI); + col *= scan; + + // Music-video vignette. + float vig = 1.0 - smoothstep(0.22, 0.82, distance(uv, vec2(0.5))); + col *= 0.78 + 0.22 * vig; + + // Keep text readable. + col = mix(col, src, glyph * 0.16); + + fragColor = vec4(clamp(col, 0.0, 1.0), 1.0); +} diff --git a/dot_config/ghostty/shaders/custom/cash_money_badge.glsl b/dot_config/ghostty/shaders/custom/cash_money_badge.glsl new file mode 100644 index 0000000..54dc9a5 --- /dev/null +++ b/dot_config/ghostty/shaders/custom/cash_money_badge.glsl @@ -0,0 +1,267 @@ +#define PI 3.141592653589793 + +float smin(float a, float b, float k) { + float h = max(k - abs(a - b), 0.0) / k; + return min(a, b) - h * h * h * k * (1.0 / 6.0); +} + +float rectSDF(vec2 p, vec2 b) { + vec2 d = abs(p) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +float fill(float d, float aa) { + return 1.0 - smoothstep(0.0, aa, d); +} + +float stroke(float d, float w, float aa) { + return 1.0 - smoothstep(0.0, aa, abs(d) - w); +} + +float box01(vec2 uv, vec2 c, vec2 s, float aa) { + return fill(rectSDF(uv - c, s), aa); +} + +float frame01(vec2 uv, vec2 c, vec2 s, float w, float aa) { + return stroke(rectSDF(uv - c, s), w, aa); +} + +float in01(vec2 uv) { + return step(0.0, uv.x) * step(0.0, uv.y) * step(uv.x, 1.0) * step(uv.y, 1.0); +} + +// ------------------------------------------------------------------ +// Very simple block-letter glyphs in a 0..1 local cell. +// Not perfect typography, but close enough to read. +// ------------------------------------------------------------------ + +float glyphC(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.52, 0.84), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.52, 0.16), vec2(0.30, 0.08), aa)); + return m * in01(uv); +} + +float glyphA(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.78, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.50, 0.84), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.30, 0.08), aa)); + return m * in01(uv); +} + +float glyphS(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.50, 0.84), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.50, 0.16), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.22, 0.67), vec2(0.10, 0.17), aa)); + m = max(m, box01(uv, vec2(0.78, 0.33), vec2(0.10, 0.17), aa)); + return m * in01(uv); +} + +float glyphH(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.78, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.30, 0.08), aa)); + return m * in01(uv); +} + +float glyphM(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.16, 0.50), vec2(0.09, 0.42), aa)); + m = max(m, box01(uv, vec2(0.84, 0.50), vec2(0.09, 0.42), aa)); + m = max(m, box01(uv, vec2(0.38, 0.65), vec2(0.08, 0.27), aa)); + m = max(m, box01(uv, vec2(0.62, 0.65), vec2(0.08, 0.27), aa)); + m = max(m, box01(uv, vec2(0.50, 0.84), vec2(0.25, 0.08), aa)); + return m * in01(uv); +} + +float glyphO(vec2 uv, float aa) { + float outer = box01(uv, vec2(0.50, 0.50), vec2(0.34, 0.42), aa); + float inner = box01(uv, vec2(0.50, 0.50), vec2(0.18, 0.24), aa); + return max(0.0, outer - inner) * in01(uv); +} + +float glyphN(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.20, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.80, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.08, 0.42), aa)); + return m * in01(uv); +} + +float glyphE(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.52, 0.84), vec2(0.30, 0.08), aa)); + m = max(m, box01(uv, vec2(0.48, 0.50), vec2(0.26, 0.08), aa)); + m = max(m, box01(uv, vec2(0.52, 0.16), vec2(0.30, 0.08), aa)); + return m * in01(uv); +} + +float glyphY(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.72), vec2(0.10, 0.20), aa)); + m = max(m, box01(uv, vec2(0.78, 0.72), vec2(0.10, 0.20), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.10, 0.12), aa)); + m = max(m, box01(uv, vec2(0.50, 0.20), vec2(0.10, 0.20), aa)); + return m * in01(uv); +} + +float glyphR(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.50, 0.84), vec2(0.28, 0.08), aa)); + m = max(m, box01(uv, vec2(0.72, 0.68), vec2(0.10, 0.16), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.26, 0.08), aa)); + m = max(m, box01(uv, vec2(0.68, 0.24), vec2(0.10, 0.20), aa)); + return m * in01(uv); +} + +float glyphD(vec2 uv, float aa) { + float m = 0.0; + m = max(m, box01(uv, vec2(0.22, 0.50), vec2(0.10, 0.42), aa)); + m = max(m, box01(uv, vec2(0.50, 0.84), vec2(0.26, 0.08), aa)); + m = max(m, box01(uv, vec2(0.50, 0.16), vec2(0.26, 0.08), aa)); + m = max(m, box01(uv, vec2(0.74, 0.50), vec2(0.10, 0.34), aa)); + return m * in01(uv); +} + +float drawGlyph(int g, vec2 uv, float aa) { + if (g == 0) return glyphC(uv, aa); + if (g == 1) return glyphA(uv, aa); + if (g == 2) return glyphS(uv, aa); + if (g == 3) return glyphH(uv, aa); + if (g == 4) return glyphM(uv, aa); + if (g == 5) return glyphO(uv, aa); + if (g == 6) return glyphN(uv, aa); + if (g == 7) return glyphE(uv, aa); + if (g == 8) return glyphY(uv, aa); + if (g == 9) return glyphR(uv, aa); + if (g == 10) return glyphD(uv, aa); + return 0.0; +} + +float placeGlyph(vec2 q, vec4 box, int glyphId, float aa) { + vec2 uv = (q - box.xy) / (box.zw - box.xy); + return drawGlyph(glyphId, uv, aa); +} + +float dollarMark(vec2 uv, float aa) { + float m = 0.0; + + // vertical bar + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.05, 0.42), aa)); + + // top/bottom heavy bars to make a chunky $ + m = max(m, box01(uv, vec2(0.50, 0.82), vec2(0.22, 0.10), aa)); + m = max(m, box01(uv, vec2(0.50, 0.50), vec2(0.22, 0.10), aa)); + m = max(m, box01(uv, vec2(0.50, 0.18), vec2(0.22, 0.10), aa)); + + // left upper / right lower chunks + m = max(m, box01(uv, vec2(0.30, 0.66), vec2(0.10, 0.18), aa)); + m = max(m, box01(uv, vec2(0.70, 0.34), vec2(0.10, 0.18), aa)); + + return m * in01(uv); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 base = texture(iChannel0, uv); + vec3 col = base.rgb; + + float aa = 1.6 / iResolution.y; + + // ---------------------------------------------------------- + // Bouncing rectangular badge, DVD-logo style + // ---------------------------------------------------------- + vec2 badgeSize = vec2(0.18, 0.44); + vec2 minP = badgeSize * 0.5 + vec2(0.02, 0.03); + vec2 maxP = vec2(1.0) - minP; + + vec2 travel = maxP - minP; + vec2 phase = fract(vec2(iTime * 0.060, iTime * 0.047) + vec2(0.21, 0.58)); + vec2 tri = abs(phase * 2.0 - 1.0); + vec2 center = minP + travel * tri; + + vec2 p = uv - center; + p.x *= iResolution.x / iResolution.y; + + vec2 halfSize = vec2(badgeSize.x * 0.5 * iResolution.x / iResolution.y, badgeSize.y * 0.5); + + // q = normalized coordinates inside the badge + vec2 q = p / halfSize; + q = q * 0.5 + 0.5; + + float outer = fill(rectSDF(p, halfSize), aa); + float border = frame01(p, vec2(0.0), halfSize, 0.006, aa); + + // shadow + float shadow = fill(rectSDF(p - vec2(0.010, -0.012), halfSize), aa) * 0.18; + col = mix(col, col * 0.80, shadow); + + // white sticker body + vec3 logoCol = vec3(0.0); + logoCol += outer * vec3(0.96); + logoCol = mix(logoCol, vec3(0.04), border); + + // top word: CASH MONEY + float top = 0.0; + float y0 = 0.78; + float y1 = 0.96; + float w = 0.075; + float gap = 0.010; + + top = max(top, placeGlyph(q, vec4(0.04, y0, 0.04 + w, y1), 0, aa)); // C + top = max(top, placeGlyph(q, vec4(0.04 + 1.0*(w+gap), y0, 0.04 + 1.0*(w+gap) + w, y1), 1, aa)); // A + top = max(top, placeGlyph(q, vec4(0.04 + 2.0*(w+gap), y0, 0.04 + 2.0*(w+gap) + w, y1), 2, aa)); // S + top = max(top, placeGlyph(q, vec4(0.04 + 3.0*(w+gap), y0, 0.04 + 3.0*(w+gap) + w, y1), 3, aa)); // H + + float start2 = 0.40; + top = max(top, placeGlyph(q, vec4(start2 + 0.0*(w+gap), y0, start2 + 0.0*(w+gap) + w, y1), 4, aa)); // M + top = max(top, placeGlyph(q, vec4(start2 + 1.0*(w+gap), y0, start2 + 1.0*(w+gap) + w, y1), 5, aa)); // O + top = max(top, placeGlyph(q, vec4(start2 + 2.0*(w+gap), y0, start2 + 2.0*(w+gap) + w, y1), 6, aa)); // N + top = max(top, placeGlyph(q, vec4(start2 + 3.0*(w+gap), y0, start2 + 3.0*(w+gap) + w, y1), 7, aa)); // E + top = max(top, placeGlyph(q, vec4(start2 + 4.0*(w+gap), y0, start2 + 4.0*(w+gap) + w, y1), 8, aa)); // Y + + // bottom word: RECORDS + float bottom = 0.0; + float by0 = 0.03; + float by1 = 0.19; + float bw = 0.095; + float bg = 0.012; + float bstart = 0.10; + + bottom = max(bottom, placeGlyph(q, vec4(bstart + 0.0*(bw+bg), by0, bstart + 0.0*(bw+bg) + bw, by1), 9, aa)); // R + bottom = max(bottom, placeGlyph(q, vec4(bstart + 1.0*(bw+bg), by0, bstart + 1.0*(bw+bg) + bw, by1), 7, aa)); // E + bottom = max(bottom, placeGlyph(q, vec4(bstart + 2.0*(bw+bg), by0, bstart + 2.0*(bw+bg) + bw, by1), 0, aa)); // C + bottom = max(bottom, placeGlyph(q, vec4(bstart + 3.0*(bw+bg), by0, bstart + 3.0*(bw+bg) + bw, by1), 5, aa)); // O + bottom = max(bottom, placeGlyph(q, vec4(bstart + 4.0*(bw+bg), by0, bstart + 4.0*(bw+bg) + bw, by1), 9, aa)); // R + bottom = max(bottom, placeGlyph(q, vec4(bstart + 5.0*(bw+bg), by0, bstart + 5.0*(bw+bg) + bw, by1), 10, aa)); // D + bottom = max(bottom, placeGlyph(q, vec4(bstart + 6.0*(bw+bg), by0, bstart + 6.0*(bw+bg) + bw, by1), 2, aa)); // S + + // central $ + vec2 suv = (q - vec2(0.18, 0.23)) / vec2(0.64, 0.50); + float dollar = dollarMark(suv, aa); + + // black print + float printMask = max(max(top, bottom), dollar); + logoCol = mix(logoCol, vec3(0.03), printMask); + + // small gold glint so it still fits the bling theme + float glint = pow(max(0.0, sin((uv.x * 4.0 + uv.y * 2.0) * PI * 2.0 - iTime * 1.4)), 18.0); + logoCol += outer * glint * vec3(1.0, 0.84, 0.35) * 0.12; + + // subtle sticker highlight + float shine = 1.0 - smoothstep(0.0, 0.25, abs(q.x - 0.25) + abs(q.y - 0.78)); + logoCol += outer * shine * vec3(1.0) * 0.08; + + // composite behind text + col = mix(col, col + logoCol, outer * 0.22); + + fragColor = vec4(clamp(col, 0.0, 1.0), base.a); +} diff --git a/dot_config/ghostty/shaders/custom/cash_money_dvd.glsl b/dot_config/ghostty/shaders/custom/cash_money_dvd.glsl new file mode 100644 index 0000000..62ce714 --- /dev/null +++ b/dot_config/ghostty/shaders/custom/cash_money_dvd.glsl @@ -0,0 +1,142 @@ +#define PI 3.141592653589793 + +float sdEllipse(vec2 p, vec2 r) { + vec2 q = p / r; + return (length(q) - 1.0) * min(r.x, r.y); +} + +float sdCircle(vec2 p, float r) { + return length(p) - r; +} + +float sdBox(vec2 p, vec2 b) { + vec2 d = abs(p) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +float opStroke(float d, float w) { + return abs(d) - w; +} + +float fill(float d) { + return 1.0 - smoothstep(0.0, 0.004, d); +} + +float stroke(float d, float w) { + return 1.0 - smoothstep(0.0, 0.004, opStroke(d, w)); +} + +// Simple dollar sign SDF-ish shape +float dollarSign(vec2 p) { + float s = 0.0; + + // main vertical bar + float bar = fill(sdBox(p, vec2(0.018, 0.18))); + + // upper curve + vec2 pu = p - vec2(0.02, 0.07); + float upperOuter = stroke(sdCircle(pu, 0.11), 0.020); + float upperCut = fill(sdBox(pu - vec2(-0.07, 0.00), vec2(0.08, 0.14))); + float upper = upperOuter * (1.0 - upperCut); + + // lower curve + vec2 pl = p - vec2(-0.02, -0.07); + float lowerOuter = stroke(sdCircle(pl, 0.11), 0.020); + float lowerCut = fill(sdBox(pl - vec2(0.07, 0.00), vec2(0.08, 0.14))); + float lower = lowerOuter * (1.0 - lowerCut); + + s = max(bar, max(upper, lower)); + return s; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 base = texture(iChannel0, uv); + vec3 col = base.rgb; + + // ------------------------------------------------------------------ + // Bouncing "DVD logo" style motion + // ------------------------------------------------------------------ + vec2 logoSize = vec2(0.23, 0.13); // width/height of medallion in UV space + vec2 minP = logoSize * 0.5 + vec2(0.03, 0.04); + vec2 maxP = vec2(1.0) - minP; + + // Ping-pong motion + vec2 travel = maxP - minP; + vec2 phase = fract(vec2(iTime * 0.070, iTime * 0.052) + vec2(0.17, 0.61)); + vec2 tri = abs(phase * 2.0 - 1.0); + vec2 center = minP + travel * tri; + + // Local coordinates around logo center + vec2 p = uv - center; + p.x *= iResolution.x / iResolution.y; // aspect correction + + // ------------------------------------------------------------------ + // Cash Money inspired medallion + // ------------------------------------------------------------------ + float outer = sdEllipse(p, vec2(0.17, 0.095)); + float inner = sdEllipse(p, vec2(0.145, 0.078)); + float core = sdEllipse(p, vec2(0.122, 0.060)); + + float outerFill = fill(outer); + float innerRing = stroke(inner, 0.010); + float coreFill = fill(core); + + // Rim beading / jewelry vibe + float angle = atan(p.y, p.x); + float beads = pow(0.5 + 0.5 * sin(angle * 26.0 - iTime * 2.2), 8.0); + beads *= stroke(sdEllipse(p, vec2(0.158, 0.086)), 0.008); + + // Chrome/gold light sweep + float sweep = pow(max(0.0, sin((uv.x * 4.0 + uv.y * 2.6) * PI * 2.0 - iTime * 1.7)), 18.0); + + vec3 darkGold = vec3(0.28, 0.12, 0.02); + vec3 gold = vec3(0.95, 0.67, 0.16); + vec3 paleGold = vec3(1.00, 0.88, 0.52); + vec3 diamond = vec3(1.00, 0.96, 0.85); + + vec3 logoCol = vec3(0.0); + + // outer medallion + logoCol += outerFill * mix(darkGold, gold, 0.65); + logoCol += innerRing * paleGold * 0.9; + logoCol += beads * paleGold * 0.8; + logoCol += coreFill * mix(gold, paleGold, 0.35); + + // embossed center + float emboss = 0.5 + 0.5 * sin(p.x * 28.0 + p.y * 12.0 - iTime * 0.6); + logoCol += coreFill * emboss * vec3(0.10, 0.05, 0.01); + + // dollar sign centerpiece + float ds = dollarSign(p * 1.7); + logoCol = mix(logoCol, diamond, ds * 0.9); + logoCol += ds * paleGold * 0.35; + + // little sparkle hits + float sparkle1 = exp(-length((p - vec2(-0.07, 0.03)) * vec2(1.0, 1.2)) * 60.0); + float sparkle2 = exp(-length((p - vec2(0.08, -0.01)) * vec2(1.0, 1.2)) * 80.0); + float cross1 = (1.0 - smoothstep(0.0, 0.004, abs(p.x + 0.07))) * (1.0 - smoothstep(0.0, 0.05, abs(p.y - 0.03))); + cross1 += (1.0 - smoothstep(0.0, 0.004, abs(p.y - 0.03))) * (1.0 - smoothstep(0.0, 0.05, abs(p.x + 0.07))); + float cross2 = (1.0 - smoothstep(0.0, 0.003, abs(p.x - 0.08))) * (1.0 - smoothstep(0.0, 0.04, abs(p.y + 0.01))); + cross2 += (1.0 - smoothstep(0.0, 0.003, abs(p.y + 0.01))) * (1.0 - smoothstep(0.0, 0.04, abs(p.x - 0.08))); + + float twinkle = 0.65 + 0.35 * sin(iTime * 5.0); + logoCol += (sparkle1 * cross1 + sparkle2 * cross2) * paleGold * twinkle * 0.9; + + // moving light sweep across logo + logoCol += outerFill * sweep * vec3(1.0, 0.92, 0.60) * 0.45; + + // subtle shadow behind logo + float shadow = fill(sdEllipse(p - vec2(0.010, -0.010), vec2(0.17, 0.095))); + shadow *= 0.18; + + // Logo mask + float logoMask = outerFill; + + // Keep it in background so text stays readable + // Darken behind medallion slightly, then add logo + col = mix(col, col * 0.82, shadow); + col = mix(col, col + logoCol, logoMask * 0.32); + + fragColor = vec4(clamp(col, 0.0, 1.0), base.a); +} diff --git a/dot_config/ghostty/shaders/custom/probe_invert.glsl b/dot_config/ghostty/shaders/custom/probe_invert.glsl new file mode 100644 index 0000000..af9c847 --- /dev/null +++ b/dot_config/ghostty/shaders/custom/probe_invert.glsl @@ -0,0 +1,5 @@ +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 c = texture(iChannel0, uv); + fragColor = vec4(1.0 - c.rgb, 1.0); +} diff --git a/dot_config/ghostty/shaders/dot_claude/settings.local.json b/dot_config/ghostty/shaders/dot_claude/settings.local.json new file mode 100644 index 0000000..7a39247 --- /dev/null +++ b/dot_config/ghostty/shaders/dot_claude/settings.local.json @@ -0,0 +1,30 @@ +{ + "permissions": { + "allow": [ + "Bash(mount)", + "Bash(getenforce)", + "Bash(podman --version)", + "Read(//etc/**)", + "Bash(grep \"^$\\(whoami\\):\")", + "Bash(mkdir -p \"/run/media/mr0xb/1TB Samsung 860/postgres-data\")", + "Bash(mkdir -p ~/podman)", + "Bash(podman unshare *)", + "Bash(podman secret *)", + "Bash(openssl rand *)", + "Bash(podman kube *)", + "Bash(podman pod *)", + "Bash(podman ps *)", + "Bash(podman logs *)", + "Bash(rm -rf \"/run/media/mr0xb/1TB Samsung 860/postgres-data\")", + "Bash(podman exec *)", + "Bash(podman inspect *)", + "Bash(podman image *)", + "Bash(podman run *)", + "Bash(chcon -Rt container_file_t \"/run/media/mr0xb/1TB Samsung 860/postgres-data\")", + "Bash(PGPASSWORD='ksJZqsVlMZZ2G+f6qSp+GdykGIIKjZq3' psql -h 127.0.0.1 -p 5432 -U postgres -c \"select 1;\")", + "Bash(timeout 2 bash -c \"echo > /dev/tcp/127.0.0.1/5432\")", + "Bash(ip -4 addr show)", + "Bash(timeout 2 bash -c \"echo > /dev/tcp/192.168.1.69/5432\")" + ] + } +} diff --git a/dot_config/ghostty/shaders/fireworks-rockets.glsl b/dot_config/ghostty/shaders/fireworks-rockets.glsl new file mode 100644 index 0000000..e2f0b5a --- /dev/null +++ b/dot_config/ghostty/shaders/fireworks-rockets.glsl @@ -0,0 +1,109 @@ +// This Ghostty shader is a lightly modified port of https://www.shadertoy.com/view/4dBGRw + +#define BLACK_BLEND_THRESHOLD .4 + +//Creates a diagonal red-and-white striped pattern. +vec3 barberpole(vec2 pos, vec2 rocketpos) { + float d = (pos.x - rocketpos.x) + (pos.y - rocketpos.y); + vec3 col = vec3(1.0); + + d = mod(d * 20., 2.0); + if (d > 1.0) { + col = vec3(1.0, 0.0, 0.0); + } + + return col; +} + +vec3 rocket(vec2 pos, vec2 rocketpos) { + vec3 col = vec3(0.0); + float f = 0.; + float absx = abs(rocketpos.x - pos.x); + float absy = abs(rocketpos.y - pos.y); + + // Wooden stick + if (absx < 0.01 && absy < 0.22) { + col = vec3(1.0, 0.5, 0.5); + } + + // Barberpole + if (absx < 0.05 && absy < 0.15) { + col = barberpole(pos, rocketpos); + } + + // Rocket Point + float pointw = (rocketpos.y - pos.y - 0.25) * -0.7; + if ((rocketpos.y - pos.y) > 0.1) { + f = smoothstep(pointw - 0.001, pointw + 0.001, absx); + + col = mix(vec3(1.0, 0.0, 0.0), col, f); + } + + // Shadow + f = -.5 + smoothstep(-0.05, 0.05, (rocketpos.x - pos.x)); + col *= 0.7 + f; + + return col; +} + +float rand(float val, float seed) { + return cos(val * sin(val * seed) * seed); +} + +float distance2(in vec2 a, in vec2 b) { + return dot(a - b, a - b); +} + +mat2 rr = mat2(cos(1.0), -sin(1.0), sin(1.0), cos(1.0)); + +vec3 drawParticles(vec2 pos, vec3 particolor, float time, vec2 cpos, float gravity, float seed, float timelength) { + vec3 col = vec3(0.0); + vec2 pp = vec2(1.0, 0.0); + for (float i = 1.0; i <= 128.0; i++) { + float d = rand(i, seed); + float fade = (i / 128.0) * time; + vec2 particpos = cpos + time * pp * d; + pp = rr * pp; + col = mix(particolor / fade, col, smoothstep(0.0, 0.0001, distance2(particpos, pos))); + } + col *= smoothstep(0.0, 1.0, (timelength - time) / timelength); + + return col; +} +vec3 drawFireworks(float time, vec2 uv, vec3 particolor, float seed) { + float timeoffset = 2.0; + vec3 col = vec3(0.0); + if (time <= 0.) { + return col; + } + if (mod(time, 6.0) > timeoffset) { + col = drawParticles(uv, particolor, mod(time, 6.0) - timeoffset, vec2(rand(ceil(time / 6.0), seed), -0.5), 0.5, ceil(time / 6.0), seed); + } else { + col = rocket(uv * 3., vec2(3. * rand(ceil(time / 6.0), seed), 3. * (-0.5 + (timeoffset - mod(time, 6.0))))); + } + return col; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + vec2 uv = 1.0 - 2.0 * fragCoord.xy / iResolution.xy; + uv.x *= iResolution.x / iResolution.y; + vec3 col = vec3(0.1, 0.1, 0.2); + + // Flip the y-axis so that the rocket is drawn from the bottom of the screen + uv.y = -uv.y; + + col += 0.1 * uv.y; + + col += drawFireworks(iTime, uv, vec3(1.0, 0.1, 0.1), 1.); + col += drawFireworks(iTime - 2.0, uv, vec3(0.0, 1.0, 0.5), 2.); + col += drawFireworks(iTime - 4.0, uv, vec3(1.0, 1.0, 0.1), 3.); + + vec2 termUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, termUV); + + float alpha = step(length(terminalColor.rgb), BLACK_BLEND_THRESHOLD); + vec3 blendedColor = mix(terminalColor.rgb * 1.0, col.rgb * 0.3, alpha); + + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/dot_config/ghostty/shaders/galaxy.glsl b/dot_config/ghostty/shaders/galaxy.glsl new file mode 100644 index 0000000..78d46e6 --- /dev/null +++ b/dot_config/ghostty/shaders/galaxy.glsl @@ -0,0 +1,139 @@ +float triangle(float x, float period) { + return 2.0 * abs(3.0* ((x / period) - floor((x / period) + 0.5))) - 1.0; +} + +float field(in vec3 position) { + float strength = 7.0 + 0.03 * log(1.0e-6 + fract(sin(iTime) * 373.11)); + float accumulated = 0.0; + float previousMagnitude = 0.0; + float totalWeight = 0.0; + + for (int i = 0; i < 6; ++i) { + float magnitude = dot(position, position); + position = abs(position) / magnitude + vec3(-0.5, -0.8 + 0.1 * sin(-iTime * 0.1 + 2.0), -1.1 + 0.3 * cos(iTime * 0.3)); + float weight = exp(-float(i) / 7.0); + accumulated += weight * exp(-strength * pow(abs(magnitude - previousMagnitude), 2.3)); + totalWeight += weight; + previousMagnitude = magnitude; + } + + return max(0.0, 5.0 * accumulated / totalWeight - 0.7); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + const float baseSpeed = 0.02; + const int maxIterations = 16; + const float formulaParameter = 0.79; + const float volumeSteps = 7.0; + const float stepSize = 0.24; + const float zoomFactor = 0.1; + const float tilingFactor = 0.85; + const float baseBrightness = 0.0008; + const float darkMatter = 0.2; + const float distanceFading = 0.56; + const float colorSaturation = 0.9; + const float transverseMotion = 0.2; + const float cloudOpacity = 0.28; + const float zoomSpeed = 0.00002; + const float effectIntensity = 0.02; // 0.0 = terminal only, 1.0 = original intensity + + vec2 normalizedCoordinates = 2.0 * fragCoord.xy / vec2(512) - 1.0; + vec2 scaledCoordinates = normalizedCoordinates * vec2(512) / 512.0; + + float timeElapsed = iTime; + float speedAdjustment = -baseSpeed; + float formulaAdjustment = formulaParameter; + + speedAdjustment = zoomSpeed * cos(iTime * 0.02 + 3.1415926 / 4.0); + + vec2 uvCoordinates = scaledCoordinates; + + float rotationXZ = 0.9; + float rotationYZ = -0.6; + float rotationXY = 0.9 + iTime * 0.08; + + mat2 rotationMatrixXZ = mat2(vec2(cos(rotationXZ), sin(rotationXZ)), vec2(-sin(rotationXZ), cos(rotationXZ))); + mat2 rotationMatrixYZ = mat2(vec2(cos(rotationYZ), sin(rotationYZ)), vec2(-sin(rotationYZ), cos(rotationYZ))); + mat2 rotationMatrixXY = mat2(vec2(cos(rotationXY), sin(rotationXY)), vec2(-sin(rotationXY), cos(rotationXY))); + + vec2 canvasCenter = vec2(0.5, 0.5); + vec3 rayDirection = vec3(uvCoordinates * zoomFactor, 1.0); + vec3 cameraPosition = vec3(0.0, 0.0, 0.0); + cameraPosition.x -= 2.0 * (canvasCenter.x - 0.5); + cameraPosition.y -= 2.0 * (canvasCenter.y - 0.5); + + vec3 forwardVector = vec3(0.0, 0.0, 1.0); + cameraPosition.x += transverseMotion * cos(0.01 * iTime) + 0.001 * iTime; + cameraPosition.y += transverseMotion * sin(0.01 * iTime) + 0.001 * iTime; + cameraPosition.z += 0.003 * iTime; + + rayDirection.xz *= rotationMatrixXZ; + forwardVector.xz *= rotationMatrixXZ; + rayDirection.yz *= rotationMatrixYZ; + forwardVector.yz *= rotationMatrixYZ; + + cameraPosition.xy *= -1.0 * rotationMatrixXY; + cameraPosition.xz *= rotationMatrixXZ; + cameraPosition.yz *= rotationMatrixYZ; + + float zoomOffset = (timeElapsed - 3311.0) * speedAdjustment; + cameraPosition += forwardVector * zoomOffset; + float sampleOffset = mod(zoomOffset, stepSize); + float normalizedSampleOffset = sampleOffset / stepSize; + + float stepDistance = 0.24; + float secondaryStepDistance = stepDistance + stepSize / 2.0; + vec3 accumulatedColor = vec3(0.0); + float fieldContribution = 0.0; + vec3 backgroundColor = vec3(0.0); + + for (float stepIndex = 0.0; stepIndex < volumeSteps; ++stepIndex) { + vec3 primaryPosition = cameraPosition + (stepDistance + sampleOffset) * rayDirection; + vec3 secondaryPosition = cameraPosition + (secondaryStepDistance + sampleOffset) * rayDirection; + + primaryPosition = abs(vec3(tilingFactor) - mod(primaryPosition, vec3(tilingFactor * 2.0))); + secondaryPosition = abs(vec3(tilingFactor) - mod(secondaryPosition, vec3(tilingFactor * 2.0))); + + fieldContribution = field(secondaryPosition); + + float particleAccumulator = 0.0, particleDistance = 0.0; + for (int i = 0; i < maxIterations; ++i) { + primaryPosition = abs(primaryPosition) / dot(primaryPosition, primaryPosition) - formulaAdjustment; + float distanceChange = abs(length(primaryPosition) - particleDistance); + particleAccumulator += i > 2 ? min(12.0, distanceChange) : distanceChange; + particleDistance = length(primaryPosition); + } + particleAccumulator *= particleAccumulator * particleAccumulator; + + float fadeFactor = pow(distanceFading, max(0.0, float(stepIndex) - normalizedSampleOffset)); + accumulatedColor += vec3(stepDistance, stepDistance * stepDistance, stepDistance * stepDistance * stepDistance * stepDistance) + * particleAccumulator * baseBrightness * fadeFactor; + backgroundColor += mix(0.4, 1.0, cloudOpacity) * vec3(1.8 * fieldContribution * fieldContribution * fieldContribution, + 1.4 * fieldContribution * fieldContribution, fieldContribution) * fadeFactor; + stepDistance += stepSize; + secondaryStepDistance += stepSize; + } + + accumulatedColor = mix(vec3(length(accumulatedColor)), accumulatedColor, colorSaturation); + + vec4 foregroundColor = vec4(accumulatedColor * 0.01, 1.0); + backgroundColor *= cloudOpacity; + backgroundColor.b *= 1.8; + backgroundColor.r *= 0.05; + + backgroundColor.b = 0.5 * mix(backgroundColor.g, backgroundColor.b, 0.8); + backgroundColor.g = 0.0; + backgroundColor.bg = mix(backgroundColor.gb, backgroundColor.bg, 0.5 * (cos(iTime * 0.01) + 1.0)); + + vec2 terminalUV = fragCoord.xy / iResolution.xy; + vec4 terminalColor = texture(iChannel0, terminalUV); + + float brightnessThreshold = 0.1; + float terminalBrightness = dot(terminalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); + + if (terminalBrightness < brightnessThreshold) { + fragColor = mix(terminalColor, vec4(foregroundColor.rgb + backgroundColor, 1.0), 0.24 * effectIntensity); + } else { + fragColor = terminalColor; + } +} diff --git a/dot_config/ghostty/shaders/geocities.glsl b/dot_config/ghostty/shaders/geocities.glsl new file mode 100644 index 0000000..4c5b384 --- /dev/null +++ b/dot_config/ghostty/shaders/geocities.glsl @@ -0,0 +1,202 @@ +// geocities.glsl — a tribute to the golden age of blinking, tiled, +// under-construction personal homepages. Caution-stripe wallpaper, +// a rainbow sparkle field with hard blink (not a gentle twinkle), +// a scrolling pixel-font "UNDER CONSTRUCTION" marquee, and a bouncing +// rotating star badge, DVD-logo style. + +// transparent background +const bool transparent = true; + +// terminal contents luminance threshold to be considered background (0.0 to 1.0) +const float threshold = 0.02; + +// show/hide individual gimmicks +const bool showStripes = true; +const bool showSparkles = true; +const bool showMarquee = true; +const bool showBadge = true; + +// caution-stripe wallpaper opacity (0.0 to 1.0) +const float stripeOpacity = 0.02; + +// sparkle field brightness +const float sparkleIntensity = 0.1; + +// marquee scroll speed, in pixels per second +const float scrollSpeed = 90.0; + +// --------------------------------------------------------------- +// helpers +// --------------------------------------------------------------- + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +float hash21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +// 0 -> 1 -> 0 triangle wave, used to ping-pong the bouncing badge +float triangleWave(float x, float period) { + float t = fract(x / period); + return 1.0 - abs(2.0 * t - 1.0); +} + +// --------------------------------------------------------------- +// tiny 5x7 pixel font, just enough glyphs to spell "UNDER CONSTRUCTION" +// each row is packed as a 5-bit value, bit weight 16 = leftmost column +// --------------------------------------------------------------- + +const int FONT_ROWS = 7; +const int FONT[77] = int[77]( + 0, 0, 0, 0, 0, 0, 0, // 0: space + 17, 17, 17, 17, 17, 17, 14, // 1: U + 17, 25, 21, 21, 19, 17, 17, // 2: N + 30, 17, 17, 17, 17, 17, 30, // 3: D + 31, 16, 16, 30, 16, 16, 31, // 4: E + 30, 17, 17, 30, 20, 18, 17, // 5: R + 15, 16, 16, 16, 16, 16, 15, // 6: C + 14, 17, 17, 17, 17, 17, 14, // 7: O + 15, 16, 16, 14, 1, 1, 30, // 8: S + 31, 4, 4, 4, 4, 4, 4, // 9: T + 31, 4, 4, 4, 4, 4, 31 // 10: I +); + +// "UNDER CONSTRUCTION" as indices into the glyph table above +const int MSG_LEN = 18; +const int MSG[18] = int[18](1, 2, 3, 4, 5, 0, 6, 7, 2, 8, 9, 5, 1, 6, 9, 10, 7, 2); + +float fontBit(int code, int row, int col) { + int rowVal = FONT[code * FONT_ROWS + row]; + float shifted = floor(float(rowVal) / pow(2.0, float(4 - col))); + return mod(shifted, 2.0); +} + +// --------------------------------------------------------------- +// background gimmicks +// --------------------------------------------------------------- + +vec3 hazardStripes(vec2 fragCoord) { + float stripeWidth = 18.0; + float diag = (fragCoord.x + fragCoord.y) + iTime * 40.0; + float m = mod(diag, stripeWidth * 2.0); + vec3 yellow = vec3(1.0, 0.82, 0.0); + vec3 blk = vec3(0.05); + return m < stripeWidth ? yellow : blk; +} + +vec3 sparkleStars(vec2 uv, vec2 resolution) { + vec2 gridUV = uv; + gridUV.x *= resolution.x / resolution.y; + gridUV *= 26.0; + + vec2 ipos = floor(gridUV); + vec2 fpos = fract(gridUV); + + // only a fraction of cells host a star + float rnd = hash21(ipos); + if (rnd > 0.12) return vec3(0.0); + + vec2 center = vec2(hash21(ipos + 3.1), hash21(ipos + 7.7)); + float d = length(fpos - center); + + // hard on/off blink rather than a smooth twinkle, tacky on purpose + float phase = hash21(ipos + 11.0) * 10.0; + float blink = step(0.5, fract(iTime * (1.5 + rnd * 4.0) + phase)); + + float glow = smoothstep(0.12, 0.0, d); + vec3 hue = hsv2rgb(vec3(fract(rnd * 4.0 + iTime * 0.1), 1.0, 1.0)); + return hue * glow * blink; +} + +vec3 starBadge(vec2 fragCoord, vec2 resolution) { + float radius = 26.0; + float px = mix(radius, resolution.x - radius, triangleWave(iTime * 0.09, 1.0)); + float py = mix(radius, resolution.y - radius, triangleWave(iTime * 0.13 + 0.37, 1.0)); + vec2 p = fragCoord - vec2(px, py); + + float d = length(p); + float a = atan(p.y, p.x) - iTime * 2.0; + float starR = radius * (0.55 + 0.45 * cos(a * 5.0)); + float shape = smoothstep(1.5, -1.5, d - starR); + + vec3 hue = hsv2rgb(vec3(fract(iTime * 0.3), 1.0, 1.0)); + return hue * shape; +} + +// returns rgb + coverage alpha for the scrolling marquee ticker +vec4 marquee(vec2 fragCoord, vec2 resolution) { + float scale = clamp(resolution.y / 220.0, 2.0, 6.0); + float charW = 6.0 * scale; // 5 columns + 1 spacing column + float charH = 8.0 * scale; // 7 rows + 1 spacing row + + int gap = 6; // blank characters between loops of the message + int totalChars = MSG_LEN + gap; + + // band hugs the bottom edge of the terminal + float bandY0 = resolution.y - charH - scale * 2.0; + float localY = fragCoord.y - bandY0; + if (localY < 0.0 || localY >= charH) return vec4(0.0); + int row = int(floor(localY / scale)); + if (row >= FONT_ROWS) return vec4(0.0); + + float scrollX = fragCoord.x + iTime * scrollSpeed; + float totalWidth = float(totalChars) * charW; + float wrapped = mod(scrollX, totalWidth); + int charIndex = int(floor(wrapped / charW)); + if (charIndex >= MSG_LEN) return vec4(0.0); // in the gap, blank + + float localX = mod(wrapped, charW); + int col = int(floor(localX / scale)); + if (col >= 5) return vec4(0.0); + + int code = MSG[charIndex]; + if (fontBit(code, row, col) < 0.5) return vec4(0.0); + + vec3 color = hsv2rgb(vec3(fract(float(charIndex) / float(MSG_LEN) + iTime * 0.15), 1.0, 1.0)); + return vec4(color, 1.0); +} + +// --------------------------------------------------------------- +// main +// --------------------------------------------------------------- + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord / iResolution.xy; + vec4 terminalColor = texture(iChannel0, uv); + + vec3 deco = vec3(0.0); + + if (showStripes) { + deco += hazardStripes(fragCoord) * stripeOpacity; + } + if (showSparkles) { + deco += sparkleStars(uv, iResolution.xy) * sparkleIntensity; + } + if (showBadge) { + deco = max(deco, starBadge(fragCoord, iResolution.xy)); + } + if (showMarquee) { + vec4 marq = marquee(fragCoord, iResolution.xy); + deco = mix(deco, marq.rgb, marq.a); + } + + if (transparent) { + deco += terminalColor.rgb; + } + + // only show the effect where the terminal is background (not text) + float mask = 1.0 - step(threshold, luminance(terminalColor.rgb)); + vec3 blended = mix(terminalColor.rgb, deco, mask); + + fragColor = vec4(blended, terminalColor.a); +} diff --git a/dot_config/ghostty/shaders/iamond_teeth_cursor.glsl b/dot_config/ghostty/shaders/iamond_teeth_cursor.glsl new file mode 100644 index 0000000..4537947 --- /dev/null +++ b/dot_config/ghostty/shaders/iamond_teeth_cursor.glsl @@ -0,0 +1,91 @@ +#define PI 3.141592653589793 + +vec2 pxToNdc(vec2 p, float isPosition) { + return (p * 2.0 - iResolution.xy * isPosition) / iResolution.y; +} + +float segPos(vec2 p, vec2 a, vec2 b) { + vec2 ba = b - a; + return clamp(dot(p - a, ba) / max(dot(ba, ba), 0.000001), 0.0, 1.0); +} + +float segDist(vec2 p, vec2 a, vec2 b) { + float h = segPos(p, a, b); + return length(p - (a + (b - a) * h)); +} + +float diamond(vec2 p, vec2 c, float r) { + float d = abs(p.x - c.x) + abs(p.y - c.y); + return 1.0 - smoothstep(r * 0.25, r, d); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 base = texture(iChannel0, uv); + vec3 col = base.rgb; + + vec2 p = pxToNdc(fragCoord.xy, 1.0); + + // Ghostty cursor rect: xy is the top-left-ish corner, zw is width/height. + vec2 curPx = vec2( + iCurrentCursor.x + iCurrentCursor.z * 0.5, + iCurrentCursor.y - iCurrentCursor.w * 0.5 + ); + + vec2 prevPx = vec2( + iPreviousCursor.x + iPreviousCursor.z * 0.5, + iPreviousCursor.y - iPreviousCursor.w * 0.5 + ); + + vec2 cur = pxToNdc(curPx, 1.0); + vec2 prev = pxToNdc(prevPx, 1.0); + + float cell = max(0.008, max(iCurrentCursor.z, iCurrentCursor.w) * 2.0 / iResolution.y); + float age = clamp(iTime - iTimeCursorChange, 0.0, 2.0); + float pulse = exp(-age * 4.5); + + float moved = smoothstep(cell * 1.2, cell * 5.0, distance(cur, prev)); + + // Orange-gold trail after cursor jumps. + float h = segPos(p, prev, cur); + float trailD = segDist(p, prev, cur); + float trail = (1.0 - smoothstep(cell * 0.18, cell * 0.85, trailD)); + trail *= sin(h * PI) * moved * pulse; + + col += trail * vec3(1.0, 0.36, 0.05) * 0.90; + + // Gold glow around current cursor. + float d = length(p - cur); + float shimmer = 0.75 + 0.25 * sin(iTime * 9.0 + d * 90.0); + float glow = exp(-d / (cell * 4.0)) * 0.28 * shimmer; + col += glow * vec3(1.0, 0.62, 0.12); + + // Expanding diamond ring when cursor moves. + float ringRadius = cell * (1.30 + 2.20 * pulse); + float ring = 1.0 - smoothstep(cell * 0.10, cell * 0.35, abs(d - ringRadius)); + col += ring * vec3(1.0, 0.92, 0.65) * (0.42 + 0.75 * pulse); + + // Tiny orbiting diamonds: pinky ring / grill sparkle. + float orbit = 0.0; + for (int k = 0; k < 8; k++) { + float fi = float(k); + float dir = mix(-1.0, 1.0, step(0.5, mod(fi, 2.0))); + float a = fi * PI * 2.0 / 8.0 + iTime * (1.5 + 0.1 * fi) * dir; + float rad = cell * (2.4 + 0.45 * sin(iTime * 2.0 + fi * 1.7)); + vec2 q = cur + vec2(cos(a), sin(a)) * rad; + + float tw = 0.65 + 0.35 * sin(iTime * 7.0 + fi * 2.0); + orbit += diamond(p, q, cell * 0.45) * tw; + } + + col += orbit * vec3(1.0, 0.86, 0.50) * 0.70; + + // Cross flare directly on cursor. + float flareX = (1.0 - smoothstep(0.0, cell * 0.035, abs(p.y - cur.y))) * + (1.0 - smoothstep(0.0, cell * 4.5, abs(p.x - cur.x))); + float flareY = (1.0 - smoothstep(0.0, cell * 0.035, abs(p.x - cur.x))) * + (1.0 - smoothstep(0.0, cell * 4.5, abs(p.y - cur.y))); + col += (flareX + flareY) * vec3(1.0, 0.92, 0.60) * 0.11; + + fragColor = vec4(clamp(col, 0.0, 1.0), base.a); +} diff --git a/dot_config/ghostty/shaders/rectangle_boom_cursor.glsl b/dot_config/ghostty/shaders/rectangle_boom_cursor.glsl new file mode 100644 index 0000000..afe26e3 --- /dev/null +++ b/dot_config/ghostty/shaders/rectangle_boom_cursor.glsl @@ -0,0 +1,154 @@ +// CONFIGURATION +const float DURATION = 0.15; // How long the ripple animates (seconds) +const float MAX_SIZE = 0.05; // Max radius in normalized coords (0.5 = 1/4 screen height) +const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0) +vec4 COLOR = vec4(0.35, 0.36, 0.44, 1.0); // change to iCurrentCursorColor for your cursor's color +const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction +const float BLUR = 3.0; // Blur level in pixels + +// Easing functions +float easeOutQuad(float t) { + return 1.0 - (1.0 - t) * (1.0 - t); +} +float easeInOutQuad(float t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0; +} +float easeOutCubic(float t) { + return 1.0 - pow(1.0 - t, 3.0); +} +float easeOutQuart(float t) { + return 1.0 - pow(1.0 - t, 4.0); +} +float easeOutQuint(float t) { + return 1.0 - pow(1.0 - t, 5.0); +} +float easeOutExpo(float t) { + return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t); +} +float easeOutCirc(float t) { + return sqrt(1.0 - pow(t - 1.0, 2.0)); +} +float easeOutSine(float t) { + return sin((t * 3.1415916) / 2.0); +} +float easeOutElastic(float t) { + const float c4 = (2.0 * 3.1415916) / 3.0; + return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; +} +float easeOutBounce(float t) { + const float n1 = 7.5625; + const float d1 = 2.75; + if (t < 1.0 / d1) { + return n1 * t * t; + } else if (t < 2.0 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else { + return n1 * (t -= 2.625 / d1) * t + 0.984375; + } +} +float easeOutBack(float t) { + const float c1 = 1.70158; + const float c3 = c1 + 1.0; + return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0); +} + +// Pulse fade functions +float smoothstepPulse(float t) { + return 4.0 * t * (1.0 - t); +} +float easeOutPulse(float t) { + return t * (2.0 - t); +} +float powerCurvePulse(float t) { + float x = t * 2.0 - 1.0; + return 1.0 - x * x; +} +float doubleSmoothstepPulse(float t) { + return smoothstep(0.0, 0.5, t) * (1.0 - smoothstep(0.5, 1.0, t)); +} +float exponentialDecayPulse(float t) { + return exp(-3.0 * t) * sin(t * 3.1415916); +} +float sinPulse(float t) { + return sin(t * 3.1415916); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b){ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // Normalization & setup (-1 to 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + + float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor + + // check for significant width change + float widthChange = abs(currentCursor.z - previousCursor.z); + float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD; + float isModeChange = step(widthThresholdNorm, widthChange); + + + // ANIMATION + float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET; + // don't clamp yet; we need to know if it's > 1.0 (finished) + float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0 + + // WHY NOT BRANCHLESS??? here ya go: + // because we NEVER have divergence, even in this if/else branchfull logic + // why? because its UNIFORM branching (ie, all fragments take the same path) which modern GPUs handles efficiently + // its far more efficient than calculating the ripple EVERY FRAME even when not needed(branchless) + if (isModeChange > 0.0 && isAnimating > 0.0) { + // float easedProgress = rippleProgress; + // float easedProgress = easeOutQuad(rippleProgress); + // float easedProgress = easeInOutQuad(rippleProgress); + // float easedProgress = easeOutCubic(rippleProgress); + // float easedProgress = easeOutQuart(rippleProgress); + // float easedProgress = easeOutQuint(rippleProgress); + // float easedProgress = easeOutExpo(rippleProgress); + float easedProgress = easeOutCirc(rippleProgress); + // float easedProgress = easeOutSine(rippleProgress); + // float easedProgress = easeOutBack(rippleProgress); + + // easedProgress = clamp(easedProgress, 0.0, 1.0); + + // RIPPLE CALCULATION + float rippleExpansion = easedProgress * MAX_SIZE; + + // float fade = 1.0; // no fade + // float fade = 1.0 - easedProgress; // linear fade + // float fade = 1.0 - smoothstepPulse(rippleProgress); + float fade = 1.0 - easeOutPulse(rippleProgress); + // float fade = 1.0 - powerCurvePulse(rippleProgress); + // float fade = doubleSmoothstepPulse(rippleProgress); + // float fade = exponentialDecayPulse(rippleProgress); + // float fade = sinPulse(rippleProgress); + + vec2 halfSizeCC = vec2(currentCursor.z, currentCursor.w) * 0.5 + vec2(rippleExpansion); + float sdfRectRing = getSdfRectangle(vu, centerCC, halfSizeCC); + + // Antialias (1-pixel width in normalized coords) + float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x; + float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfRectRing)) * fade; + // Apply ripple effect + fragColor = mix(fragColor, COLOR, ripple * COLOR.a); + } + // else: do nothing, keep original fragColor +} diff --git a/dot_config/ghostty/shaders/ripple_cursor.glsl b/dot_config/ghostty/shaders/ripple_cursor.glsl new file mode 100644 index 0000000..1ca5a7e --- /dev/null +++ b/dot_config/ghostty/shaders/ripple_cursor.glsl @@ -0,0 +1,132 @@ +// CONFIGURATION +const float DURATION = 0.15; // How long the ripple animates (seconds) +const float MAX_RADIUS = 0.05; // Max radius in normalized coords (0.5 = 1/4 screen height) +const float RING_THICKNESS = 0.02; // Ring width in normalized coords +const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction +vec4 COLOR = vec4(0.35, 0.36, 0.44, 1.0); // change to iCurrentCursorColor for your cursor's color +const float BLUR = 3.0; // Blur level in pixels +const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0) + + +// Easing functions +float easeOutQuad(float t) { + return 1.0 - (1.0 - t) * (1.0 - t); +} +float easeInOutQuad(float t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0; +} +float easeOutCubic(float t) { + return 1.0 - pow(1.0 - t, 3.0); +} +float easeOutQuart(float t) { + return 1.0 - pow(1.0 - t, 4.0); +} +float easeOutQuint(float t) { + return 1.0 - pow(1.0 - t, 5.0); +} +float easeOutExpo(float t) { + return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t); +} +float easeOutCirc(float t) { + return sqrt(1.0 - pow(t - 1.0, 2.0)); +} +float easeOutSine(float t) { + return sin((t * 3.1415916) / 2.0); +} +float easeOutElastic(float t) { + const float c4 = (2.0 * 3.1415916) / 3.0; + return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; +} +float easeOutBounce(float t) { + const float n1 = 7.5625; + const float d1 = 2.75; + if (t < 1.0 / d1) { + return n1 * t * t; + } else if (t < 2.0 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else { + return n1 * (t -= 2.625 / d1) * t + 0.984375; + } +} +float easeOutBack(float t) { + const float c1 = 1.70158; + const float c3 = c1 + 1.0; + return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0); +} + +// Pulse fade functions +float easeOutPulse(float t) { + return t * (2.0 - t); +} +float exponentialDecayPulse(float t) { + return exp(-3.0 * t) * sin(t * 3.1415916); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // Normalization & setup (-1 to 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + + float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor + + // check for significant width change + float widthChange = abs(currentCursor.z - previousCursor.z); + float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD; + float isModeChange = step(widthThresholdNorm, widthChange); + + + // ANIMATION + float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET; + // don't clamp yet; we need to know if it's > 1.0 (finished) + float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0 + + if (isModeChange > 0.0 && isAnimating > 0.0) { + // Apply easing to progress + // float easedProgress = rippleProgress; + // float easedProgress = easeOutQuad(rippleProgress); + // float easedProgress = easeInOutQuad(rippleProgress); + // float easedProgress = easeOutCubic(rippleProgress); + // float easedProgress = easeOutQuart(rippleProgress); + // float easedProgress = easeOutQuint(rippleProgress); + // float easedProgress = easeOutExpo(rippleProgress); + float easedProgress = easeOutCirc(rippleProgress); + // float easedProgress = easeOutSine(rippleProgress); + // float easedProgress = easeOutBack(rippleProgress); + + // RIPPLE CALCULATION + float rippleRadius = easedProgress * MAX_RADIUS; + + // float fade = 1.0; // no fade + // float fade = 1.0 - easedProgress; // linear fade + float fade = 1.0 - easeOutPulse(rippleProgress); + // float fade = 1.0 - exponentialDecayPulse(rippleProgress); + + // Calculate distance from frag to cursor center + float dist = distance(vu, centerCC); + + float sdfRing = abs(dist - rippleRadius) - RING_THICKNESS * 0.5; + + // Antialias (1-pixel width in normalized coords) + float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x; + float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfRing)) * fade; + + // Apply ripple effect + fragColor = mix(fragColor, COLOR, ripple * COLOR.a); + } + // else: do nothing, keep original fragColor +} diff --git a/dot_config/ghostty/shaders/ripple_rectangle_cursor.glsl b/dot_config/ghostty/shaders/ripple_rectangle_cursor.glsl new file mode 100644 index 0000000..7b1aa34 --- /dev/null +++ b/dot_config/ghostty/shaders/ripple_rectangle_cursor.glsl @@ -0,0 +1,138 @@ +// CONFIGURATION +const float DURATION = 0.15; // How long the ripple animates (seconds) +const float MAX_SIZE = 0.05; // Max radius in normalized coords (0.5 = 1/4 screen height) +const float RING_THICKNESS = 0.02; // Ring width in normalized coords +const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction +vec4 COLOR = vec4(0.35, 0.36, 0.44, 1.0); // change to iCurrentCursorColor for your cursor's color +const float BLUR = 1.0; // Blur level in pixels +const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0) + + +// Easing functions +float easeOutQuad(float t) { + return 1.0 - (1.0 - t) * (1.0 - t); +} +float easeInOutQuad(float t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0; +} +float easeOutCubic(float t) { + return 1.0 - pow(1.0 - t, 3.0); +} +float easeOutQuart(float t) { + return 1.0 - pow(1.0 - t, 4.0); +} +float easeOutQuint(float t) { + return 1.0 - pow(1.0 - t, 5.0); +} +float easeOutExpo(float t) { + return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t); +} +float easeOutCirc(float t) { + return sqrt(1.0 - pow(t - 1.0, 2.0)); +} +float easeOutSine(float t) { + return sin((t * 3.1415916) / 2.0); +} +float easeOutElastic(float t) { + const float c4 = (2.0 * 3.1415916) / 3.0; + return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; +} +float easeOutBounce(float t) { + const float n1 = 7.5625; + const float d1 = 2.75; + if (t < 1.0 / d1) { + return n1 * t * t; + } else if (t < 2.0 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else { + return n1 * (t -= 2.625 / d1) * t + 0.984375; + } +} +float easeOutBack(float t) { + const float c1 = 1.70158; + const float c3 = c1 + 1.0; + return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0); +} + +// Pulse fade functions +float easeOutPulse(float t) { + return t * (2.0 - t); +} +float exponentialDecayPulse(float t) { + return exp(-3.0 * t) * sin(t * 3.1415916); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +float getSdfRectangle(in vec2 p, in vec2 xy, in vec2 b){ + vec2 d = abs(p - xy) - b; + return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // Normalization & setup (-1 to 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + + float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor + + // check for significant width change + float widthChange = abs(currentCursor.z - previousCursor.z); + float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD; + float isModeChange = step(widthThresholdNorm, widthChange); + + + // ANIMATION + float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET; + // don't clamp yet; we need to know if it's > 1.0 (finished) + float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0 + + if (isModeChange > 0.0 && isAnimating > 0.0) { + // Apply easing to progress + // float easedProgress = rippleProgress; + // float easedProgress = easeOutQuad(rippleProgress); + // float easedProgress = easeInOutQuad(rippleProgress); + // float easedProgress = easeOutCubic(rippleProgress); + // float easedProgress = easeOutQuart(rippleProgress); + // float easedProgress = easeOutQuint(rippleProgress); + // float easedProgress = easeOutExpo(rippleProgress); + float easedProgress = easeOutCirc(rippleProgress); + // float easedProgress = easeOutSine(rippleProgress); + // float easedProgress = easeOutBack(rippleProgress); + + // RIPPLE CALCULATION + float rippleExpansion = easedProgress * MAX_SIZE; + + // float fade = 1.0; // no fade + // float fade = 1.0 - easedProgress; // linear fade + float fade = 1.0 - easeOutPulse(rippleProgress); + // float fade = 1.0 - exponentialDecayPulse(rippleProgress); + + // Calculate distance from frag to cursor center + // float dist = distance(vu, centerCC); + + // float sdfRing = abs(dist - rippleExpansion) - RING_THICKNESS * 0.5; + vec2 halfSizeCC = vec2(currentCursor.z, currentCursor.w) * 0.5 + vec2(rippleExpansion); + float sdfRectRing = abs(getSdfRectangle(vu, centerCC, halfSizeCC)) - RING_THICKNESS * 0.5; + // Antialias (1-pixel width in normalized coords) + float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x; + float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfRectRing)) * fade; + + // Apply ripple effect + fragColor = mix(fragColor, COLOR, ripple * COLOR.a); + } + // else: do nothing, keep original fragColor +} diff --git a/dot_config/ghostty/shaders/sonic_boom_cursor.glsl b/dot_config/ghostty/shaders/sonic_boom_cursor.glsl new file mode 100644 index 0000000..39355d1 --- /dev/null +++ b/dot_config/ghostty/shaders/sonic_boom_cursor.glsl @@ -0,0 +1,148 @@ +// CONFIGURATION +const float DURATION = 0.15; // How long the ripple animates (seconds) +const float MAX_RADIUS = 0.06; // Max radius in normalized coords (0.5 = 1/4 screen height) +const float ANIMATION_START_OFFSET = 0.0; // Start the ripple slightly progressed (0.0 - 1.0) +vec4 COLOR = vec4(0.35, 0.36, 0.44, 1.0); // change to iCurrentCursorColor for your cursor's color +const float CURSOR_WIDTH_CHANGE_THRESHOLD = 0.5; // Triggers ripple if cursor width changes by this fraction +const float BLUR = 3.0; // Blur level in pixels + + +// Easing functions +float easeOutQuad(float t) { + return 1.0 - (1.0 - t) * (1.0 - t); +} +float easeInOutQuad(float t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0; +} +float easeOutCubic(float t) { + return 1.0 - pow(1.0 - t, 3.0); +} +float easeOutQuart(float t) { + return 1.0 - pow(1.0 - t, 4.0); +} +float easeOutQuint(float t) { + return 1.0 - pow(1.0 - t, 5.0); +} +float easeOutExpo(float t) { + return t == 1.0 ? 1.0 : 1.0 - pow(2.0, -10.0 * t); +} +float easeOutCirc(float t) { + return sqrt(1.0 - pow(t - 1.0, 2.0)); +} +float easeOutSine(float t) { + return sin((t * 3.1415916) / 2.0); +} +float easeOutElastic(float t) { + const float c4 = (2.0 * 3.1415916) / 3.0; + return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; +} +float easeOutBounce(float t) { + const float n1 = 7.5625; + const float d1 = 2.75; + if (t < 1.0 / d1) { + return n1 * t * t; + } else if (t < 2.0 / d1) { + return n1 * (t -= 1.5 / d1) * t + 0.75; + } else if (t < 2.5 / d1) { + return n1 * (t -= 2.25 / d1) * t + 0.9375; + } else { + return n1 * (t -= 2.625 / d1) * t + 0.984375; + } +} +float easeOutBack(float t) { + const float c1 = 1.70158; + const float c3 = c1 + 1.0; + return 1.0 + c3 * pow(t - 1.0, 3.0) + c1 * pow(t - 1.0, 2.0); +} + +// Pulse fade functions +float smoothstepPulse(float t) { + return 4.0 * t * (1.0 - t); +} +float easeOutPulse(float t) { + return t * (2.0 - t); +} +float powerCurvePulse(float t) { + float x = t * 2.0 - 1.0; + return 1.0 - x * x; +} +float doubleSmoothstepPulse(float t) { + return smoothstep(0.0, 0.5, t) * (1.0 - smoothstep(0.5, 1.0, t)); +} +float exponentialDecayPulse(float t) { + return exp(-3.0 * t) * sin(t * 3.1415916); +} +float sinPulse(float t) { + return sin(t * 3.1415916); +} + +vec2 normalize(vec2 value, float isPosition) { + return (value * 2.0 - (iResolution.xy * isPosition)) / iResolution.y; +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord){ + #if !defined(WEB) + fragColor = texture(iChannel0, fragCoord.xy / iResolution.xy); + #endif + + // Normalization & setup (-1 to 1 coords) + vec2 vu = normalize(fragCoord, 1.); + vec2 offsetFactor = vec2(-.5, 0.5); + + vec4 currentCursor = vec4(normalize(iCurrentCursor.xy, 1.), normalize(iCurrentCursor.zw, 0.)); + vec4 previousCursor = vec4(normalize(iPreviousCursor.xy, 1.), normalize(iPreviousCursor.zw, 0.)); + + vec2 centerCC = currentCursor.xy - (currentCursor.zw * offsetFactor); + + float cellWidth = max(currentCursor.z, previousCursor.z); // width of the 'block' cursor + + // check for significant width change + float widthChange = abs(currentCursor.z - previousCursor.z); + float widthThresholdNorm = cellWidth * CURSOR_WIDTH_CHANGE_THRESHOLD; + float isModeChange = step(widthThresholdNorm, widthChange); + + + // ANIMATION + float rippleProgress = (iTime - iTimeCursorChange) / DURATION + ANIMATION_START_OFFSET; + // don't clamp yet; we need to know if it's > 1.0 (finished) + float isAnimating = 1.0 - step(1.0, rippleProgress); // progress < 1.0 ? 1.0: 0.0 + + if (isModeChange > 0.0 && isAnimating > 0.0) { + // float easedProgress = rippleProgress; + // float easedProgress = easeOutQuad(rippleProgress); + // float easedProgress = easeInOutQuad(rippleProgress); + // float easedProgress = easeOutCubic(rippleProgress); + // float easedProgress = easeOutQuart(rippleProgress); + // float easedProgress = easeOutQuint(rippleProgress); + // float easedProgress = easeOutExpo(rippleProgress); + float easedProgress = easeOutCirc(rippleProgress); + // float easedProgress = easeOutSine(rippleProgress); + // float easedProgress = easeOutBack(rippleProgress); + + // easedProgress = clamp(easedProgress, 0.0, 1.0); + + // RIPPLE CALCULATION + float rippleRadius = easedProgress * MAX_RADIUS; + + // float fade = 1.0; // no fade + // float fade = 1.0 - easedProgress; // linear fade + // float fade = 1.0 - smoothstepPulse(rippleProgress); + float fade = 1.0 - easeOutPulse(rippleProgress); + // float fade = 1.0 - powerCurvePulse(rippleProgress); + // float fade = doubleSmoothstepPulse(rippleProgress); + // float fade = exponentialDecayPulse(rippleProgress); + // float fade = sinPulse(rippleProgress); + + // Calculate distance from frag to cursor center + float dist = distance(vu, centerCC); + + float sdfCircle = dist - rippleRadius; + + // Antialias (1-pixel width in normalized coords) + float antiAliasSize = normalize(vec2(BLUR, BLUR), 0.0).x; + float ripple = (1.0 - smoothstep(-antiAliasSize, antiAliasSize, sdfCircle)) * fade; + + // Apply ripple effect + fragColor = mix(fragColor, COLOR, ripple * COLOR.a); + } +} diff --git a/dot_config/ghostty/shaders/starfield-colors.glsl b/dot_config/ghostty/shaders/starfield-colors.glsl new file mode 100644 index 0000000..fca393f --- /dev/null +++ b/dot_config/ghostty/shaders/starfield-colors.glsl @@ -0,0 +1,162 @@ +// transparent background +const bool transparent = true; + +// terminal contents luminance threshold to be considered background (0.0 to 1.0) +const float threshold = 0.05; + +// overall star brightness (0.0 = invisible, 1.0 = original brightness) +const float intensity = 0.09; + +// divisions of grid +const float repeats = 15.; + +// number of layers +const float layers = 20.; + +// star colours +const vec3 blue = vec3(51., 64., 195.) / 255.; +const vec3 cyan = vec3(117., 250., 254.) / 255.; +const vec3 white = vec3(255., 255., 255.) / 255.; +const vec3 yellow = vec3(251., 245., 44.) / 255.; +const vec3 red = vec3(247, 2., 20.) / 255.; + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +// spectrum function +vec3 spectrum(vec2 pos) { + pos.x *= 4.; + vec3 outCol = vec3(0); + if (pos.x > 0.) { + outCol = mix(blue, cyan, fract(pos.x)); + } + if (pos.x > 1.) { + outCol = mix(cyan, white, fract(pos.x)); + } + if (pos.x > 2.) { + outCol = mix(white, yellow, fract(pos.x)); + } + if (pos.x > 3.) { + outCol = mix(yellow, red, fract(pos.x)); + } + + return 1. - (pos.y * (1. - outCol)); +} + +float N21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +vec2 N22(vec2 p) { + float n = N21(p); + return vec2(n, N21(p + n)); +} + +mat2 scale(vec2 _scale) { + return mat2(_scale.x, 0.0, + 0.0, _scale.y); +} + +// 2D Noise based on Morgan McGuire +float noise(in vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + float a = N21(i); + float b = N21(i + vec2(1.0, 0.0)); + float c = N21(i + vec2(0.0, 1.0)); + float d = N21(i + vec2(1.0, 1.0)); + + // Smooth Interpolation + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve + + // Mix 4 corners percentages + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +float perlin2(vec2 uv, int octaves, float pscale) { + float col = 1.; + float initScale = 4.; + for (int l; l < octaves; l++) { + float val = noise(uv * initScale); + if (col <= 0.01) { + col = 0.; + break; + } + val -= 0.01; + val *= 0.5; + col *= val; + initScale *= pscale; + } + return col; +} + +vec3 stars(vec2 uv, float offset) { + float timeScale = -(iTime + offset) / layers; + float trans = fract(timeScale); + float newRnd = floor(timeScale); + vec3 col = vec3(0.); + + // Translate uv then scale for center + uv -= vec2(0.5); + uv = scale(vec2(trans)) * uv; + uv += vec2(0.5); + + // Create square aspect ratio + uv.x *= iResolution.x / iResolution.y; + + // Create boxes + uv *= repeats; + + // Get position + vec2 ipos = floor(uv); + + // Return uv as 0 to 1 + uv = fract(uv); + + // Calculate random xy and size + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; + float rndSize = N21(ipos) * 100. + 200.; + + vec2 j = (rndXY - uv) * rndSize; + float sparkle = 1. / dot(j, j); + + // Set stars to be pure white + col += spectrum(fract(rndXY * newRnd * ipos)) * vec3(sparkle); + + col *= smoothstep(1., 0.8, trans); + return col; // Return pure white stars only +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord / iResolution.xy; + + vec3 col = vec3(0.); + + for (float i = 0.; i < layers; i++) { + col += stars(uv, i); + } + col *= intensity; + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + if (transparent) { + col += terminalColor.rgb; + } + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(threshold, luminance(terminalColor.rgb)); + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/dot_config/ghostty/shaders/starfield.glsl b/dot_config/ghostty/shaders/starfield.glsl new file mode 100644 index 0000000..f82b5d3 --- /dev/null +++ b/dot_config/ghostty/shaders/starfield.glsl @@ -0,0 +1,135 @@ +// transparent background +const bool transparent = false; + +// terminal contents luminance threshold to be considered background (0.0 to 1.0) +const float threshold = 0.15; + +// divisions of grid +const float repeats = 30.; + +// number of layers +const float layers = 21.; + +// star colors +const vec3 white = vec3(1.0); // Set star color to pure white + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +float N21(vec2 p) { + p = fract(p * vec2(233.34, 851.73)); + p += dot(p, p + 23.45); + return fract(p.x * p.y); +} + +vec2 N22(vec2 p) { + float n = N21(p); + return vec2(n, N21(p + n)); +} + +mat2 scale(vec2 _scale) { + return mat2(_scale.x, 0.0, + 0.0, _scale.y); +} + +// 2D Noise based on Morgan McGuire +float noise(in vec2 st) { + vec2 i = floor(st); + vec2 f = fract(st); + + // Four corners in 2D of a tile + float a = N21(i); + float b = N21(i + vec2(1.0, 0.0)); + float c = N21(i + vec2(0.0, 1.0)); + float d = N21(i + vec2(1.0, 1.0)); + + // Smooth Interpolation + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve + + // Mix 4 corners percentages + return mix(a, b, u.x) + + (c - a) * u.y * (1.0 - u.x) + + (d - b) * u.x * u.y; +} + +float perlin2(vec2 uv, int octaves, float pscale) { + float col = 1.; + float initScale = 4.; + for (int l; l < octaves; l++) { + float val = noise(uv * initScale); + if (col <= 0.01) { + col = 0.; + break; + } + val -= 0.01; + val *= 0.5; + col *= val; + initScale *= pscale; + } + return col; +} + +vec3 stars(vec2 uv, float offset) { + float timeScale = -(iTime + offset) / layers; + float trans = fract(timeScale); + float newRnd = floor(timeScale); + vec3 col = vec3(0.); + + // Translate uv then scale for center + uv -= vec2(0.5); + uv = scale(vec2(trans)) * uv; + uv += vec2(0.5); + + // Create square aspect ratio + uv.x *= iResolution.x / iResolution.y; + + // Create boxes + uv *= repeats; + + // Get position + vec2 ipos = floor(uv); + + // Return uv as 0 to 1 + uv = fract(uv); + + // Calculate random xy and size + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; + float rndSize = N21(ipos) * 100. + 200.; + + vec2 j = (rndXY - uv) * rndSize; + float sparkle = 1. / dot(j, j); + + // Set stars to be pure white + col += white * sparkle; + + col *= smoothstep(1., 0.8, trans); + return col; // Return pure white stars only +} + +void mainImage(out vec4 fragColor, in vec2 fragCoord) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord / iResolution.xy; + + vec3 col = vec3(0.); + + for (float i = 0.; i < layers; i++) { + col += stars(uv, i); + } + + // Sample the terminal screen texture including alpha channel + vec4 terminalColor = texture(iChannel0, uv); + + if (transparent) { + col += terminalColor.rgb; + } + + // Make a mask that is 1.0 where the terminal content is not black + float mask = 1 - step(threshold, luminance(terminalColor.rgb)); + + vec3 blendedColor = mix(terminalColor.rgb, col, mask); + + // Apply terminal's alpha to control overall opacity + fragColor = vec4(blendedColor, terminalColor.a); +} diff --git a/dot_config/ghostty/themes/cyberdream b/dot_config/ghostty/themes/cyberdream new file mode 100644 index 0000000..b7a65af --- /dev/null +++ b/dot_config/ghostty/themes/cyberdream @@ -0,0 +1,23 @@ +# cyberdream theme for ghostty +palette = 0=#16181a +palette = 1=#ff6e5e +palette = 2=#5eff6c +palette = 3=#f1ff5e +palette = 4=#5ea1ff +palette = 5=#bd5eff +palette = 6=#5ef1ff +palette = 7=#ffffff +palette = 8=#3c4048 +palette = 9=#ff6e5e +palette = 10=#5eff6c +palette = 11=#f1ff5e +palette = 12=#5ea1ff +palette = 13=#bd5eff +palette = 14=#5ef1ff +palette = 15=#ffffff + +background = #16181a +foreground = #ffffff +cursor-color = #ffffff +selection-background = #3c4048 +selection-foreground = #ffffff diff --git a/dot_config/ghostty/themes/cyberdream-light b/dot_config/ghostty/themes/cyberdream-light new file mode 100644 index 0000000..3cd3669 --- /dev/null +++ b/dot_config/ghostty/themes/cyberdream-light @@ -0,0 +1,23 @@ +# cyberdream theme for ghostty +palette = 0=#ffffff +palette = 1=#d11500 +palette = 2=#008b0c +palette = 3=#997b00 +palette = 4=#0057d1 +palette = 5=#a018ff +palette = 6=#008c99 +palette = 7=#16181a +palette = 8=#acacac +palette = 9=#d11500 +palette = 10=#008b0c +palette = 11=#997b00 +palette = 12=#0057d1 +palette = 13=#a018ff +palette = 14=#008c99 +palette = 15=#16181a + +background = #ffffff +foreground = #16181a +cursor-color = #16181a +selection-background = #acacac +selection-foreground = #16181a diff --git a/dot_config/ghostty/themes/cyberpunk b/dot_config/ghostty/themes/cyberpunk new file mode 100644 index 0000000..9204f04 --- /dev/null +++ b/dot_config/ghostty/themes/cyberpunk @@ -0,0 +1,23 @@ +# cyberpunk theme for ghostty +palette = 0=#000000 +palette = 1=#ff0055 +palette = 2=#00ff9f +palette = 3=#f3e600 +palette = 4=#00baff +palette = 5=#ff00ff +palette = 6=#00ffff +palette = 7=#e0e0e0 +palette = 8=#555555 +palette = 9=#ff5585 +palette = 10=#55ffbf +palette = 11=#ffff55 +palette = 12=#55ccff +palette = 13=#ff55ff +palette = 14=#55ffff +palette = 15=#ffffff + +background = #0d0d0f +foreground = #e0e0e0 +cursor-color = #f3e600 +selection-background = #2d2d30 +selection-foreground = #ffffff diff --git a/dot_config/go/telemetry/local/asm@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count b/dot_config/go/telemetry/local/asm@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count new file mode 100644 index 0000000000000000000000000000000000000000..dd79ccae179cd65be5485e527e98f42baeecba12 GIT binary patch literal 16384 zcmeI!O-_SA7{+my%ElNkFiF>Kp=oNu%Fk3+HQKl^ae?g=Ct;ug+Sr{(@hBd}nJBZ-`TX6PS$-aje^T52m0m@m7rELIBRy`ru{LjI6ss_u%nR*Sr`PJ5{jj1o z7~D9*SHbMb><^BwPcIzd>T$1Yn(2}Xhghi;VlMup!0vV*>UGQWZFhCdwoc%s^#0y< z)^(60P!u>SeM7~x{z`1v_q<_W{Yprx1n!r`J;Qj<{-&FdwhHFq$W79HNNjxN={Dj! zpZKoloaK$R`DLCr@{@5;?)PL6FSPrh;^m0yQ|BlX{zbOz)f8h!E1`KD%Hp4=lZG zl&b~ftYB1{hG9*=585Pt6*yl}(@aHgq;MtmE#3B=lI;rZp2?64Rm>G;v0N=yw7Qtn z*J#{Xy2pdwi&k%(-(Fr@I`y4uMbp%hGM{m-Clg-$uxj4oic3XCdrJ*lY0z*TwbxN| zrQIQEQv_0=Uoggh@QT|LOk3|?n(APFJE2YI!vZV=iABr zx%H{}MKAhXU(QFxyVUMbm*tD12Lcd)00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf uKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P-lx5O@cN&x{8E literal 0 HcmV?d00001 diff --git a/dot_config/go/telemetry/local/compile@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count b/dot_config/go/telemetry/local/compile@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count new file mode 100644 index 0000000000000000000000000000000000000000..417290ff5538a19ddc0b31904c3f7acaeba968fa GIT binary patch literal 16384 zcmeH}&u`N(6vxd03BrWRTU|x0z%_f1QQ2Nc!`@?#Bt@gh28q6^`GG0 z{{-CD&T!{tpiZbl->6dG^UL?W=Z~Kh@5h>zOfap^k1{!_G*j`2mn@!kqB$YtgbVhX z6}(F0Zqn@^Brgw=-bs?AtKa8n8Gl>l7tv1Vx9EE%3q?g5XCgQ0#n@zyJ~35uX%ZH) zbJ*=4_M&4MSQ`#Mrg6!u$@l1Z`0B%(cWF#T-tR?`X{&i=dyNSL1a^+V%$wGoYww>l zG{4tgCcfJq-<9axp5=Voey`!NEBpQHK5lT{`eo3nq=_-%YKM(0ES(-yC*KLH)$?1c9B_XZx@kKn?|CnZ9z1?1RT>jwsX=Pfc z`s}i-S@~hD2ciAfx|ywIeEGQfUCp0~?_2%me6QlP7H7F?YK07^56*XeF6b!_gSW|U z+y6(Q{_}5CjY3ti1_B@e0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY r0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JQJCj@>0@x0Mr literal 0 HcmV?d00001 diff --git a/dot_config/go/telemetry/local/empty_upload.token b/dot_config/go/telemetry/local/empty_upload.token new file mode 100644 index 0000000..e69de29 diff --git a/dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count b/dot_config/go/telemetry/local/go@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count new file mode 100644 index 0000000000000000000000000000000000000000..bfe4684328cf8885f398f7b0630497430f91b672 GIT binary patch literal 16384 zcmeH}%Z}496o!L90>VvPcYp;FyG+um>PTL35gK+yFk-=~Y2rzPl6d4e6|7(!j zJVW0E+)O-i)udAm9ooeoRdt+`|D5CR*wJ}SBuiMzq&RT{USyI9aug?wOgi>2%d!sR zl)YzBoKe#Cx_!sncf8)A=h5=_-JaV&W?^mZbPVff!6V_Plmuz$M%@0!L>_bHE8?BK zZhx<5AMl1}gTYryk~k}V+6RMoUp{=I#81P1&$d-Yi`VJB#rgl7k>zx*B>e2omAGwn zI=j_s+PHz-zMM#ltl-kTcdV5n+AHhlK=8fROm)67_#&SO4K*UV+OCW}{<^ZS3dtQtJo~FL)dM0Q6O!ZFFp#2;1Qywy^{)&Xv z@eO+ramq4(l(4Y2Kd<8-C%!!5B6X!NA|_Q|#dBJAOAQI=_%B!KeG!al*3;1<$5*4S-}(9t{khWdYVG{)S~Y!E>y7%U zDmZZ#%SDYj)B1;vdWGM7x#3=a{vS8$M@5{dBCoh!R0%w)^`$8AgE4c{I9Gdk)pflx z8ud5yxeSwd=Jgu8nR!ijU%>^i32| zdTrWtu~jtRrfE2S{r%wsB)83sOr?@WKY1bbG9xv+OH#@Df&1z>&Q+r1k&Kg!v!>r{ zHT;8yzklWXy!_s{AMukcve6(IiJohUwNRXeD)M4-ucgitDr&_P>^57wd+sSsIoEDq za+W4p@6kPNA6^`vaVAvM+H>7vqVdmQ^3?br7Pw-+*n5GOB=%MZN=gBsnZmpRX}^mTt$9p~-iFeWd_ z`V_c+Lsp4xk9+M_AoJ?2hVSL@j^WJSpN{M3E)BoJh%y`Xl`nMUodky;R!% zBk?dME;DhP%E-nyZ2yN;m^;$SGeXDG6#FX5dAVDfGDp>ab5_34VV9RXtceO${>=Vm zD(?pq*>?V&DgC>Y8?PMPQ{tX<YE90%~YX$GAf#Y4fZO;V)7Z7QN$Ma99%Gda^pEt_EnVgaNj;jCmynLa#RifmPjFXJBmfvbO z{DWe<@_k-zH|}TrB#Ue`2*#r4nqn;!XQ7I`nA~fr^Ms08F$K+5ySeY4(u{MR&LwAQ zlJ%b4)6U_=@fl}AMeTjpEhd`$4W>^`Ua-U?_KUrjcw5e3b(z&CYqPb<V=Bx&Y2_KAV`++Y73I8KEzOvt>c2fNU+A#Q%N5pCg(`n;|1y>L zgQ;vg|K5!LUCNDD4(=)OK)NyH42EMh$MfgMjOq9vCWQ zdKUBK{Pyx%$<*fYOo*YRpW+U?wAJTI<{RD18*)M3a!v z(6qHs0+s%ykT5@Ia?Y2u)_T21 zho%Li3F-E(9&YX&>PptJ2}ygZeg^Xk)v)RFb*_ETbQ9SBzX;HEo|g@V`QG24xPj8k zhUaad<*nV4?%@B(U@<4`(M2>?o|~laA;Y~QKdk0{ z=mySno*WhVNiBaJiI53a2cP7-XEVNA=ApdzQ2&~Do#8< zSZn|K{3@?2Z+AT({*iyIye>irKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb t2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uWd&@C$+Ra~c2u literal 0 HcmV?d00001 diff --git a/dot_config/go/telemetry/local/vet@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count b/dot_config/go/telemetry/local/vet@go1.26.4-go1.26.4-linux-amd64-2026-07-04.v1.count new file mode 100644 index 0000000000000000000000000000000000000000..b15cc2c347422552545ad870a3b0a47843408e12 GIT binary patch literal 16384 zcmeI!y-EZz5Ww-Eji&Jx0$1Pd2g@F$Q<1Y<(Zj-S*^NtJH-TJk(YNzad=uT%LJw?g zjw}8lMP>#v!>^i|il#S%iQzSA{MJPi)U)l48Z-GOgjn0bT$#=~t@1Q4=jn2u7V9+C zU-wDw>Nl?asb<-)>Rs?%s0Xc@p-n~;<)aB3>!;5;pDproQOK45BUe=qTJ_d#U*xK~ zyuZHHsvg?1ka8Mn|D5lKL +// +// session_name "My singleton session" + +// When `session_name` is provided, attaches to that session +// if it is already running or creates it otherwise. +// Default: false +// +// attach_to_session true + +// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible +// Options: +// - true (default) +// - false +// +// auto_layout false + +// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected +// Options: +// - true (default) +// - false +// +// session_serialization false + +// Whether pane viewports are serialized along with the session, default is false +// Options: +// - true +// - false (default) +// +// serialize_pane_viewport false + +// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0 +// defaults to the scrollback size. If this number is higher than the scrollback size, it will +// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true. +// +// scrollback_lines_to_serialize 10000 + +// Enable or disable the rendering of styled and colored underlines (undercurl). +// May need to be disabled for certain unsupported terminals +// (Requires restart) +// Default: true +// +// styled_underlines false + +// How often in seconds sessions are serialized +// +// serialization_interval 10000 + +// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know +// metadata info on this session) +// (Requires restart) +// Default: false +// +// disable_session_metadata false + +// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it) +// (Requires restart) +// Default: true (if the host terminal supports it) +// +// support_kitty_keyboard_protocol false +// Whether to make sure a local web server is running when a new Zellij session starts. +// This web server will allow creating new sessions and attaching to existing ones that have +// opted in to being shared in the browser. +// When enabled, navigate to http://127.0.0.1:8082 +// (Requires restart) +// +// Note: a local web server can still be manually started from within a Zellij session or from the CLI. +// If this is not desired, one can use a version of Zellij compiled without +// `web_server_capability` +// +// Possible values: +// - true +// - false +// Default: false +// +// web_server false +// Whether to allow sessions started in the terminal to be shared through a local web server, assuming one is +// running (see the `web_server` option for more details). +// (Requires restart) +// +// Note: This is an administrative separation and not intended as a security measure. +// +// Possible values: +// - "on" (allow web sharing through the local web server if it +// is online) +// - "off" (do not allow web sharing unless sessions explicitly opt-in to it) +// - "disabled" (do not allow web sharing and do not permit sessions started in the terminal to opt-in to it) +// Default: "off" +// +// web_sharing "off" +// A path to a certificate file to be used when setting up the web client to serve the +// connection over HTTPs +// +// web_server_cert "/path/to/cert.pem" +// A path to a key file to be used when setting up the web client to serve the +// connection over HTTPs +// +// web_server_key "/path/to/key.pem" +/// Whether to enforce https connections to the web server when it is bound to localhost +/// (127.0.0.0/8) +/// +/// Note: https is ALWAYS enforced when bound to non-local interfaces +/// +/// Default: false +// +// enforce_https_for_localhost false + +// Whether to stack panes when resizing beyond a certain size +// Default: true +// +// stacked_resize false + +// Whether to show tips on startup +// Default: true +// +// show_startup_tips false + +// Whether to show release notes on first version run +// Default: true +// +// show_release_notes false + +// Whether to enable mouse hover effects and pane grouping functionality +// default is true +// advanced_mouse_actions false + +// Whether to enable mouse hover visual effects (frame highlight and help text) +// default is true +// mouse_hover_effects false + +// Whether to show visual bell indicators (pane/tab frame flash and [!] suffix) +// default is true +// visual_bell true + +// Whether to focus panes on mouse hover +// default is false +// focus_follows_mouse false + +// Whether clicking a pane to focus it also sends the click into the pane +// default is false +// mouse_click_through false + +// The ip address the web server should listen on when it starts +// Default: "127.0.0.1" +// (Requires restart) +// web_server_ip "127.0.0.1" + +// The port the web server should listen on when it starts +// Default: 8082 +// (Requires restart) +// web_server_port 8082 + +// A command to run (will be wrapped with sh -c and provided the RESURRECT_COMMAND env variable) +// after Zellij attempts to discover a command inside a pane when resurrecting sessions, the STDOUT +// of this command will be used instead of the discovered RESURRECT_COMMAND +// can be useful for removing wrappers around commands +// Note: be sure to escape backslashes and similar characters properly +// post_command_discovery_hook "echo $RESURRECT_COMMAND | sed " + +// Number of async worker tasks to spawn per active client. +// +// Allocating few tasks may result in resource contention and lags. Small values (around 4) should +// typically work best. Set to 0 to use the number of (physical) CPU cores. +// Note: This only applies to web clients at the moment. +// client_async_worker_tasks 4 diff --git a/dot_local/bin/executable_fedora-backup-home b/dot_local/bin/executable_fedora-backup-home new file mode 100644 index 0000000..01dd3d3 --- /dev/null +++ b/dot_local/bin/executable_fedora-backup-home @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +usage() { + cat <<'USAGE' +Usage: fedora-backup-home DESTINATION [options] + +Rsync your home folder to an external drive or mounted network share. +Dry-run is the default. Add --run when the preview looks right. + +Examples: + fedora-backup-home /run/media/$USER/BackupDrive + fedora-backup-home /run/media/$USER/BackupDrive --run + fedora-backup-home /mnt/nas/backups --run --delete + +Options: + --run Actually copy files. Without this, rsync runs in dry-run mode. + --delete Delete files in the backup that no longer exist in your home folder. + -h, --help Show this help. +USAGE +} + +log() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } +die() { printf '\033[31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } + +[[ $# -gt 0 ]] || { usage; exit 1; } + +DEST_ROOT="" +RUN=false +DELETE=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --run) RUN=true ;; + --delete) DELETE=true ;; + -h|--help) usage; exit 0 ;; + -*) die "Unknown option: $1" ;; + *) + if [[ -z "$DEST_ROOT" ]]; then DEST_ROOT="$1"; else die "Unexpected extra argument: $1"; fi + ;; + esac + shift +done + +[[ -n "$DEST_ROOT" ]] || die "Missing DESTINATION." +command -v rsync >/dev/null 2>&1 || die "rsync is not installed. Run: sudo dnf5 install rsync" +[[ -d "$DEST_ROOT" ]] || die "Destination does not exist: $DEST_ROOT" + +HOST="$(hostname -s 2>/dev/null || hostname)" +DEST="$DEST_ROOT/${HOST}-${USER}-home" +mkdir -p "$DEST" + +# Prevent accidental recursive backup if destination is inside $HOME. +case "$(realpath -m "$DEST")" in + "$(realpath -m "$HOME")"/*) die "Destination is inside your home folder; choose an external path." ;; +esac + +RSYNC_OPTS=(-aAXH --human-readable --info=progress2) +[[ "$RUN" == "false" ]] && RSYNC_OPTS+=(--dry-run --itemize-changes) +[[ "$DELETE" == "true" ]] && RSYNC_OPTS+=(--delete) + +EXCLUDES=( + --exclude='/.cache/' + --exclude='/.local/share/Trash/' + --exclude='/.var/app/*/cache/' + --exclude='/Downloads/*.iso' + --exclude='/Downloads/*.img' + --exclude='/Downloads/*.qcow2' + --exclude='/.npm/_cacache/' + --exclude='/.cargo/registry/' + --exclude='/.cargo/git/' + --exclude='/.gradle/caches/' + --exclude='/**/node_modules/' + --exclude='/**/.venv/' +) + +log "Backing up $HOME to $DEST" +if [[ "$RUN" == "false" ]]; then + printf 'Mode: DRY RUN. Add --run to actually copy files.\n' +else + printf 'Mode: REAL RUN.\n' +fi +[[ "$DELETE" == "true" ]] && printf 'Delete mode: enabled.\n' + +rsync "${RSYNC_OPTS[@]}" "${EXCLUDES[@]}" "$HOME/" "$DEST/" + +log "Done" +if [[ "$RUN" == "false" ]]; then + printf 'Review the dry-run above, then rerun with --run when ready.\n' +fi diff --git a/dot_local/bin/executable_fedora-clean b/dot_local/bin/executable_fedora-clean new file mode 100644 index 0000000..03df820 --- /dev/null +++ b/dot_local/bin/executable_fedora-clean @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +usage() { + cat <<'USAGE' +Usage: fedora-clean [options] + +Clean common Fedora desktop clutter. + +Options: + --aggressive Also clear thumbnails, browser crash dumps, and offer Podman prune. + -y, --yes Accept this script's prompts and pass -y where possible. + -h, --help Show this help. +USAGE +} + +log() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } +warn() { printf '\033[33mWARN:\033[0m %s\n' "$*" >&2; } +die() { printf '\033[31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } +have() { command -v "$1" >/dev/null 2>&1; } +confirm() { + local prompt="$1" answer + if [[ "${ASSUME_YES}" == "true" ]]; then return 0; fi + read -r -p "$prompt [y/N] " answer + [[ "$answer" =~ ^[Yy]$ ]] +} + +DNF="$(command -v dnf5 || command -v dnf || true)" +[[ -n "$DNF" ]] || die "Could not find dnf5 or dnf." + +AGGRESSIVE=false +ASSUME_YES=false +while [[ $# -gt 0 ]]; do + case "$1" in + --aggressive) AGGRESSIVE=true ;; + -y|--yes) ASSUME_YES=true ;; + -h|--help) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac + shift +done + +YUM_YES=() +[[ "$ASSUME_YES" == "true" ]] && YUM_YES=(-y) + +log "Disk usage before cleanup" +df -hT -x tmpfs -x devtmpfs / "$HOME" 2>/dev/null || df -hT -x tmpfs -x devtmpfs + +log "Removing unused RPM packages" +sudo "$DNF" autoremove "${YUM_YES[@]}" || warn "DNF autoremove did not complete. Review the output above." + +log "Cleaning downloaded DNF packages" +sudo "$DNF" clean packages || warn "DNF clean packages failed." + +if have flatpak; then + log "Removing unused Flatpak runtimes" + flatpak uninstall --unused "${YUM_YES[@]}" || warn "Flatpak unused-runtime cleanup did not complete." +fi + +if have journalctl; then + log "Current journal disk usage" + journalctl --disk-usage || true + if confirm "Vacuum systemd journal to 14 days?"; then + sudo journalctl --vacuum-time=14d + fi +fi + +if [[ "$AGGRESSIVE" == "true" ]]; then + log "Aggressive user-cache cleanup" + if confirm "Clear GNOME thumbnail cache?"; then + rm -rf -- "$HOME/.cache/thumbnails"/* 2>/dev/null || true + fi + if confirm "Clear user crash-report cache under ~/.cache/abrt?"; then + rm -rf -- "$HOME/.cache/abrt"/* 2>/dev/null || true + fi + if have podman && confirm "Prune unused Podman images/containers/networks?"; then + podman system prune -a + fi +fi + +log "Disk usage after cleanup" +df -hT -x tmpfs -x devtmpfs / "$HOME" 2>/dev/null || df -hT -x tmpfs -x devtmpfs diff --git a/dot_local/bin/executable_fedora-reset-audio b/dot_local/bin/executable_fedora-reset-audio new file mode 100644 index 0000000..c4df113 --- /dev/null +++ b/dot_local/bin/executable_fedora-reset-audio @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +usage() { + cat <<'USAGE' +Usage: fedora-reset-audio + +Restart the common Fedora Workstation audio user services: + pipewire, pipewire-pulse, wireplumber + +Useful when Bluetooth/audio devices disappear or sound gets weird. +USAGE +} + +[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && { usage; exit 0; } + +printf '\nRestarting audio user services...\n' +systemctl --user restart pipewire pipewire-pulse wireplumber +printf '\nStatus:\n' +systemctl --user --no-pager --full status pipewire pipewire-pulse wireplumber || true diff --git a/dot_local/bin/executable_fedora-update b/dot_local/bin/executable_fedora-update new file mode 100644 index 0000000..460b715 --- /dev/null +++ b/dot_local/bin/executable_fedora-update @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +usage() { + cat <<'USAGE' +Usage: fedora-update [options] + +Update Fedora RPM packages, Flatpaks, and firmware. + +Options: + --offline Prepare the DNF transaction as an offline update, then ask before rebooting. + --no-flatpak Skip Flatpak updates. + --no-firmware Skip fwupd firmware checks/updates. + -y, --yes Pass -y to DNF/Flatpak where possible and accept prompts from this script. + -h, --help Show this help. +USAGE +} + +log() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } +warn() { printf '\033[33mWARN:\033[0m %s\n' "$*" >&2; } +die() { printf '\033[31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } +have() { command -v "$1" >/dev/null 2>&1; } +confirm() { + local prompt="$1" answer + if [[ "${ASSUME_YES}" == "true" ]]; then return 0; fi + read -r -p "$prompt [y/N] " answer + [[ "$answer" =~ ^[Yy]$ ]] +} + +DNF="$(command -v dnf5 || command -v dnf || true)" +[[ -n "$DNF" ]] || die "Could not find dnf5 or dnf." + +OFFLINE=false +DO_FLATPAK=true +DO_FIRMWARE=true +ASSUME_YES=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --offline) OFFLINE=true ;; + --no-flatpak) DO_FLATPAK=false ;; + --no-firmware) DO_FIRMWARE=false ;; + -y|--yes) ASSUME_YES=true ;; + -h|--help) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac + shift +done + +YUM_YES=() +[[ "$ASSUME_YES" == "true" ]] && YUM_YES=(-y) + +log "Refreshing and updating RPM packages with $(basename "$DNF")" +if [[ "$OFFLINE" == "true" ]]; then + sudo "$DNF" upgrade --refresh --offline "${YUM_YES[@]}" + log "DNF offline transaction prepared" +else + sudo "$DNF" upgrade --refresh "${YUM_YES[@]}" +fi + +if [[ "$DO_FLATPAK" == "true" ]]; then + if have flatpak; then + log "Updating Flatpaks" + flatpak update "${YUM_YES[@]}" + log "Removing unused Flatpak runtimes" + flatpak uninstall --unused "${YUM_YES[@]}" || true + else + warn "flatpak not found; skipping Flatpak updates." + fi +fi + +if [[ "$DO_FIRMWARE" == "true" ]]; then + if have fwupdmgr; then + log "Checking firmware updates with fwupd" + sudo fwupdmgr refresh --force || warn "fwupdmgr refresh failed; continuing." + sudo fwupdmgr get-updates || true + if confirm "Run firmware updates now?"; then + sudo fwupdmgr update || warn "Firmware update command returned a non-zero status." + fi + else + warn "fwupdmgr not found; install fwupd to manage firmware updates." + fi +fi + +log "Checking whether a reboot is recommended" +NEEDS_RESTARTING_OUTPUT="$(mktemp)" +set +e +sudo "$DNF" needs-restarting >"$NEEDS_RESTARTING_OUTPUT" 2>&1 +status=$? +set -e + +if [[ $status -eq 0 ]]; then + printf 'No reboot required according to dnf needs-restarting.\n' +elif grep -qiE 'No such command|unknown command|unrecognized|Unable to resolve|not found' "$NEEDS_RESTARTING_OUTPUT"; then + warn "Could not run '$(basename "$DNF") needs-restarting'. Try: sudo $DNF install dnf5-plugins" +else + cat "$NEEDS_RESTARTING_OUTPUT" + warn "A reboot is recommended." +fi +rm -f "$NEEDS_RESTARTING_OUTPUT" + +if [[ "$OFFLINE" == "true" ]]; then + if confirm "Reboot now to run the offline DNF transaction?"; then + sudo "$DNF" offline reboot + else + printf 'Run this later to apply it: sudo %s offline reboot\n' "$DNF" + fi +fi diff --git a/dot_zshrc b/dot_zshrc new file mode 100644 index 0000000..233c046 --- /dev/null +++ b/dot_zshrc @@ -0,0 +1,8 @@ +# fzf: fuzzy completion + key bindings (Ctrl-T, Ctrl-R, Alt-C) +if command -v fzf >/dev/null 2>&1; then + eval "$(fzf --zsh)" +fi + +eval "$(/home/mr0xb/.local/bin/mise activate zsh)" +# starship prompt +eval "$(starship init zsh)"