my dotfiles
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add ghostty terminal configuration with custom shaders and themes

theMackabu c9dc98a7 22210c46

+1875
+33
ghostty/bettercrt.glsl
··· 1 + // Original shader collected from: https://www.shadertoy.com/view/WsVSzV 2 + // Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) 3 + // Slight modifications were made to give a green-ish effect. 4 + 5 + // This shader was modified by April Hall (arithefirst) 6 + // Sourced from https://github.com/m-ahdal/ghostty-shaders/blob/main/retro-terminal.glsl 7 + // Changes made: 8 + // - Removed tint 9 + // - Made the boundaries match ghostty's background color 10 + 11 + float warp = 0.25; // simulate curvature of CRT monitor 12 + float scan = 0.50; // simulate darkness between scanlines 13 + 14 + void mainImage(out vec4 fragColor, in vec2 fragCoord) 15 + { 16 + // squared distance from center 17 + vec2 uv = fragCoord / iResolution.xy; 18 + vec2 dc = abs(0.5 - uv); 19 + dc *= dc; 20 + 21 + // warp the fragment coordinates 22 + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; 23 + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; 24 + 25 + // determine if we are drawing in a scanline 26 + float apply = abs(sin(fragCoord.y) * 0.25 * scan); 27 + 28 + // sample the texture 29 + vec3 color = texture(iChannel0, uv).rgb; 30 + 31 + // mix the sampled color with the scanline intensity 32 + fragColor = vec4(mix(color, vec3(0.0), apply), 1.0); 33 + }
+50
ghostty/bloom.glsl
··· 1 + // Golden spiral samples, [x, y, weight] weight is inverse of distance. 2 + const vec3[24] samples = { 3 + vec3(0.1693761725038636, 0.9855514761735895, 1), 4 + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), 5 + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), 6 + vec3(1.554155680728463, -1.2588090085709776, 0.5), 7 + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), 8 + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), 9 + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), 10 + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), 11 + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), 12 + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), 13 + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), 14 + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), 15 + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), 16 + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), 17 + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), 18 + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), 19 + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), 20 + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), 21 + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), 22 + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), 23 + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), 24 + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), 25 + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), 26 + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) 27 + }; 28 + 29 + float lum(vec4 c) { 30 + return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; 31 + } 32 + 33 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 34 + vec2 uv = fragCoord.xy / iResolution.xy; 35 + 36 + vec4 color = texture(iChannel0, uv); 37 + 38 + vec2 step = vec2(1.414) / iResolution.xy; 39 + 40 + for (int i = 0; i < 24; i++) { 41 + vec3 s = samples[i]; 42 + vec4 c = texture(iChannel0, uv + s.xy * step); 43 + float l = lum(c); 44 + if (l > 0.2) { 45 + color += l * s.z * c * 0.2; 46 + } 47 + } 48 + 49 + fragColor = color; 50 + }
+311
ghostty/config
··· 1 + # keybind = global:cmd+grave_accent=toggle_quick_terminal 2 + 3 + # font settings 4 + font-size = 11 5 + bold-is-bright = true 6 + font-style-italic = Regular Italic 7 + 8 + # font options 9 + font-family = "SFMono Nerd Font" 10 + #font-family = "Berkeley Mono" 11 + # font-family = "Fragment Mono" 12 + # font-family = "MonaspiceNe NFM" 13 + 14 + # theme 15 + background = #000000 16 + # foreground = #c7c7c7 17 + unfocused-split-opacity = 1 18 + 19 + # shaders 20 + # custom-shader = ./starfield-colors.glsl 21 + # custom-shader-animation = always 22 + 23 + # window 24 + window-padding-x = 10 25 + window-padding-y = 10,3 26 + window-padding-color = extend 27 + window-inherit-working-directory = false 28 + background-opacity = 0.7 29 + background-blur = 20 30 + 31 + # size 32 + window-height = 45 33 + window-width = 111 34 + 35 + # shell 36 + link-url = true 37 + mouse-hide-while-typing = false 38 + cursor-style = underline 39 + shell-integration = detect 40 + shell-integration-features = no-cursor,no-sudo 41 + macos-titlebar-style = hidden 42 + macos-option-as-alt = true 43 + keybind = shift+enter=text:\r 44 + 45 + # colors 46 + cursor-color = #c7c7c7 47 + selection-background = #c1ddff 48 + cursor-invert-fg-bg = false 49 + selection-invert-fg-bg = false 50 + 51 + # palette 52 + 53 + # custom 54 + palette = 0=#1d1f21 55 + palette = 1=#c91b00 56 + palette = 2=#00c200 57 + palette = 3=#d29922 58 + palette = 4=#59a6ff 59 + palette = 5=#c930c7 60 + palette = 6=#00c5c7 61 + palette = 7=#c7c7c7 62 + palette = 8=#676767 63 + palette = 9=#ff6d67 64 + palette = 10=#5ff967 65 + palette = 11=#fefb67 66 + palette = 12=#6871ff 67 + palette = 13=#ff76ff 68 + palette = 14=#5ffdff 69 + palette = 15=#fffeff 70 + 71 + # default 72 + palette = 16=#000000 73 + palette = 17=#00005f 74 + palette = 18=#000087 75 + palette = 19=#0000af 76 + palette = 20=#0000d7 77 + palette = 21=#0000ff 78 + palette = 22=#005f00 79 + palette = 23=#005f5f 80 + palette = 24=#005f87 81 + palette = 25=#005faf 82 + palette = 26=#005fd7 83 + palette = 27=#005fff 84 + palette = 28=#008700 85 + palette = 29=#00875f 86 + palette = 30=#008787 87 + palette = 31=#0087af 88 + palette = 32=#0087d7 89 + palette = 33=#0087ff 90 + palette = 34=#00af00 91 + palette = 35=#00af5f 92 + palette = 36=#00af87 93 + palette = 37=#00afaf 94 + palette = 38=#00afd7 95 + palette = 39=#00afff 96 + palette = 40=#00d700 97 + palette = 41=#00d75f 98 + palette = 42=#00d787 99 + palette = 43=#00d7af 100 + palette = 44=#00d7d7 101 + palette = 45=#00d7ff 102 + palette = 46=#00ff00 103 + palette = 47=#00ff5f 104 + palette = 48=#00ff87 105 + palette = 49=#00ffaf 106 + palette = 50=#00ffd7 107 + palette = 51=#00ffff 108 + palette = 52=#5f0000 109 + palette = 53=#5f005f 110 + palette = 54=#5f0087 111 + palette = 55=#5f00af 112 + palette = 56=#5f00d7 113 + palette = 57=#5f00ff 114 + palette = 58=#5f5f00 115 + palette = 59=#5f5f5f 116 + palette = 60=#5f5f87 117 + palette = 61=#5f5faf 118 + palette = 62=#5f5fd7 119 + palette = 63=#5f5fff 120 + palette = 64=#5f8700 121 + palette = 65=#5f875f 122 + palette = 66=#5f8787 123 + palette = 67=#5f87af 124 + palette = 68=#5f87d7 125 + palette = 69=#5f87ff 126 + palette = 70=#5faf00 127 + palette = 71=#5faf5f 128 + palette = 72=#5faf87 129 + palette = 73=#5fafaf 130 + palette = 74=#5fafd7 131 + palette = 75=#5fafff 132 + palette = 76=#5fd700 133 + palette = 77=#5fd75f 134 + palette = 78=#5fd787 135 + palette = 79=#5fd7af 136 + palette = 80=#5fd7d7 137 + palette = 81=#5fd7ff 138 + palette = 82=#5fff00 139 + palette = 83=#5fff5f 140 + palette = 84=#5fff87 141 + palette = 85=#5fffaf 142 + palette = 86=#5fffd7 143 + palette = 87=#5fffff 144 + palette = 88=#870000 145 + palette = 89=#87005f 146 + palette = 90=#870087 147 + palette = 91=#8700af 148 + palette = 92=#8700d7 149 + palette = 93=#8700ff 150 + palette = 94=#875f00 151 + palette = 95=#875f5f 152 + palette = 96=#875f87 153 + palette = 97=#875faf 154 + palette = 98=#875fd7 155 + palette = 99=#875fff 156 + palette = 100=#878700 157 + palette = 101=#87875f 158 + palette = 102=#878787 159 + palette = 103=#8787af 160 + palette = 104=#8787d7 161 + palette = 105=#8787ff 162 + palette = 106=#87af00 163 + palette = 107=#87af5f 164 + palette = 108=#87af87 165 + palette = 109=#87afaf 166 + palette = 110=#87afd7 167 + palette = 111=#87afff 168 + palette = 112=#87d700 169 + palette = 113=#87d75f 170 + palette = 114=#87d787 171 + palette = 115=#87d7af 172 + palette = 116=#87d7d7 173 + palette = 117=#87d7ff 174 + palette = 118=#87ff00 175 + palette = 119=#87ff5f 176 + palette = 120=#87ff87 177 + palette = 121=#87ffaf 178 + palette = 122=#87ffd7 179 + palette = 123=#87ffff 180 + palette = 124=#af0000 181 + palette = 125=#af005f 182 + palette = 126=#af0087 183 + palette = 127=#af00af 184 + palette = 128=#af00d7 185 + palette = 129=#af00ff 186 + palette = 130=#af5f00 187 + palette = 131=#af5f5f 188 + palette = 132=#af5f87 189 + palette = 133=#af5faf 190 + palette = 134=#af5fd7 191 + palette = 135=#af5fff 192 + palette = 136=#af8700 193 + palette = 137=#af875f 194 + palette = 138=#af8787 195 + palette = 139=#af87af 196 + palette = 140=#af87d7 197 + palette = 141=#af87ff 198 + palette = 142=#afaf00 199 + palette = 143=#afaf5f 200 + palette = 144=#afaf87 201 + palette = 145=#afafaf 202 + palette = 146=#afafd7 203 + palette = 147=#afafff 204 + palette = 148=#afd700 205 + palette = 149=#afd75f 206 + palette = 150=#afd787 207 + palette = 151=#afd7af 208 + palette = 152=#afd7d7 209 + palette = 153=#afd7ff 210 + palette = 154=#afff00 211 + palette = 155=#afff5f 212 + palette = 156=#afff87 213 + palette = 157=#afffaf 214 + palette = 158=#afffd7 215 + palette = 159=#afffff 216 + palette = 160=#d70000 217 + palette = 161=#d7005f 218 + palette = 162=#d70087 219 + palette = 163=#d700af 220 + palette = 164=#d700d7 221 + palette = 165=#d700ff 222 + palette = 166=#d75f00 223 + palette = 167=#d75f5f 224 + palette = 168=#d75f87 225 + palette = 169=#d75faf 226 + palette = 170=#d75fd7 227 + palette = 171=#d75fff 228 + palette = 172=#d78700 229 + palette = 173=#d7875f 230 + palette = 174=#d78787 231 + palette = 175=#d787af 232 + palette = 176=#d787d7 233 + palette = 177=#d787ff 234 + palette = 178=#d7af00 235 + palette = 179=#d7af5f 236 + palette = 180=#d7af87 237 + palette = 181=#d7afaf 238 + palette = 182=#d7afd7 239 + palette = 183=#d7afff 240 + palette = 184=#d7d700 241 + palette = 185=#d7d75f 242 + palette = 186=#d7d787 243 + palette = 187=#d7d7af 244 + palette = 188=#d7d7d7 245 + palette = 189=#d7d7ff 246 + palette = 190=#d7ff00 247 + palette = 191=#d7ff5f 248 + palette = 192=#d7ff87 249 + palette = 193=#d7ffaf 250 + palette = 194=#d7ffd7 251 + palette = 195=#d7ffff 252 + palette = 196=#ff0000 253 + palette = 197=#ff005f 254 + palette = 198=#ff0087 255 + palette = 199=#ff00af 256 + palette = 200=#ff00d7 257 + palette = 201=#ff00ff 258 + palette = 202=#ff5f00 259 + palette = 203=#ff5f5f 260 + palette = 204=#ff5f87 261 + palette = 205=#ff5faf 262 + palette = 206=#ff5fd7 263 + palette = 207=#ff5fff 264 + palette = 208=#ff8700 265 + palette = 209=#ff875f 266 + palette = 210=#ff8787 267 + palette = 211=#ff87af 268 + palette = 212=#ff87d7 269 + palette = 213=#ff87ff 270 + palette = 214=#ffaf00 271 + palette = 215=#ffaf5f 272 + palette = 216=#ffaf87 273 + palette = 217=#ffafaf 274 + palette = 218=#ffafd7 275 + palette = 219=#ffafff 276 + palette = 220=#ffd700 277 + palette = 221=#ffd75f 278 + palette = 222=#ffd787 279 + palette = 223=#ffd7af 280 + palette = 224=#ffd7d7 281 + palette = 225=#ffd7ff 282 + palette = 226=#ffff00 283 + palette = 227=#ffff5f 284 + palette = 228=#ffff87 285 + palette = 229=#ffffaf 286 + palette = 230=#ffffd7 287 + palette = 231=#ffffff 288 + palette = 232=#080808 289 + palette = 233=#121212 290 + palette = 234=#1c1c1c 291 + palette = 235=#262626 292 + palette = 236=#303030 293 + palette = 237=#3a3a3a 294 + palette = 238=#444444 295 + palette = 239=#4e4e4e 296 + palette = 240=#585858 297 + palette = 241=#626262 298 + palette = 242=#6c6c6c 299 + palette = 243=#767676 300 + palette = 244=#808080 301 + palette = 245=#8a8a8a 302 + palette = 246=#949494 303 + palette = 247=#9e9e9e 304 + palette = 248=#a8a8a8 305 + palette = 249=#b2b2b2 306 + palette = 250=#bcbcbc 307 + palette = 251=#c6c6c6 308 + palette = 252=#d0d0d0 309 + palette = 253=#dadada 310 + palette = 254=#e4e4e4 311 + palette = 255=#eeeeee
+310
ghostty/crt.glsl
··· 1 + // source: https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f 2 + // credits: https://github.com/qwerasd205 3 + //============================================================== 4 + // 5 + // [CRTS] PUBLIC DOMAIN CRT-STYLED SCALAR by Timothy Lottes 6 + // 7 + // [+] Adapted with alterations for use in Ghostty by Qwerasd. 8 + // For more information on changes, see comment below license. 9 + // 10 + //============================================================== 11 + // 12 + // LICENSE = UNLICENSE (aka PUBLIC DOMAIN) 13 + // 14 + //-------------------------------------------------------------- 15 + // This is free and unencumbered software released into the 16 + // public domain. 17 + //-------------------------------------------------------------- 18 + // Anyone is free to copy, modify, publish, use, compile, sell, 19 + // or distribute this software, either in source code form or as 20 + // a compiled binary, for any purpose, commercial or 21 + // non-commercial, and by any means. 22 + //-------------------------------------------------------------- 23 + // In jurisdictions that recognize copyright laws, the author or 24 + // authors of this software dedicate any and all copyright 25 + // interest in the software to the public domain. We make this 26 + // dedication for the benefit of the public at large and to the 27 + // detriment of our heirs and successors. We intend this 28 + // dedication to be an overt act of relinquishment in perpetuity 29 + // of all present and future rights to this software under 30 + // copyright law. 31 + //-------------------------------------------------------------- 32 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 33 + // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 34 + // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 + // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 36 + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 37 + // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 38 + // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 39 + // DEALINGS IN THE SOFTWARE. 40 + //-------------------------------------------------------------- 41 + // For more information, please refer to 42 + // <http://unlicense.org/> 43 + //============================================================== 44 + 45 + // This shader is a modified version of the excellent 46 + // FixingPixelArtFast by Timothy Lottes on Shadertoy. 47 + // 48 + // The original shader can be found at: 49 + // https://www.shadertoy.com/view/MtSfRK 50 + // 51 + // Modifications have been made to reduce the verbosity, 52 + // and many of the comments have been removed / reworded. 53 + // Additionally, the license has been moved to the top of 54 + // the file, and can be read above. I (Qwerasd) choose to 55 + // release the modified version under the same license. 56 + 57 + // The appearance of this shader can be altered 58 + // by adjusting the parameters defined below. 59 + 60 + // "Scanlines" per real screen pixel. 61 + // e.g. SCALE 0.5 means each scanline is 2 pixels. 62 + // Recommended values: 63 + // o High DPI displays: 0.33333333 64 + // - Low DPI displays: 0.66666666 65 + #define SCALE 0.33333333 66 + 67 + // "Tube" warp 68 + #define CRTS_WARP 1 69 + 70 + // Darkness of vignette in corners after warping 71 + // 0.0 = completely black 72 + // 1.0 = no vignetting 73 + #define MIN_VIN 0.5 74 + 75 + // Try different masks 76 + // #define CRTS_MASK_GRILLE 1 77 + // #define CRTS_MASK_GRILLE_LITE 1 78 + // #define CRTS_MASK_NONE 1 79 + #define CRTS_MASK_SHADOW 1 80 + 81 + // Scanline thinness 82 + // 0.50 = fused scanlines 83 + // 0.70 = recommended default 84 + // 1.00 = thinner scanlines (too thin) 85 + #define INPUT_THIN 0.75 86 + 87 + // Horizonal scan blur 88 + // -3.0 = pixely 89 + // -2.5 = default 90 + // -2.0 = smooth 91 + // -1.0 = too blurry 92 + #define INPUT_BLUR -2.75 93 + 94 + // Shadow mask effect, ranges from, 95 + // 0.25 = large amount of mask (not recommended, too dark) 96 + // 0.50 = recommended default 97 + // 1.00 = no shadow mask 98 + #define INPUT_MASK 0.65 99 + 100 + float FromSrgb1(float c) { 101 + return (c <= 0.04045) ? c * (1.0 / 12.92) : 102 + pow(c * (1.0 / 1.055) + (0.055 / 1.055), 2.4); 103 + } 104 + vec3 FromSrgb(vec3 c) { 105 + return vec3( 106 + FromSrgb1(c.r), FromSrgb1(c.g), FromSrgb1(c.b)); 107 + } 108 + 109 + vec3 CrtsFetch(vec2 uv) { 110 + return FromSrgb(texture(iChannel0, uv.xy).rgb); 111 + } 112 + 113 + #define CrtsRcpF1(x) (1.0/(x)) 114 + #define CrtsSatF1(x) clamp((x),0.0,1.0) 115 + 116 + float CrtsMax3F1(float a, float b, float c) { 117 + return max(a, max(b, c)); 118 + } 119 + 120 + vec2 CrtsTone( 121 + float thin, 122 + float mask) { 123 + #ifdef CRTS_MASK_NONE 124 + mask = 1.0; 125 + #endif 126 + 127 + #ifdef CRTS_MASK_GRILLE_LITE 128 + // Normal R mask is {1.0,mask,mask} 129 + // LITE R mask is {mask,1.0,1.0} 130 + mask = 0.5 + mask * 0.5; 131 + #endif 132 + 133 + vec2 ret; 134 + float midOut = 0.18 / ((1.5 - thin) * (0.5 * mask + 0.5)); 135 + float pMidIn = 0.18; 136 + ret.x = ((-pMidIn) + midOut) / ((1.0 - pMidIn) * midOut); 137 + ret.y = ((-pMidIn) * midOut + pMidIn) / (midOut * (-pMidIn) + midOut); 138 + 139 + return ret; 140 + } 141 + 142 + vec3 CrtsMask(vec2 pos, float dark) { 143 + #ifdef CRTS_MASK_GRILLE 144 + vec3 m = vec3(dark, dark, dark); 145 + float x = fract(pos.x * (1.0 / 3.0)); 146 + if (x < (1.0 / 3.0)) m.r = 1.0; 147 + else if (x < (2.0 / 3.0)) m.g = 1.0; 148 + else m.b = 1.0; 149 + return m; 150 + #endif 151 + 152 + #ifdef CRTS_MASK_GRILLE_LITE 153 + vec3 m = vec3(1.0, 1.0, 1.0); 154 + float x = fract(pos.x * (1.0 / 3.0)); 155 + if (x < (1.0 / 3.0)) m.r = dark; 156 + else if (x < (2.0 / 3.0)) m.g = dark; 157 + else m.b = dark; 158 + return m; 159 + #endif 160 + 161 + #ifdef CRTS_MASK_NONE 162 + return vec3(1.0, 1.0, 1.0); 163 + #endif 164 + 165 + #ifdef CRTS_MASK_SHADOW 166 + pos.x += pos.y * 3.0; 167 + vec3 m = vec3(dark, dark, dark); 168 + float x = fract(pos.x * (1.0 / 6.0)); 169 + if (x < (1.0 / 3.0)) m.r = 1.0; 170 + else if (x < (2.0 / 3.0)) m.g = 1.0; 171 + else m.b = 1.0; 172 + return m; 173 + #endif 174 + } 175 + 176 + vec3 CrtsFilter( 177 + vec2 ipos, 178 + vec2 inputSizeDivOutputSize, 179 + vec2 halfInputSize, 180 + vec2 rcpInputSize, 181 + vec2 rcpOutputSize, 182 + vec2 twoDivOutputSize, 183 + float inputHeight, 184 + vec2 warp, 185 + float thin, 186 + float blur, 187 + float mask, 188 + vec2 tone 189 + ) { 190 + // Optional apply warp 191 + vec2 pos; 192 + #ifdef CRTS_WARP 193 + // Convert to {-1 to 1} range 194 + pos = ipos * twoDivOutputSize - vec2(1.0, 1.0); 195 + 196 + // Distort pushes image outside {-1 to 1} range 197 + pos *= vec2( 198 + 1.0 + (pos.y * pos.y) * warp.x, 199 + 1.0 + (pos.x * pos.x) * warp.y); 200 + 201 + // TODO: Vignette needs optimization 202 + float vin = 1.0 - ( 203 + (1.0 - CrtsSatF1(pos.x * pos.x)) * (1.0 - CrtsSatF1(pos.y * pos.y))); 204 + vin = CrtsSatF1((-vin) * inputHeight + inputHeight); 205 + 206 + // Leave in {0 to inputSize} 207 + pos = pos * halfInputSize + halfInputSize; 208 + #else 209 + pos = ipos * inputSizeDivOutputSize; 210 + #endif 211 + 212 + // Snap to center of first scanline 213 + float y0 = floor(pos.y - 0.5) + 0.5; 214 + // Snap to center of one of four pixels 215 + float x0 = floor(pos.x - 1.5) + 0.5; 216 + 217 + // Inital UV position 218 + vec2 p = vec2(x0 * rcpInputSize.x, y0 * rcpInputSize.y); 219 + // Fetch 4 nearest texels from 2 nearest scanlines 220 + vec3 colA0 = CrtsFetch(p); 221 + p.x += rcpInputSize.x; 222 + vec3 colA1 = CrtsFetch(p); 223 + p.x += rcpInputSize.x; 224 + vec3 colA2 = CrtsFetch(p); 225 + p.x += rcpInputSize.x; 226 + vec3 colA3 = CrtsFetch(p); 227 + p.y += rcpInputSize.y; 228 + vec3 colB3 = CrtsFetch(p); 229 + p.x -= rcpInputSize.x; 230 + vec3 colB2 = CrtsFetch(p); 231 + p.x -= rcpInputSize.x; 232 + vec3 colB1 = CrtsFetch(p); 233 + p.x -= rcpInputSize.x; 234 + vec3 colB0 = CrtsFetch(p); 235 + 236 + // Vertical filter 237 + // Scanline intensity is using sine wave 238 + // Easy filter window and integral used later in exposure 239 + float off = pos.y - y0; 240 + float pi2 = 6.28318530717958; 241 + float hlf = 0.5; 242 + float scanA = cos(min(0.5, off * thin) * pi2) * hlf + hlf; 243 + float scanB = cos(min(0.5, (-off) * thin + thin) * pi2) * hlf + hlf; 244 + 245 + // Horizontal kernel is simple gaussian filter 246 + float off0 = pos.x - x0; 247 + float off1 = off0 - 1.0; 248 + float off2 = off0 - 2.0; 249 + float off3 = off0 - 3.0; 250 + float pix0 = exp2(blur * off0 * off0); 251 + float pix1 = exp2(blur * off1 * off1); 252 + float pix2 = exp2(blur * off2 * off2); 253 + float pix3 = exp2(blur * off3 * off3); 254 + float pixT = CrtsRcpF1(pix0 + pix1 + pix2 + pix3); 255 + 256 + #ifdef CRTS_WARP 257 + // Get rid of wrong pixels on edge 258 + pixT *= max(MIN_VIN, vin); 259 + #endif 260 + 261 + scanA *= pixT; 262 + scanB *= pixT; 263 + 264 + // Apply horizontal and vertical filters 265 + vec3 color = 266 + (colA0 * pix0 + colA1 * pix1 + colA2 * pix2 + colA3 * pix3) * scanA + 267 + (colB0 * pix0 + colB1 * pix1 + colB2 * pix2 + colB3 * pix3) * scanB; 268 + 269 + // Apply phosphor mask 270 + color *= CrtsMask(ipos, mask); 271 + 272 + // Tonal control, start by protecting from /0 273 + float peak = max(1.0 / (256.0 * 65536.0), 274 + CrtsMax3F1(color.r, color.g, color.b)); 275 + // Compute the ratios of {R,G,B} 276 + vec3 ratio = color * CrtsRcpF1(peak); 277 + // Apply tonal curve to peak value 278 + peak = peak * CrtsRcpF1(peak * tone.x + tone.y); 279 + // Reconstruct color 280 + return ratio * peak; 281 + } 282 + 283 + float ToSrgb1(float c) { 284 + return (c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 0.41666) - 0.055); 285 + } 286 + vec3 ToSrgb(vec3 c) { 287 + return vec3( 288 + ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b)); 289 + } 290 + 291 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 292 + float aspect = iResolution.x / iResolution.y; 293 + fragColor.rgb = CrtsFilter( 294 + fragCoord.xy, 295 + vec2(1.0), 296 + iResolution.xy * SCALE * 0.5, 297 + 1.0 / (iResolution.xy * SCALE), 298 + 1.0 / iResolution.xy, 299 + 2.0 / iResolution.xy, 300 + iResolution.y, 301 + vec2(1.0 / (50.0 * aspect), 1.0 / 50.0), 302 + INPUT_THIN, 303 + INPUT_BLUR, 304 + INPUT_MASK, 305 + CrtsTone(INPUT_THIN, INPUT_MASK) 306 + ); 307 + 308 + // Linear to SRGB for output. 309 + fragColor.rgb = ToSrgb(fragColor.rgb); 310 + }
+308
ghostty/crt2.glsl
··· 1 + //============================================================== 2 + // 3 + // [CRTS] PUBLIC DOMAIN CRT-STYLED SCALAR by Timothy Lottes 4 + // 5 + // [+] Adapted with alterations for use in Ghostty by Qwerasd. 6 + // For more information on changes, see comment below license. 7 + // 8 + //============================================================== 9 + // 10 + // LICENSE = UNLICENSE (aka PUBLIC DOMAIN) 11 + // 12 + //-------------------------------------------------------------- 13 + // This is free and unencumbered software released into the 14 + // public domain. 15 + //-------------------------------------------------------------- 16 + // Anyone is free to copy, modify, publish, use, compile, sell, 17 + // or distribute this software, either in source code form or as 18 + // a compiled binary, for any purpose, commercial or 19 + // non-commercial, and by any means. 20 + //-------------------------------------------------------------- 21 + // In jurisdictions that recognize copyright laws, the author or 22 + // authors of this software dedicate any and all copyright 23 + // interest in the software to the public domain. We make this 24 + // dedication for the benefit of the public at large and to the 25 + // detriment of our heirs and successors. We intend this 26 + // dedication to be an overt act of relinquishment in perpetuity 27 + // of all present and future rights to this software under 28 + // copyright law. 29 + //-------------------------------------------------------------- 30 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 31 + // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 32 + // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 33 + // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 34 + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 35 + // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 36 + // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 37 + // DEALINGS IN THE SOFTWARE. 38 + //-------------------------------------------------------------- 39 + // For more information, please refer to 40 + // <http://unlicense.org/> 41 + //============================================================== 42 + 43 + // This shader is a modified version of the excellent 44 + // FixingPixelArtFast by Timothy Lottes on Shadertoy. 45 + // 46 + // The original shader can be found at: 47 + // https://www.shadertoy.com/view/MtSfRK 48 + // 49 + // Modifications have been made to reduce the verbosity, 50 + // and many of the comments have been removed / reworded. 51 + // Additionally, the license has been moved to the top of 52 + // the file, and can be read above. I (Qwerasd) choose to 53 + // release the modified version under the same license. 54 + 55 + // The appearance of this shader can be altered 56 + // by adjusting the parameters defined below. 57 + 58 + // "Scanlines" per real screen pixel. 59 + // e.g. SCALE 0.5 means each scanline is 2 pixels. 60 + // Recommended values: 61 + // o High DPI displays: 0.33333333 62 + // - Low DPI displays: 0.66666666 63 + #define SCALE 0.33333333 64 + 65 + // "Tube" warp 66 + #define CRTS_WARP 1 67 + 68 + // Darkness of vignette in corners after warping 69 + // 0.0 = completely black 70 + // 1.0 = no vignetting 71 + #define MIN_VIN 0.5 72 + 73 + // Try different masks 74 + // #define CRTS_MASK_GRILLE 1 75 + // #define CRTS_MASK_GRILLE_LITE 1 76 + // #define CRTS_MASK_NONE 1 77 + #define CRTS_MASK_SHADOW 1 78 + 79 + // Scanline thinness 80 + // 0.50 = fused scanlines 81 + // 0.70 = recommended default 82 + // 1.00 = thinner scanlines (too thin) 83 + #define INPUT_THIN 0.75 84 + 85 + // Horizonal scan blur 86 + // -3.0 = pixely 87 + // -2.5 = default 88 + // -2.0 = smooth 89 + // -1.0 = too blurry 90 + #define INPUT_BLUR -2.75 91 + 92 + // Shadow mask effect, ranges from, 93 + // 0.25 = large amount of mask (not recommended, too dark) 94 + // 0.50 = recommended default 95 + // 1.00 = no shadow mask 96 + #define INPUT_MASK 0.65 97 + 98 + float FromSrgb1(float c) { 99 + return (c <= 0.04045) ? c * (1.0 / 12.92) : 100 + pow(c * (1.0 / 1.055) + (0.055 / 1.055), 2.4); 101 + } 102 + vec3 FromSrgb(vec3 c) { 103 + return vec3( 104 + FromSrgb1(c.r), FromSrgb1(c.g), FromSrgb1(c.b)); 105 + } 106 + 107 + vec3 CrtsFetch(vec2 uv) { 108 + return FromSrgb(texture(iChannel0, uv.xy).rgb); 109 + } 110 + 111 + #define CrtsRcpF1(x) (1.0/(x)) 112 + #define CrtsSatF1(x) clamp((x),0.0,1.0) 113 + 114 + float CrtsMax3F1(float a, float b, float c) { 115 + return max(a, max(b, c)); 116 + } 117 + 118 + vec2 CrtsTone( 119 + float thin, 120 + float mask) { 121 + #ifdef CRTS_MASK_NONE 122 + mask = 1.0; 123 + #endif 124 + 125 + #ifdef CRTS_MASK_GRILLE_LITE 126 + // Normal R mask is {1.0,mask,mask} 127 + // LITE R mask is {mask,1.0,1.0} 128 + mask = 0.5 + mask * 0.5; 129 + #endif 130 + 131 + vec2 ret; 132 + float midOut = 0.18 / ((1.5 - thin) * (0.5 * mask + 0.5)); 133 + float pMidIn = 0.18; 134 + ret.x = ((-pMidIn) + midOut) / ((1.0 - pMidIn) * midOut); 135 + ret.y = ((-pMidIn) * midOut + pMidIn) / (midOut * (-pMidIn) + midOut); 136 + 137 + return ret; 138 + } 139 + 140 + vec3 CrtsMask(vec2 pos, float dark) { 141 + #ifdef CRTS_MASK_GRILLE 142 + vec3 m = vec3(dark, dark, dark); 143 + float x = fract(pos.x * (1.0 / 3.0)); 144 + if (x < (1.0 / 3.0)) m.r = 1.0; 145 + else if (x < (2.0 / 3.0)) m.g = 1.0; 146 + else m.b = 1.0; 147 + return m; 148 + #endif 149 + 150 + #ifdef CRTS_MASK_GRILLE_LITE 151 + vec3 m = vec3(1.0, 1.0, 1.0); 152 + float x = fract(pos.x * (1.0 / 3.0)); 153 + if (x < (1.0 / 3.0)) m.r = dark; 154 + else if (x < (2.0 / 3.0)) m.g = dark; 155 + else m.b = dark; 156 + return m; 157 + #endif 158 + 159 + #ifdef CRTS_MASK_NONE 160 + return vec3(1.0, 1.0, 1.0); 161 + #endif 162 + 163 + #ifdef CRTS_MASK_SHADOW 164 + pos.x += pos.y * 3.0; 165 + vec3 m = vec3(dark, dark, dark); 166 + float x = fract(pos.x * (1.0 / 6.0)); 167 + if (x < (1.0 / 3.0)) m.r = 1.0; 168 + else if (x < (2.0 / 3.0)) m.g = 1.0; 169 + else m.b = 1.0; 170 + return m; 171 + #endif 172 + } 173 + 174 + vec3 CrtsFilter( 175 + vec2 ipos, 176 + vec2 inputSizeDivOutputSize, 177 + vec2 halfInputSize, 178 + vec2 rcpInputSize, 179 + vec2 rcpOutputSize, 180 + vec2 twoDivOutputSize, 181 + float inputHeight, 182 + vec2 warp, 183 + float thin, 184 + float blur, 185 + float mask, 186 + vec2 tone 187 + ) { 188 + // Optional apply warp 189 + vec2 pos; 190 + #ifdef CRTS_WARP 191 + // Convert to {-1 to 1} range 192 + pos = ipos * twoDivOutputSize - vec2(1.0, 1.0); 193 + 194 + // Distort pushes image outside {-1 to 1} range 195 + pos *= vec2( 196 + 1.0 + (pos.y * pos.y) * warp.x, 197 + 1.0 + (pos.x * pos.x) * warp.y); 198 + 199 + // TODO: Vignette needs optimization 200 + float vin = 1.0 - ( 201 + (1.0 - CrtsSatF1(pos.x * pos.x)) * (1.0 - CrtsSatF1(pos.y * pos.y))); 202 + vin = CrtsSatF1((-vin) * inputHeight + inputHeight); 203 + 204 + // Leave in {0 to inputSize} 205 + pos = pos * halfInputSize + halfInputSize; 206 + #else 207 + pos = ipos * inputSizeDivOutputSize; 208 + #endif 209 + 210 + // Snap to center of first scanline 211 + float y0 = floor(pos.y - 0.5) + 0.5; 212 + // Snap to center of one of four pixels 213 + float x0 = floor(pos.x - 1.5) + 0.5; 214 + 215 + // Inital UV position 216 + vec2 p = vec2(x0 * rcpInputSize.x, y0 * rcpInputSize.y); 217 + // Fetch 4 nearest texels from 2 nearest scanlines 218 + vec3 colA0 = CrtsFetch(p); 219 + p.x += rcpInputSize.x; 220 + vec3 colA1 = CrtsFetch(p); 221 + p.x += rcpInputSize.x; 222 + vec3 colA2 = CrtsFetch(p); 223 + p.x += rcpInputSize.x; 224 + vec3 colA3 = CrtsFetch(p); 225 + p.y += rcpInputSize.y; 226 + vec3 colB3 = CrtsFetch(p); 227 + p.x -= rcpInputSize.x; 228 + vec3 colB2 = CrtsFetch(p); 229 + p.x -= rcpInputSize.x; 230 + vec3 colB1 = CrtsFetch(p); 231 + p.x -= rcpInputSize.x; 232 + vec3 colB0 = CrtsFetch(p); 233 + 234 + // Vertical filter 235 + // Scanline intensity is using sine wave 236 + // Easy filter window and integral used later in exposure 237 + float off = pos.y - y0; 238 + float pi2 = 6.28318530717958; 239 + float hlf = 0.5; 240 + float scanA = cos(min(0.5, off * thin) * pi2) * hlf + hlf; 241 + float scanB = cos(min(0.5, (-off) * thin + thin) * pi2) * hlf + hlf; 242 + 243 + // Horizontal kernel is simple gaussian filter 244 + float off0 = pos.x - x0; 245 + float off1 = off0 - 1.0; 246 + float off2 = off0 - 2.0; 247 + float off3 = off0 - 3.0; 248 + float pix0 = exp2(blur * off0 * off0); 249 + float pix1 = exp2(blur * off1 * off1); 250 + float pix2 = exp2(blur * off2 * off2); 251 + float pix3 = exp2(blur * off3 * off3); 252 + float pixT = CrtsRcpF1(pix0 + pix1 + pix2 + pix3); 253 + 254 + #ifdef CRTS_WARP 255 + // Get rid of wrong pixels on edge 256 + pixT *= max(MIN_VIN, vin); 257 + #endif 258 + 259 + scanA *= pixT; 260 + scanB *= pixT; 261 + 262 + // Apply horizontal and vertical filters 263 + vec3 color = 264 + (colA0 * pix0 + colA1 * pix1 + colA2 * pix2 + colA3 * pix3) * scanA + 265 + (colB0 * pix0 + colB1 * pix1 + colB2 * pix2 + colB3 * pix3) * scanB; 266 + 267 + // Apply phosphor mask 268 + color *= CrtsMask(ipos, mask); 269 + 270 + // Tonal control, start by protecting from /0 271 + float peak = max(1.0 / (256.0 * 65536.0), 272 + CrtsMax3F1(color.r, color.g, color.b)); 273 + // Compute the ratios of {R,G,B} 274 + vec3 ratio = color * CrtsRcpF1(peak); 275 + // Apply tonal curve to peak value 276 + peak = peak * CrtsRcpF1(peak * tone.x + tone.y); 277 + // Reconstruct color 278 + return ratio * peak; 279 + } 280 + 281 + float ToSrgb1(float c) { 282 + return (c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 0.41666) - 0.055); 283 + } 284 + vec3 ToSrgb(vec3 c) { 285 + return vec3( 286 + ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b)); 287 + } 288 + 289 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 290 + float aspect = iResolution.x / iResolution.y; 291 + fragColor.rgb = CrtsFilter( 292 + fragCoord.xy, 293 + vec2(1.0), 294 + iResolution.xy * SCALE * 0.5, 295 + 1.0 / (iResolution.xy * SCALE), 296 + 1.0 / iResolution.xy, 297 + 2.0 / iResolution.xy, 298 + iResolution.y, 299 + vec2(1.0 / (50.0 * aspect), 1.0 / 50.0), 300 + INPUT_THIN, 301 + INPUT_BLUR, 302 + INPUT_MASK, 303 + CrtsTone(INPUT_THIN, INPUT_MASK) 304 + ); 305 + 306 + // Linear to SRGB for output. 307 + fragColor.rgb = ToSrgb(fragColor.rgb); 308 + }
+117
ghostty/glitchy.glsl
··· 1 + // modified version of https://www.shadertoy.com/view/wld3WN 2 + // amount of seconds for which the glitch loop occurs 3 + #define DURATION 10. 4 + // percentage of the duration for which the glitch is triggered 5 + #define AMT .1 6 + 7 + #define SS(a, b, x) (smoothstep(a, b, x) * smoothstep(b, a, x)) 8 + 9 + #define UI0 1597334673U 10 + #define UI1 3812015801U 11 + #define UI2 uvec2(UI0, UI1) 12 + #define UI3 uvec3(UI0, UI1, 2798796415U) 13 + #define UIF (1. / float(0xffffffffU)) 14 + 15 + // Hash by David_Hoskins 16 + vec3 hash33(vec3 p) 17 + { 18 + uvec3 q = uvec3(ivec3(p)) * UI3; 19 + q = (q.x ^ q.y ^ q.z)*UI3; 20 + return -1. + 2. * vec3(q) * UIF; 21 + } 22 + 23 + // Gradient noise by iq 24 + float gnoise(vec3 x) 25 + { 26 + // grid 27 + vec3 p = floor(x); 28 + vec3 w = fract(x); 29 + 30 + // quintic interpolant 31 + vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.); 32 + 33 + // gradients 34 + vec3 ga = hash33(p + vec3(0., 0., 0.)); 35 + vec3 gb = hash33(p + vec3(1., 0., 0.)); 36 + vec3 gc = hash33(p + vec3(0., 1., 0.)); 37 + vec3 gd = hash33(p + vec3(1., 1., 0.)); 38 + vec3 ge = hash33(p + vec3(0., 0., 1.)); 39 + vec3 gf = hash33(p + vec3(1., 0., 1.)); 40 + vec3 gg = hash33(p + vec3(0., 1., 1.)); 41 + vec3 gh = hash33(p + vec3(1., 1., 1.)); 42 + 43 + // projections 44 + float va = dot(ga, w - vec3(0., 0., 0.)); 45 + float vb = dot(gb, w - vec3(1., 0., 0.)); 46 + float vc = dot(gc, w - vec3(0., 1., 0.)); 47 + float vd = dot(gd, w - vec3(1., 1., 0.)); 48 + float ve = dot(ge, w - vec3(0., 0., 1.)); 49 + float vf = dot(gf, w - vec3(1., 0., 1.)); 50 + float vg = dot(gg, w - vec3(0., 1., 1.)); 51 + float vh = dot(gh, w - vec3(1., 1., 1.)); 52 + 53 + // interpolation 54 + float gNoise = va + u.x * (vb - va) + 55 + u.y * (vc - va) + 56 + u.z * (ve - va) + 57 + u.x * u.y * (va - vb - vc + vd) + 58 + u.y * u.z * (va - vc - ve + vg) + 59 + u.z * u.x * (va - vb - ve + vf) + 60 + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh); 61 + 62 + return 2. * gNoise; 63 + } 64 + 65 + // gradient noise in range [0, 1] 66 + float gnoise01(vec3 x) 67 + { 68 + return .5 + .5 * gnoise(x); 69 + } 70 + 71 + // warp uvs for the crt effect 72 + vec2 crt(vec2 uv) 73 + { 74 + float tht = atan(uv.y, uv.x); 75 + float r = length(uv); 76 + // curve without distorting the center 77 + r /= (1. - .1 * r * r); 78 + uv.x = r * cos(tht); 79 + uv.y = r * sin(tht); 80 + return .5 * (uv + 1.); 81 + } 82 + 83 + 84 + void mainImage( out vec4 fragColor, in vec2 fragCoord ) 85 + { 86 + vec2 uv = fragCoord / iResolution.xy; 87 + float t = iTime; 88 + 89 + // smoothed interval for which the glitch gets triggered 90 + float glitchAmount = SS(DURATION * .001, DURATION * AMT, mod(t, DURATION)); 91 + float displayNoise = 0.; 92 + vec3 col = vec3(0.); 93 + vec2 eps = vec2(5. / iResolution.x, 0.); 94 + vec2 st = vec2(0.); 95 + 96 + // analog distortion 97 + float y = uv.y * iResolution.y; 98 + float distortion = gnoise(vec3(0., y * .01, t * 500.)) * (glitchAmount * 4. + .1); 99 + distortion *= gnoise(vec3(0., y * .02, t * 250.)) * (glitchAmount * 2. + .025); 100 + 101 + ++displayNoise; 102 + distortion += smoothstep(.999, 1., sin((uv.y + t * 1.6) * 2.)) * .02; 103 + distortion -= smoothstep(.999, 1., sin((uv.y + t) * 2.)) * .02; 104 + st = uv + vec2(distortion, 0.); 105 + // chromatic aberration 106 + col.r += textureLod(iChannel0, st + eps + distortion, 0.).r; 107 + col.g += textureLod(iChannel0, st, 0.).g; 108 + col.b += textureLod(iChannel0, st - eps - distortion, 0.).b; 109 + 110 + // white noise + scanlines 111 + displayNoise = 0.2 * clamp(displayNoise, 0., 1.); 112 + col += (.15 + .65 * glitchAmount) * (hash33(vec3(fragCoord, mod(float(iFrame), 113 + 1000.))).r) * displayNoise; 114 + col -= (.25 + .75 * glitchAmount) * (sin(4. * t + uv.y * iResolution.y * 1.75)) 115 + * displayNoise; 116 + fragColor = vec4(col, 1.0); 117 + }
+144
ghostty/glow-rgbsplit-twitchy.glsl
··· 1 + // First it does a "chromatic aberration" by splitting the rgb signals by a product of sin functions 2 + // over time, then it does a glow effect in a perceptual color space 3 + // Based on kalgynirae's Ghostty passable glow shader and NickWest's Chromatic Aberration shader demo 4 + // Passable glow: https://github.com/kalgynirae/dotfiles/blob/main/ghostty/glow.glsl 5 + // "Chromatic Aberration": https://www.shadertoy.com/view/Mds3zn 6 + 7 + // sRGB linear -> nonlinear transform from https://bottosson.github.io/posts/colorwrong/ 8 + float f(float x) { 9 + if (x >= 0.0031308) { 10 + return 1.055 * pow(x, 1.0 / 2.4) - 0.055; 11 + } else { 12 + return 12.92 * x; 13 + } 14 + } 15 + 16 + float f_inv(float x) { 17 + if (x >= 0.04045) { 18 + return pow((x + 0.055) / 1.055, 2.4); 19 + } else { 20 + return x / 12.92; 21 + } 22 + } 23 + 24 + // Oklab <-> linear sRGB conversions from https://bottosson.github.io/posts/oklab/ 25 + vec4 toOklab(vec4 rgb) { 26 + vec3 c = vec3(f_inv(rgb.r), f_inv(rgb.g), f_inv(rgb.b)); 27 + float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b; 28 + float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b; 29 + float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b; 30 + float l_ = pow(l, 1.0 / 3.0); 31 + float m_ = pow(m, 1.0 / 3.0); 32 + float s_ = pow(s, 1.0 / 3.0); 33 + return vec4( 34 + 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, 35 + 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, 36 + 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, 37 + rgb.a 38 + ); 39 + } 40 + 41 + vec4 toRgb(vec4 oklab) { 42 + vec3 c = oklab.rgb; 43 + float l_ = c.r + 0.3963377774 * c.g + 0.2158037573 * c.b; 44 + float m_ = c.r - 0.1055613458 * c.g - 0.0638541728 * c.b; 45 + float s_ = c.r - 0.0894841775 * c.g - 1.2914855480 * c.b; 46 + float l = l_ * l_ * l_; 47 + float m = m_ * m_ * m_; 48 + float s = s_ * s_ * s_; 49 + vec3 linear_srgb = vec3( 50 + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, 51 + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, 52 + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s 53 + ); 54 + return vec4( 55 + clamp(f(linear_srgb.r), 0.0, 1.0), 56 + clamp(f(linear_srgb.g), 0.0, 1.0), 57 + clamp(f(linear_srgb.b), 0.0, 1.0), 58 + oklab.a 59 + ); 60 + } 61 + 62 + // Bloom samples from https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f 63 + const vec3[24] samples = { 64 + vec3(0.1693761725038636, 0.9855514761735895, 1), 65 + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), 66 + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), 67 + vec3(1.554155680728463, -1.2588090085709776, 0.5), 68 + vec3(1.681364377589461, 1.4741145918052656, 0.4472135954999579), 69 + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), 70 + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), 71 + vec3(0.5874641440200847, -2.7667464429345077, 0.35355339059327373), 72 + vec3(2.997715703369726, 0.11704939884745152, 0.3333333333333333), 73 + vec3(0.41360842451688395, 3.1351121305574803, 0.31622776601683794), 74 + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), 75 + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), 76 + vec3(2.888202648340422, -2.1583061557896213, 0.2773500981126146), 77 + vec3(2.7150778983300325, 2.5745586041105715, 0.2672612419124244), 78 + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), 79 + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), 80 + vec3(1.0130775986052671, -3.9967078676335834, 0.24253562503633297), 81 + vec3(4.229723673607257, 0.33081361055181563, 0.23570226039551587), 82 + vec3(0.40107790291173834, 4.340407413572593, 0.22941573387056174), 83 + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), 84 + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), 85 + vec3(3.8639122286635708, -2.6589814382925123, 0.21320071635561041), 86 + vec3(3.3486228404946234, 3.4331800232609, 0.20851441405707477), 87 + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) 88 + }; 89 + 90 + float offsetFunction(float iTime) { 91 + float amount = 1.0; 92 + const float periods[4] = {6.0, 16.0, 19.0, 27.0}; 93 + for (int i = 0; i < 4; i++) { 94 + amount *= 1.0 + 0.5 * sin(iTime*periods[i]); 95 + } 96 + //return amount; 97 + return amount * periods[3]; 98 + } 99 + 100 + const float DIM_CUTOFF = 0.35; 101 + const float BRIGHT_CUTOFF = 0.65; 102 + const float ABBERATION_FACTOR = 0.05; 103 + 104 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 105 + vec2 uv = fragCoord.xy / iResolution.xy; 106 + 107 + float amount = offsetFunction(iTime); 108 + 109 + vec3 col; 110 + col.r = texture( iChannel0, vec2(uv.x-ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).r; 111 + col.g = texture( iChannel0, uv ).g; 112 + col.b = texture( iChannel0, vec2(uv.x+ABBERATION_FACTOR*amount / iResolution.x, uv.y) ).b; 113 + 114 + vec4 splittedColor = vec4(col, 1.0); 115 + vec4 source = toOklab(splittedColor); 116 + vec4 dest = source; 117 + 118 + if (source.x > DIM_CUTOFF) { 119 + dest.x *= 1.2; 120 + // dest.x = 1.2; 121 + } else { 122 + vec2 step = vec2(1.414) / iResolution.xy; 123 + vec3 glow = vec3(0.0); 124 + for (int i = 0; i < 24; i++) { 125 + vec3 s = samples[i]; 126 + float weight = s.z; 127 + vec4 c = toOklab(texture(iChannel0, uv + s.xy * step)); 128 + if (c.x > DIM_CUTOFF) { 129 + glow.yz += c.yz * weight * 0.3; 130 + if (c.x <= BRIGHT_CUTOFF) { 131 + glow.x += c.x * weight * 0.05; 132 + } else { 133 + glow.x += c.x * weight * 0.10; 134 + } 135 + } 136 + } 137 + // float lightness_diff = clamp(glow.x - dest.x, 0.0, 1.0); 138 + // dest.x = lightness_diff; 139 + // dest.yz = dest.yz * (1.0 - lightness_diff) + glow.yz * lightness_diff; 140 + dest.xyz += glow.xyz; 141 + } 142 + 143 + fragColor = toRgb(dest); 144 + }
+304
ghostty/in-game-crt.glsl
··· 1 + // In-game CRT shader 2 + // Author: sarphiv 3 + // License: CC BY-NC-SA 4.0 4 + // Description: 5 + // Shader for ghostty that is focussed on being usable while looking like a stylized CRT terminal in a modern video game. 6 + // I know a tiny bit about shaders, and nothing about GLSL, 7 + // so this is a Frakenstein's monster combination of other shaders together with a lot of surgery. 8 + // On the bright side, i've cleaned up the body parts and surgery a lot. 9 + 10 + // Based on: 11 + // 1. https://gist.github.com/mitchellh/39d62186910dcc27cad097fed16eb882 (forces the choice of license) 12 + // 2. https://gist.github.com/qwerasd205/c3da6c610c8ffe17d6d2d3cc7068f17f 13 + // 3. https://gist.github.com/seanwcom/0fbe6b270aaa5f28823e053d3dbb14ca 14 + 15 + 16 + // Settings: 17 + // How straight the terminal is in each axis 18 + // (x, y) \in R^2 : x, y > 0 19 + #define CURVE 13.0, 11.0 20 + 21 + // How far apart the different colors are from each other 22 + // x \in R 23 + #define COLOR_FRINGING_SPREAD 1.0 24 + 25 + // How much the ghost images are spread out 26 + // x \in R : x >= 0 27 + #define GHOSTING_SPREAD 0.75 28 + // How visible ghost images are 29 + // x \in R : x >= 0 30 + #define GHOSTING_STRENGTH 1.0 31 + 32 + // How much of the non-linearly darkened colors are mixed in 33 + // [0, 1] 34 + #define DARKEN_MIX 0.4 35 + 36 + // How far in the vignette spreads 37 + // x \in R : x >= 0 38 + #define VIGNETTE_SPREAD 0.3 39 + // How bright the vignette is 40 + // x \in R : x >= 0 41 + #define VIGNETTE_BRIGHTNESS 6.4 42 + 43 + // Tint all colors 44 + // [0, 1]^3 45 + #define TINT 0.93, 1.00, 0.96 46 + 47 + // How visible the scan line effect is 48 + // NOTE: Technically these are not scan lines, but rather the lack of them 49 + // [0, 1] 50 + #define SCAN_LINES_STRENGTH 0.15 51 + // How bright the spaces between the lines are 52 + // [0, 1] 53 + #define SCAN_LINES_VARIANCE 0.35 54 + // Pixels per scan line effect 55 + // x \in R : x > 0 56 + #define SCAN_LINES_PERIOD 4.0 57 + 58 + // How visible the aperture grille is 59 + // x \in R : x >= 0 60 + #define APERTURE_GRILLE_STRENGTH 0.2 61 + // Pixels per aperture grille 62 + // x \in R : x > 0 63 + #define APERTURE_GRILLE_PERIOD 2.0 64 + 65 + // How much the screen flickers 66 + // x \in R : x >= 0 67 + #define FLICKER_STRENGTH 0.05 68 + // How fast the screen flickers 69 + // x \in R : x > 0 70 + #define FLICKER_FREQUENCY 15.0 71 + 72 + // How much noise is added to filled areas 73 + // [0, 1] 74 + #define NOISE_CONTENT_STRENGTH 0.15 75 + // How much noise is added everywhere 76 + // [0, 1] 77 + #define NOISE_UNIFORM_STRENGTH 0.03 78 + 79 + // How big the bloom is 80 + // x \in R : x >= 0 81 + #define BLOOM_SPREAD 8.0 82 + // How visible the bloom is 83 + // [0, 1] 84 + #define BLOOM_STRENGTH 0.04 85 + 86 + // How fast colors fade in and out 87 + // [0, 1] 88 + #define FADE_FACTOR 0.55 89 + 90 + 91 + 92 + // Disabled values for when the settings are not defined 93 + #ifndef COLOR_FRINGING_SPREAD 94 + #define COLOR_FRINGING_SPREAD 0.0 95 + #endif 96 + 97 + #if !defined(GHOSTING_SPREAD) || !defined(GHOSTING_STRENGTH) 98 + #undef GHOSTING_SPREAD 99 + #undef GHOSTING_STRENGTH 100 + #define GHOSTING_SPREAD 0.0 101 + #define GHOSTING_STRENGTH 0.0 102 + #endif 103 + 104 + #ifndef DARKEN_MIX 105 + #define DARKEN_MIX 0.0 106 + #endif 107 + 108 + #if !defined(VIGNETTE_SPREAD) || !defined(VIGNETTE_BRIGHTNESS) 109 + #undef VIGNETTE_SPREAD 110 + #undef VIGNETTE_BRIGHTNESS 111 + #define VIGNETTE_SPREAD 0.0 112 + #define VIGNETTE_BRIGHTNESS 1.0 113 + #endif 114 + 115 + #ifndef TINT 116 + #define TINT 1.00, 1.00, 1.00 117 + #endif 118 + 119 + #if !defined(SCAN_LINES_STRENGTH) || !defined(SCAN_LINES_VARIANCE) || !defined(SCAN_LINES_PERIOD) 120 + #undef SCAN_LINES_STRENGTH 121 + #undef SCAN_LINES_VARIANCE 122 + #undef SCAN_LINES_PERIOD 123 + #define SCAN_LINES_STRENGTH 0.0 124 + #define SCAN_LINES_VARIANCE 1.0 125 + #define SCAN_LINES_PERIOD 1.0 126 + #endif 127 + 128 + #if !defined(APERTURE_GRILLE_STRENGTH) || !defined(APERTURE_GRILLE_PERIOD) 129 + #undef APERTURE_GRILLE_STRENGTH 130 + #undef APERTURE_GRILLE_PERIOD 131 + #define APERTURE_GRILLE_STRENGTH 0.0 132 + #define APERTURE_GRILLE_PERIOD 1.0 133 + #endif 134 + 135 + #if !defined(FLICKER_STRENGTH) || !defined(FLICKER_FREQUENCY) 136 + #undef FLICKER_STRENGTH 137 + #undef FLICKER_FREQUENCY 138 + #define FLICKER_STRENGTH 0.0 139 + #define FLICKER_FREQUENCY 1.0 140 + #endif 141 + 142 + #if !defined(NOISE_CONTENT_STRENGTH) || !defined(NOISE_UNIFORM_STRENGTH) 143 + #undef NOISE_CONTENT_STRENGTH 144 + #undef NOISE_UNIFORM_STRENGTH 145 + #define NOISE_CONTENT_STRENGTH 0.0 146 + #define NOISE_UNIFORM_STRENGTH 0.0 147 + #endif 148 + 149 + #if !defined(BLOOM_SPREAD) || !defined(BLOOM_STRENGTH) 150 + #undef BLOOM_SPREAD 151 + #undef BLOOM_STRENGTH 152 + #define BLOOM_SPREAD 0.0 153 + #define BLOOM_STRENGTH 0.0 154 + #endif 155 + 156 + #ifndef FADE_FACTOR 157 + #define FADE_FACTOR 1.00 158 + #endif 159 + 160 + 161 + 162 + // Constants 163 + #define PI 3.1415926535897932384626433832795 164 + 165 + #ifdef BLOOM_SPREAD 166 + // Golden spiral samples used for bloom. 167 + // [x, y, weight] weight is inverse of distance. 168 + const vec3[24] bloom_samples = { 169 + vec3( 0.1693761725038636, 0.9855514761735895, 1), 170 + vec3(-1.333070830962943, 0.4721463328627773, 0.7071067811865475), 171 + vec3(-0.8464394909806497, -1.51113870578065, 0.5773502691896258), 172 + vec3( 1.554155680728463, -1.2588090085709776, 0.5), 173 + vec3( 1.681364377589461, 1.4741145918052656, 0.4472135954999579), 174 + vec3(-1.2795157692199817, 2.088741103228784, 0.4082482904638631), 175 + vec3(-2.4575847530631187, -0.9799373355024756, 0.3779644730092272), 176 + vec3( 0.5874641440200847, -2.7667464429345077, 0.35355339059327373), 177 + vec3( 2.997715703369726, 0.11704939884745152, 0.3333333333333333), 178 + vec3( 0.41360842451688395, 3.1351121305574803, 0.31622776601683794), 179 + vec3(-3.167149933769243, 0.9844599011770256, 0.30151134457776363), 180 + vec3(-1.5736713846521535, -3.0860263079123245, 0.2886751345948129), 181 + vec3( 2.888202648340422, -2.1583061557896213, 0.2773500981126146), 182 + vec3( 2.7150778983300325, 2.5745586041105715, 0.2672612419124244), 183 + vec3(-2.1504069972377464, 3.2211410627650165, 0.2581988897471611), 184 + vec3(-3.6548858794907493, -1.6253643308191343, 0.25), 185 + vec3( 1.0130775986052671, -3.9967078676335834, 0.24253562503633297), 186 + vec3( 4.229723673607257, 0.33081361055181563, 0.23570226039551587), 187 + vec3( 0.40107790291173834, 4.340407413572593, 0.22941573387056174), 188 + vec3(-4.319124570236028, 1.159811599693438, 0.22360679774997896), 189 + vec3(-1.9209044802827355, -4.160543952132907, 0.2182178902359924), 190 + vec3( 3.8639122286635708, -2.6589814382925123, 0.21320071635561041), 191 + vec3( 3.3486228404946234, 3.4331800232609, 0.20851441405707477), 192 + vec3(-2.8769733643574344, 3.9652268864187157, 0.20412414523193154) 193 + }; 194 + #endif 195 + 196 + 197 + 198 + 199 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 200 + // Get texture coordinates 201 + vec2 uv = fragCoord.xy / iResolution.xy; 202 + 203 + #ifdef CURVE 204 + // Curve texture coordinates to mimic non-flat CRT monior 205 + uv = (uv - 0.5) * 2.0; 206 + uv.xy *= 1.0 + pow((abs(vec2(uv.y, uv.x)) / vec2(CURVE)), vec2(2.0)); 207 + uv = (uv / 2.0) + 0.5; 208 + #endif 209 + 210 + 211 + // Retrieve colors from appropriate locations 212 + fragColor.r = texture(iChannel0, vec2(uv.x + 0.0003 * COLOR_FRINGING_SPREAD, uv.y + 0.0003 * COLOR_FRINGING_SPREAD)).x; 213 + fragColor.g = texture(iChannel0, vec2(uv.x + 0.0000 * COLOR_FRINGING_SPREAD, uv.y - 0.0006 * COLOR_FRINGING_SPREAD)).y; 214 + fragColor.b = texture(iChannel0, vec2(uv.x - 0.0006 * COLOR_FRINGING_SPREAD, uv.y + 0.0000 * COLOR_FRINGING_SPREAD)).z; 215 + fragColor.a = texture(iChannel0, uv).a; 216 + 217 + 218 + // Add faint ghost images 219 + fragColor.r += 0.04 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(+0.025, -0.027) + uv.xy).x; 220 + fragColor.g += 0.02 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(-0.022, -0.020) + uv.xy).y; 221 + fragColor.b += 0.04 * GHOSTING_STRENGTH * texture(iChannel0, GHOSTING_SPREAD * vec2(-0.020, -0.018) + uv.xy).z; 222 + 223 + 224 + // Quadratically darken everything 225 + fragColor.rgb = mix(fragColor.rgb, fragColor.rgb*fragColor.rgb, DARKEN_MIX); 226 + 227 + 228 + // Vignette effect 229 + fragColor.rgb *= VIGNETTE_BRIGHTNESS * pow(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y), VIGNETTE_SPREAD); 230 + 231 + 232 + // Tint all colors 233 + fragColor.rgb *= vec3(TINT); 234 + 235 + 236 + // NOTE: At this point, RGB values may be above 1 237 + 238 + 239 + // Add scan lines effect 240 + fragColor.rgb *= mix( 241 + 1.0, 242 + SCAN_LINES_VARIANCE/2.0*(1.0 + sin(2*PI* uv.y * iResolution.y/SCAN_LINES_PERIOD)), 243 + SCAN_LINES_STRENGTH 244 + ); 245 + 246 + 247 + // Add aperture grille 248 + int aperture_grille_step = int(8 * mod(fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD); 249 + float aperture_grille_mask; 250 + 251 + if (aperture_grille_step < 3) 252 + aperture_grille_mask = 0.0; 253 + else if (aperture_grille_step < 4) 254 + aperture_grille_mask = mod(8*fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD; 255 + else if (aperture_grille_step < 7) 256 + aperture_grille_mask = 1.0; 257 + else if (aperture_grille_step < 8) 258 + aperture_grille_mask = mod(-8*fragCoord.x, APERTURE_GRILLE_PERIOD) / APERTURE_GRILLE_PERIOD; 259 + 260 + fragColor.rgb *= 1.0 - APERTURE_GRILLE_STRENGTH*aperture_grille_mask; 261 + 262 + 263 + // Add flicker 264 + fragColor *= 1.0 - FLICKER_STRENGTH/2.0*(1.0 + sin(2*PI*FLICKER_FREQUENCY*iTime)); 265 + 266 + 267 + // Add noise 268 + // NOTE: Hard-coded noise distributions 269 + float noiseContent = smoothstep(0.4, 0.6, fract(sin(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y) * iTime * 4096.0) * 65536.0)); 270 + float noiseUniform = smoothstep(0.4, 0.6, fract(sin(uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y) * iTime * 8192.0) * 65536.0)); 271 + fragColor.rgb *= clamp(noiseContent + 1.0 - NOISE_CONTENT_STRENGTH, 0.0, 1.0); 272 + fragColor.rgb = clamp(fragColor.rgb + noiseUniform * NOISE_UNIFORM_STRENGTH, 0.0, 1.0); 273 + 274 + 275 + // NOTE: At this point, RGB values are again within [0, 1] 276 + 277 + 278 + // Remove output outside of screen bounds 279 + if (uv.x < 0.0 || uv.x > 1.0) 280 + fragColor.rgb *= 0.0; 281 + if (uv.y < 0.0 || uv.y > 1.0) 282 + fragColor.rgb *= 0.0; 283 + 284 + 285 + #ifdef BLOOM_SPREAD 286 + // Add bloom 287 + vec2 step = BLOOM_SPREAD * vec2(1.414) / iResolution.xy; 288 + 289 + for (int i = 0; i < 24; i++) { 290 + vec3 bloom_sample = bloom_samples[i]; 291 + vec4 neighbor = texture(iChannel0, uv + bloom_sample.xy * step); 292 + float luminance = 0.299 * neighbor.r + 0.587 * neighbor.g + 0.114 * neighbor.b; 293 + 294 + fragColor += luminance * bloom_sample.z * neighbor * BLOOM_STRENGTH; 295 + } 296 + 297 + fragColor = clamp(fragColor, 0.0, 1.0); 298 + #endif 299 + 300 + 301 + // Add fade effect to smoothen out color transitions 302 + // NOTE: May need to be iTime/iTimeDelta dependent 303 + fragColor = vec4(FADE_FACTOR*fragColor.rgb, FADE_FACTOR); 304 + }
+119
ghostty/mnoise.glsl
··· 1 + vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } 2 + vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } 3 + vec4 permute(vec4 x) { return mod289(((x * 34.0) + 10.0) * x); } 4 + vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } 5 + float snoise(vec3 v) { 6 + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); 7 + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); 8 + 9 + // First corner 10 + vec3 i = floor(v + dot(v, C.yyy)); 11 + vec3 x0 = v - i + dot(i, C.xxx); 12 + 13 + // Other corners 14 + vec3 g = step(x0.yzx, x0.xyz); 15 + vec3 l = 1.0 - g; 16 + vec3 i1 = min(g.xyz, l.zxy); 17 + vec3 i2 = max(g.xyz, l.zxy); 18 + 19 + // x0 = x0 - 0.0 + 0.0 * C.xxx; 20 + // x1 = x0 - i1 + 1.0 * C.xxx; 21 + // x2 = x0 - i2 + 2.0 * C.xxx; 22 + // x3 = x0 - 1.0 + 3.0 * C.xxx; 23 + vec3 x1 = x0 - i1 + C.xxx; 24 + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y 25 + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y 26 + 27 + // Permutations 28 + i = mod289(i); 29 + vec4 p = permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + 30 + vec4(0.0, i1.y, i2.y, 1.0)) + 31 + i.x + vec4(0.0, i1.x, i2.x, 1.0)); 32 + 33 + // Gradients: 7x7 points over a square, mapped onto an octahedron. 34 + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 35 + float n_ = 0.142857142857; // 1.0/7.0 36 + vec3 ns = n_ * D.wyz - D.xzx; 37 + 38 + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) 39 + 40 + vec4 x_ = floor(j * ns.z); 41 + vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) 42 + 43 + vec4 x = x_ * ns.x + ns.yyyy; 44 + vec4 y = y_ * ns.x + ns.yyyy; 45 + vec4 h = 1.0 - abs(x) - abs(y); 46 + 47 + vec4 b0 = vec4(x.xy, y.xy); 48 + vec4 b1 = vec4(x.zw, y.zw); 49 + 50 + // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; 51 + // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; 52 + vec4 s0 = floor(b0) * 2.0 + 1.0; 53 + vec4 s1 = floor(b1) * 2.0 + 1.0; 54 + vec4 sh = -step(h, vec4(0.0)); 55 + 56 + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 57 + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 58 + 59 + vec3 p0 = vec3(a0.xy, h.x); 60 + vec3 p1 = vec3(a0.zw, h.y); 61 + vec3 p2 = vec3(a1.xy, h.z); 62 + vec3 p3 = vec3(a1.zw, h.w); 63 + 64 + // Normalise gradients 65 + vec4 norm = 66 + taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); 67 + p0 *= norm.x; 68 + p1 *= norm.y; 69 + p2 *= norm.z; 70 + p3 *= norm.w; 71 + 72 + // Mix final noise value 73 + vec4 m = 74 + max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); 75 + m = m * m; 76 + return 105.0 * 77 + dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); 78 + } 79 + 80 + float noise2D(vec2 uv) { 81 + uvec2 pos = uvec2(floor(uv * 1000.)); 82 + return float((pos.x * 68657387u ^ pos.y * 361524851u + pos.x) % 890129u) * 83 + (1.0 / 890128.0); 84 + } 85 + 86 + float roundRectSDF(vec2 center, vec2 size, float radius) { 87 + return length(max(abs(center) - size + radius, 0.)) - radius; 88 + } 89 + 90 + void mainImage(out vec4 fragColor, in vec2 fragCoord) { 91 + vec2 uv = fragCoord / iResolution.xy, sd = vec2(2.), sdh = vec2(1.); 92 + vec4 ghosttyCol = texture(iChannel0, uv); 93 + float ratio = iResolution.y / iResolution.x, 94 + fw = max(fwidth(uv.x), fwidth(uv.y)); 95 + 96 + vec2 puv = floor(uv * vec2(60., 60. * ratio)) / 60.; 97 + puv += 98 + (smoothstep(0., 0.7, noise2D(puv)) - 0.5) * 0.05 - vec2(0., iTime * 0.08); 99 + 100 + uv = fract(vec2(uv.x, uv.y * ratio) * 10.); 101 + float d = roundRectSDF((sd + 0.01) * (uv - .5), sdh, 0.075), 102 + d2 = roundRectSDF((sd + 0.065) * (fract(uv * 6.) - .5), sdh, 0.2), 103 + noiseTime = iTime * 0.03, noise = snoise(vec3(puv, noiseTime)); 104 + 105 + noise += snoise(vec3(puv * 1.1, noiseTime + 0.5)) + .1; 106 + noise += snoise(vec3(puv * 2., noiseTime + 0.8)); 107 + noise = pow(noise, 2.); 108 + 109 + vec3 col1 = vec3(0.), col2 = vec3(0.), col3 = vec3(0.07898), 110 + col4 = vec3(0.089184), 111 + fcol = mix(mix(mix(col1, col3, smoothstep(0.0, 0.3, noise)), col2, 112 + smoothstep(0.0, 0.5, noise)), 113 + col4, smoothstep(0.0, 1.0, noise)); 114 + 115 + fragColor = vec4( 116 + ghosttyCol.rgb + 117 + mix(col4, fcol, smoothstep(fw, -fw, d) * smoothstep(fw, -fw, d2)), 118 + ghosttyCol.a); 119 + }
+34
ghostty/retro-terminal.glsl
··· 1 + // Original shader collected from: https://www.shadertoy.com/view/WsVSzV 2 + // Licensed under Shadertoy's default since the original creator didn't provide any license. (CC BY NC SA 3.0) 3 + // Slight modifications were made to give a green-ish effect. 4 + 5 + float warp = 0.25; // simulate curvature of CRT monitor 6 + float scan = 0.50; // simulate darkness between scanlines 7 + 8 + void mainImage(out vec4 fragColor, in vec2 fragCoord) 9 + { 10 + // squared distance from center 11 + vec2 uv = fragCoord / iResolution.xy; 12 + vec2 dc = abs(0.5 - uv); 13 + dc *= dc; 14 + 15 + // warp the fragment coordinates 16 + uv.x -= 0.5; uv.x *= 1.0 + (dc.y * (0.3 * warp)); uv.x += 0.5; 17 + uv.y -= 0.5; uv.y *= 1.0 + (dc.x * (0.4 * warp)); uv.y += 0.5; 18 + 19 + // sample inside boundaries, otherwise set to black 20 + if (uv.y > 1.0 || uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0) 21 + fragColor = vec4(0.0, 0.0, 0.0, 1.0); 22 + else 23 + { 24 + // determine if we are drawing in a scanline 25 + float apply = abs(sin(fragCoord.y) * 0.5 * scan); 26 + 27 + // sample the texture and apply a teal tint 28 + vec3 color = texture(iChannel0, uv).rgb; 29 + vec3 tealTint = vec3(0.0, 0.8, 0.6); // teal color (slightly more green than blue) 30 + 31 + // mix the sampled color with the teal tint based on scanline intensity 32 + fragColor = vec4(mix(color * tealTint, vec3(0.0), apply), 1.0); 33 + } 34 + }
+145
ghostty/starfield-colors.glsl
··· 1 + // divisions of grid 2 + const float repeats = 30.; 3 + 4 + // number of layers 5 + const float layers = 21.; 6 + 7 + // star colours 8 + const vec3 blue = vec3(51.,64.,195.)/255.; 9 + const vec3 cyan = vec3(117.,250.,254.)/255.; 10 + const vec3 white = vec3(255.,255.,255.)/255.; 11 + const vec3 yellow = vec3(251.,245.,44.)/255.; 12 + const vec3 red = vec3(247,2.,20.)/255.; 13 + 14 + // spectrum function 15 + vec3 spectrum(vec2 pos){ 16 + pos.x *= 4.; 17 + vec3 outCol = vec3(0); 18 + if( pos.x > 0.){ 19 + outCol = mix(blue, cyan, fract(pos.x)); 20 + } 21 + if( pos.x > 1.){ 22 + outCol = mix(cyan, white, fract(pos.x)); 23 + } 24 + if( pos.x > 2.){ 25 + outCol = mix(white, yellow, fract(pos.x)); 26 + } 27 + if( pos.x > 3.){ 28 + outCol = mix(yellow, red, fract(pos.x)); 29 + } 30 + 31 + return 1.-(pos.y * (1.-outCol)); 32 + } 33 + 34 + float N21(vec2 p) { 35 + p = fract(p * vec2(233.34, 851.73)); 36 + p += dot(p, p + 23.45); 37 + return fract(p.x * p.y); 38 + } 39 + 40 + vec2 N22(vec2 p) { 41 + float n = N21(p); 42 + return vec2(n, N21(p + n)); 43 + } 44 + 45 + mat2 scale(vec2 _scale) { 46 + return mat2(_scale.x, 0.0, 47 + 0.0, _scale.y); 48 + } 49 + 50 + // 2D Noise based on Morgan McGuire 51 + float noise(in vec2 st) { 52 + vec2 i = floor(st); 53 + vec2 f = fract(st); 54 + 55 + // Four corners in 2D of a tile 56 + float a = N21(i); 57 + float b = N21(i + vec2(1.0, 0.0)); 58 + float c = N21(i + vec2(0.0, 1.0)); 59 + float d = N21(i + vec2(1.0, 1.0)); 60 + 61 + // Smooth Interpolation 62 + vec2 u = f * f * (3.0 - 2.0 * f); // Cubic Hermite Curve 63 + 64 + // Mix 4 corners percentages 65 + return mix(a, b, u.x) + 66 + (c - a) * u.y * (1.0 - u.x) + 67 + (d - b) * u.x * u.y; 68 + } 69 + 70 + float perlin2(vec2 uv, int octaves, float pscale) { 71 + float col = 1.; 72 + float initScale = 4.; 73 + for (int l; l < octaves; l++) { 74 + float val = noise(uv * initScale); 75 + if (col <= 0.01) { 76 + col = 0.; 77 + break; 78 + } 79 + val -= 0.01; 80 + val *= 0.5; 81 + col *= val; 82 + initScale *= pscale; 83 + } 84 + return col; 85 + } 86 + 87 + vec3 stars(vec2 uv, float offset) { 88 + float timeScale = -(iTime + offset) / layers; 89 + float trans = fract(timeScale); 90 + float newRnd = floor(timeScale); 91 + vec3 col = vec3(0.); 92 + 93 + // Translate uv then scale for center 94 + uv -= vec2(0.5); 95 + uv = scale(vec2(trans)) * uv; 96 + uv += vec2(0.5); 97 + 98 + // Create square aspect ratio 99 + uv.x *= iResolution.x / iResolution.y; 100 + 101 + // Create boxes 102 + uv *= repeats; 103 + 104 + // Get position 105 + vec2 ipos = floor(uv); 106 + 107 + // Return uv as 0 to 1 108 + uv = fract(uv); 109 + 110 + // Calculate random xy and size 111 + vec2 rndXY = N22(newRnd + ipos * (offset + 1.)) * 0.9 + 0.05; 112 + float rndSize = N21(ipos) * 100. + 200.; 113 + 114 + vec2 j = (rndXY - uv) * rndSize; 115 + float sparkle = 1. / dot(j, j); 116 + 117 + // Set stars to be pure white 118 + col += spectrum(fract(rndXY*newRnd*ipos)) * vec3(sparkle); 119 + 120 + col *= smoothstep(1., 0.8, trans); 121 + return col; // Return pure white stars only 122 + } 123 + 124 + void mainImage( out vec4 fragColor, in vec2 fragCoord ) 125 + { 126 + // Normalized pixel coordinates (from 0 to 1) 127 + vec2 uv = fragCoord/iResolution.xy; 128 + 129 + vec3 col = vec3(0.); 130 + 131 + for (float i = 0.; i < layers; i++ ){ 132 + col += stars(uv, i); 133 + } 134 + 135 + // Sample the terminal screen texture including alpha channel 136 + vec4 terminalColor = texture(iChannel0, uv); 137 + 138 + // Make a mask that is 1.0 where the terminal content is not black 139 + float mask = 1 - step(0.5, dot(terminalColor.rgb, vec3(1.0))); 140 + vec3 blendedColor = mix(terminalColor.rgb, col, mask); 141 + 142 + // Apply terminal's alpha to control overall opacity 143 + fragColor = vec4(blendedColor, terminalColor.a); 144 + 145 + }