mirror of
https://github.com/boxpositron/absolute-dotfiles.git
synced 2026-02-28 03:30:37 +00:00
fix(colorscheme): update theme name from "catppuccin-mocha" to "Catppuccin Frappe"
feat(shaders): add CRT-styled shader with public domain license and adjustments for Ghostty, including parameter definitions and tonal control functions. refactor(shader): optimize color conversion and output to SRGB for better visual quality feat(shaders): add flicker, glow, and starfield shader effects for terminal ambiance.
This commit is contained in:
@@ -1 +1 @@
|
||||
theme = "catppuccin-mocha"
|
||||
theme = "Catppuccin Frappe"
|
||||
310
.config/ghostty/shaders/crt.glsl
Normal file
310
.config/ghostty/shaders/crt.glsl
Normal file
@@ -0,0 +1,310 @@
|
||||
// source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f
|
||||
// credits: https://github.com/qwerasd205
|
||||
//==============================================================
|
||||
//
|
||||
// [CRTS] PUBLIC DOMAIN CRT-STYLED SCALAR by Timothy Lottes
|
||||
//
|
||||
// [+] Adapted with alterations for use in Ghostty by Qwerasd.
|
||||
// For more information on changes, see comment below license.
|
||||
//
|
||||
//==============================================================
|
||||
//
|
||||
// LICENSE = UNLICENSE (aka PUBLIC DOMAIN)
|
||||
//
|
||||
//--------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the
|
||||
// public domain.
|
||||
//--------------------------------------------------------------
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell,
|
||||
// or distribute this software, either in source code form or as
|
||||
// a compiled binary, for any purpose, commercial or
|
||||
// non-commercial, and by any means.
|
||||
//--------------------------------------------------------------
|
||||
// In jurisdictions that recognize copyright laws, the author or
|
||||
// authors of this software dedicate any and all copyright
|
||||
// interest in the software to the public domain. We make this
|
||||
// dedication for the benefit of the public at large and to the
|
||||
// detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity
|
||||
// of all present and future rights to this software under
|
||||
// copyright law.
|
||||
//--------------------------------------------------------------
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//--------------------------------------------------------------
|
||||
// For more information, please refer to
|
||||
// <http://unlicense.org/>
|
||||
//==============================================================
|
||||
|
||||
// This shader is a modified version of the excellent
|
||||
// FixingPixelArtFast by Timothy Lottes on Shadertoy.
|
||||
//
|
||||
// The original shader can be found at:
|
||||
// https://www.shadertoy.com/view/MtSfRK
|
||||
//
|
||||
// Modifications have been made to reduce the verbosity,
|
||||
// and many of the comments have been removed / reworded.
|
||||
// Additionally, the license has been moved to the top of
|
||||
// the file, and can be read above. I (Qwerasd) choose to
|
||||
// release the modified version under the same license.
|
||||
|
||||
// The appearance of this shader can be altered
|
||||
// by adjusting the parameters defined below.
|
||||
|
||||
// "Scanlines" per real screen pixel.
|
||||
// e.g. SCALE 0.5 means each scanline is 2 pixels.
|
||||
// Recommended values:
|
||||
// o High DPI displays: 0.33333333
|
||||
// - Low DPI displays: 0.66666666
|
||||
#define SCALE 0.33333333
|
||||
|
||||
// "Tube" warp
|
||||
#define CRTS_WARP 1
|
||||
|
||||
// Darkness of vignette in corners after warping
|
||||
// 0.0 = completely black
|
||||
// 1.0 = no vignetting
|
||||
#define MIN_VIN 0.5
|
||||
|
||||
// Try different masks
|
||||
// #define CRTS_MASK_GRILLE 1
|
||||
// #define CRTS_MASK_GRILLE_LITE 1
|
||||
// #define CRTS_MASK_NONE 1
|
||||
#define CRTS_MASK_SHADOW 1
|
||||
|
||||
// Scanline thinness
|
||||
// 0.50 = fused scanlines
|
||||
// 0.70 = recommended default
|
||||
// 1.00 = thinner scanlines (too thin)
|
||||
#define INPUT_THIN 0.75
|
||||
|
||||
// Horizonal scan blur
|
||||
// -3.0 = pixely
|
||||
// -2.5 = default
|
||||
// -2.0 = smooth
|
||||
// -1.0 = too blurry
|
||||
#define INPUT_BLUR -2.75
|
||||
|
||||
// Shadow mask effect, ranges from,
|
||||
// 0.25 = large amount of mask (not recommended, too dark)
|
||||
// 0.50 = recommended default
|
||||
// 1.00 = no shadow mask
|
||||
#define INPUT_MASK 0.65
|
||||
|
||||
float FromSrgb1(float c) {
|
||||
return (c <= 0.04045) ? c * (1.0 / 12.92) :
|
||||
pow(c * (1.0 / 1.055) + (0.055 / 1.055), 2.4);
|
||||
}
|
||||
vec3 FromSrgb(vec3 c) {
|
||||
return vec3(
|
||||
FromSrgb1(c.r), FromSrgb1(c.g), FromSrgb1(c.b));
|
||||
}
|
||||
|
||||
vec3 CrtsFetch(vec2 uv) {
|
||||
return FromSrgb(texture(iChannel0, uv.xy).rgb);
|
||||
}
|
||||
|
||||
#define CrtsRcpF1(x) (1.0/(x))
|
||||
#define CrtsSatF1(x) clamp((x),0.0,1.0)
|
||||
|
||||
float CrtsMax3F1(float a, float b, float c) {
|
||||
return max(a, max(b, c));
|
||||
}
|
||||
|
||||
vec2 CrtsTone(
|
||||
float thin,
|
||||
float mask) {
|
||||
#ifdef CRTS_MASK_NONE
|
||||
mask = 1.0;
|
||||
#endif
|
||||
|
||||
#ifdef CRTS_MASK_GRILLE_LITE
|
||||
// Normal R mask is {1.0,mask,mask}
|
||||
// LITE R mask is {mask,1.0,1.0}
|
||||
mask = 0.5 + mask * 0.5;
|
||||
#endif
|
||||
|
||||
vec2 ret;
|
||||
float midOut = 0.18 / ((1.5 - thin) * (0.5 * mask + 0.5));
|
||||
float pMidIn = 0.18;
|
||||
ret.x = ((-pMidIn) + midOut) / ((1.0 - pMidIn) * midOut);
|
||||
ret.y = ((-pMidIn) * midOut + pMidIn) / (midOut * (-pMidIn) + midOut);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
vec3 CrtsMask(vec2 pos, float dark) {
|
||||
#ifdef CRTS_MASK_GRILLE
|
||||
vec3 m = vec3(dark, dark, dark);
|
||||
float x = fract(pos.x * (1.0 / 3.0));
|
||||
if (x < (1.0 / 3.0)) m.r = 1.0;
|
||||
else if (x < (2.0 / 3.0)) m.g = 1.0;
|
||||
else m.b = 1.0;
|
||||
return m;
|
||||
#endif
|
||||
|
||||
#ifdef CRTS_MASK_GRILLE_LITE
|
||||
vec3 m = vec3(1.0, 1.0, 1.0);
|
||||
float x = fract(pos.x * (1.0 / 3.0));
|
||||
if (x < (1.0 / 3.0)) m.r = dark;
|
||||
else if (x < (2.0 / 3.0)) m.g = dark;
|
||||
else m.b = dark;
|
||||
return m;
|
||||
#endif
|
||||
|
||||
#ifdef CRTS_MASK_NONE
|
||||
return vec3(1.0, 1.0, 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef CRTS_MASK_SHADOW
|
||||
pos.x += pos.y * 3.0;
|
||||
vec3 m = vec3(dark, dark, dark);
|
||||
float x = fract(pos.x * (1.0 / 6.0));
|
||||
if (x < (1.0 / 3.0)) m.r = 1.0;
|
||||
else if (x < (2.0 / 3.0)) m.g = 1.0;
|
||||
else m.b = 1.0;
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 CrtsFilter(
|
||||
vec2 ipos,
|
||||
vec2 inputSizeDivOutputSize,
|
||||
vec2 halfInputSize,
|
||||
vec2 rcpInputSize,
|
||||
vec2 rcpOutputSize,
|
||||
vec2 twoDivOutputSize,
|
||||
float inputHeight,
|
||||
vec2 warp,
|
||||
float thin,
|
||||
float blur,
|
||||
float mask,
|
||||
vec2 tone
|
||||
) {
|
||||
// Optional apply warp
|
||||
vec2 pos;
|
||||
#ifdef CRTS_WARP
|
||||
// Convert to {-1 to 1} range
|
||||
pos = ipos * twoDivOutputSize - vec2(1.0, 1.0);
|
||||
|
||||
// Distort pushes image outside {-1 to 1} range
|
||||
pos *= vec2(
|
||||
1.0 + (pos.y * pos.y) * warp.x,
|
||||
1.0 + (pos.x * pos.x) * warp.y);
|
||||
|
||||
// TODO: Vignette needs optimization
|
||||
float vin = 1.0 - (
|
||||
(1.0 - CrtsSatF1(pos.x * pos.x)) * (1.0 - CrtsSatF1(pos.y * pos.y)));
|
||||
vin = CrtsSatF1((-vin) * inputHeight + inputHeight);
|
||||
|
||||
// Leave in {0 to inputSize}
|
||||
pos = pos * halfInputSize + halfInputSize;
|
||||
#else
|
||||
pos = ipos * inputSizeDivOutputSize;
|
||||
#endif
|
||||
|
||||
// Snap to center of first scanline
|
||||
float y0 = floor(pos.y - 0.5) + 0.5;
|
||||
// Snap to center of one of four pixels
|
||||
float x0 = floor(pos.x - 1.5) + 0.5;
|
||||
|
||||
// Inital UV position
|
||||
vec2 p = vec2(x0 * rcpInputSize.x, y0 * rcpInputSize.y);
|
||||
// Fetch 4 nearest texels from 2 nearest scanlines
|
||||
vec3 colA0 = CrtsFetch(p);
|
||||
p.x += rcpInputSize.x;
|
||||
vec3 colA1 = CrtsFetch(p);
|
||||
p.x += rcpInputSize.x;
|
||||
vec3 colA2 = CrtsFetch(p);
|
||||
p.x += rcpInputSize.x;
|
||||
vec3 colA3 = CrtsFetch(p);
|
||||
p.y += rcpInputSize.y;
|
||||
vec3 colB3 = CrtsFetch(p);
|
||||
p.x -= rcpInputSize.x;
|
||||
vec3 colB2 = CrtsFetch(p);
|
||||
p.x -= rcpInputSize.x;
|
||||
vec3 colB1 = CrtsFetch(p);
|
||||
p.x -= rcpInputSize.x;
|
||||
vec3 colB0 = CrtsFetch(p);
|
||||
|
||||
// Vertical filter
|
||||
// Scanline intensity is using sine wave
|
||||
// Easy filter window and integral used later in exposure
|
||||
float off = pos.y - y0;
|
||||
float pi2 = 6.28318530717958;
|
||||
float hlf = 0.5;
|
||||
float scanA = cos(min(0.5, off * thin) * pi2) * hlf + hlf;
|
||||
float scanB = cos(min(0.5, (-off) * thin + thin) * pi2) * hlf + hlf;
|
||||
|
||||
// Horizontal kernel is simple gaussian filter
|
||||
float off0 = pos.x - x0;
|
||||
float off1 = off0 - 1.0;
|
||||
float off2 = off0 - 2.0;
|
||||
float off3 = off0 - 3.0;
|
||||
float pix0 = exp2(blur * off0 * off0);
|
||||
float pix1 = exp2(blur * off1 * off1);
|
||||
float pix2 = exp2(blur * off2 * off2);
|
||||
float pix3 = exp2(blur * off3 * off3);
|
||||
float pixT = CrtsRcpF1(pix0 + pix1 + pix2 + pix3);
|
||||
|
||||
#ifdef CRTS_WARP
|
||||
// Get rid of wrong pixels on edge
|
||||
pixT *= max(MIN_VIN, vin);
|
||||
#endif
|
||||
|
||||
scanA *= pixT;
|
||||
scanB *= pixT;
|
||||
|
||||
// Apply horizontal and vertical filters
|
||||
vec3 color =
|
||||
(colA0 * pix0 + colA1 * pix1 + colA2 * pix2 + colA3 * pix3) * scanA +
|
||||
(colB0 * pix0 + colB1 * pix1 + colB2 * pix2 + colB3 * pix3) * scanB;
|
||||
|
||||
// Apply phosphor mask
|
||||
color *= CrtsMask(ipos, mask);
|
||||
|
||||
// Tonal control, start by protecting from /0
|
||||
float peak = max(1.0 / (256.0 * 65536.0),
|
||||
CrtsMax3F1(color.r, color.g, color.b));
|
||||
// Compute the ratios of {R,G,B}
|
||||
vec3 ratio = color * CrtsRcpF1(peak);
|
||||
// Apply tonal curve to peak value
|
||||
peak = peak * CrtsRcpF1(peak * tone.x + tone.y);
|
||||
// Reconstruct color
|
||||
return ratio * peak;
|
||||
}
|
||||
|
||||
float ToSrgb1(float c) {
|
||||
return (c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 0.41666) - 0.055);
|
||||
}
|
||||
vec3 ToSrgb(vec3 c) {
|
||||
return vec3(
|
||||
ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b));
|
||||
}
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||
float aspect = iResolution.x / iResolution.y;
|
||||
fragColor.rgb = CrtsFilter(
|
||||
fragCoord.xy,
|
||||
vec2(1.0),
|
||||
iResolution.xy * SCALE * 0.5,
|
||||
1.0 / (iResolution.xy * SCALE),
|
||||
1.0 / iResolution.xy,
|
||||
2.0 / iResolution.xy,
|
||||
iResolution.y,
|
||||
vec2(1.0 / (50.0 * aspect), 1.0 / 50.0),
|
||||
INPUT_THIN,
|
||||
INPUT_BLUR,
|
||||
INPUT_MASK,
|
||||
CrtsTone(INPUT_THIN, INPUT_MASK)
|
||||
);
|
||||
|
||||
// Linear to SRGB for output.
|
||||
fragColor.rgb = ToSrgb(fragColor.rgb);
|
||||
}
|
||||
42
.config/ghostty/shaders/flicker.glsl
Normal file
42
.config/ghostty/shaders/flicker.glsl
Normal file
@@ -0,0 +1,42 @@
|
||||
// https://github.com/12jihan/ghostty_shaders/blob/main/flicker.glsl
|
||||
|
||||
float rand(vec2 co) {
|
||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||
vec2 uv = fragCoord/iResolution.xy;
|
||||
|
||||
// Random timing for glitches
|
||||
float timeScale = floor(iTime * 2.0);
|
||||
float randomTrigger = step(0.52, rand(vec2(timeScale, 0.80)));
|
||||
|
||||
// RGB Split with random intensity
|
||||
float splitStrength = randomTrigger * 0.20 * rand(vec2(timeScale, 2.0));
|
||||
float r = texture(iChannel0, vec2(uv.x + splitStrength, uv.y)).r;
|
||||
float g = texture(iChannel0, uv).g;
|
||||
float b = texture(iChannel0, vec2(uv.x - splitStrength, uv.y)).b;
|
||||
|
||||
// Random vertical glitch blocks
|
||||
float blockNoise = rand(vec2(floor(uv.y * 32.0), timeScale));
|
||||
float blockOffset = (step(0.996, blockNoise) * 2.0 - 1.0) * 0.02;
|
||||
uv.x = uv.x + blockOffset * randomTrigger;
|
||||
|
||||
// CRT scanlines
|
||||
float scanline = sin(uv.y * 1000.0) * 0.04 + 0.96;
|
||||
|
||||
// Vertical sync glitch
|
||||
float vSync = sin(uv.y * 50.0 + iTime * 5.0) * randomTrigger * 0.01;
|
||||
uv.x += vSync;
|
||||
|
||||
vec3 color = vec3(r, g, b);
|
||||
|
||||
// Apply scanlines and noise
|
||||
color *= scanline;
|
||||
color *= (0.95 + rand(uv + timeScale) * 0.05);
|
||||
|
||||
// Random color noise at glitch moments
|
||||
color += randomTrigger * rand(uv + iTime) * 0.01;
|
||||
|
||||
fragColor = vec4(color, 0.95);
|
||||
}
|
||||
22
.config/ghostty/shaders/glow.glsl
Normal file
22
.config/ghostty/shaders/glow.glsl
Normal file
@@ -0,0 +1,22 @@
|
||||
// https://github.com/12jihan/ghostty_shaders/blob/main/glow.glsl
|
||||
|
||||
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||
vec2 uv = fragCoord/iResolution.xy;
|
||||
|
||||
// Base color from terminal
|
||||
vec3 color = texture(iChannel0, uv).rgb;
|
||||
|
||||
// Add bloom/glow
|
||||
float bloom = 0.05;
|
||||
vec3 glow = vec3(0.0);
|
||||
for(float i = 0.0; i < 4.0; i++) {
|
||||
vec2 offset = vec2(i) / iResolution.xy;
|
||||
glow += texture(iChannel0, uv + offset).rgb;
|
||||
glow += texture(iChannel0, uv - offset).rgb;
|
||||
}
|
||||
|
||||
// Combine glow with original color
|
||||
color += glow * bloom;
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
136
.config/ghostty/shaders/starfield.glsl
Normal file
136
.config/ghostty/shaders/starfield.glsl
Normal file
@@ -0,0 +1,136 @@
|
||||
// https://github.com/hackr-sh/ghostty-shaders/blob/main/starfield.glsl
|
||||
// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user