diff --git a/desktopenvs/hyprdrive/ghostty/config b/desktopenvs/hyprdrive/ghostty/config new file mode 100644 index 0000000..92ea251 --- /dev/null +++ b/desktopenvs/hyprdrive/ghostty/config @@ -0,0 +1,64 @@ +# CyberQueer — Ghostty config +# Ported from ../kitty/{kitty.conf,themes/cyberqueer.conf}. Palette matches +# ~/Dotfiles/colors.conf (COLOR_TEXT/BG/HIGHLIGHT/DARK/RED) plus the same +# neon green/yellow/magenta/cyan tints used in the kitty theme so ANSI +# output looks identical across both terminals. Kitty could only fake a +# glow with a static background image (../kitty/scanlines.png); here it's +# a real per-frame bloom shader — see shaders/cyberqueer-glow.glsl. +# +# NOT wired up as the active terminal yet: no keybinds or $TERMINAL changes +# point at Ghostty. This file just needs `ghostty --config-file=` +# (or deploying to ~/.config/ghostty/config) to try it. + +font-family = Agave Nerd Font +font-size = 13 + +cursor-style = bar +cursor-style-blink = false +shell-integration-features = no-cursor + +background-opacity = 0.4 +background-blur = true + +window-padding-x = 4 +window-padding-y = 4 +scrollback-limit = 10485760 +confirm-close-surface = false + +# No titlebar, no tab bar — Hyprland handles window placement/borders itself +# (matches kitty's borderless look under this compositor). Note: an old +# Ghostty bug (ghostty-org/ghostty#3178, fixed in 1.0.1) made this exact +# Arch+Hyprland combo render as a single flat color with gtk-titlebar=false; +# using window-decoration=none instead of gtk-titlebar avoids that specific +# combo, but if the "flat pane, no text" symptom ever comes back, this is +# the first place to check by reverting. +window-decoration = none +window-show-tab-bar = never + +custom-shader = shaders/cyberqueer-glow.glsl +custom-shader-animation = always + +foreground = D6ABAB +background = 1A1A1A +selection-foreground = E40046 +selection-background = 5018DD +cursor-color = E40046 +cursor-text = 5018DD +split-divider-color = 5018DD + +palette = 0=1A1A1A +palette = 1=E40046 +palette = 2=33E6A0 +palette = 3=E8B23D +palette = 4=5018DD +palette = 5=A6178C +palette = 6=34C6C6 +palette = 7=D6ABAB +palette = 8=4B3A55 +palette = 9=F50505 +palette = 10=5CFFC2 +palette = 11=FFD873 +palette = 12=8C6FFF +palette = 13=FF5FC0 +palette = 14=6FF5F0 +palette = 15=F2DEDE diff --git a/desktopenvs/hyprdrive/ghostty/shaders/cyberqueer-glow.glsl b/desktopenvs/hyprdrive/ghostty/shaders/cyberqueer-glow.glsl new file mode 100644 index 0000000..581fcc5 --- /dev/null +++ b/desktopenvs/hyprdrive/ghostty/shaders/cyberqueer-glow.glsl @@ -0,0 +1,202 @@ +// CyberQueer glow shader for Ghostty's custom-shader hook. +// Real per-pixel bloom (unlike kitty, which can only fake this with a static +// background image — see ../../kitty/scanlines.png). Deliberately +// color-preserving: it blooms whatever color a glyph already is, so the +// suite's violet/crimson/neon ANSI palette blooms in its own hues instead of +// a single hardcoded tint. +// +// Only one custom-shader reliably renders on Linux/OpenGL (stacking multiple +// silently drops all but the last), so bloom + scanlines + grain + glitch + +// the boot intro all live here as a single pass rather than several files. +// +// Four effects, composited in order: +// 1. occasional glitch/roll burst (analog-signal tear + vertical roll + +// chromatic aberration), ported from the technique in +// github.com/0xhckr/ghostty-shaders/blob/main/glitchy.glsl +// 2. bloom (existing, sampled post-glitch-warp) +// 3. scanlines + ambient grain (existing) +// 4. a one-time hologram boot intro: the picture resolves out of colored +// static via a downward sweep over the first ~1.8s of iTime. + +// ---------- shared noise helpers (glitch §1 + intro §4) ---------- +// SS: a windowed pulse — 0 outside [a,b], rising then falling inside it. +#define SS(a, b, x) (smoothstep(a, b, x) * smoothstep(b, a, x)) + +#define UI0 1597334673u +#define UI1 3812015801u +#define UI2 uvec2(UI0, UI1) +#define UI3 uvec3(UI0, UI1, 2798796415u) +#define UIF (1.0 / float(0xffffffffu)) + +// Hash by David Hoskins — reused from glitchy.glsl for the glitch burst's +// analog distortion and the intro's static field. +vec3 hash33(vec3 p) { + uvec3 q = uvec3(ivec3(p)) * UI3; + q = (q.x ^ q.y ^ q.z) * UI3; + return -1.0 + 2.0 * vec3(q) * UIF; +} + +// Gradient noise by iq — continuous in space and time, so animating it +// reads as organic shimmer rather than a hard per-frame strobe (deliberate: +// this drives a full-window effect, so avoiding flicker matters). +float gnoise(vec3 x) { + vec3 p = floor(x); + vec3 w = fract(x); + vec3 u = w * w * w * (w * (w * 6.0 - 15.0) + 10.0); + + vec3 ga = hash33(p + vec3(0.0, 0.0, 0.0)); + vec3 gb = hash33(p + vec3(1.0, 0.0, 0.0)); + vec3 gc = hash33(p + vec3(0.0, 1.0, 0.0)); + vec3 gd = hash33(p + vec3(1.0, 1.0, 0.0)); + vec3 ge = hash33(p + vec3(0.0, 0.0, 1.0)); + vec3 gf = hash33(p + vec3(1.0, 0.0, 1.0)); + vec3 gg = hash33(p + vec3(0.0, 1.0, 1.0)); + vec3 gh = hash33(p + vec3(1.0, 1.0, 1.0)); + + float va = dot(ga, w - vec3(0.0, 0.0, 0.0)); + float vb = dot(gb, w - vec3(1.0, 0.0, 0.0)); + float vc = dot(gc, w - vec3(0.0, 1.0, 0.0)); + float vd = dot(gd, w - vec3(1.0, 1.0, 0.0)); + float ve = dot(ge, w - vec3(0.0, 0.0, 1.0)); + float vf = dot(gf, w - vec3(1.0, 0.0, 1.0)); + float vg = dot(gg, w - vec3(0.0, 1.0, 1.0)); + float vh = dot(gh, w - vec3(1.0, 1.0, 1.0)); + + return 2.0 * (va + u.x * (vb - va) + + u.y * (vc - va) + + u.z * (ve - va) + + u.x * u.y * (va - vb - vc + vd) + + u.y * u.z * (va - vc - ve + vg) + + u.z * u.x * (va - vb - ve + vf) + + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh)); +} + +float gnoise01(vec3 x) { + return 0.5 + 0.5 * gnoise(x); +} + +// Golden-spiral sample offsets + inverse-distance weights for the bloom, +// reused verbatim from the community bloom kernel (0xhckr/ghostty-shaders). +const vec3[24] samples = vec3[24]( + vec3(0.1693761725038636, 0.9855514761735895, 1.0), + 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; +} + +// Cheap 2D hash for the ambient grain speckles — no texture lookup needed. +float hash(vec2 p) { + p = fract(p * vec2(123.34, 456.21)); + p += dot(p, p + 45.32); + return fract(p.x * p.y); +} + +// How often (seconds) an occasional glitch/roll burst fires, and what +// fraction of that cycle it's actually active for — "occasional" means +// rare and brief, not a constant tic. +#define GLITCH_DURATION 18.0 +#define GLITCH_AMT 0.045 +// How long the hologram takes to resolve out of static when it first boots. +#define INTRO_DURATION 1.8 + +void mainImage(out vec4 fragColor, in vec2 fragCoord) { + vec2 uv = fragCoord.xy / iResolution.xy; + float t = iTime; + + // --- 1. occasional glitch/roll burst --- + // glitchAmount is ~0 almost all the time and spikes for under a second + // once every GLITCH_DURATION seconds. + float glitchAmount = SS(GLITCH_DURATION * 0.002, GLITCH_DURATION * GLITCH_AMT, mod(t, GLITCH_DURATION)); + float rowY = fragCoord.y; + float tear = gnoise(vec3(0.0, rowY * 0.01, t * 500.0)) * (glitchAmount * 0.03 + 0.0015); + float roll = glitchAmount * gnoise(vec3(t * 3.0, 0.0, 0.0)) * 0.05; + vec2 guv = uv + vec2(tear, roll); + guv.y = fract(guv.y); // vertical roll wraps top/bottom, like a CRT losing vertical hold + + vec2 caOffset = vec2(2.0 / iResolution.x, 0.0) * (1.0 + glitchAmount * 3.0); + vec4 color; + color.r = texture(iChannel0, guv + caOffset).r; + color.g = texture(iChannel0, guv).g; + color.b = texture(iChannel0, guv - caOffset).b; + color.a = texture(iChannel0, guv).a; + + // --- 2. bloom: color-preserving glow around bright glyphs --- + vec2 bstep = vec2(1.414) / iResolution.xy; + for (int i = 0; i < 24; i++) { + vec3 s = samples[i]; + vec4 c = texture(iChannel0, guv + s.xy * bstep); + float l = lum(c); + if (l > 0.25) { + color += l * s.z * c * 0.15; + } + } + + // burst noise: a brief flash of static riding on top of the tear/roll + float burst = hash33(vec3(fragCoord, mod(float(iFrame), 1000.0))).r; + color.rgb += burst * glitchAmount * 0.35; + + // --- 3. scanlines: a hard-edged dark line every 3rd physical row --- + float scan = mod(fragCoord.y, 3.0) < 1.0 ? 0.90 : 1.0; + color.rgb *= scan; + + // holographic grain: sparse, low-alpha, slowly time-varying speckles in + // the theme's accent/violet/danger hues. Update rate capped at ~8Hz and + // intensity kept low deliberately — this sits behind text all day, so it + // should read as ambient shimmer, not a strobe. + vec2 grainCell = floor(fragCoord.xy / 2.0) + floor(iTime * 8.0); + float n = hash(grainCell); + if (n > 0.985) { + vec3 speck = n > 0.9925 ? vec3(0.894, 0.0, 0.271) // accent E40046 + : n > 0.99 ? vec3(0.961, 0.020, 0.020) // danger F50505 + : vec3(0.314, 0.094, 0.867); // violet 5018DD + color.rgb += speck * 0.10; + } + + // --- 4. hologram boot intro: resolve out of colored static over + // INTRO_DURATION seconds via a downward sweep, then never run again for + // the life of the shader (t only grows). Uses gnoise (continuous) rather + // than a per-frame hash flip, so the static shimmers instead of strobing. + float introProgress = clamp(t / INTRO_DURATION, 0.0, 1.0); + float sweepFrac = introProgress * 1.15 - 0.05; + float resolved = 1.0 - smoothstep(sweepFrac - 0.05, sweepFrac + 0.05, uv.y); + + float n1 = gnoise01(vec3(fragCoord * 0.08, t * 6.0)); + float n2 = gnoise01(vec3(fragCoord * 0.08 + 19.0, t * 6.0)); + vec3 violet = vec3(0.314, 0.094, 0.867); + vec3 accent = vec3(0.894, 0.0, 0.271); + vec3 danger = vec3(0.961, 0.020, 0.020); + vec3 introField = mix(violet, accent, n1); + introField = mix(introField, danger, smoothstep(0.75, 1.0, n2) * 0.5); + introField *= (0.18 + 0.22 * n2); // keep it dim — ambient static, not a flash + + float sweepBand = 1.0 - smoothstep(0.0, 0.12, abs(uv.y - sweepFrac)); + vec3 sweepGlow = violet * sweepBand * 1.2; + + vec3 finalRGB = mix(introField, color.rgb, resolved) + sweepGlow; + + fragColor = vec4(finalRGB, color.a); +} diff --git a/desktopenvs/hyprdrive/kitty/kitty.conf b/desktopenvs/hyprdrive/kitty/kitty.conf index c3db446..18dea78 100644 --- a/desktopenvs/hyprdrive/kitty/kitty.conf +++ b/desktopenvs/hyprdrive/kitty/kitty.conf @@ -11,6 +11,16 @@ window_padding_width 4 scrollback_lines 20000 background_opacity 0.4 background_blur 1 + +# Holographic scanlines + noise grain + soft ambient violet/crimson bloom, +# matching the suite's HologramOverlay treatment (orbit-menu/astro-menu/ +# station-bar/beacon) — a static tiled equivalent since kitty has no +# per-frame draw hook to animate it, and no shader hook to bloom glyphs +# directly, so the "glow" comes from ambient light behind the text instead. +background_image scanlines.png +background_image_layout tiled +background_tint 0.3 + editor nvim confirm_os_window_close 0 diff --git a/desktopenvs/hyprdrive/kitty/scanlines.png b/desktopenvs/hyprdrive/kitty/scanlines.png new file mode 100644 index 0000000..71ca6e0 Binary files /dev/null and b/desktopenvs/hyprdrive/kitty/scanlines.png differ